redis高可用一般有两种方式实现:哨兵和集群。在哨兵 sentinel 机制中,可以解决 redis 高可用的问题, 即当 master 故障后可以自动将 slave 提升为 master 从而可以保证 redis 服务的正常使用,但是无法解决 redis 单机写入的瓶颈问题, 即单机的 redis 写入性能受限于单机的内存大小、 并发数量、 网卡速率等因素。
  redis 官方在 redis 3.0 版本之后推出了无中心架构的 redis cluster机制, 在无中心的 redis 集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接, 特点如下:

  1:所有 Redis 节点使用(PING 机制)互联。
  2:集群中某个节点的失效, 是整个集群中超过半数的节点监测都失效才算真正的失效(类似Sdown和Odown) 。
  3:客户端不需要 proxy 即可直接连接 redis, 应用程序需要写全部的 redis 服务器 IP。
  4:redis cluster 把所有的 redis node 映射到 0-16383 个槽位(slot)上, 读写需要到指定的 redis node 上进行操作,因此有多少个 reids node 相当于 redis 并发扩展了多少倍。
  5:Redis cluster 预先分配 16384 个(slot)槽位,当需要在 redis 集群中写入一个 key -value 的时候,会使用 CRC16(key) mod 16384 之后的值,决定将 key 写入值哪一个槽位从而决定写入哪一个 Redis 节点上, 从而有效解决单机瓶颈。

Sentinel(哨兵)

手动配置主从

  需要手动先指定某一台 Redis 服务器为 master,然后将其他 slave 服务器修改配置文件或使用命令配置为 master 服务器的 slave。哨兵的前提是已经手动实现了一个 redis master-slave 的运行环境。
  例如我们将192.168.32.81上的redis服务设置为master,192.168.32.82、192.168.32.83设置为slave,192.168.32.81中配置文件masterauth 设置为123456
  在192.168.32.82上设置主节点信息SLAVEOF 192.168.32.81 6379(redis5版本命令为REPLICAOF 192.168.7.101 6379)

1
2
3
4
192.168.32.82:6379> SLAVEOF 192.168.32.81 6379
OK
192.168.32.82:6379> CONFIG SET masterauth "123456"
OK

  同样,192.168.32.83也要设置主节点信息及密码

1
2
3
4
192.168.7.103:6379> SLAVEOF 192.168.7.101 6379
OK
192.168.7.103:6379> CONFIG SET masterauth "123456"
OK

  此时通过info Replication命令,在两个从节点上可以看到角色已变更为slave,且master_link_status状态要为up,说明主从结构配置完成。

1
2
3
4
5
6
127.0.0.1:6379> info Replication
# Replication
role:slave
master_host:192.168.32.81
master_port:6379
master_link_status:up

  需要注意的是:不同的 redis 版本之间存在兼容性问题, 因此各 master 和 slave 之间必须保持版本一致,且redis slave 也要开启持久化并设置和 master 同样的连接密码,此外,如果开启了安全模式,未设置密码的话也会导致主从无法连接。

配置Sentinel

  哨兵可以不和 Redis 服务器部署在一起。可以使用另外不同的机子,一般采用单数个哨兵(至少3个)。不过为了节约服务器,我们还是和redis服务器部署到一起。
  3个机子都手动添加Sentinel配置文件
  vim /apps/redis/etc/sentinel.conf

1
2
3
4
5
6
7
8
9
10
11
12
bind 0.0.0.0
port 26379
daemonize yes
pidfile "redis-sentinel.pid"
logfile "sentinel_26379.log"
dir "/usr/local/redis"
sentinel monitor mymaster 192.168.32.81 6379 2 #法定人数限制(quorum),即有几个slave 认为 master down 了就进行故障转移
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 30000 #(SDOWN)主观下线的时间
sentinel parallel-syncs mymaster 1 #发生故障转移时候同时向新 master 同步数据的slave 数量, 数字越小总同步时间越长
sentinel failover-timeout mymaster 180000 #所有 slaves 指向新的 master 所需的超时时间
sentinel deny-scripts-reconfig yes #禁止修改脚本

  通过/apps/redis/bin/redis-sentinel /apps/redis/etc/sentinel.conf命令指定配置文件,启动哨兵,此时通过ss -tanl命令可以看到已监听26379端口,说明哨兵服务已启动。

1
2
3
4
5
6
7
8
9
[root@CentOS8 ~]# redis-cli -h 192.168.32.81 -p 26379
192.168.32.81:26379> info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.32.81:6379,slaves=2,sentinels=3

  可以通过redis-cli指定26379端口连接哨兵服务器,info Sentinel查看哨兵状态,显示status=ok,slaves=2,sentinels=3,与我们之前设计的相同,说明哨兵服务正常。
  此时,当master故障后,哨兵会通过投票机制,选举一个slave作为新的master,继续实现主从结构,而程序应用也会在主从切换的时候收到通知,Jedis 会进行连接的切换(在 JedisPool 中添加了 Sentinel 和MasterName 参数, JRedis Sentinel 底层基于 Redis 订阅实现 Redis 主从服务的切换通知, 当 Reids 发生主从切换时, Sentinel 会发送通知主动通知 Jedis 进行连接的切换, JedisSentinelPool 在每次从连接池中获取链接对象的时候,都要对连接对象进行检测,如果此链接和 Sentinel 的 Master 服务连接参数不一致,则会关闭此连接,重新获取新的 Jedis 连接对象。),实现redis的高可用。

Redis Cluster

  在哨兵 sentinel 机制中,可以解决 redis 高可用的问题, 即当 master 故障后可以自动将 slave 提升为 master 从而可以保证 redis 服务的正常使用,但是无法解决 redis 单机写入的瓶颈问题, 即单机的 redis 写入性能受限于单机的内存大小、 并发数量、 网卡速率等因素,所以Redis自带的Cluster就是很好的一个解决方案。

集群前提

  1.每个 redis node 节点采用相同的硬件配置、相同的密码、 相同的 redis 版本。
  2.每个节点必须开启的参数
cluster-enabled yes #必须开启集群状态, 开启后 redis 进程会有 cluster 显示cluster-config-file nodes-6380.conf #此文件有 redis cluster 集群自动创建和维护,不需
要任何手动操作
  3.所有 redis 服务器必须没有任何数据
  4.先启动为单机 redis 且没有任何 key value

集群部署

Redis 3、4

  Redis 3 和 4 版本需要使用到集群管理工具 redis-trib.rb,这个工具是 redis 官方推出的管理 redis 集群的工具,集成在 redis 的源码 src 目录下,是基于 redis 提供的集群命令封装成简单、便捷、实用的操作工具, redis-trib.rb 是 redis 作者用 ruby 开发完成的。所以需要有ruby环境,如果系统自带的ruby版本较低(需要Ruby version >= 2.3.0),那就需要重新编译安装更高版本。

编译安装ruby
1
2
 yum remove ruby rubygems -y
wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.5.tar.gz
1
2
3
4
tar xf ruby-2.5.5.tar.gz
cd ruby-2.5.5
./configure
make -j 4 && make install

  安装redis的gem包(Gem是一个管理Ruby库和程序的标准包,它通过Ruby Gem(如 http://rubygems.org/ )源来查找、安装、升级和卸载软件包,非常的便捷)。

1
gem install redis

  之后就可以使用redis-trib.rb命令来创建管理集群了。

集群创建

  通过命令redis-trib.rb create来创建集群,选项–replicas 指定 master 的slave数量.
  需要注意的是,集群至少也需要3台master,(–replicas 指定的slave数量可以为0,不过一般不建议),如果指定slave数量为2的话就至少需要9个redis服务器了(3主6从),比较浪费资源,所以我们一般设置replicas数值为1。
  如果设置slave数量为0,则所有的6个服务器均为master,无法实现高可,集群信息如下图所示:

1
2
3
4
5
6
7
8
127.0.0.1:6379> cluster nodes
c65ab2a5e9d8a9435d54f0ef7db302c62b6f9308 192.168.32.82:6379@16379 master - 0 1573794294000 3 connected 5461-8191
a13d711b6b54909e5aed44cc8f75195915bbfb95 192.168.32.85:6379@16379 master - 0 1573794293235 6 connected 13653-16383
5d614e18da36f9d7b3536566205281743adc95c5 192.168.32.8:6379@16379 myself,master - 0 1573794294000 1 connected 0-2730
6fe42df7ea9c4dbb00d9bae6f7e4238367b1089b 192.168.32.81:6379@16379 master - 0 1573794292212 2 connected 2731-5460
e3beb9f45b73b265050499ee093ed1a473a3d566 192.168.32.83:6379@16379 master - 0 1573794295286 4 connected 8192-10922
8ae323030e3ae28519a27058c6592b94d1aae734 192.168.32.84:6379@16379 master - 0 1573794295000 5 connected 10923-13652
127.0.0.1:6379>

  如果设置slave数量为2,若创建集群是加入的服务器数量不够9台,则会报错:

1
2
3
4
5
6
7
8
9
10
11
12
[root@CentOS8 ~]#redis-trib.rb create --replicas 2 \
192.168.32.8:6379 \
192.168.32.81:6379 \
192.168.32.82:6379 \
192.168.32.83:6379 \
192.168.32.84:6379 \
192.168.32.85:6379
>>> Creating cluster
*** ERROR: Invalid configuration for cluster creation.
*** Redis Cluster requires at least 3 master nodes.
*** This is not possible with 6 nodes and 2 replicas per node.
*** At least 9 nodes are required.

  若之前有创建集群失败的一些操作,或集群中有的redis服务器中有数据信息的话,也是无法创建成功的。会报类似如下如下信息:

1
/usr/local/share/gems/gems/redis-4.1.3/lib/redis/client.rb:126:in `call': ERR Slot 2823 is already busy (Redis::CommandError)

  所以我们一般在创建集群之前,先连上redis服务器清空数据,并重置集群关系,确保所有的redis服务器都没有数据且都为单机master。

1
2
FLUSHALL
cluster reset

  然后执行创建集群命令

1
2
3
4
5
6
7
redis-trib.rb create --replicas 1 \
192.168.32.8:6379 \
192.168.32.81:6379 \
192.168.32.82:6379 \
192.168.32.83:6379 \
192.168.32.84:6379 \
192.168.32.85:6379

  即可成功创建集群。连接redis,登陆,即可看到集群主从关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@CentOS8 ~]#redis-cli
127.0.0.1:6379> cluster nodes
NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> cluster nodes
c65ab2a5e9d8a9435d54f0ef7db302c62b6f9308 192.168.32.82:6379@16379 master - 0 1573798716854 3 connected 10923-16383
a13d711b6b54909e5aed44cc8f75195915bbfb95 192.168.32.85:6379@16379 slave 6fe42df7ea9c4dbb00d9bae6f7e4238367b1089b 0 1573798715000 6 connected
5d614e18da36f9d7b3536566205281743adc95c5 192.168.32.8:6379@16379 myself,master - 0 1573798716000 1 connected 0-5460
6fe42df7ea9c4dbb00d9bae6f7e4238367b1089b 192.168.32.81:6379@16379 master - 0 1573798717877 2 connected 5461-10922
8ae323030e3ae28519a27058c6592b94d1aae734 192.168.32.84:6379@16379 slave 5d614e18da36f9d7b3536566205281743adc95c5 0 1573798715834 5 connected
e3beb9f45b73b265050499ee093ed1a473a3d566 192.168.32.83:6379@16379 slave c65ab2a5e9d8a9435d54f0ef7db302c62b6f9308 0 1573798716000 4 connected
127.0.0.1:6379>

  监控集群状态

1
redis-trib.rb check 192.168.32.8:6379
Redis 5

  Redis 5 版本可以直接用redis-cli客户端命令加各种命令参数来管理创建集群(配置文件中如果已配置正确的密码,则不需要-a 选项,-a选项会有warning警告)。
  创建集群

1
2
3
4
5
6
7
redis-cli -a 123456 --cluster create --cluster-replicas 1 \
192.168.32.8:6379 \
192.168.32.81:6379 \
192.168.32.82:6379 \
192.168.32.83:6379 \
192.168.32.84:6379 \
192.168.32.85:6379

  监控集群状态

1
redis-cli -a 123456 --cluster check 192.168.32.8:6379

集群管理维护

  集群运行时间长久之后,难免由于硬件故障、网络规划、 业务增长等原因对已有集群进行相应的调整, 比如增加 Redis node 节点、 减少节点、 节点迁移、更换服务器等。

动态添加节点

  同步之前 Redis node 的配置文件到 192.168.32.86 Redis 编译安装目录, 注意修改配置文件的监听 IP。

1
2
scp redis.conf 192.168.32.86:/apps/redis/etc/
scp redis_6380.conf 192.168.32.86:/apps/redis/etc/

  对预备加入的redis服务器清除数据并执行集群重置

1
2
FLUSHALL
cluster reset

  redis3、4 中添加节点(Adding node 192.168.32.87:6379 to cluster 192.168.32.8:6379)

1
redis-trib.rb add-node 192.168.32.87:6379 192.168.32.8:6379

  redis5 中添加节点(Adding node 192.168.32.87:6379 to cluster 192.168.32.8:6379)

1
redis-cli --cluster add-node 192.168.32.87:6379 192.168.32.8:6379
重新分配槽位

  集群槽位迁移时,迁出的服务器中不能有数据,否则会迁移失败并终止,且需要修复集群,才可以进行第二次迁移。
  redis3、4 中对新加的主机重新分配槽位(后可跟集群中任意主机ip:port):

1
redis-trib.rb reshard 192.168.32.8:6379

  redis5 对新加的主机重新分配槽位(后可跟集群中任意主机ip:port):

1
redis-cli --cluster reshard 192.168.32.8:6379

  输入命令后根据提示输入

1
2
3
4
5
6
7
8
9
How many slots do you want to move (from 1 to 16384)? 4096  #需要迁移多少槽位
What is the receiving node ID? 5d614e18da36f9d7b3536566205281743adc95c5 #选择迁移到哪个redis主机
What is the receiving node ID? 6bffc0037eea959f0dcc11aca657f928d86cfc75
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:6bffc0037eea959f0dcc11aca657f928d86cfc75 #选择从哪个主机迁出
Source node #2:done #输入done结束选择
Do you want to proceed with the proposed reshard plan (yes/no)? yes #是否执行,yes确认,之后就会迁移完毕
修复集群

  如果迁移失败,则需要修复集群。

  redis3、4 中对对报错redis服务器进行单独修复(后跟需要修复的主机ip:port):

1
redis-trib.rb fix 192.168.32.82:6379

  redis5 中对对报错redis服务器进行单独修复(后跟需要修复的主机ip:port):

1
redis-cli --cluster fix 192.168.32.82:6379
配置主从关系

  在整个 Redis cluster 集群中,每个 master 至少有一个 slave。也可以有多个,但是至少要有一个提供数据备份和服务高可用。
  redis-trib.rb info 192.168.32.8:6379

1
2
3
4
5
6
7
8
[root@CentOS8 ~]#redis-trib.rb info 192.168.32.8:6379
192.168.32.8:6379 (5d614e18...) -> 0 keys | 4096 slots | 1 slaves.
192.168.32.82:6379 (c65ab2a5...) -> 0 keys | 4096 slots | 0 slaves.
192.168.32.81:6379 (6fe42df7...) -> 0 keys | 4096 slots | 1 slaves.
192.168.32.87:6379 (6bffc003...) -> 0 keys | 4096 slots | 1 slaves.
192.168.32.86:6379 (e06732b2...) -> 0 keys | 0 slots | 0 slaves.
[OK] 0 keys in 5 masters.
0.00 keys per slot on average.

  我们看到之前的3主3从结构因为我们加了两个服务器变成了5主3从,新加的两个服务器,我们需要将它们设置为一主一从来实现高可用。于是我们要将192.168.32.86变为192.168.32.82的slave。
  连接登陆192.168.32.86上的redis服务器,先查好192.168。32.82的ID为c65ab2a5e9d8a9435d54f0ef7db302c62b6f9308,执行

1
cluster replicate c65ab2a5e9d8a9435d54f0ef7db302c62b6f9308
删除节点

  删除节点,需要先将redis主机上的槽位都迁移到其他主机上才可以操作。
  迁移完成后,redis3、4 删除节点(要删除的redis主机要写节点号,集群可以写集群中任意主机ip+port)

1
2
3
4
[root@CentOS8 ~]#redis-trib.rb del-node 192.168.32.8:6379 6bffc0037eea959f0dcc11aca657f928d86cfc75
>>> Removing node 6bffc0037eea959f0dcc11aca657f928d86cfc75 from cluster 192.168.32.8:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

  redis5 删除节点

1
redis-cli --cluster del-node 192.168.32.8:6379 6bffc0037eea959f0dcc11aca657f928d86cfc75

  主节点被删除之后,其之前它的 slave 自动称为了 Redis 集群中其他 master的 slave,此节点如果不需要也可以一并删除。


一个低调的男人