由于项目需要,研究了一下redis的集群方式,记录如下:
环境:centos7,由于是测试,我就把三个redis放在一台机子上了。反正redis是单线程的,倒也无所谓。
redis集群的方式有好几种,分类下来其实大概是四种:
1.redis本身的集群。redis3.x开始引入了redis-cluster,是redis官方推出的集群方式,官方文档中也全面地说明了设计成当前这个鸟样的原因,这个无可非议,然而这也带来了redis-cluster本身无法保证能稳定地在正式生产环境中使用的几个问题,例如无法解决脑裂问题、迁移困难(这货用的不是一致性哈希,而是引入了类似于HashMap那样哈希槽的概念)、去中心化设计带来的多数选举的问题,以及我们组的leader被坑了的一个节点死掉,集群全部不能用的问题。由于不能保证在正式环境中稳定使用,直接否决。
2.加代理。加代理本身可选的就比较多了,比较常用的就有豌豆荚的codis、推特的Twemproxy。其中Twemproxy本身配置使用比较简单,应用广泛,但是却不能平滑地增加删除redis节点,一旦增加节点,工作量很大;而且这货没有监控界面。与之相反,codis就有监控界面,而且能平滑地增减redis节点,相对来说更优秀。增加一层代理要增加对访问的转发,肯定会降低效率,但相对来讲还是可以接受的。对比之下我就先测试了codis,后文讲放弃codis的原因。
3. 使用之前的哨兵模式。哨兵模式既可以用来做高可用,也可以结合高可用做集群分片。确实是个好东西,但依然有些问题,那就是jedis。jedis支持集群,然而这货的SharedJedisPool碰到哨兵模式就蒙圈了,不知道为何jedis官方选择忽略对这个被广泛用于redis集群的方案的支持。好在有人写了对应的连接池分片Sentinel连接池实现,这玩意儿估计用着就飞起了。我没用分片集群,直接用的是sentinel支持的高可用,一主多从的配置,后文讲原因。
4.自己分片。这个很猛的,不过现在的敏捷开发阶段不太适用这种方式,这玩意儿考虑的问题比较多,周期拉的太长会耽误项目进度的。下了班之余可以玩玩。
以上四种方式中,我首先测试的是codis,即第二种方案。对codis的测试可谓一波三折。codis是用go语言写的,安装go环境就够折腾的;之后搭建zookeeper集群倒是很顺利,但随即发现github下载地址总是无法下载release版的codis,无奈通过centos命令行下载源码自己编译。好不容易编译完毕,配置的复杂又让我眼前一黑,艰苦地搞定之后,死活启动不起来。无奈之下放弃codis。codis是个好东西,不过依赖环境繁杂也就罢了,本身的配置有些太麻烦了,怪不得很多博客里面都写到,联系了codis的作者,看来不联系要费好长时间还未必能搞定。
放弃的时候我想起了leader的话,leader说咱们做的这个玩意儿压力没那么大,追求的是稳定性。好,方向直指高可用,于是我直奔哨兵模式就过去了。sentinel的分片可以后续考虑,先搞定高可用,一主多从上上上。本文就是记录的这个过程。
步骤一:安装redis
我扒拉了一台正在用的测试服务器,开始搞测试。为了便于随后删除测试的东西,我把redis都装在根目录下建立的一个目录里了。
下载redis-3.2.8.tar.gz,由于不能直接下载,我到官网下载的,放在这个目录下。然后分出三个目录,redis1、redis2、redis3
cd /crmtestXieHao
tar -zxvf redis-3.2.8.tar.gz
mv redis-3.2.8 /crmtestXieHao/redis1
这样就把一个redis解压到了redis1目录下。如法炮制,依次解压了放到redis2、redis3下面。这样就有了三台redis的未编译版本。
下面开始挨个编译安装,以redis1为例:
cd /crmtestXieHao/redis1/redis-3.2.8
make && make install && make test
上面这个命令在redis2、redis3目录下的redis解压目录里各执行一遍,编译安装redis就完毕了。其实不用make test也一样,不过对我这样一个强迫症患者来说,一定要搞好每一步。但是make test命令需要依赖一个tcl8.6.1-src.tar.gz的玩意儿,下载了安装就行了,不费事儿。
另外,需要在redis1、redis2、redis3下各新建一个data目录、temp目录,分别用来作为redis的数据目录和sentinel的目录。
步骤二:配置redis.conf
安装完毕就要开始配置了。由于是一主多从的架子,所以我选择redis1为主,redis2、redis3为从。在每个redis解压目录下都有一个redis.conf,先修改主redis的配置。
bind 192.168.5.17
protected-mode no
port 6379
daemonize yes
pidfile "/var/run/redis_6379.pid"
dir "/crmtestXieHao/redis1/data"
slave-priority 100
appendonly yes
appendfsync everysec
从节点redis2的redis.conf配置
bind 192.168.5.17
protected-mode no
port 6380
daemonize yes
pidfile "/var/run/redis_6380.pid"
dir "/crmtestXieHao/redis2/data"
slaveof 192.168.5.17 6379
slave-read-only yes
slave-priority 90
appendonly yes
appendfsync everysec
从节点redis3的redis.conf配置
bind 192.168.5.17
protected-mode no
port 6381
daemonize yes
pidfile "/var/run/redis_6381.pid"
dir "/crmtestXieHao/redis3/data"
slaveof 192.168.5.17 6379
slave-read-only yes
slave-priority 80
appendonly yes
appendfsync everysec
步骤三:配置sentinel.conf
在每个redis的目录下,与redis.conf并列的各有一个sentinel.conf文件,这就是哨兵的配置。每个redis都有一个哨兵,其配置基本相同。分别罗列如下:
redis1下的sentinel.conf
protected-mode no
port 26379
dir "/crmtestXieHao/redis1/temp"
sentinel monitor redis1 192.168.5.17 6379 2
sentinel down-after-milliseconds redis1 10000
sentinel failover-timeout redis1 60000
redis2下的sentinel.conf
protected-mode no
port 26380
dir "/crmtestXieHao/redis2/temp"
sentinel monitor redis1 192.168.5.17 6379 2
sentinel down-after-milliseconds redis1 10000
sentinel failover-timeout redis1 60000
redis3下的sentinel.conf
protected-mode no
port 26381
dir "/crmtestXieHao/redis3/temp"
sentinel monitor redis1 192.168.5.17 6379 2
sentinel down-after-milliseconds redis1 10000
sentinel failover-timeout redis1 60000
步骤四:启动redis和sentinel
依次启动redis1、redis2、redis3
cd /crmtestXieHao/redis1/redis-3.2.8/src
./redis-server /crmtestXieHao/redis1/redis-3.2.8/redis.conf &
cd /crmtestXieHao/redis2/redis-3.2.8/src
./redis-server /crmtestXieHao/redis2/redis-3.2.8/redis.conf &
cd /crmtestXieHao/redis3/redis-3.2.8/src
./redis-server /crmtestXieHao/redis3/redis-3.2.8/redis.conf &
依次启动每台redis的哨兵
cd /crmtestXieHao/redis1/redis-3.2.8/src
./redis-sentinel /crmtestXieHao/redis1/redis-3.2.8/sentinel.conf &
cd /crmtestXieHao/redis2/redis-3.2.8/src
./redis-sentinel /crmtestXieHao/redis2/redis-3.2.8/sentinel.conf &
cd /crmtestXieHao/redis3/redis-3.2.8/src
./redis-sentinel /crmtestXieHao/redis3/redis-3.2.8/sentinel.conf &
步骤五:各个redis状态查看
redis1、redis2、redis3状态查看命令cd /crmtestXieHao/redis1/redis-3.2.8/src
./redis-cli -h 192.168.5.17 -p 6379 info Replication
./redis-cli -h 192.168.5.17 -p 6380 info Replication
./redis-cli -h 192.168.5.17 -p 6381 info Replication
由于主redis是可读可写的,从redis是只读的,所以可以进入client往主redis里塞入数据查看
cd /crmtestXieHao/redis1/redis-3.2.8/src
./redis-cli -h 192.168.5.17 -p 6379
192.168.5.17:6379> set name xiehao
OK
192.168.5.17:6379> get name
"xiehao"
从redis测试:
./redis-cli -h 192.168.5.17 -p 6380
192.168.5.17:6380> set aa test
(error) READONLY You can't write against a read only slave.
192.168.5.17:6380> get name
"xiehao"
步骤六:failover测试
./redis-cli -h 192.168.5.17 -p 6379
192.168.5.17:6379> PING
PONG
192.168.5.17:6379> SHUTDOWN
not connected>
[root@b2b-3 src]# 23841:X 05 May 07:55:45.653 # +sdown master redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.679 # +sdown master redis1 192.168.5.17 6379
23827:X 05 May 07:55:45.708 # +sdown master redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.750 # +odown master redis1 192.168.5.17 6379 #quorum 2/2
23833:X 05 May 07:55:45.750 # +new-epoch 1
23833:X 05 May 07:55:45.750 # +try-failover master redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.766 # +vote-for-leader bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 1
23841:X 05 May 07:55:45.783 # +new-epoch 1
23827:X 05 May 07:55:45.783 # +new-epoch 1
23827:X 05 May 07:55:45.799 # +vote-for-leader bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 1
23841:X 05 May 07:55:45.799 # +vote-for-leader bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 1
23827:X 05 May 07:55:45.799 # +odown master redis1 192.168.5.17 6379 #quorum 3/2
23827:X 05 May 07:55:45.799 # Next failover delay: I will not start a failover before Fri May 5 07:57:46 2017
23833:X 05 May 07:55:45.799 # b570d53fe425a4bc6bcdd1a882c4e8a0a4cf0402 voted for bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 1
23833:X 05 May 07:55:45.799 # c0771e8b12ec534794e9e384ff99c787526d79ea voted for bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 1
23833:X 05 May 07:55:45.818 # +elected-leader master redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.818 # +failover-state-select-slave master redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.885 # +selected-slave slave 192.168.5.17:6381 192.168.5.17 6381 @ redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.885 * +failover-state-send-slaveof-noone slave 192.168.5.17:6381 192.168.5.17 6381 @ redis1 192.168.5.17 6379
23833:X 05 May 07:55:45.940 * +failover-state-wait-promotion slave 192.168.5.17:6381 192.168.5.17 6381 @ redis1 192.168.5.17 6379
23841:X 05 May 07:55:46.755 # +odown master redis1 192.168.5.17 6379 #quorum 3/2
23841:X 05 May 07:55:46.756 # Next failover delay: I will not start a failover before Fri May 5 07:57:46 2017
23833:X 05 May 07:55:46.887 # +promoted-slave slave 192.168.5.17:6381 192.168.5.17 6381 @ redis1 192.168.5.17 6379
23833:X 05 May 07:55:46.887 # +failover-state-reconf-slaves master redis1 192.168.5.17 6379
23833:X 05 May 07:55:46.957 * +slave-reconf-sent slave 192.168.5.17:6380 192.168.5.17 6380 @ redis1 192.168.5.17 6379
23841:X 05 May 07:55:46.958 # +config-update-from sentinel bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 192.168.5.17 26380 @ redis1 192.168.5.17 6379
23841:X 05 May 07:55:46.958 # +switch-master redis1 192.168.5.17 6379 192.168.5.17 6381
23827:X 05 May 07:55:46.958 # +config-update-from sentinel bc2ff5fd48c6b477f2174127f9dd0f23fcef94cc 192.168.5.17 26380 @ redis1 192.168.5.17 6379
23827:X 05 May 07:55:46.958 # +switch-master redis1 192.168.5.17 6379 192.168.5.17 6381
23841:X 05 May 07:55:46.958 * +slave slave 192.168.5.17:6380 192.168.5.17 6380 @ redis1 192.168.5.17 6381
23841:X 05 May 07:55:46.958 * +slave slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23827:X 05 May 07:55:46.958 * +slave slave 192.168.5.17:6380 192.168.5.17 6380 @ redis1 192.168.5.17 6381
23827:X 05 May 07:55:46.958 * +slave slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23833:X 05 May 07:55:47.909 # -odown master redis1 192.168.5.17 6379
23833:X 05 May 07:55:47.910 * +slave-reconf-inprog slave 192.168.5.17:6380 192.168.5.17 6380 @ redis1 192.168.5.17 6379
23833:X 05 May 07:55:47.910 * +slave-reconf-done slave 192.168.5.17:6380 192.168.5.17 6380 @ redis1 192.168.5.17 6379
23833:X 05 May 07:55:47.967 # +failover-end master redis1 192.168.5.17 6379
23833:X 05 May 07:55:47.967 # +switch-master redis1 192.168.5.17 6379 192.168.5.17 6381
23833:X 05 May 07:55:47.967 * +slave slave 192.168.5.17:6380 192.168.5.17 6380 @ redis1 192.168.5.17 6381
23833:X 05 May 07:55:47.967 * +slave slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23827:X 05 May 07:55:56.999 # +sdown slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23841:X 05 May 07:55:57.012 # +sdown slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23833:X 05 May 07:55:57.993 # +sdown slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
可以看到日志
23833:X 05 May 07:55:47.967 # +switch-master redis1 192.168.5.17 6379 192.168.5.17 6381
哨兵将挂机的6379主redis切换成6381的redis节点。哨兵模式下,系统会根据我们配置在redis.conf中的slave-priority,选出slave-priority值最小的推举成新的master主节点。如果之前的主节点再次启动,将会以从节点的形式挂到主节点下,我们启动试试
cd /crmtestXieHao/redis1/redis-3.2.8/src
./redis-server /crmtestXieHao/redis1/redis-3.2.8/redis.conf &
[4] 23854
[root@b2b-3 src]# 23827:X 05 May 07:57:30.679 # -sdown slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23841:X 05 May 07:57:30.711 # -sdown slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23833:X 05 May 07:57:30.787 # -sdown slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
23827:X 05 May 07:57:40.655 * +convert-to-slave slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
^C
[4]+ Done ./redis-server /crmtestXieHao/redis1/redis-3.2.8/redis.conf
可以看到log信息
+convert-to-slave slave 192.168.5.17:6379 192.168.5.17 6379 @ redis1 192.168.5.17 6381
之前的主节点重启之后成为了从节点。我们可以从客户端看看状态
./redis-cli -h 192.168.5.17 -p 6379 info Replication
# Replication
role:slave
master_host:192.168.5.17
master_port:6381
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:27780
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
尝试从客户端放入数据看看:
./redis-cli -h 192.168.5.17 -p 6379
192.168.5.17:6379> set aa test
(error) READONLY You can't write against a read only slave.
192.168.5.17:6379> get name
"xiehao"
192.168.5.17:6379>
经过以上步骤,基本的sentinel下的高可用一主多从redis就配置完成了。