redis在linux中安装部署

2023-12-14 20:43:06

redis是一个高性能的内存数据库,几乎在当下的所有技术方案中,都会选择使用redis进行数据缓存。它支持丰富的数据结构,部署方案也灵活,支持单机、主从、哨兵、集群等。这篇文章就介绍一下这几种部署方案。
首先需要去redis官网下载源码包:https://redis.io/download
下载后的源码包上传到服务器,将源码包解压到指定目录:

tar -zvxf redis-6.2.8.tar.gz

redis是使用c语言编写的,在安装redis之前,首先需要确认系统中是否已经安装了c语言环境,如果没有安装,先安装gcc编译器:

yum -y install gcc gcc-c++

以上步骤做完了,进入解压目录执行编译安装:

make && make install

如果安装没有出错,会看到下面信息表示安装成功:

Hint: It's a good idea to run 'make test' ;)

make[1]: Leaving directory `/root/redis-6.2.8/src'
[root@localhost redis-6.2.8]# make install
cd src && make install
make[1]: Entering directory `/root/redis-6.2.8/src'
    CC Makefile.dep
make[1]: Leaving directory `/root/redis-6.2.8/src'
make[1]: Entering directory `/root/redis-6.2.8/src'

Hint: It's a good idea to run 'make test' ;)

    INSTALL redis-server
    INSTALL redis-benchmark
    INSTALL redis-cli
make[1]: Leaving directory `/root/redis-6.2.8/src'

redis安装成功,接下来就是启动服务和使用,最简单的使用方式是直接运行redis-server命令,这种方式会以前台进行方式启动服务,如果看到下面的内容表示服务启动成功了:

[root@localhost redis-6.2.8]# ./src/redis-server 
9967:C 13 Dec 2023 18:15:29.884 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
9967:C 13 Dec 2023 18:15:29.884 # Redis version=6.2.8, bits=64, commit=00000000, modified=0, pid=9967, just started
9967:C 13 Dec 2023 18:15:29.884 # Warning: no config file specified, using the default config. In order to specify a config file use ./src/redis-server /path/to/redis.conf
9967:M 13 Dec 2023 18:15:29.885 * Increased maximum number of open files to 10032 (it was originally set to 1024).
9967:M 13 Dec 2023 18:15:29.885 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.2.8 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 9967
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           https://redis.io       
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

9967:M 13 Dec 2023 18:15:29.885 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
9967:M 13 Dec 2023 18:15:29.885 # Server initialized
9967:M 13 Dec 2023 18:15:29.885 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
9967:M 13 Dec 2023 18:15:29.885 * Ready to accept connections

在开发中基本上不会用这种方式启动,前台启动方式一旦shell关闭服务也会停止。
下面就介绍一下在日常开发中的几种部署方式。

一、单机部署

单机部署是redis最简单的一种方式,当我们想体验一下redis或测试环境简单使用时,就可以选择这种方式,它部署简单,占用资源少,可以很快速的启动服务。但由于是单机模式,一旦宕机将导致整个服务不可用,在生产环境中一般不会使用这种模式。
前面已经介绍了单机启动服务方式,但是那种是前台启动,开发中需要对配置文件做一些调整,使用指定的配置文件启动服务。下面是对配置文件内容做了一些简单调整,在安装目录下创建一个6379文件夹,复制配置文件redis.conf到这个目录中,并修改配置文件中的以下内容:

# 服务绑定的IP地址,默认是127.0.0.1,只能通过本地连接redis服务,其他主机连接不了。
# 这里添加了IP地址192.168.56.101,表示其他主机可以通过这个IP连接redis服务。
# 更简单的配置方式是直接配置0.0.0.0,表示所有IP都可以连接
# 需要注意的是这里的IP不是指限制哪些IP可以连接,是指redis服务在哪些IP对外提供服务
bind 127.0.0.1 192.168.56.101

# redis端口号,默认是6379,如果一个服务器上面部署多个redis实例,需要指定不同的端口号
port 6379

# 指定redis服务以守护进程方式运行
daemonize yes

# 指定redis服务pid文件路径
pidfile /root/redis-6.2.8/6379/data/redis_6379.pid


# 指定redis服务日志输出文件
logfile "/root/redis-6.2.8/6379/data/redis.log"

# 指定redis持久化文件目录
dir /root/redis-6.2.8/6379/data/

# 指定服务密码
requirepass 123456

# 主从连接时指定主节点密码
masterauth 123456

# 最大内存大小,建议设置避免因为内存不足导致服务失败
maxmemory 1gb

# 到达最大内存时的键淘汰策略,默认是不淘汰,这里就需要根据实际业务场景选择了,
# 如果只是作为缓存使用,数据丢失后可以再加载回来就选择合适的淘汰策略,可以避免因为内存不足的请求失败
maxmemory-policy volatile-ttl

# 开启aof持久化方式
appendonly yes

# aof持久化文件名
appendfilename "appendonly.aof"

# 每一秒钟持久化一次,服务宕机最多丢失1s数据
# appendfsync always
appendfsync everysec
# appendfsync no

调整配置文件后,重新启动服务器,测试服务是否可用:

[root@localhost redis-6.2.8]# ./src/redis-server ./6379/redis.conf 
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ps -ef | grep redis
root     10128     1  0 19:11 ?        00:00:00 ./src/redis-server 127.0.0.1:6379
root     10134  1487  0 19:12 pts/0    00:00:00 grep --color=auto redis
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ./src/redis-cli 
127.0.0.1:6379> set hello world!
(error) NOAUTH Authentication required.
127.0.0.1:6379> 
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> set hello world!
OK
127.0.0.1:6379> keys *
1) "hello"
127.0.0.1:6379> get hello
"world!"
127.0.0.1:6379> 

上面就是单机部署方式的全部内容,发现非常简单。

二、主从部署

由于存在单点故障,在资源比较有限的情况下可以选择主从方式部署,这种模式是同时启动两台或多台redis服务,其中一台是主节点,其他机器是从节点,主节点可以进行读写,从节点只能读取数据。当主节点出现故障时,手动在从节点中选择一个从节点升级为主节点对外提供服务,其他的从节点调整为这个主节点的从节点,并进行数据同步。
由于是模拟主从节点关系,就以最简单的一主一从方式部署,将上面的配置文件复制一份到新建的文件夹6380下,修改里面的目录路径和服务端口号,再启动这个服务:

# 服务绑定的IP地址,默认是127.0.0.1,只能通过本地连接redis服务,其他主机连接不了。
# 这里添加了IP地址192.168.56.101,表示其他主机可以通过这个IP连接redis服务。
# 更简单的配置方式是直接配置0.0.0.0,表示所有IP都可以连接
# 需要注意的是这里的IP不是指限制哪些IP可以连接,是指redis服务在哪些IP对外提供服务
bind 127.0.0.1 192.168.56.101

# redis端口号,默认是6379,如果一个服务器上面部署多个redis实例,需要指定不同的端口号
port 6380

# 指定redis服务以守护进程方式运行
daemonize yes

# 指定redis服务pid文件路径
pidfile /root/redis-6.2.8/6380/data/redis_6380.pid


# 指定redis服务日志输出文件
logfile "/root/redis-6.2.8/6380/data/redis.log"

# 指定redis持久化文件目录
dir /root/redis-6.2.8/6380/data/

# 指定服务密码
requirepass 123456

# 主从连接时指定主节点密码
masterauth 123456

# 最大内存大小,建议设置避免因为内存不足导致服务失败
maxmemory 1gb

# 到达最大内存时的键淘汰策略,默认是不淘汰,这里就需要根据实际业务场景选择了,
# 如果只是作为缓存使用,数据丢失后可以再加载回来就选择合适的淘汰策略,可以避免因为内存不足的请求失败
maxmemory-policy volatile-ttl

# 开启aof持久化方式
appendonly yes

# aof持久化文件名
appendfilename "appendonly.aof"

# 每一秒钟持久化一次,服务宕机最多丢失1s数据
# appendfsync always
appendfsync everysec
# appendfsync no

服务启动后查看进程信息,连接到服务上面,并配置新服务是6379服务的从节点:

[root@localhost redis-6.2.8]# ./src/redis-server ./6380/redis.conf 
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ps -ef | grep redis
root     10128     1  0 19:11 ?        00:00:01 ./src/redis-server 127.0.0.1:6379
root     10205     1  0 19:30 ?        00:00:00 ./src/redis-server 127.0.0.1:6380
root     10211 28641  0 19:30 pts/1    00:00:00 grep --color=auto redis
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ./src/redis-cli -p 6380 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6380> keys *
(empty array)
127.0.0.1:6380> config set masterauth 123456
OK
127.0.0.1:6380> keys *
(empty array)
# 设置同步的主节点IP和端口
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> keys *
1) "hello"
127.0.0.1:6380> 

通过上面的操作就完成了一个主从模式的搭建,可以分别查看服务信息:
6379服务上面可以查看到有一个slave节点连接上来了:

127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=392,lag=0
master_failover_state:no-failover
master_replid:882d159be58a8dd0d3f5e89410e398e7f1682617
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:392
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:392
127.0.0.1:6379> 

在6380上面查看信息可以看到它连接的主节点IP和端口号:

127.0.0.1:6380> info Replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_read_repl_offset:378
slave_repl_offset:378
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:882d159be58a8dd0d3f5e89410e398e7f1682617
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:378
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:155
repl_backlog_histlen:224
127.0.0.1:6380> 

这时在主节点上运行的命令都会同步到从节点。如果从节点要断开与主节点的复制,只需要在从节点上运行下面的命令:

127.0.0.1:6380> replicaof no one
OK
127.0.0.1:6380> 

要实现主从节点的数据复制涉及到下面几个命令:

# 设置主节点身份认证,在配置文件中已添加:masterauth 123456 这一步就可以省略
127.0.0.1:6380> config set masterauth 123456
OK

# 从节点同步的主节点的IP和端口
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK

# 断开与主节点的数据复制
127.0.0.1:6380> replicaof no one
OK

这种部署方式可以解决单点故障,但是当主节点出现故障时需要手动调整主节点,还是不够灵活,为了解决这个问题,就需要使用下面的哨兵模式

三、哨兵模式

哨兵模式是在主从模式的基础上,增加哨兵节点,哨兵节点不存储数据,它是用来监控redis节点状态的,当发现主节点不可用时,自动在从节点中选择一个节点升级为主节点向外提供服务,同时调整其他从节点的主节点。在调整过程中不需要人为介入自动完成。
为了模拟主从切换的过程,需要再启动一个从节点6381,只需要将6380的配置文件修改端口号和目录即可,启动该节点设置它为6379的从节点:

[root@localhost redis-6.2.8]# ./src/redis-cli -p 6381 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6380> keys *
(empty array)
127.0.0.1:6381> config set masterauth 123456
OK
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info Replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_read_repl_offset:5690
slave_repl_offset:5690
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:87fef522d222acb9e9ef7eaa6aa74d4f92405112
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:5690
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:5677
repl_backlog_histlen:14
127.0.0.1:6381> 
127.0.0.1:6381> keys *
1) "testkey"
2) "hello"
127.0.0.1:6381> 

在6379上面看到两个副本节点都已经连接成功:

127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=5816,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=5816,lag=1
master_failover_state:no-failover
master_replid:87fef522d222acb9e9ef7eaa6aa74d4f92405112
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:5816
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1065
repl_backlog_histlen:4752
127.0.0.1:6379> 

接下来就是配置sentinel,哨兵模式必须要保证哨兵节点的高可用,所以sentinel必须是集群部署,并且多个sentinel部署到不同的服务器上面,避免一个节点出现故障导致其他的节点不可用,模拟环境就都在一个虚拟机上面测试了,分别在三个端口上面启动三个服务,分别是:26379、26380、26381。以其中一个配置文件为例,它的内容修改为下面这种:

# sentinel服务端口号
port 26379

# 以守护进程方式启动
daemonize yes

# 进程ID文件
pidfile /root/redis-6.2.8/sentinel/26379/data/redis-sentinel.pid

# 日志文件
logfile "/root/redis-6.2.8/sentinel/26379/data/redis-sentinel.log"

# 文件目录
dir /root/redis-6.2.8/sentinel/26379/data

# 指定sentinel监听的主节点名、主节点IP、端口号和法定节点数量;
# 不必指定副本节点信息,它会通过主节点获取到
sentinel monitor demo-master 192.168.56.101 6379 2

# 指定主节点的连接密码
sentinel auth-pass demo-master 123456

# sentinel认为主节点主观宕机,当sentinel节点ping主节点在指定时间内没有响应就认为节点不可用,此时是S_DOWN状态
sentinel down-after-milliseconds demo-master 5000

# 在进行故障转移过程中同时指向新主节点的副本数量。
# 如果副本节点是提供查询服务,那么就设置最小值,避免因为副本节点执行同步时无法对外提供服务
sentinel parallel-syncs demo-master 1

# 故障转移的超时时间,如果在这个时间内还没有完成故障转移,则认为失败
sentinel failover-timeout demo-master 180000

这里面需要注意一点,所有sentinel的master-name要保持一致,我使用的master-name是demo-master,修改配置文件后启动三个sentinel:

[root@localhost redis-6.2.8]# ./src/redis-sentinel ./sentinel/26379/sentinel.conf 
[root@localhost redis-6.2.8]# ./src/redis-sentinel ./sentinel/26380/sentinel.conf 
[root@localhost redis-6.2.8]# ./src/redis-sentinel ./sentinel/26381/sentinel.conf 
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ps -ef | grep redis
root     10128     1  0 Dec13 ?        00:00:49 ./src/redis-server 127.0.0.1:6379
root     10306     1  0 Dec13 ?        00:00:40 ./src/redis-server 127.0.0.1:6380
root     12452     1  0 09:34 ?        00:00:00 ./src/redis-server 127.0.0.1:6381
root     12536     1  0 09:48 ?        00:00:00 ./src/redis-sentinel *:26379 [sentinel]
root     12542     1  0 09:48 ?        00:00:00 ./src/redis-sentinel *:26380 [sentinel]
root     12548     1  0 09:48 ?        00:00:00 ./src/redis-sentinel *:26381 [sentinel]
root     12556 12485  0 09:48 pts/3    00:00:00 grep --color=auto redis

[root@localhost data]# cat redis-sentinel.log 
12536:X 14 Dec 2023 09:48:01.601 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
12536:X 14 Dec 2023 09:48:01.601 # Redis version=6.2.8, bits=64, commit=00000000, modified=0, pid=12536, just started
12536:X 14 Dec 2023 09:48:01.601 # Configuration loaded
12536:X 14 Dec 2023 09:48:01.602 * Increased maximum number of open files to 10032 (it was originally set to 1024).
12536:X 14 Dec 2023 09:48:01.602 * monotonic clock: POSIX clock_gettime
12536:X 14 Dec 2023 09:48:01.603 * Running mode=sentinel, port=26379.
12536:X 14 Dec 2023 09:48:01.603 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
12536:X 14 Dec 2023 09:48:01.607 # Sentinel ID is d16326ba6e89d714cf1bcfbfe2f637bff83565f4
12536:X 14 Dec 2023 09:48:01.607 # +monitor master demo-master 192.168.56.101 6379 quorum 2
12536:X 14 Dec 2023 09:48:01.607 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:48:01.611 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:48:09.145 * +sentinel sentinel 8762b5f66a32812efca716c3fbfcd061d1db7143 127.0.0.1 26380 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:48:12.266 * +sentinel sentinel 8aaea7bfa6321da45d267c0c4680d5870f402855 127.0.0.1 26381 @ demo-master 192.168.56.101 6379

通过上面的进程信息和日志内容可以确认所有的sentinel都已经启动成功并且正在监控redis集群,下面做一下测试,现在把redis服务的主节点进程杀掉,在通过日志信息查看是否可以实现自动故障转移,在执行操作前先分别在三个redis节点上确认主从关系后,直接kill -9杀掉6379对应的进程,再次查看sentinel日志内容:

12536:X 14 Dec 2023 09:56:48.141 # +sdown master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:48.193 # +odown master demo-master 192.168.56.101 6379 #quorum 2/2
12536:X 14 Dec 2023 09:56:48.194 # +new-epoch 1
12536:X 14 Dec 2023 09:56:48.194 # +try-failover master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:48.202 # +vote-for-leader d16326ba6e89d714cf1bcfbfe2f637bff83565f4 1
12536:X 14 Dec 2023 09:56:48.214 # 8aaea7bfa6321da45d267c0c4680d5870f402855 voted for d16326ba6e89d714cf1bcfbfe2f637bff83565f4 1
12536:X 14 Dec 2023 09:56:48.217 # 8762b5f66a32812efca716c3fbfcd061d1db7143 voted for d16326ba6e89d714cf1bcfbfe2f637bff83565f4 1
12536:X 14 Dec 2023 09:56:48.303 # +elected-leader master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:48.303 # +failover-state-select-slave master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:48.362 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:48.362 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:48.428 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:49.233 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:49.233 # +failover-state-reconf-slaves master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:49.299 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:50.273 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:50.273 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:50.363 # -odown master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:50.363 # +failover-end master demo-master 192.168.56.101 6379
12536:X 14 Dec 2023 09:56:50.363 # +switch-master demo-master 192.168.56.101 6379 127.0.0.1 6380
12536:X 14 Dec 2023 09:56:50.363 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ demo-master 192.168.56.101 6380
12536:X 14 Dec 2023 09:56:50.363 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ demo-master 192.168.56.101 6380
12536:X 14 Dec 2023 09:56:55.418 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ demo-master 192.168.56.101 6380

日志中可以发现已经在进行故障转移了。新的主节点是6380,并且6381自动连接到6380上成为从节点。在故障转移过程中没有人为参与操作,完全自动感知并切换。
接下来重启6379服务,会发现6379自动以从节点身份加入到主从模式中。

12536:X 14 Dec 2023 10:19:36.722 * +reboot slave 127.0.0.1:6379 127.0.0.1 6379 @ demo-master 192.168.56.101 6380
12536:X 14 Dec 2023 10:19:36.799 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ demo-master 192.168.56.101 6380

sentinel监控和故障转移:

S_DOWN:主观下线。当一个哨兵ping主节点master超过配置的 down-after-milliseconds 时间仍没有应答,就标记为主观下线。
O_DOWN:客观下线。如果达到quorum数量的哨兵都标记一个master下线了,那么就是客观下线。这时会开始新的选择主节点流程。

从节点升级为主节点顺序:

(1)按照slave优先级进行排序,replica-priority越低,优先级就越高,但是0是一个特殊值,如果一个节点的replica-priority=0,那么这个节点不会被选择成为master。replica-priority的默认值是100。
(2)如果replica-priority相同,那么看replica offset,哪个slave复制了越多的数据,优先级就越高。
(3)如果上面两个条件都相同,那么选择一个run id比较小的那个slave。

四、集群部署

哨兵模式实现了故障发现和转移,一般来说可以满足大部分的使用场景,但是当数据规模非常大时很容易达到硬件资源的瓶颈,为了解决这种问题,就需要采用集群化部署方案,通过横向扩展打破资源瓶颈。采用redis集群部署方案就可以满足这种场景的需求,我们知道redis数据保存位置是通过计算键的hash槽来实现的,而集群化部署就是通过将hash槽分布到不同的redis节点实现扩容。
这里在一台服务器上面启动6个实例模拟redis集群模式,端口号范围是 7001~7006。集群模式开启非常简单,只需要在配置文件中cluster模块中打开相关配置即可,在项目的根目录下创建一个文件夹cluster,在它里面再根据端口号新建6个目录,将配置文件复制到每个目录下并修改配置文件的端口号和文件路径,同时启动这6个服务:

# 服务绑定的IP地址
bind 127.0.0.1 192.168.56.101

# redis端口号
port 7001

# 指定redis服务以守护进程方式运行
daemonize yes

# 指定redis服务pid文件路径
pidfile /root/redis-6.2.8/cluster/7001/data/redis_7001.pid

# 指定redis服务日志输出文件
logfile "/root/redis-6.2.8/cluster/7001/data/redis.log"

# 指定redis持久化文件目录
dir /root/redis-6.2.8/cluster/7001/data/

# 指定服务密码
requirepass 123456

# 主从连接时指定主节点密码
masterauth 123456

# 最大内存大小,建议设置避免因为内存不足导致服务失败
maxmemory 1gb

# 到达最大内存时的键淘汰策略,默认是不淘汰,这里就需要根据实际业务场景选择了,
# 如果只是作为缓存使用,数据丢失后可以再加载回来就选择合适的淘汰策略,可以避免因为内存不足的请求失败
maxmemory-policy volatile-ttl

# 开启aof持久化方式
appendonly yes

# aof持久化文件名
appendfilename "appendonly.aof"

# 每一秒钟持久化一次,服务宕机最多丢失1s数据
# appendfsync always
appendfsync everysec
# appendfsync no

# 开启集群模式
cluster-enabled yes

# 集群节点文件名称,不需要手动创建,由集群的redis节点自己维护
cluster-config-file /root/redis-6.2.8/cluster/7001/data/nodes-7001.conf

# 节点心跳失败的超时时间
cluster-node-timeout 5000

# 指定实例的IP
replica-announce-ip 192.168.56.101

查看服务启动后的进程信息:

[root@localhost redis-6.2.8]# ./src/redis-server ./cluster/7001/redis.conf
[root@localhost redis-6.2.8]# ./src/redis-server ./cluster/7002/redis.conf
[root@localhost redis-6.2.8]# ./src/redis-server ./cluster/7003/redis.conf
[root@localhost redis-6.2.8]# ./src/redis-server ./cluster/7004/redis.conf
[root@localhost redis-6.2.8]# ./src/redis-server ./cluster/7005/redis.conf
[root@localhost redis-6.2.8]# ./src/redis-server ./cluster/7006/redis.conf
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ps -ef | grep redis
root     14074     1  0 18:00 ?        00:00:00 ./src/redis-server 127.0.0.1:7001 [cluster]
root     14080     1  0 18:00 ?        00:00:00 ./src/redis-server 127.0.0.1:7002 [cluster]
root     14086     1  0 18:00 ?        00:00:00 ./src/redis-server 127.0.0.1:7003 [cluster]
root     14092     1  0 18:00 ?        00:00:00 ./src/redis-server 127.0.0.1:7004 [cluster]
root     14098     1  0 18:00 ?        00:00:00 ./src/redis-server 127.0.0.1:7005 [cluster]
root     14104     1  0 18:00 ?        00:00:00 ./src/redis-server 127.0.0.1:7006 [cluster]
root     14110 12248  0 18:00 pts/2    00:00:00 grep --color=auto redis
[root@localhost redis-6.2.8]# 

接下来就是进行集群的初始化操作,集群初始化就是将16384个hash槽分配到不同的主节点上,由于这里配置了6个节点,分为3主节点3从节点。每个主节点都有一个从节点,执行分配命令如下:

[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 --cluster create 192.168.56.101:7001 192.168.56.101:7002 192.168.56.101:7003 192.168.56.101:7004 192.168.56.101:7005 192.168.56.101:7006 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.56.101:7005 to 192.168.56.101:7001
Adding replica 192.168.56.101:7006 to 192.168.56.101:7002
Adding replica 192.168.56.101:7004 to 192.168.56.101:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001
   slots:[0-5460] (5461 slots) master
M: 32575a098691bf62a876311bd50f11e61016f5d8 192.168.56.101:7002
   slots:[5461-10922] (5462 slots) master
M: bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 192.168.56.101:7003
   slots:[10923-16383] (5461 slots) master
S: 9bf4b98df5b88b13b27c10d57247a51d3c9d9391 192.168.56.101:7004
   replicates bfbd54d5cf466231fc1868bd7f8c9fd85ce90867
S: 68e82c2818957f2a5f84870eabdf731c88100119 192.168.56.101:7005
   replicates e7f27418b4af8b06bb62966d8de81a7bac041c86
S: c228d6357bab662f0020f9920c21bb2e3c549ae5 192.168.56.101:7006
   replicates 32575a098691bf62a876311bd50f11e61016f5d8
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join

>>> Performing Cluster Check (using node 192.168.56.101:7001)
M: e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 32575a098691bf62a876311bd50f11e61016f5d8
M: 32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004
   slots: (0 slots) slave
   replicates bfbd54d5cf466231fc1868bd7f8c9fd85ce90867
S: 68e82c2818957f2a5f84870eabdf731c88100119 127.0.0.1:7005
   slots: (0 slots) slave
   replicates e7f27418b4af8b06bb62966d8de81a7bac041c86
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost redis-6.2.8]# 

看到上面的信息表示集群初始化成功,16384个hash槽均匀分布给了3个主节点。这个集群目前已经可以正常使用了。
下面介绍几个redis集群在日常运维中的常用命令和使用场景:

  1. 检查集群信息使用 ./redis-cli --cluster check 127.0.0.1:7001 命令:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 --cluster check 127.0.0.1:7001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7001 (e7f27418...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7002 (32575a09...) -> 0 keys | 5462 slots | 1 slaves.
127.0.0.1:7003 (bfbd54d5...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: e7f27418b4af8b06bb62966d8de81a7bac041c86 127.0.0.1:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 32575a098691bf62a876311bd50f11e61016f5d8
M: 32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004
   slots: (0 slots) slave
   replicates bfbd54d5cf466231fc1868bd7f8c9fd85ce90867
S: 68e82c2818957f2a5f84870eabdf731c88100119 127.0.0.1:7005
   slots: (0 slots) slave
   replicates e7f27418b4af8b06bb62966d8de81a7bac041c86
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost redis-6.2.8]# 
  1. 查看集群节点信息使用 ./redis-cli -p 7001 cluster nodes 命令:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7001 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006@17006 slave 32575a098691bf62a876311bd50f11e61016f5d8 0 1702551087060 2 connected
32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002@17002 master - 0 1702551088064 2 connected 5461-10922
bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003@17003 master - 0 1702551089070 3 connected 10923-16383
9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004@17004 slave bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 0 1702551088568 3 connected
68e82c2818957f2a5f84870eabdf731c88100119 127.0.0.1:7005@17005 slave e7f27418b4af8b06bb62966d8de81a7bac041c86 0 1702551087563 1 connected
e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001@17001 myself,master - 0 1702551088000 1 connected 0-5460
[root@localhost redis-6.2.8]# 
  1. 连接redis集群需要在命令后跟-c,如:./redis-cli -p 7001 -c 否则是连接单个节点:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7001 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7001> set hello world!
OK
127.0.0.1:7001> set nihao nihaoya
-> Redirected to slot [11081] located at 127.0.0.1:7003
OK
127.0.0.1:7003> 

Redis Cluster集群中slave节点能复制master节点数据,但是无法get数据,显示只能到对应的master节点读取。这是因为Redis Cluster集群中的从节点,官方默认设置的是不分担读请求、只作备份和故障转移用,当有请求读向从节点时,会被重定向对应的主节点来处理。如果要在从节点要读取数据,需要在get数据之前先使用命令readonly,这个命令告诉Redis Cluster集群当前从节点客户端愿意读取可能过时的数据并且对写请求不感兴趣。如上面的hello命令写入了7001节点,它的从节点是7005,我们直接连接到7005节点测试获取数据:

[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7005 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7005> get hello
-> Redirected to slot [866] located at 127.0.0.1:7001
"world!"
127.0.0.1:7001> 
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7005 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7005> readonly
OK
127.0.0.1:7005> get hello
"world!"
127.0.0.1:7005> 
  1. 查看集群信息使用 ./redis-cli -p 7001 cluster info 命令:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7001 cluster info
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:6847
cluster_stats_messages_pong_sent:6836
cluster_stats_messages_sent:13683
cluster_stats_messages_ping_received:6831
cluster_stats_messages_pong_received:6847
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:13683
  1. 在线上会有这种情况,当向集群中添加节点或将某个节点从集群中移除,或者因为硬件原因需要更换服务器,这个时候就需要将某个节点上的hash槽分配到其他的节点上,hash槽分配使用 ./redis-cli --cluster reshard 127.0.0.1:7001 命令:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 --cluster reshard 127.0.0.1:7001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: e7f27418b4af8b06bb62966d8de81a7bac041c86 127.0.0.1:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 32575a098691bf62a876311bd50f11e61016f5d8
M: 32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004
   slots: (0 slots) slave
   replicates bfbd54d5cf466231fc1868bd7f8c9fd85ce90867
S: 68e82c2818957f2a5f84870eabdf731c88100119 127.0.0.1:7005
   slots: (0 slots) slave
   replicates e7f27418b4af8b06bb62966d8de81a7bac041c86
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 1
What is the receiving node ID? e7f27418b4af8b06bb62966d8de81a7bac041c86
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: 32575a098691bf62a876311bd50f11e61016f5d8
Source node #2: done

Ready to move 1 slots.
  Source nodes:
    M: 32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002
       slots:[5461-10922] (5462 slots) master
       1 additional replica(s)
  Destination node:
    M: e7f27418b4af8b06bb62966d8de81a7bac041c86 127.0.0.1:7001
       slots:[0-5460] (5461 slots) master
       1 additional replica(s)
  Resharding plan:
    Moving slot 5461 from 32575a098691bf62a876311bd50f11e61016f5d8
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 5461 from 127.0.0.1:7002 to 127.0.0.1:7001: 
[root@localhost redis-6.2.8]# 

上面是分步执行的命令,也可以合成一条命令执行:

./redis-cli --cluster reshard 127.0.0.1:7001 --cluster-from 32575a098691bf62a876311bd50f11e61016f5d8 --cluster-to e7f27418b4af8b06bb62966d8de81a7bac041c86 --cluster-slots 1 --cluster-yes

# 命令含义
redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
  1. 如果某个节点需要从集群中删除,使用下面命令 ./redis-cli --cluster del-node 127.0.0.1:7001 68e82c2818957f2a5f84870eabdf731c88100119 这一串字符表示节点ID,这里删除的是7005这个节点:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 --cluster del-node 127.0.0.1:7001 68e82c2818957f2a5f84870eabdf731c88100119
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Removing node 68e82c2818957f2a5f84870eabdf731c88100119 from cluster 127.0.0.1:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7001 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006@17006 slave 32575a098691bf62a876311bd50f11e61016f5d8 0 1702553434659 2 connected
32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002@17002 master - 0 1702553435562 2 connected 5462-10922
bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003@17003 master - 0 1702553435663 3 connected 10923-16383
9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004@17004 slave bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 0 1702553434000 3 connected
e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001@17001 myself,master - 0 1702553433000 7 connected 0-5461
[root@localhost redis-6.2.8]# 
  1. 要将某个节点添加到集群中,使用 ./redis-cli -a 123456 --cluster add-node 192.168.56.101:7005 192.168.56.101:7001 命令,192.168.56.101:7005 是要添加的节点,192.168.56.101:7001 是集群中的连接节点,可以是集群中的任意节点:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 --cluster add-node 192.168.56.101:7005 192.168.56.101:7001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 192.168.56.101:7005 to cluster 192.168.56.101:7001
>>> Performing Cluster Check (using node 192.168.56.101:7001)
M: e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001
   slots:[0-5461] (5462 slots) master
S: c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 32575a098691bf62a876311bd50f11e61016f5d8
M: 32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002
   slots:[5462-10922] (5461 slots) master
   1 additional replica(s)
M: bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004
   slots: (0 slots) slave
   replicates bfbd54d5cf466231fc1868bd7f8c9fd85ce90867
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.56.101:7005 to make it join the cluster.
[OK] New node added correctly.
[root@localhost redis-6.2.8]# 
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7001 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006@17006 slave 32575a098691bf62a876311bd50f11e61016f5d8 0 1702553779000 2 connected
32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002@17002 master - 0 1702553780227 2 connected 5462-10922
bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003@17003 master - 0 1702553780730 3 connected 10923-16383
68e82c2818957f2a5f84870eabdf731c88100119 127.0.0.1:7005@17005 master - 0 1702553780000 5 connected
9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004@17004 slave bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 0 1702553779000 3 connected
e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001@17001 myself,master - 0 1702553779000 7 connected 0-5461
[root@localhost redis-6.2.8]# 

上面显示7005已经添加到集群中,并且是master节点身份,但是此时并没有分配hash槽给该节点,此时如果想让该节点以master节点运行,就执行 reshard 命令分配hash槽给该节点,但是这里我不想让它以master节点运行,想让它成为7001节点的从节点,使用下面的命令 ./redis-cli -p 7005 cluster replicate e7f27418b4af8b06bb62966d8de81a7bac041c86

[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7005 cluster replicate e7f27418b4af8b06bb62966d8de81a7bac041c86
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
OK
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 -p 7001 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
c228d6357bab662f0020f9920c21bb2e3c549ae5 127.0.0.1:7006@17006 slave 32575a098691bf62a876311bd50f11e61016f5d8 0 1702554248000 2 connected
32575a098691bf62a876311bd50f11e61016f5d8 127.0.0.1:7002@17002 master - 0 1702554249504 2 connected 5462-10922
bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 127.0.0.1:7003@17003 master - 0 1702554249504 3 connected 10923-16383
68e82c2818957f2a5f84870eabdf731c88100119 127.0.0.1:7005@17005 slave e7f27418b4af8b06bb62966d8de81a7bac041c86 0 1702554249000 7 connected
9bf4b98df5b88b13b27c10d57247a51d3c9d9391 127.0.0.1:7004@17004 slave bfbd54d5cf466231fc1868bd7f8c9fd85ce90867 0 1702554248599 3 connected
e7f27418b4af8b06bb62966d8de81a7bac041c86 192.168.56.101:7001@17001 myself,master - 0 1702554248000 7 connected 0-5461
[root@localhost redis-6.2.8]# 
  1. 有些时候,集群的hash槽分配倾斜,想让集群重新平衡分片,可以使用 ./redis-cli --cluster rebalance 192.168.56.101:7001 命令达到目的:
[root@localhost redis-6.2.8]# ./src/redis-cli -a 123456 --cluster rebalance 192.168.56.101:7001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing Cluster Check (using node 192.168.56.101:7001)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** No rebalancing needed! All nodes are within the 2.00% threshold.
[root@localhost redis-6.2.8]# 

由于所有hash槽分配很均匀,所以就没有执行重平衡,要想验证效果,可以使用 reshard 命令将hash槽的分配变为不均匀,就可以看到效果了,但是这里需要注意:如果某个master节点上没有分配hash槽(也就是hash槽数量是0),这里再进行重平衡也不会分配hash槽到那个节点上

命令总结:

以下命令如果redis已经配置了密码,需要用 -a password 在命令中。
1. 集群初始化命令:
./redis-cli --cluster create 192.168.56.101:7001 192.168.56.101:7002 192.168.56.101:7003 192.168.56.101:7004 192.168.56.101:7005 192.168.56.101:7006 --cluster-replicas 1

2. 查看集群节点:
./redis-cli -p 7001 cluster nodes

3. 查看集群信息集群信息:
./redis-cli -p 7001 cluster info

4. 检查集群状态:
./redis-cli --cluster check 127.0.0.1:7001

5. 将hash槽分散到其他节点:
./redis-cli --cluster reshard 127.0.0.1:7001
多个命令合成一条命令执行:
./redis-cli --cluster reshard 127.0.0.1:7001 --cluster-from 32575a098691bf62a876311bd50f11e61016f5d8 --cluster-to e7f27418b4af8b06bb62966d8de81a7bac041c86 --cluster-slots 1 --cluster-yes
redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes

6. 删除节点
./redis-cli --cluster del-node 127.0.0.1:7001 <node-id>

7. 添加节点:192.168.56.101:7005 是添加节点 192.168.56.101:7001是集群中的连接节点,可以是集群中的任意节点
./redis-cli --cluster add-node 192.168.56.101:7005 192.168.56.101:7001

8. 使节点成为某个节点的从节点:连接到那个节点,让这个节点成为某个节点的从节点
./redis-cli -p 7005 cluster replicate e7f27418b4af8b06bb62966d8de81a7bac041c86

9. 自动重新分片
./redis-cli --cluster rebalance 192.168.56.101:7001

redis集群hash槽分配使用的是一致性hash算法,是使用crc16算法进行具体计算的。下面是java版本的crc16算法实现的:

/**
 * CRC16算法
 * 
 * @Author xingo
 * @Date 2023/12/13
 */
public final class CRC16 {

    private static final int[] LOOKUP_TABLE = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6,
            0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273,
            0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF,
            0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528,
            0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695,
            0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886,
            0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A,
            0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF,
            0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60,
            0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5,
            0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59,
            0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2,
            0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F,
            0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8,
            0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424,
            0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691,
            0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A,
            0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F,
            0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3,
            0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64,
            0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9,
            0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 };

    private CRC16() {
    }

    public static int crc16(byte[] bytes) {
        int crc = 0x0000;

        for (byte b : bytes) {
            crc = (crc << 8) ^ LOOKUP_TABLE[((crc >>> 8) ^ (b & 0xFF)) & 0xFF];
        }
        return crc & 0xFFFF;
    }
}

redis集群计算键的hash槽工具类:

import java.util.Arrays;

/**
 * redis集群工具
 * 
 * @Author xingo
 * @Date 2023/12/13
 */
public class ClusterRedisUtils {

    public static final int MAX_SLOT = 16384;

    /**
     * 计算键的hash槽
     * @param key
     * @return
     */
    public static int calcSlot(String key) {
        if (key == null) {
            return 0;
        }

        int start = key.indexOf('{');
        if (start != -1) {
            int end = key.indexOf('}');
            key = key.substring(start+1, end);
        }

        int result = CRC16.crc16(key.getBytes()) % MAX_SLOT;
        return result;
    }

    private static int indexOf(byte[] array, byte element) {
        for (int i = 0; i < array.length; ++i) {
            if (array[i] == element) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 计算键的hash槽
     * @param key
     * @return
     */
    public static int calcSlot(byte[] key) {
        if (key == null) {
            return 0;
        }

        int start = indexOf(key, (byte) '{');
        if (start != -1) {
            int end = indexOf(key, (byte) '}');
            key = Arrays.copyOfRange(key, start+1, end);
        }

        int result = CRC16.crc16(key) % MAX_SLOT;
        return result;
    }
}

文章来源:https://blog.csdn.net/dream_xin2013/article/details/134972365
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。