在Redis中,与Sentinel(哨兵)实现的高可用相比,集群(cluster)更多的是强调数据的分片或者是节点的伸缩性,若是在集群的主节点上加入对应的从节点,集群还能够自动故障转移,所以相比Sentinel(哨兵)仍是有很多优点的。
如下简单测试Redis的集群(单机多实例的模式),来体验一下集群的自动故障转移功能,同时结合Python,来观察自动故障转移过程当中应用程序端的表现。node
redis集群实例安装python
启动6个redis集群实例,集群模式,除了正常的配置项目以外,须要在每一个主节点中增长集群配置redis
cluster-enabled yes # 开启集群模 cluster-node-timeout 1000 # 节点超时时间,单位毫秒,设置一个较小的超时时间,目的是为了后面测试自动故障转移的效果
分配slot & 主节点握手数据库
主节点分配slot给主节点,三个主节点分配16383个slot
8001主----->8004从
8002主----->8005从
8003主----->8006从缓存
#!/bin/bash
for ((i=0;i<=16383;i++))
do
if [ $i -le 5461 ]; then
/usr/local/redis5_1/bin/redis-cli -h 127.0.0.1 -p 8001 -a root CLUSTER ADDSLOTS $i
elif [ $i -gt 5461 ]&&[ $i -le 10922 ]; then
/usr/local/redis5_1/bin/redis-cli -h 127.0.0.1 -p 8002 -a root CLUSTER ADDSLOTS $i
elif [ $i -gt 10922 ]; then
/usr/local/redis5_1/bin/redis-cli -h 127.0.0.1 -p 8003 -a root CLUSTER ADDSLOTS $i
fi
donebash
分配完slot以后,在第一个主节点上执行cluster meet 127.0.0.1 8002,cluster meet 127.0.0.1 8003
无须在其余两个主节点上meet另外两个主节点,随后三个主节点之间关系肯定会自动肯定,目前集群中是三个主节点异步
添加主节点对应的从节点,须要登陆到每一个主节点的实例上,执行性能
三个从节点分别加入到主节点以后,此时6个节点所有加入到集群中测试
Python链接至集群测试spa
这里须要安装redis-py-cluster依赖包
#!/usr/bin/env python3 import time from time import ctime,sleep from rediscluster import StrictRedisCluster startup_nodes = [ {"host":"111.231.253.***", "port":8001}, {"host":"111.231.253.***", "port":8002}, {"host":"111.231.253.***", "port":8003}, {"host":"111.231.253.***", "port":8004}, {"host":"111.231.253.***", "port":8005}, {"host":"111.231.253.***", "port":8006} ] redis_conn= StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True,password="root") for i in range(0, 100000): try: redis_conn.set('name' + str(i), str(i)) print('setting name' + str(i) +"--->" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))) except: print("connect to redis cluster error") time.sleep(2)
执行上述写入测试脚本以后,数据基本上均匀地落在三个节点上
自动故障转移测试
修改Python脚本,每隔1s写入一条数据,目的是便于观察在主节点宕机,集群自动故障转移这个时间段之以内(1s钟左右),对于应用程序的影响,或者说应用程序在自动故障转移先后的表现。
以下脚本循环往Redis集群中写入数据,执行期间,强制杀掉一个主节点,观察应用程序链接状况。
同时,若是发生异常,暂停应用程序2s,由于上面一开始配置的集群故障转移时间是1s,若是应用程序暂停2s,彻底能够跳过故障转移的过程,
当故障转移完成以后,应用程序又恢复成正常状态,虽然8001节点宕机,应用程序继续链接8001节点,可是应用程序彻底无感知。
import time from time import ctime,sleep from rediscluster import StrictRedisCluster startup_nodes = [ {"host":"111.231.253.***", "port":8001}, {"host":"111.231.253.***", "port":8002}, {"host":"111.231.253.***", "port":8003}, {"host":"111.231.253.***", "port":8004}, {"host":"111.231.253.***", "port":8005}, {"host":"111.231.253.***", "port":8006} ] redis_conn= StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True,password="root") for i in range(0, 100000): try: redis_conn.set('name' + str(i), str(i)) print('setting name' + str(i) +"--->" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))) time.sleep(1) except: print("connect to redis cluster error") time.sleep(2)
发如今杀掉主节点以后,仅发生了一次链接错误,随后由于Redis集群的自动故障转移成功,对应于程序来讲是透明的,所以应用程序随后正常工做,不受其中一个主节点宕机的影响。
集群此时的状态,8001节点宕机,明显,8001对应的从节点8004接管主节点,升级为master,对外提供服务
观察升级为主节点的8004实例日志,会发如今强制杀掉原8001主节点以后,1秒钟以内,成功替代8001升级为master节点
若是在故障转移的过程当中,没有应用程序访问Redis,应用程序甚至彻底不知道Redis集群发生了故障转移,只要不发生集群中某一个节点的主从节点同时宕机,整个集群就没有问题,且对应用程序彻底透明。
随后重启宕机的8001节点,会发现8001节点自动变为其原从节点(8004)的从节点
总体上来看,Redis集群的配置和使用以及自动故障转移仍是比较简单易容的,这里没有用redis-trib.rb 而是采用手动分配slot和建立集群的方式,目的是了解完整的配置流程。
须要注意的是:
1,若是开启了密码验证模式,全部的主从节点必须配置masterauth,由于某一个节点宕机重启以后,会自动变为从节点,此时若是想要从master复制数据,就必须须要主节点的密码
2,StrictRedisCluster决定了全部主从节点的密码必需要是同样的。
表面上看Redis集群简单易用,自动故障转移是没有问题的,保证了高可用,看似没有问题。
若是细想,这个过程仍是有问题的,有没有发现,虽然故障转移保证了高可用,可是当从节点升级为主节点以后,若是保证升级为主节点的从节点(8004)必定可以彻底复制原主节点(8001)上的数据?
补充:刚写完就发现,redis在主从复制上,有一个wait 命令,以下
wait命令可让默认的异步复制变为同步复制,
wait numsslave timeout,含义是等待复制到的slave节点的个数和超时时间,若是超时间为0,表示会一直等待(同步到从节点)
若是从节点不可达,则wait会一直阻塞主节点,此时主节点是没法对外提供服务的。
这个就相似于MySQL的半同步复制,主节点上的数据,必定要同步(虽然是relaylog)到从节点,主节点才会提交。不过回头想一想,取决于如何去对待Redis或者怎么使用Redis,Redis更多的时候是做为一个缓存使用,而不是落地的数据库,既然是缓存,就应该更多地去考虑性能。