DBA Redis 主从复制
功能概述
Redis的主从复制与MySQL相同,本身并不提供任何高可用方面的功能,需要借助其他技术进行实现,但却是高可用架构的基础前提。
相较于MySQL来说,Redis的主从复制搭建比较简单,关注的点也比较少,且因内部原因数据同步速率影响较小(如果网速慢另当别论)。
下面我准备使用3台服务器来搭建Redis主从复制,一方面也为后面的高可用架构做基础铺垫。
地址规划
以下是地址规划:
作用 | IP地址 | 服务端口 | 操作系统 | 配置 |
---|---|---|---|---|
Master | 192.168.0.120 | 6379 | Centos7.3 基础设施服务器 | 2颗CPU 2G内存 20G硬盘 |
SLAVE1 | 192.168.0.130 | 6379 | Centos7.3 基础设施服务器 | 2颗CPU 2G内存 20G硬盘 |
SLAVE2 | 192.168.0.140 | 6379 | Centos7.3 基础设施服务器 | 2颗CPU 2G内存 20G硬盘 |
所有节点选用Redis版本为6.2.1,也是目前最新版。
安装Redis
为所有服务器安装Redis:
$ cd ~
$ wget https://download.redis.io/releases/redis-6.2.1.tar.gz
配置目录,所有节点都执行:
$ mkdir -p /usr/local/redis_cluster/redis_6379/{conf,pid,logs}
# 目录说明:
/usr/local/redis_cluster/ # redis服务相关文件目录
└── redis_6379 # 6379端口数据文件相关目录
├── conf # 6379端口配置文件存放目录
├── logs # 6379端口日志文件存放目录
└── pid # 6379端口pid文件存放目录
进行解压:
$ tar -zxvf redis-6.2.1.tar.gz -C /usr/local/redis_cluster/
编译安装:
$ cd /usr/local/redis_cluster/redis-6.2.1/
$ make # 在src目录下生成各种服务命令
$ make install # 添加服务命令软链接至环境变量
书写配置文件:
$ vim /usr/local/redis_cluster/redis_6379/conf/redis.cnf
# 以守护进程模式启动
daemonize yes
# 注意修改不同的地址
# 绑定的主机地址,一般设为本地即可,如设置为0.0.0.0则允许所有地址登录
bind 192.168.0.120
# 监听端口
port 6379
# pid文件和log文件的保存地址
pidfile /usr/local/redis_cluster/redis_6379/pid/redis_6379.pid
logfile /usr/local/redis_cluster/redis_6379/logs/redis_6379.log
# 设置数据库的数量,默认数据库为0
databases 16
# 指定本地持久化文件的文件名,默认是dump.rdb
dbfilename redis_6379.rdb
# 本地数据库的目录
dir /usr/local/redis_cluster/redis_6379
配置HOSTS文件:
192.168.0.120 master
192.168.0.130 node1
192.168.0.140 node2
搭建主从
1)启动Master:
$ redis-server /usr/local/redis_cluster/redis_6379/conf/redis.cnf
2)选择链接方式,从库链接主库的方式有3种,选择任意一种:
- 配置文件中加入 slaveof 主库HOST 主库PORT,Redis服务启动生效
- 在redis-server启动命令后加入 --slaveof 主库HOST 主库PORT,单次启动生效,重启失效
- 在redis-shell中使用命令 slaveof 主库HOST 主库PORT 立即生效,重启失效
3)这里我选择第2种,2个从库进行启动即可:
$ redis-server /usr/local/redis_cluster/redis_6379/conf/redis.cnf --slaveof 192.168.0.120 6379
$ ps -ef | grep redis
4)登录主库,查看链接情况:
$ redis-cli -h master -p 6379
master:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.0.130,port=6379,state=online,offset=196,lag=0
slave1:ip=192.168.0.140,port=6379,state=online,offset=196,lag=1
master_failover_state:no-failover
master_replid:aea7f187e94343b82b229d8a5a3c5e407aedc0f2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:196
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:196
5)主库尝试写入数据:
master:6379> set k1 "v1"
OK
6)从库进行查看:
$ redis-cli -h node1 -p 6379
node1:6379> keys *
1) "k1"
node1:6379>
$ redis-cli -h node2 -p 6379
node2:6379> keys *
1) "k1"
node2:6379>
7)尝试从库写入数据,会发生异常提示,仅允许主库写入:
node2:6379> set k2 "v2"
(error) READONLY You can't write against a read only replica.
关系解除
如果要解除从库与主库的关系,可在从库的redis-shell中使用以下命令:
slaveof no one
复制过程
如图所示:
查看主从节点的日志,为了照顾英文不好的读者,这里使用译文:
$ tail -f /usr/local/redis_cluster/redis_6379/logs/redis_6379.log
28788:M 2021年3月31日06:26:15.229 *副本192.168.0.130:6379要求同步
28788:M 2021年3月31日06:26:15.229 *接受了来自192.168.0.130:6379的部分重新同步请求。从偏移量15开始发送0字节的积压。 # 这里是因为主库本身没有任何数据而做的主从关系
28788:M 2021年3月31日06:26:16.607 *副本192.168.0.140:6379要求同步
28788:M 2021年3月31日06:26:16.607 *副本192.168.0.140:6379请求完全重新同步
28788:M 2021年3月31日06:26:16.607 *使用目标:磁盘启动BGSAVE for SYNC
28788:M 2021年3月31日06:26:16.608 *通过pid 33284开始后台保存
33284:C 2021年3月31日06:26:16.610 * DB保存在磁盘上
33284:C 2021年3月31日06:26:16.611 * RDB:0写入时复制使用的内存
28788:M 2021年3月31日06:26:16.687 *背景保存成功终止
28788:M 2021年3月31日06:26:16.688 *与副本192.168.0.140:6379的同步成功
28788:M 2021年3月31日06:26:15.229 *副本192.168.0.130:6379要求同步
28788:M 2021年3月31日06:26:15.229 *接受了来自192.168.0.130:6379的部分重新同步请求。从偏移量15开始发送0字节的积压。
28788:M 2021年3月31日06:26:16.607 *副本192.168.0.140:6379要求同步
28788:M 2021年3月31日06:26:16.607 *副本192.168.0.140:6379请求完全重新同步
28788:M 2021年3月31日06:26:16.607 *使用目标:磁盘启动BGSAVE for SYNC
28788:M 2021年3月31日06:26:16.608 *通过pid 33284开始后台保存
33284:C 2021年3月31日06:26:16.610 * DB保存在磁盘上
33284:C 2021年3月31日06:26:16.611 * RDB:0写入时复制使用的内存
28788:M 2021年3月31日06:26:16.687 *背景保存成功终止
28788:M 2021年3月31日06:26:16.688 *与副本192.168.0.140:6379的同步成功
查看从节点的日志,为了照顾英文不好的读者,这里使用译文:
$ tail -f /usr/local/redis_cluster/redis_6379/logs/redis_6379.log
28108:S 2021年3月31日06:26:15.225 * DB从磁盘加载:0.000秒
28108:S 2021年3月31日06:26:15.225 *在变成副本之前,使用我自己的master参数合成一个缓存的master:通过部分传输,我也许可以与新master同步。
28108:S 2021年3月31日06:26:15.225 *准备接受连接
28108:S 2021年3月31日06:26:15.225 *连接至主192.168.0.120:6379
28108:S 2021年3月31日06:26:15.225 * MASTER <-> REPLICA同步开始
28108:S 2021年3月31日06:26:15.226 * SYNC的非阻塞连接触发了该事件。
28108:S 2021年3月31日06:26:15.226 *主服务器回复为PING,复制可以继续...
28108:S 2021年3月31日06:26:15.227 *尝试进行部分重新同步(请求aea7f187e94343b82b229d8a5a3c5e407aedc0f2:15)。
28108:S 2021年3月31日06:26:15.228 *与主机成功完成部分重新同步。
28108:S 2021年3月31日06:26:15.228 * MASTER <-> REPLICA sync:Master接受了部分重新同步。
主库宕机
如果主库宕机后会发生什么?进行操作:
$ redis-cli -h master -p 6379 shutdown
查看从库日志:
$ tail -f /usr/local/redis_cluster/redis_6379/logs/redis_6379.log
28108:S 2021年3月31日06:40:55.037#SYNC套接字上的错误情况:连接被拒绝
28108:S 2021年3月31日06:40:56.043 *连接至主192.168.0.120:6379
28108:S 2021年3月31日06:40:56.043 * MASTER <-> REPLICA同步开始
28108:S 2021年3月31日06:40:56.044#SYNC套接字上的错误情况:连接被拒绝
28108:S 2021年3月31日06:40:57.052 *连接至主192.168.0.120:6379
28108:S 2021年3月31日06:40:57.052 * MASTER <-> REPLICA同步开始
28108:S 2021年3月31日06:40:57.053#SYNC套接字上的错误情况:连接被拒绝
28108:S 2021年3月31日06:40:58.058 *连接至主192.168.0.120:6379
28108:S 2021年3月31日06:40:58.059 * MASTER <-> REPLICA同步开始
28108:S 2021年3月31日06:40:58.059#SYNC套接字上的错误情况:连接被拒绝
28108:S 2021年3月31日06:40:59.065 *连接至主192.168.0.120:6379
28108:S 2021年3月31日06:40:59.066 * MASTER <-> REPLICA同步开始
28108:S 2021年3月31日06:40:59.067#SYNC套接字上的错误情况:连接被拒绝
28108:S 2021年3月31日06:41:00.070 *连接至主192.168.0.120:6379
28108:S 2021年3月31日06:41:00.072 * MASTER <-> REPLICA同步开始
28108:S 2021年3月31日06:41:00.072#SYNC套接字上的错误情况:连接被拒绝
28108:S 2021年3月31日06:41:01.080 *连接至主192.168.0.120:6379
它会不断的请求主库,永不间断。
故障恢复
主库发生故障后,应当将其中一个从库立马转换为主库身份。
如下,将node1转换为主库身份,首先,node1的slaveof要设置为空:
$ redis-cli -h node1 -p 6379
node1:6379> slaveof no one
OK
node1:6379>
其次,你应该登录node2,然后进行设置node1为新主库:
$ redis-cli -h node2 -p 6379
node2:6379> slaveof 192.168.1.130 6379
OK
node2:6379>
查看复制信息:
node2:6379> info replication
# Replication
role:slave
master_host:192.168.1.130
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1270
master_link_down_since_seconds:348
slave_priority:100
slave_read_only:1
connected_slaves:0
master_failover_state:no-failover
master_replid:aea7f187e94343b82b229d8a5a3c5e407aedc0f2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1270
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:1256
然后将原主库master进行修复后作为从库链接至node1,这里我不再进行演示了。
另外,如果application原本接入的是已宕机主库master,你还需要通知开发人员进行手动切换。
为了后续章节,我这里再将master上线并设置为主库。