在之前的博客《Redis实战总结-配置、持久化、复制》给出了一种Redis主从复制机制,简单地实现了Redis高可用。然后,如果Master服务器宕机,会导致整个Redis瘫痪,这种方式的高可用性较低。正常会采用多台Redis服务器构成一个集群,即使某台,或者某几台Redis宕机,Redis集群仍能正常运行,从而提高其高可用性。
在Redis中,主要存在两种方式实现Redis集群机制:
Redis Sentinel集群机制:在Redis2.X版本,往往都是通过这种方式实现Redis的高可用。redis-sentinel是在master-slave机制上加入监控机制哨兵Sentinel实现的。
Redis Cluster集群机制:在Redis3.0版本后推出了redis-cluster集群机制。redis-cluster集群中各个节点之间是对等的,即master-master模式。
**注意:**Redis Sentinel集群是解决HA问题的(主从同步),Redis Cluster集群是解决sharding问题的(分区),两种不重复,可以混合使用。
- Sharding机制:http://blog.csdn.net/basycia/article/details/52013098
- HA机制:https://baike.baidu.com/item/%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7(HA)/2355576
下面详解这两种集群,并给出具体的演示示例。
1. Redis Sentinel集群机制
Redis-Sentinel是在master-slave机制上加入监控机制哨兵Sentinel实现的。Sentinel主要功能就是为Redis Master-Slave集群提供:
- 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
在Sentinel集群中,一个最小的Master-Slave单元包含一个master和一个slave服务器。当master失效后,sentinel自动将slave提升为master,从而可以减少管理员的人工切换slave的操作过程。
1.1 Redis-Sentinel集群架构图
1.2 各个机器配置
部署在本地机器上,保证各个端口号不一样,具体配置如下
-
Redis服务器:
- master:127.0.0.1:6379
- slave01:127.0.0.1:6389
- slave02:127.0.0.1:6399
-
Sentinel服务器
- sentinel01:127.0.0.1:26379
- sentinel02:127.0.0.1:26389
- sentinel03:127.0.0.1:26399
1.3 redis.conf和sentinel.conf配置
-
redis.conf
- master特殊配置如下:
# 后台线程启动 daemonize yes # 监听端口号 port 6379 # 访问验证密码 requirepass "123456" -
- slave特殊配置如下:
# 后台线程启动 daemonize yes # 监听端口号,如果为slave02,端口号为6399 port 6389 # 主节点访问密码 masterauth "123456" # 访问验证密码 requirepass "123456" # 主节点服务器IP和端口号 slaveof 127.0.0.1 6379 sentinel.conf
# 后台线程启动
daemonize yes
# 监听端口号,如果为sentinel02,则端口号为26389,如果为sentinel01,则端口号为26399
port 26379
#1表示在sentinel集群中只要有两个节点检测到redis主节点出故障就进行切换
sentinel monitor mymaster 127.0.0.1 6379 1
# master节点密码验证
sentinel auth-pass mymaster 123456
#如果3秒内mymaster无响应,则认为mymaster宕机了
sentinel down-after-milliseconds mymaster 3000
# 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长
sentinel parallel-syncs mymaster 1
#如果10秒后,mysater仍没活过来,则启动failover
sentinel failover-timeout mymaster 10000
注意:
- 1.如果上述涉及的所有配置均放置在同一目录下,需保证各配置名称不同;
- 2.在配置中,不同实例的日志输出、快照文件要求名称不能一样,具体可自行配置;
- 3.一定要保证”sentinel myid”不相同,否则无法进行故障转移
1.4 启动集群及启动后结果详情展示
-
各Redis节点启动:
redis-server redis_****.conf
-
各Sentinel节点启动
redis-sentinel sentinel_*****.conf
- Redis Master节点详情展示
Redis Slave节点效果截图展示
各个Sentinel节点详情展示
1.5 高可用性场景测试
- Master宕机
- sentinel使用failover机制重新选举出master
- Master恢复
- master节点恢复后,由Master变成slave
- Slave宕机
- 哨兵发现6399已经宕机,等待6399的恢复(主观下线)
- Slave重启6399节点
如果想详细了解sentinel机制的话,可以参考博客:
http://shift-alt-ctrl.iteye.com/blog/1884370
2. Redis Cluster集群机制
2.1 Redis-cluster介绍
Redis-cluster是一种服务器Sharding技术,Redis3.0以后版本正式提供支持。
Redis-cluster没有使用一致性hash,而是引入了哈希槽的概念。Redis-cluster中有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。Cluster中的每个节点负责一部分hash槽(hash slot),比如集群中存在三个节点,则可能存在的一种分配如下:
- 节点A包含0到5500号哈希槽;
- 节点B包含5501到11000号哈希槽;
- 节点C包含11001 到 16384号哈希槽。
这种集群架构很容易扩展,如果扩充一个节点D,只需要将A、B、C节点中的部分槽放置在D上;如果想移除节点A,只需要将A的slot转移到B和C节点上。由于将哈希槽从一个节点移动到另一个节点不需要停止服务,只需要通过命令直接再分配,因而上述拓展不会造成集群不可用。目前这种方式还是一种半自动的方式,需要人工介入。
2.2 Redis-Cluster主从复制
在Redis-Cluster中,如果某个节点宕机或者处在不可用状态时,那它负责的Hash槽也将失效,导致整个集群不可用。因而为了提供高可用性,正常会将每个节点配置成主从式结构,即一个master节点,挂在多个slave节点。如果Master节点失效时,集群便会选取一个slave节点作为master,继续提供服务,从而不会导致整个集群不可用。
2.3 Redis-Cluster集群模拟
2.3.1 Redis-Cluster集群准备
- 集群部署图
-
集群由三个节点组成,每个节点均为主从式架构。因而共需要创建6个Redis实例,分配如下:
- Redis01:127.0.0.1:7000
- Redis02:127.0.0.1:7001
- Redis03:127.0.0.1:7002
- Redis04:127.0.0.1:7003
- Redis05:127.0.0.1:7004
- Redis06:127.0.0.1:7005
对于每个实例的redis_700*.conf配置如下:
# 监听端口号
port 700*
# 开启集群
cluster-enabled yes
# 修改集群加载配置文件,不需要手动创建,启动后默认生成,并且需要时自动更新
cluster-config-file /Users/guweiyu/develop/redis/redis-cluster/workpid/nodes-7000.conf
# 集群中的节点能够失联的最大时间,超过这个时间,该节点就会被认为故障
cluster-node-timeout 15000
# 默认为“no”,表示部分Key所在的节点不可用时,集群仍然为可达节点提供服务;如果为“yes”,表示部分key所在的节点不可用时,则整个集群停止服务。注意:实际使用中要修改为"yes"
cluster-require-full-coverage no -
安装ruby,如果为Mac OS系统,直接执行即可:
brew install ruby
2.3.2 集群启动
-
启动所有Redis实例,可以编写一个启动和停止所有redis实例的脚本(start.sh,stop.sh)
redis-server redis_7000.conf
redis-server redis_7001.conf
redis-server redis_7002.conf
redis-server redis_7003.conf
redis-server redis_7004.conf
redis-server redis_7005.conf ps -ef | grep redis-server
echo "redis 7000-7005全部启动完成" redis-cli -p 7000 shutdown
redis-cli -p 7001 shutdown
redis-cli -p 7002 shutdown
redis-cli -p 7003 shutdown
redis-cli -p 7004 shutdown
redis-cli -p 7005 shutdown ps -ef | grep redis-server
echo "redis-server 7000-7005节点已全部停止"
1创建redis-cluster
Redis中创建集群是通过redis-trib.rb命令实现的,redis-trib.rb位于Redis源码的src目录下,可将其直接拷贝到当前目录下。
运行命令
./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
如果出现如下错误:
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- redis (LoadError)
from /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from ./redis-trib.rb:25:in `<main>'
这是由于没有安装redis的第三方接口导致的。因此需要给Ruby安装client包,如下(必须加上sudo执行,否则会执行失败):
sudo gem install redis
再执行创建集群命令,结果如下:
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
Adding replica 127.0.0.1:7004 to 127.0.0.1:7000
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
Adding replica 127.0.0.1:7003 to 127.0.0.1:7002
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: aab0162a039d2f224322afe6caf2e153230f2d82 127.0.0.1:7000
slots:0-5460 (5461 slots) master
M: 058204226f52757925a606b9697a8e39756bfdff 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
M: 857075aef280cf35cd369ebc30738cd31c05e479 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
S: 7dac141fa9510315905f505be52bba0208c391ab 127.0.0.1:7003
replicates aab0162a039d2f224322afe6caf2e153230f2d82
S: 65a2bc432e5930e97f0fd172eb838af9f07229b6 127.0.0.1:7004
replicates 058204226f52757925a606b9697a8e39756bfdff
S: 3d2a665d2e2eb28acb0a187c1a0b4bbce9ce87d2 127.0.0.1:7005
replicates 857075aef280cf35cd369ebc30738cd31c05e479
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join...
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: aab0162a039d2f224322afe6caf2e153230f2d82 127.0.0.1:7000
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: 3d2a665d2e2eb28acb0a187c1a0b4bbce9ce87d2 127.0.0.1:7005
slots: (0 slots) slave
replicates 857075aef280cf35cd369ebc30738cd31c05e479
S: 65a2bc432e5930e97f0fd172eb838af9f07229b6 127.0.0.1:7004
slots: (0 slots) slave
replicates 058204226f52757925a606b9697a8e39756bfdff
S: 7dac141fa9510315905f505be52bba0208c391ab 127.0.0.1:7003
slots: (0 slots) slave
replicates aab0162a039d2f224322afe6caf2e153230f2d82
M: 857075aef280cf35cd369ebc30738cd31c05e479 127.0.0.1:7002
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: 058204226f52757925a606b9697a8e39756bfdff 127.0.0.1:7001
slots:5461-10922 (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
创建成功,16384个Hash槽分配完成,所有节点(Master和slave节点)均已加入到集群中。三个Master节点分配的Hash槽及从节点如下:
-
Master01:127.0.0.1:7000
M: aab0162a039d2f224322afe6caf2e153230f2d82
slots:0-5460 (5461 slots) master
127.0.0.1:7004 to 127.0.0.1:7000 Master02:127.0.0.1:7001
M: 058204226f52757925a606b9697a8e39756bfdff
slots:5461-10922 (5462 slots) master
127.0.0.1:7005 to 127.0.0.1:7001M: 857075aef280cf35cd369ebc30738cd31c05e479
slots:10923-16383 (5461 slots) master
127.0.0.1:7003 to 127.0.0.1:7002
Master03:127.0.0.1:7002
2.3.3 集群测试
- 测试集群存取值
客户端命令redis-cli连接集群需要带上”-c”, 比如redis-cli -c -p 端口号
127.0.0.1:7000> set test1 guweiyu
OK
127.0.0.1:7000> set name guweiyu
-> Redirected to slot [5798] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get name
"guweiyu"
127.0.0.1:7001> get test1
-> Redirected to slot [4768] located at 127.0.0.1:7000
"guweiyu"
127.0.0.1:7000>
测试发现”set test1 guweiyu”,直接返回OK,说明该值就是存储在7000上,执行“set name guweiyu”发生了Redirected到7001上,获取的时候,同样出现上述情况。这个是Redis Cluster去中心特性,访问集群中的任一节点,均可直接操作集群。
主节点宕机测试
从节点宕机