为什么有哨兵模式了,还要用Redis Cluster集群?

哨兵模式有一些缺陷,例如:

  • Master宕机后,切换新的Master需要花一定的时间,导致这段时间无法提供访问;
  • 哨兵的配置略微复杂,性能和高可用性表现一般;
  • 哨兵模式下,只有一个主节点对外提供服务,没法支持很高的并发;
  • 单个主节点的时候,内存也不宜设置的过大,否则会导致持久化文件过大,影响数据恢复和主从同步的效率。

因此,小型互联网公司使用哨兵模式还凑合,但是大型互联网公司需要采取Redis Cluster集群。

Redis Cluster集群结构

image.png

  1. 数据分片存储,每一个小集群里存的数据是不重复的;
  2. 要求至少三个主结点。

Redis Cluster集群配置

  1. 修改配置文件 ```bash port 8001 dir /usr/local/redis-cluster/8001 cluster-enabled yes cluster-config-file nodes-8001.conf cluster-node-timeout 5000

    注释bind

    127.0.0.1

protected-mode no appendonly yes

如果需要设置密码

requirepass 123456 masterauth 123456

  1. 其他实例也做相应的修改。
  2. 2. 启动redis-server:
  3. ```bash
  4. redis-server redis-8001.conf

如果发现redis-server没有启动成功,那么就去看日志文件,例如我这里看到如下问题:
image.png
说明没有这个文件夹,那么手动创建就好了。

创建好文件夹后,重新启动,发现启动成功了。
image.png

  1. 对三台虚拟机都进行配置,每台虚拟机起两个实例。
  2. 通过命令来形成集群
    redis-cli -a 123456 --cluster create --cluster-replicas 1 192.168.31.27:8001  192.168.31.27:8002  192.168.31.147:8001 192.168.31.147:8002 192.168.31.118:8001 192.168.31.118:8002
    
  • -a后面跟密码
  • —cluster-replicas后面的1表示1个从节点

image.png
输入yes表示接受。

image.png

可以看到,redis cluster共有16384个slot,每个实例保存不同的slot:
image.png

  1. 进入redis集群,一定要带上-c参数

    redis-cli -p 8001 -a 123456 -c
    
  2. 设置,观察是否可以设置成功:

    192.168.31.147:8001> set lang-cluster 123
    -> Redirected to slot [13250] located at 192.168.31.118:8001
    OK
    

    成功。

分配算法的原理

关键是根据key获取到对应的slot:
image.png
最后一行,就是对key做哈希,然后对16384取模,得到对应的槽位slot。

Cluster的选举

  1. Master挂了;
  2. Slave发现Master挂了;
  3. 将自己记录的集群currentEpoch加1, 并且广播FAILOVER_AUTH_REQUEST信息;
  4. 其他节点收到该信息,只有其他集群的Master会响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ACK;
  5. Slave收集返回的FAILOVER_AUTH_ACK,当超过半数Master以后,变成新的Master;
  6. 如果多个Slave票数一样,重新选举。

为了防止多个slave同时发起请求,采取了延迟公式:

DELAY = 500ms + random(0 ~ 500) + SLAVE_RANK * 1000ms;

集群脑裂

指的是,由于网络波动等问题,Master可能和Slave断开连接了,但是并没有宕机。此时Slave会发起选举选出新的Master,导致一个集群同时出现了多个Master对外提供数据的写服务,导致数据不一致。

在网络恢复后,之前断开连接的Master要重新回到集群,回来后它变成Slave,在进行主从同步时,这个Master之前写入的数据会被丢失。

解决方式:

min-slaves-to-write 1

该配置指的是,至少要有1个slave写成功了,才算真正的写成功。

这样配置牺牲了集群的一定的可用性,所以需要根据具体场景进行权衡。

集群批量操作

当进行批量操作,例如:

mset key1 value1 key2 value2

如果计算出来的两个key落在不同的slot上,Redis会让它失败,因为这种操作Redis需要保证原子性。

如果就是希望用批量操作,那么在key前面加上{xxx},{}里的值用来做redis做哈希计算,保证落在同一个slot上即可,

mset {user1}:key1 value1 {user1}:key2 value2

添加新的集群

  1. 将实例加入到集群中
    redis-cli -a 123456 --cluster add-node 192.168.31.27:8003 192.168.31.27:8001
    
    第一个IP为新节点的IP和Port,第二个为集群内任意节点的iP和port。

加入成功后还不能对该结点进行读写操作,因为此时没有slot分配给它。

  1. 进行数据的重新分片。
    redis-cli -a 123456 --cluster reshard 192.168.31.27:8001
    
    回答一些问题以后,将数据和槽位迁移到新机器上。