为什么做这个:现在生产上的redis没有把dump.rdb文件映射到磁盘出来,如果重新建容器,数据会丢失,除非直接从磁盘上找到docker容器的位置,然后直接拿到dump.rdb
方案无法解决的问题:master挂掉到新的slave变成master之前这一段时间master对应的槽redis无法读写
选三台新的服务器:10.1.167.143 10.1.167.145 10.1.167.146
每台服务上开三个redis 端口号为6001 6002 6003
docker-compose文件和三个redis.conf配置文件见附件,原docker-compose文件没有把dump.rdb映射出来,新的已经加上
- 三台新服务器新建容器,docker-compose up -d 后啥都不要做,否则会报错 [ERR] Node 10.2.158.19:7002 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.,这种个情况,需要删掉新容器,从新生成容器
2.为原来的3个master 每个都建立新的3个slave
./redis-trib.rb add-node --slave --master-id 3dd3c6d92935c638e3c5690fee2040825a1a0045 10.2.158.19:7002 10.1.44.163:7002
说明:3dd3c6d92935c638e3c5690fee2040825a1a0045为主库的id,
10.2.158.19 新增的redis slave的ip,7002 为slave的端口号
10.1.44.163:7002 为主库的ip和端口号
3.slave完成时会自动触发数据同步,master会全拷贝到slave
4.程序更改redis配置为原来的3主3从+新的9个从,然后重启
4.关闭原来的3个slave,避免原来的slave被选举成新的master
5.redis cluster的,两种挂的情况,
1是一主和其对应的slave同时挂,这时候会丢失三分之一的slot,
2是两个master同时挂了,这时没法选举新的mater节点,因为redis规定只有master节点才能参与选举,挂了两个超过1/2,无法选举
6. 根据5原则,slave挂了一点不影响正常使用
7. 通过info命令(最后面: db0:keys=1151)查看每个master中的key数,后面验证用
8. 执行bgsave然后关掉其中一个master,等待cluster-node-timeout ms,新的master会诞生(redis.conf中 cluster-node-timeout表示超过这么多ms(一般15s) 开始选举新的阶段)
9. 通过cluster nodes关注新的master情况
10. 通过9看到新的master选举成功后,依次关掉其他两个master,(根据原则5不能一次都关掉,每次关一个等待新的master选举成功)
11. 三个新master诞生后删除无用节点,
删除无用节点:
1.是保证该节点活着,死的是删不掉的,因为删的时候需要通知它,通知不到是删不掉的,
2.启动被关掉的3主3从,先删掉slave节点,再关掉老master节点,因为删slave节点需要先通知master,也可以等到slave选取新的master再删
删除命令:
redis-trib.rb del-node 10.1.32.60:7001 '6a8505a33a9228d7b3b63824f7d78f81327452fa'
从节点IP:端口号 ’从节点的ID'
12. info命令新的节点所有的key,后和第7步做对比,需要对比三次,因为keys *只会统计自己的slot中的所有数据,所以要连接每个master后做对比
13.slot机制造成redis cluster不能模糊查询,如果不能确定key,也就无法hash,也就不能找到对应的slot
方案缺点:
master挂掉到新的slave选举成新的节点之前,集群未挂但是master无法访问,也没做读写分离,这段时间 master写数据是会报错,造成数据丢失,
期间会发生故障转移,一部分新的节点对应的slot移动到其他节点,slave变成新的master后他的slot还是以前的slot,所以可能有问题
部分原理:
原理(1)客户端初始化连接 : 客户端初始化时会根据本地ip+port 生成一个唯一hash值,客户端跟据这个hash值会固定选择对应的master
如果这个master挂了,即使集群没挂,也会造成服务起不来,3.1的版本已经修复
原理(2)客户端初始化数据: 客户端初始化时会 连接一个master,从这个master上拿到 集群元数据,即每个node对应的slot范围,把映射信息缓存到本地
主动刷新缓存的条件:访问对应的master发现 slot不在这个master,并且该master返回一个moved 状态,并且会把新的node和slot映射关系返回给它
原理(3)redis集群间通信协议 Gossip:
Gossip是一种去中心化、容错而又最终一致性的绝妙算法,其收敛性不但得到证明还具有指数级的收敛速度。使用Gossip的系统可以很容易的把Server扩展到更多的节点,满足弹性扩展轻而易举。
唯一的缺点是收敛是最终一致性,不使用那些强一致性的场景,比如2pc。
原理(3)故障转移: master断开时间超过 cluster-node-timeout/2 时节点开始转移,集群认为该节点宕机,他上面的slot会被分到其他的节点上
原理(4) 从节点选举成主节点:从节点如果跟master节点 断开时间超过cluster-node-timeout*cluster-slave-validity-factor 无法被选举成新的master节点
cluster-node-timeout 这是集群中的节点能够失联的最大时间,超过这个时间,该节点就会被认为故障.这时候主节点挂掉,集群会挂掉
cluster-slave-validity-factor 如果设置成0,则无论从节点与主节点失联多久,从节点都会尝试升级成主节点。
如果设置成正数,则cluster-node-timeout乘以cluster-slave-validity-factor得到的时间,是从节点与主节点失联后,此从节点数据有效的最长时间,超过这个时间,从节点不会启动故障迁移
原理(5)slot转移原则:请求量很大时,如何保证负载均衡,新增一个节点和减少一个节点如何保证 命中率
原理(6)客户端寻找节点 key和slot映射关系 slot=CRC16(key)/16384
客户端计算slot,然后根据初始化连接时拿到的slot和节点的映射关系,去对应的节点上取值,
节点拿到key后重新计算slot,根据本地缓存的slot和节点映射关系,如果在自己的节点上,则返回结果,如果不在自己的节点上(7),则返回move状态,顺带返回所有的slot和节点对应关系,
客户拿到后,再次连接新的节点拿数据,
原理(7)节点迁移
新增节点时:slot不会主动迁移,必须手动reshare,让集群中的部分slot会迁移到新的节点,slot和节点对应关系会变更,但slot和key的对应关系永远不变,slot会被映射到hash环的某一个位置,从这个位置顺时针查找最近的一个节点,
宕机时:当所有其他master知道某个节点宕机时,但新的slave还未选举出来,原本两个master节点的访问会集中到同一个节点上,流量暴增,优化方式是虚拟节点,每个节点生成若干个虚拟节点
均匀分布在hash环上,这样顺时针查找是会找相邻的节点也很均匀