Redis HA
一、Sentinel
HA的关键在于避免单点故障及故障恢复,在Redis Cluster未发布之前,Redis一般以主/从方式部署(这里讨论的应用从实例主要用于备份,主实例提供读写,有不少应用是读写分离的,读写操作需要取不同的Redis实例,该方案也可用于此种应用,原理都是相通的,区别在于数据操作层如何封装),该方式要实现HA主要有如下几种方案:
1,keepalived:通过keepalived的虚拟IP,提供主从的统一访问,在主出现问题时,通过keepalived运行脚本将从提升为主,待主恢复后先同步后自动变为主,该方案的好处是主从切换后,应用程序不需要知道(因为访问的虚拟IP不变),坏处是引入keepalived增加部署复杂性;
2,zookeeper:通过zookeeper来监控主从实例,维护最新有效的IP,应用通过zookeeper取得IP,对Redis进行访问;
3,sentinel:通过Sentinel监控主从实例,自动进行故障恢复,该方案有个缺陷:因为主从实例地址(IP&PORT)是不同的,当故障发生进行主从切换后,应用程序无法知道新地址,故在Jedis2.2.2中新增了对Sentinel的支持,应用通过redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis实例会及时更新到新的主实例地址。
Sentinel有如下功能:
- 监控(Monitoring):Sentinel不断的去检查你的主从实例是否按照预期在工作。
- 通知(Notification):Sentinel可以通过一个api来通知系统管理员或者另外的应用程序,被监控的Redis实例有一些问题。
- 自动故障转移(Automatic failover):如果一个主节点没有按照预期工作,Sentinel会开始故障转移过程,把一个从节点提升为主节点,并重新配置其他的从节点使用新的主节点,使用Redis服务的应用程序在连接的时候也被通知新的地址。
- 配置提供者(Configuration provider):Sentinel给客户端的服务发现提供来源:对于一个给定的服务,客户端连接到Sentinels来寻找当前主节点的地址。当故障转移发生的时候,Sentinels将报告新的地址。
- 一个健康的集群部署,至少需要三个Sentinel实例,三个Sentinel实例应该被放在失败独立的电脑上或虚拟机中,比如说不同的物理机或者在不同的可用区域上执行的虚拟机。Sentinel + Redis 分布式系统在失败期间并不确保写入请求被保存,因为Redis使用异步拷贝。可是有很多部署Sentinel的 方式来让窗口把丢失写入限制在特定的时刻,当然也有另外的不安全的方式来部署。
- 典型的Sentinel配置如下:
-
- sentinel monitor mymaster 127.0.0.1 6379 2
- sentinel down-after-milliseconds mymaster 60000
- sentinel failover-timeout mymaster 180000
- sentinel parallel-syncs mymaster 1
- sentinel monitor resque 192.168.1.3 6380 4
- sentinel down-after-milliseconds resque 10000
- sentinel failover-timeout resque 180000
- sentinel parallel-syncs resque 5
-
配置中Sentinel分别监控名为mymaster以及resque的master节点,Sentinel通过pub/sub机制自动感知配置在master上的slave节点。具体的Sentinel原理以及配置可见官方文档的翻译文档:翻译文档 - 也可以参考另外一个博主的博客,介绍的很详细:点击打开链接
二 、sharding
-
sharding机制:即通常所说的“分片”,允许数据存放在不同的物理机器上, 以适应数据量过大的场景,克服单台机器内存或者磁盘空间的限制。Redis并不支持服务器端分片(redis3.0开始支持了),不过我们可以使用Jedis提供的API来实现客户端的分片,通过“一致性hash”算法,使得数据离散地存放在不同的服务器上面。
接下来分析一下ShardedJedis的源码,ShardedJedis的工厂类:
其中包含三个参数,Shards列表,包含所有分片信息,algo表示使用的一致性哈希算法,keyTagPattern表示一致性哈希的key pattern。ShardedJedis包含了一个所有datasource的List:
SharderJedis的构造方法调用了Sharded类的构造方法,在Sharded方法中:
1 定义了一个TreeMap ,TreeMap 用于存储虚拟节点(在初始化方法中,将每台服务器节点采用hash算法划分为160个(默认的,DEFAULT_WEIGHT)虚拟节点(当然也可以配置划分权重)
2 定义一个LinkedHashMap,用于存储每一个Redis服务器的物理连接
其中shardInfo的createResource就是物理连接信息 。构造完成后,client可以通过Sharded Jedis执行相应的redis操作,我们接下来以set为例:
其一般过程就是根据key获取key对应的Jedis信息,然后再进行数据的操作,在上面我们知道resources(LinkedHashMap)用于存储每一个Redis服务器的物理连接,其key为shardedInfo对象,value为Jedis实例,因此只需要根据shardedInfo对象就可以找到jedis实例。具体获得ShardInfo的过程如下:
1)对于key采用与初始化时同样的hash(MurmurHash或者MD5)算法,然后从TreeMap获取大于等于键hash值得节点,取最邻近节点;
2)当key的hash值大于虚拟节点hash值得最大值时(也就是tail为空),取第一个虚拟节点。