CentOS下Redis部署记录(单机+主从+哨兵+集群)
Redis简介
Redis是一个开源、高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的Web应用程序。它有三个主要特点,使其优越于其它键值数据存储系统:
- Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化
- 与其它键值数据存储相比,Redis有一组相对丰富的数据类型
- Redis可以将数据复制到任意数量的从机中
部署声明
本文基于CentOS 7系统,由浅入深讲解如何部署Redis的四种模式,分别是:单机模式、主从模式、哨兵模式、集群模式
需注意,这里因为只用于演示,所以这四种模式都是部署在同一台CentOS机器上(通过不同的服务端口区分不同的Redis实例)。实际使用时,一般会使用多台机器部署,此时只需要对应修改IP即可,部署过程是一样的。
前置环境部署
如果只是部署Redis的单机模式/主从模式/哨兵模式,是不需要安装这个前置环境的
如果是要部署Redis的集群模式(Redis Cluster
),需要安装这个前置环境
这是因为Redis Cluster
需要使用ruby脚本构建。虽然CentOS 7自带ruby支持库的安装源,但是版本过低(只是2.0.0版本),Redis要求ruby的版本至少为2.2.2
(1)安装Ruby最新版本
(2)安装ruby的redis包(用于redis通讯)
gem install redis
# 若前面安装ruby版本过低就会报错:
# ERROR: Error installing redis:
# redis requires Ruby version >= 2.2.2.
单机模式
简介
单机模式是Redis最基本的模式,之后的主从、哨兵、集群模式都是据此扩展而来。而且在开发环境下,出于方便起见,一般部署单机模式即可满足调试要求。
安装
中文官网:http://www.redis.cn/
英文官网(需翻墙):https://redis.io/
# cd /data/server/
# wget http://download.redis.io/releases/redis-5.0.4.tar.gz
# tar -zxf redis-5.0.4.tar.gz
# cd redis-5.0.4/
# make MALLOC=libc
部署
默认情况下,Redis通过以下方式启动/停止:
cd src/ # 切换到启动脚本目录
./redis-server ../redis.conf # 启动Redis
Ctrl + C # 停止Redis
这种启动方式非但无法在后台运行,而且也不符合使用习惯。另外默认情况下Redis也不直接支持开机自启,为此要对其进行改造。
mkdir /data/redis
mkdir /data/etc/redis
vim /usr/local/redis-5.0.4/redis.conf
daemonize yes # 后台启动模式
# 顺便修改一下其他配置项
maxmemory 536870912 # 最大内存(单位byte),需根据实际配置,建议为当前空闲内存的50%左右
dir /data/redis # Redis的工作目录(若不存在需手建否则无法启动),默认值为[./],logfile与dbfilename受其影响
logfile "6379.log" # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump.rdb # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
# cp /data/server/redis-5.0.4/redis.conf /data/etc/redis/6379.conf
# cp /data/server/redis-5.0.4/utils/redis_init_script /etc/init.d/redisd
# vim vi /etc/init.d/redisd
#!/bin/sh
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
其含义是Redis服务必须在运行级2,3,4,5下被启动或关闭,启动的优先级是90,关闭的优先级是10
# cd /etc/init.d
# chkconfig redisd on # 设置为开机自启,若不需要自启则执行 chkconfig redisd off
# systemctl start redisd # 或 service redisd start 启动Redis服务
# systemctl stop redisd # 或 service redisd stop 停止Redis服务
测试
通过Redis测试客户端命令redis-cli
连接到Redis实例:
# cd /data/server/redis-5.0.4/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 6379 # 连接到Redis
172.168.10.10:6379> info # 查看Redis信息
主从模式
简介
在实际生产环境下,Redis基本上是不可能部署成单机模式的。一般都需要部署Redis集群实现高可用,以保障业务的稳定运行。
要学会部署Redis集群,那就先从Redis集群中最简单的主从模式说起。
在一些简单小型的应用中,我们可能会看到类似于下图的Redis部署架构。其中Master是主机,Slave是从机,而这种架构方式就是所谓的一主多从:
在这种架构模式下,主机和从机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机则只支持与主机数据的同步和读取。也就是说,客户端可以将数据写入到主机,由主机自动将数据的写入操作同步到从机。
主从模式很好的解决了数据备份问题,并且由于主从服务数据几乎是一致的,因而可以将写入数据的命令发送给主机执行,而读取数据的命令发送给不同的从机执行,从而达到读写分离的目的。
部署
下面演示如何部署一个一主三从的主从模式。
为了区分单机模式的部署位置,拷贝一下Redis目录,下文则基于/data/server/redis-ms
目录部署主从模式。
# cp -r /data/server/redis-5.0.4 /data/server/redis-ms
# mkdir /data/redis-ms/
由于每个Redis实例都是一个单独的进程,所以需要在每个Redis实例启动时为其分配一个独立的配置文件就能使他们区分开来(同时由于本文是部署在同一台机器,需为每个实例指定不同的服务端口)。
为了在同一台机器上部署一主三从的Redis,准备以下四份配置文件:
角色 | 配置文件 | 服务端口 |
---|---|---|
主机 | redis-6379.conf | 6379 |
从机 | redis-6380.conf | 6380 |
从机 | redis-6381.conf | 6381 |
从机 | redis-6382.conf | 6382 |
这四份配置文件均拷贝自 /data/server/redis-ms/redis.conf
,拷贝到 /data/etc/redis/
目录再修改即可
主机redis-6379.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6379.log" # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6379.rdb # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
从机redis-6380.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6380.log" # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6380.rdb # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
slaveof 127.0.0.1 6379 # 标注所从属的主机
从机redis-6381.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 6381
daemonize yes
pidfile /var/run/redis_6381.pid
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6381.log" # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6381.rdb # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
slaveof 127.0.0.1 6379 # 标注所从属的主机
从机redis-6382.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 6382
daemonize yes
pidfile /var/run/redis_6382.pid
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "6382.log" # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-6382.rdb # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
slaveof 127.0.0.1 6379 # 标注所从属的主机
使用redis-server命令启动Redis主从实例:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-server /data/etc/redis/redis-6379.conf # 启动Redis主机,必须先启动
# ./redis-server /data/etc/redis/redis-6380.conf # 启动Redis从机
# ./redis-server /data/etc/redis/redis-6381.conf # 启动Redis从机
# ./redis-server /data/etc/redis/redis-6382.conf # 启动Redis从机
测试
现在测试Redis主从模式是否能正常工作。
可先通过ps -ef | grep redis
命令可查看四个主从进程是否正常启动:
root 3919 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6379
root 3925 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6380
root 3930 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6381
root 3936 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6382
然后通过Redis测试客户端命令redis-cli分别连接到四台机器:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 6379 # 连接到Redis主机
# ./redis-cli -h 127.0.0.1 -p 6380 # 连接到Redis从机
# ./redis-cli -h 127.0.0.1 -p 6381 # 连接到Redis从机
# ./redis-cli -h 127.0.0.1 -p 6382 # 连接到Redis从机
分别在四个Redis测试客户端执行get命令,获取键名为site的数据:
127.0.0.1:6379> get site
(nil) # 由于是新部署的Redis集群,该键值必定不存在
127.0.0.1:6380> get site
(nil) # 由于是新部署的Redis集群,该键值必定不存在
127.0.0.1:6381> get site
(nil) # 由于是新部署的Redis集群,该键值必定不存在
127.0.0.1:6382> get site
(nil) # 由于是新部署的Redis集群,该键值必定不存在
现在在Redis主机6379的客户端写入数据(执行set命令,为键site设置数据):
127.0.0.1:6379> set site http://www.appblog.cn
再在三台Redis从机6380~6382的客户端读取数据(执行get命令,获取键名为site的数据)。由于经过主从数据同步,此时三台从机都能取到值:
127.0.0.1:6380> get site
"http://www.appblog.cn"
127.0.0.1:6381> get site
"http://www.appblog.cn"
127.0.0.1:6382> get site
"http://www.appblog.cn"
至此Redis主从模式部署完成。
下一阶段哨兵模式的部署是基于主从模式的,可以暂且不用停止Redis进程。
哨兵模式
简介
前面所配置的主从模式,虽然实现了读写分离,解决了数据备份问题和单机模式可能存在的性能问题,但是也引入了新的问题:
由于主从模式下可以将读写操作分配给不同的Redis节点,从而达到提高系统吞吐量的目的,但也正是因为这种方式造成了使用上的不便。因为客户端连接到不同的Redis节点时,都需要指定特定的IP端口,若所连接的节点因为故障下线了,主从模式便无法通知客户端切换到另一个可用节点,只能靠手动更改客户端配置并重连。
尤其是如果故障下线的是主节点,那么所有的从节点便会因为没有主节点而同步中断,整个集群会陷入瘫痪(严格来说是所有从节点变成独立节点,再无关联性),直至人工重新指定新的主节点。
为了解决上面的问题,Redis在2.8版本后开始支持哨兵模式,其架构模式如下图:
Redis的Sentinel系统(即哨兵系统)可用于管理多组Redis主从实例,它是Redis的高可用性解决方案。这个系统主要执行以下三个任务:
- 监控(Monitoring):Sentinel会不断地定期检查主/从节点服务器是否运作正常
- 提醒(Notification):当被监控的某个节点服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知
- 自动故障迁移(Automaticfailover):当一个主节点不能正常工作时,Sentinel会开始一次自动故障迁移操作,它会将失效主节点下的其中一个从节点升级为新的主节点,并让失效主节点的其他从节点改为复制新的主节点。当Redis客户端试图连接失效的主节点时,集群也会向客户端返回新主节点的地址,使得集群可以使用新主节点代替失效主节点。
部署
下面演示如何在上一阶段的主从模式基础上,增加部署一套哨兵系统。
先准备好三份配置文件:
角色 | 配置文件 | 服务端口 |
---|---|---|
哨兵 | sentinel-26380.conf | 26380 |
哨兵 | sentinel-26381.conf | 26381 |
哨兵 | sentinel-26382.conf | 26382 |
注:
① 这三份配置文件均拷贝自/data/server/redis-ms/sentinel.conf
,拷贝到/data/etc/redis-ms/
目录再修改即可
② 建议哨兵至少部署3个,并且哨兵节点数量要满足2n+1(n>=1),即奇数个
哨兵sentinel-26380.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 26380
daemonize yes # 后台启动模式(若无配置项则添加)
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile受其影响
logfile "sentinel-26380.log" # 哨兵日志名称(若无配置项则添加),正式部署请设置为合适的名称
sentinel monitor appblog.cn 127.0.0.1 6379 2 # 标注所监视的主机(其下的从机会被自动拉取,无需配置)
sentinel down-after-milliseconds appblog.cn 30000
sentinel parallel-syncs appblog.cn 1
sentinel failover-timeout appblog.cn 180000
哨兵sentinel-26381.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 26381
daemonize yes # 后台启动模式(若无配置项则添加)
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile受其影响
logfile "sentinel-26381.log" # 哨兵日志名称(若无配置项则添加),正式部署请设置为合适的名称
sentinel monitor appblog.cn 127.0.0.1 6379 2 # 标注所监视的主机(其下的从机会被自动拉取,无需配置)
sentinel down-after-milliseconds appblog.cn 30000
sentinel parallel-syncs appblog.cn 1
sentinel failover-timeout appblog.cn 180000
哨兵sentinel-26382.conf
配置文件内容如下:
bind 127.0.0.1 # 正式部署请设为合适的IP
port 26382
daemonize yes # 后台启动模式(若无配置项则添加)
dir /data/redis-ms # Redis的工作目录(若不存在需手建否则无法启动),logfile受其影响
logfile "sentinel-26382.log" # 哨兵日志名称(若无配置项则添加),正式部署请设置为合适的名称
sentinel monitor appblog.cn 127.0.0.1 6379 2 # 标注所监视的主机(其下的从机会被自动拉取,无需配置)
sentinel down-after-milliseconds appblog.cn 30000
sentinel parallel-syncs appblog.cn 1
sentinel failover-timeout appblog.cn 180000
针对上述几个sentinel-xxxxx.conf配置中的几个关键配置项说明如下:
sentinel monitor appblog.cn 127.0.0.1 6379 2
监控的主节点名字为MARKDOWN_HASH53b776dfae666acc1e325f77e97f31cbMARKDOWNHASH
(该名字任意的,有效字符为[A-Z] [a-z] [0-9] [.-])
监控的主节点服务地址127.0.0.1:6379
行尾最后的2表示当集群中有2个以上sentinel认为主节点下线时,才认为其客观下线
sentinel down-after-milliseconds appblog.cn 30000
主节点在30000 ms内无反应,哨兵会开始使用“选举机制”进行主从切换
sentinel parallel-syncs appblog.cn 1
在因主节点失效而发生故障转移(即主从切换)时,最多可以有多少个从节点同时对新的主节点进行并发同步
这个数字越小,完成故障转移所需的时间就越长(余下的从节点需要排队等待同步)
但这个数字越大,就意味着越多的从节点因为正在对新的主节点进行同步而不可用
当从节点只用于查询服务时,可将此值设为1确保最多只有一个从节点因同步而不可用
sentinel failover-timeout appblog.cn 180000
如果在该180000 ms内未能完成故障转移,则认这次故障转移超时失败
不过即使超时,从节点也会正确指向新主节点,但不会按照parallel-syncs规则进行同步
接下来即可启动Redis主从服务和Sentinel系统,启动顺序必须严格按照:
Redis Master(主节点) -> Redis Slave(从节点) -> Redis Sentinel(哨兵节点)
主从服务的启动在上一阶段已经做过,此处不再重述。Sentinel系统需要使用redis-sentinel命令启动:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-sentinel /data/etc/redis/sentinel-26380.conf # 启动Redis哨兵节点
# ./redis-sentinel /data/etc/redis/sentinel-26381.conf # 启动Redis哨兵节点
# ./redis-sentinel /data/etc/redis/sentinel-26382.conf # 启动Redis哨兵节点
测试
现在测试Sentinel系统是否能正常工作
可先通过ps -ef | grep redis
命令可查看四个主从进程和三个监控进程是否正常启动:
root 3919 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6379
root 3925 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6380
root 3930 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6381
root 3936 1 0 22:08 ? 00:00:02 ./redis-server 127.0.0.1:6382
root 4342 1 0 22:37 ? 00:00:00 ./redis-sentinel 127.0.0.1:26380 [sentinel]
root 4347 1 0 22:37 ? 00:00:00 ./redis-sentinel 127.0.0.1:26381 [sentinel]
root 4383 1 0 22:38 ? 00:00:00 ./redis-sentinel 127.0.0.1:26382 [sentinel]
然后通过Redis测试客户端命令redis-cli
连接到任意一台Sentinel机器查看监控信息(实际生产环境中,一般是不需要连接Sentinel机器的):
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 26380 # 连接到哨兵机26380
127.0.0.1:26380> info sentinel # 查看监控信息
# ./redis-cli -h 127.0.0.1 -p 26381 # 连接到哨兵机26381
127.0.0.1:26381> info sentinel # 查看监控信息
# ./redis-cli -h 127.0.0.1 -p 26382 # 连接到哨兵机26382
127.0.0.1:26382> info sentinel # 查看监控信息
# 三台哨兵的返回信息是一致的:
sentinel_masters:1 # 监控主机1台
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
# 0号主机名称为appblog.cn,地址为127.0.0.1:6379,共有三台从机,三台哨兵机
master0:name=appblog.cn,status=ok,address=127.0.0.1:6379,slaves=3,sentinels=3
现在尝试终止Redis主机进程(6379端口节点)来模拟主机下线:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 6379 # 连接到Redis主机
127.0.0.1:6379> shutdown # 终止Redis服务
然后连接到任意一台哨兵机,查看当前的监控信息:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 26380 # 连接到哨兵机26380
127.0.0.1:26380> info sentinel # 查看监控信息
# 返回监控信息
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=appblog.cn,status=ok,address=127.0.0.1:6382,slaves=3,sentinels=3 # 主机地址发生变化
不难发现主机变成127.0.0.1:6382
,登陆这台主机查看主从信息:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 6382 # 连接到Redis主机
127.0.0.1:6382> info replication # 查看主从信息
# 返回主从信息
role:master
connected_slaves:2 # 这台主机下有2台从机
slave0:ip=127.0.0.1,port=6381,state=online,offset=254791,lag=1 # 0号从机是 127.0.0.1:6381
slave1:ip=127.0.0.1,port=6380,state=online,offset=254791,lag=1 # 1号从机是 127.0.0.1:6380
由此可知,当原主机6379下线后,原从机6382被哨兵系统提升为新的主机,而其他的两台从机6380和6381变成新主机6382的从机。此时集群系统变成一主两从。
现在重新启动6379机器:
# cd /data/server/redis-ms/src/ # 切换到启动脚本目录
# ./redis-server /data/etc/redis/redis-6379.conf # 启动Redis机器
再登陆新主机127.0.0.1:6382
查看主从信息:
# cd /usr/local/redis-ms/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 6382 # 连接到Redis主机
127.0.0.1:6382> info replication # 查看主从信息
# 返回主从信息
role:master
connected_slaves:3 # 这台主机下变成有3台从机
slave0:ip=127.0.0.1,port=6381,state=online,offset=254791,lag=1 # 0号从机是 127.0.0.1:6381
slave1:ip=127.0.0.1,port=6380,state=online,offset=254791,lag=1 # 1号从机是 127.0.0.1:6380
slave2:ip=127.0.0.1,port=6379,state=online,offset=365581,lag=1 # 新挂接的2号从机是 127.0.0.1:6379
由此可知,当6379机器重新上线后,并不会恢复原主机的身份,而是被哨兵系统挂接到新主机6382下,成为其从机。此时集群系统重新变成一主三从。
至此Redis哨兵模式部署完成。
为了开始下一阶段部署,现在先停止前面部署的所有Redis进程:
pkill redis
附:哨兵模式一键启动/停止/重启脚本
此脚本是根据上文的部署方式和位置编写的,仅适用于Redis节点均在同一台机器的场景。
若要移植到其他地方使用,需要根据实际情况修改。
脚本内容如下:
#!/bin/bash
# 根据主从/哨兵模式的部署目录对应修改
cd /data/server/redis-ms/src/
# 启动函数
start()
{
./redis-server /data/etc/redis/redis-6379.conf &
./redis-server /data/etc/redis/redis-6380.conf &
./redis-server /data/etc/redis/redis-6381.conf &
./redis-server /data/etc/redis/redis-6382.conf &
./redis-sentinel /data/etc/redis/sentinel-26380.conf &
./redis-sentinel /data/etc/redis/sentinel-26381.conf &
./redis-sentinel /data/etc/redis/sentinel-26382.conf &
echo "redis all running"
}
# 停止函数
stop()
{
ps -ef | grep "redis" | grep -v "grep" |awk '{print $2}'| while read pid
do
C_PID=$(ps --no-heading $pid | wc -l)
if [[ $C_PID == "1" ]]; then
kill -9 $pid
echo "PID=$pid is dead"
else
echo "PID=$pid not exists"
fi
done
echo "all dead"
}
# 脚本入口参数 start|stop|restart
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
printf 'Usage: %s {start|stop|restart}\n'"$prog"
exit 1
;;
esac
这是shell脚本,保存为redis-mss.sh
(文件名任意)即可执行(若无法执行可能是换行符非Linux格式的问题,可尝试通过dos2unix命令修正换行符)。
使用方式如下:
# sh redis-mss.sh start # 启动
# sh redis-mss.sh stop # 停止
# sh redis-mss.sh restart # 重启
集群模式
简介
Redis在3.0版本后开始支持集群模式(Redis Cluster),目前官方一直都在维护中,具有代表性,建议优先使用。
Redis Cluster是一种服务器Sharding技术,只要将查询请求发送到Redis Cluster中的任意节点,接收到请求的节点会就将查询请求发送到正确的节点上执行:
当Redis客户端操作的key恰好在所查询的Redis节点上时,就像操作Redis单例一样。
当客户端操作的key没有分配到所查询的Redis节点上时,Redis会返回转向指令,指向正确的Redis节点,这类似于浏览器页面的302 重定向跳转。
Redis Cluster并没有使用一致性Hash,而是采用slot(槽)的概念,一共分成16384个槽。Redis Cluster要保证16384个槽对应的Redis节点都正常工作,否则一旦某个Redis节点发生故障,那它负责的slots也就失效,整个集群将不能工作。
为了增加集群的高可用性,官方推荐的方案是将Redis节点配置成主从结构,即一个主节点,挂N个从节点。这时,如果主节点失效,Redis Cluster会根据选举算法在从节点中选择一个上升为主节点,整个集群继续对外提供服务。
Redis Cluster的架构模式如下图:
上图描述的是六个redis实例构成的集群(三主三从),其中:
- 6379端口为客户端通讯端口
- 16379端口为集群总线端口
- 集群内部划分为16384个数据分槽,分布在三个主节点中
- 从节点没有分槽,不会参与集群投票,也不会提供数据读取服务,仅作为主节点的备份
- 三个主节点中平均分布着16384数据分槽的三分之一,每个节点中不会存在重复数据,仅仅使用自己的从机帮忙冗余
Redis Cluster具有以下优点:
- 无中心架构,支持动态扩容,对业务透明
- 具备Sentinel的监控和自动故障迁移能力
- 高性能,客户端直连Redis服务,免去了Proxy代理的损耗
- 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可(实际上是必须连接整个集群的,避免单点故障导致客户端不可用)
Redis Cluster同时也具有以下缺点:
- 部署和运维复杂
- 数据迁移需要人工干预
- 只能使用0号数据库
- 不支持批量操作
- 分布式逻辑和存储模块耦合
部署
下面演示如何部署集群模式。
官方推荐Redis Cluster至少需要六个节点,即三主三从。
这里准备六个Redis节点,同时为了区分主从/哨兵模式的部署位置,顺便拷贝一下Redis集群节点的目录(以节点端口号区分):
# mkdir /data/redis-cluster # 新建上面配置的Redis集群工作目录
# mkdir /data/server/redis-cluster # 创建Redis集群目录
# cp /data/server/redis-5.0.4/src/redis-trib.rb /data/server/redis-cluster/ # 集群构建脚本
# cp -r /data/server/redis-5.0.4 /data/server/redis-cluster/redis-6390 # Redis集群节点目录
# cp -r /data/server/redis-5.0.4 /data/server/redis-cluster/redis-6391 # Redis集群节点目录
# cp -r /data/server/redis-5.0.4 /data/server/redis-cluster/redis-6392 # Redis集群节点目录
# cp -r /data/server/redis-5.0.4 /data/server/redis-cluster/redis-6393 # Redis集群节点目录
# cp -r /data/server/redis-5.0.4 /data/server/redis-cluster/redis-6394 # Redis集群节点目录
# cp -r /data/server/redis-5.0.4 /data/server/redis-cluster/redis-6395 # Redis集群节点目录
下文会基于/data/server/redis-cluster/redis-xxxx
目录部署集群模式。
然后配置这六个Redis节点的配置文件,其配置基本相同(主从无需配置,在后面初次构建集群时会自动分配;以后若添加新节点,可人工指定是主节点还是从节点):
角色 | 配置文件 | 服务端口 |
---|---|---|
集群节点 | /data/server/redis-cluster/redis-6390/redis.conf | 6390 |
集群节点 | /data/server/redis-cluster/redis-6391/redis.conf | 6391 |
集群节点 | /data/server/redis-cluster/redis-6392/redis.conf | 6392 |
集群节点 | /data/server/redis-cluster/redis-6393/redis.conf | 6393 |
集群节点 | /data/server/redis-cluster/redis-6394/redis.conf | 6394 |
集群节点 | /data/server/redis-cluster/redis-6395/redis.conf | 6395 |
配置文件/data/server/redis-cluster/redis-639x/redis.conf
的内容如下(仅端口号不同):
bind 127.0.0.1 # 正式部署请设为合适的IP
port 639x
daemonize yes
pidfile /var/run/redis_639x.pid
dir /data/redis-cluster # Redis的工作目录(若不存在需手建否则无法启动),logfile与dbfilename受其影响
logfile "639x.log" # Redis日志名称(默认不配置,表示输出到stdout),正式部署请设置为合适的名称
dbfilename dump-639x.rdb # Redis数据持久化时的存储位置,正式部署请设置为合适的名称
cluster-enabled yes # 启用集群模式
cluster-config-file nodes-639x.conf # 集群节点的配置文件,由集群创建,但若同一台主机上的名称需唯一
cluster-node-timeout 15000
然后使用redis-server命令启动六个Redis节点:
# cd /data/server/redis-cluster/redis-6390/src/ # 切换到Redis-6390节点的启动脚本目录
# ./redis-server ../redis.conf # 启动Redis节点
# cd /data/server/redis-cluster/redis-6391/src/ # 切换到Redis-6391节点的启动脚本目录
# ./redis-server ../redis.conf # 启动Redis节点
# cd /data/server/redis-cluster/redis-6392/src/ # 切换到Redis-6392节点的启动脚本目录
# ./redis-server ../redis.conf # 启动Redis节点
# cd /data/server/redis-cluster/redis-6393/src/ # 切换到Redis-6393节点的启动脚本目录
# ./redis-server ../redis.conf # 启动Redis节点
# cd /data/server/redis-cluster/redis-6394/src/ # 切换到Redis-6394节点的启动脚本目录
# ./redis-server ../redis.conf # 启动Redis节点
# cd /data/server/redis-cluster/redis-6395/src/ # 切换到Redis-6395节点的启动脚本目录
# ./redis-server ../redis.conf # 启动Redis节点
先通过ps -ef | grep redis
命令可查看六个节点进程是否正常启动:
root 20305 1 0 01:41 ? 00:00:00 ./redis-server 127.0.0.1:6390 [cluster]
root 20320 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6391 [cluster]
root 20325 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6392 [cluster]
root 20330 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6393 [cluster]
root 20335 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6394 [cluster]
root 20340 1 0 01:43 ? 00:00:00 ./redis-server 127.0.0.1:6395 [cluster]
然后使用Redis官方提供的工具redis-trib.rb
(注意:这个是ruby脚本,需要安装相关支持库,否则无法运行)把这6个节点组建成集群(注意:若集群节点分布在多台不同的机器上,只需其中一个机器执行这条命令即可,但要包含所有机器的集群节点):
# cd /data/server/redis-cluster/ # 切换到集群构建脚本目录
# ./redis-trib.rb create --replicas 1 127.0.0.1:6390 127.0.0.1:6391 127.0.0.1:6392 127.0.0.1:6393 127.0.0.1:6394 127.0.0.1:6395
若以后机器IP发生变更,需要重新执行此命令重建集群(重建集群需要先停止集群中所有节点进程,然后删除原集群中所有节点的
node.conf
文件,最后按照上文步骤构建集群即可)。
此时Redis会返回正在构建的集群信息,返回的信息大概意思是“正在把slots槽位分配到6个节点的集群,其中6390、6391、6392是主节点,6394是6390的从节点,6395是6391的从节点,6393是6392的从节点”。
这里的主从分配是自动的,若确认无误则输入yes:
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes…
Using 3 masters: # 三主
127.0.0.1:6390
127.0.0.1:6391
127.0.0.1:6392
Adding replica 127.0.0.1:6394 to 127.0.0.1:6390 # 三从
Adding replica 127.0.0.1:6395 to 127.0.0.1:6391
Adding replica 127.0.0.1:6393 to 127.0.0.1:6392
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: ac2520bab97d151897afb5e6f3ca60a673010227 127.0.0.1:6390
slots:0-5460 (5461 slots) master
M: 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8 127.0.0.1:6391
slots:5461-10922 (5462 slots) master
M: ac19a87740dc0f0559f10cd1eae617cfcd51b04a 127.0.0.1:6392
slots:10923-16383 (5461 slots) master
S: d93d05facb7db5c223d0959a0e58d232334057e4 127.0.0.1:6393
replicates 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8
S: 69546e0a773b6548a37c5d55329eac575c5d7cca 127.0.0.1:6394
replicates ac19a87740dc0f0559f10cd1eae617cfcd51b04a
S: ab7405fc14dbc4e883644bccc6d8602992780b44 127.0.0.1:6395
replicates ac2520bab97d151897afb5e6f3ca60a673010227
Can I set the above configuration? (type "yes" to accept): yes # 若确认无误则输入yes
若构建集群成功,则会返回集群内这6个节点的信息:
>>> 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 127.0.0.1:6390)
M: ac2520bab97d151897afb5e6f3ca60a673010227 127.0.0.1:6390
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8 127.0.0.1:6391
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 69546e0a773b6548a37c5d55329eac575c5d7cca 127.0.0.1:6394
slots: (0 slots) slave
replicates ac19a87740dc0f0559f10cd1eae617cfcd51b04a
M: ac19a87740dc0f0559f10cd1eae617cfcd51b04a 127.0.0.1:6392
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: ab7405fc14dbc4e883644bccc6d8602992780b44 127.0.0.1:6395
slots: (0 slots) slave
replicates ac2520bab97d151897afb5e6f3ca60a673010227
S: d93d05facb7db5c223d0959a0e58d232334057e4 127.0.0.1:6393
slots: (0 slots) slave
replicates 3768ff79e3e58a0ee9c1fef1ab04e7e395196fa8
[OK] All nodes agree about slots configuration.
>>> Check for open slots…
>>> Check slots coverage…
[OK] All 16384 slots covered.
测试
现在测试Redis Cluster是否能正常工作。
通过Redis测试客户端命令redis-cli
连接到集群任意一个节点:
# cd /data/server/redis-5.0.4/src/ # 切换到启动脚本目录
# ./redis-cli -c -h 127.0.0.1 -p 6390 # 以集群方式连接到Redis-6390节点
这里需要注意,与前面单机/主从/哨兵模式不同的是,客户端命令
redis-cli
需要增加一个-c
参数,表示是连接到集群,这样客户端的读写行为才是在整个集群中可见的。
若不加-c
参数虽然也可连接,但是仅仅是连接到当前的节点,是无法进行数据读写的(除非所读写的数据的键值,经过Hash计算得到的slot槽号,刚好在这个节点里面)。
现在在6390节点执行get命令,获取键名为site的数据:
127.0.0.1:6390> get site
(nil) # 由于是新部署的Redis集群,该键值必定不存在
然后在6390节点写入数据(执行set命令,为键site设置数据):
127.0.0.1:6390> set site http://www.appblog.cn
再通过Redis测试客户端命令redis-cli
连接到集群另一个节点:
# cd /data/server/redis-5.0.4/src/ # 切换到启动脚本目录
# ./redis-cli -c -h 127.0.0.1 -p 6395 # 以集群方式连接到Redis-6395节点
在6395节点执行get命令,获取键名为site的数据(经过集群节点转发请求,可以取到数据):
127.0.0.1:6395> get site
"http://www.appblog.cn"
现在尝试一下不以集群方式连接到节点6395,会发生什么:
# cd /data/server/redis-5.0.4/src/ # 切换到启动脚本目录
# ./redis-cli -h 127.0.0.1 -p 6395 # 以单点方式连接到Redis-6395节点(无-c参数)
127.0.0.1:6395> get site # 获取键值为site的数据
(error) MOVED 9421 127.0.0.1:6392 # 报错:该数据在6392节点的9421槽位
127.0.0.1:6395> set site http://www.appblog.cn # 设置键为site的值
(error) MOVED 9421 127.0.0.1:6392 # 报错:该键应该设置到6392节点的9421槽位
# 有些版本的报错信息是这样的,意思是相同的:
# -> Redirected to slot [9421] located at 127.0.0.1:6392
之所以会发生这种情况,其实最开始的Redis Cluster架构介绍的时候就已经解释了原因:
Redis Cluster没有使用一致性Hash,而是采用slot(槽)的概念,一共分成16384个槽。在构建集群时,这些槽会不重复地平均被分配到集群中的主节点。
在读写数据时,Redis Cluster会先计算该数据的键值的slot号,然后再把读写请求分配到该slot号所属的Redis节点。
而当不以集群方式连接到集群节点时,在计算slot号后,读写请求的分配工作却无法执行,就会出现上述报错。
集群的关闭/重启
Redis Cluster的官方文档并没有提供整个集群的关闭与重启的方法。推测可能是由于集群所有节点同时挂掉的可能性不高,毕竟即使偶尔集群中某个节点挂掉,待其重启后又会自动重新加入集群,并不会带来太大影响。
但是可能性不高并不代表不会发生,如何关闭/重启整个集群的方式还是需要知道的。
集群的关闭,执行这个命令即可(如果是部署到多台IP机器,需要登陆到每一台机器执行):
# pkill redis # 是的,直接杀掉集群全部节点的进程即可
集群的重启,只需要重新启动原集群中每一个节点即可,集群会自动恢复到关闭之前的状态(前提是不能删除node-.conf、.aof、*.rdb文件,否则会造成集群数据丢失)。
至此Redis Cluster集群模式部署完成。
集群模式一键启动/停止/重启脚本
此脚本是根据上文的部署方式和位置编写的,仅适用于Redis节点均在同一台机器的场景。
若要移植到其他地方使用,需要根据实际情况修改。
脚本内容如下:
#!/bin/bash
# 根据主从/哨兵模式的部署目录对应修改
export cluster_path=/data/server/redis-cluster
# 启动函数
start()
{
${cluster_path}/redis-6390/src/redis-server ${cluster_path}/redis-6390/redis.conf &
${cluster_path}/redis-6391/src/redis-server ${cluster_path}/redis-6391/redis.conf &
${cluster_path}/redis-6392/src/redis-server ${cluster_path}/redis-6392/redis.conf &
${cluster_path}/redis-6393/src/redis-server ${cluster_path}/redis-6393/redis.conf &
${cluster_path}/redis-6394/src/redis-server ${cluster_path}/redis-6394/redis.conf &
${cluster_path}/redis-6395/src/redis-server ${cluster_path}/redis-6395/redis.conf &
echo "all running"
}
# 停止函数
stop()
{
ps -ef | grep "redis" | grep -v "grep" |awk '{print $2}'| while read pid
do
C_PID=$(ps --no-heading $pid | wc -l)
if [[ $C_PID == "1" ]]; then
kill -9 $pid
echo "PID=$pid is dead"
else
echo "PID=$pid not exists"
fi
done
echo "all dead"
}
# 脚本入口参数 start|stop|restart
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
printf 'Usage: %s {start|stop|restart}\n'"$prog"
exit 1
;;
esac
这是shell脚本,保存为redis-cluster.sh
(文件名任意)即可执行(若无法执行可能是换行符问题,可尝试通过dos2unix命令修正换行符)。
使用方式如下:
# sh redis-cluster.sh start # 启动
# sh redis-cluster.sh stop # 停止
# sh redis-cluster.sh restart # 重启
附:Redis核心配置文件汉化版注释
服务配置redis.conf
汉化配置文件redis-chs.conf下载:http://www.yezhou.me//AppBlog/files/运维/redis-cluster.png
哨兵配置sentinel.conf
汉化配置文件sentinel-chs.conf下载:http://www.yezhou.me//AppBlog/files/运维/redis-cluster.png
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/26/redis-deployment-records-under-centos-single-machine-master-slave-sentinel-cluster/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论