redis主从同步(小节4)

151 阅读6分钟

redis主从同步(小节4)

redis 高可用与集群

虽然Redis可以实现单机的数据持久化,但无论是RDB也好或者AOF也好,都解决不了单点宕机问题,即一旦单台redis服务器本身出现系统故障,硬件故障等问题后,就会直接造成数据的丢失,因此需要使用另外的技术来解决单点问题。

配置Redis主从

主备模式:可以实现Redis数据的跨主机备份。

程序端连接到高可用负载的VIP,然后连接到负载服务器设置的Redis后端real server,此模式不需要在程序里面配置redis服务器的真实IP地址,当后期redis服务器IP地址发生变更只需要更改redis相应的后端real server即可,可避免更改程序中的IP地址设置。

图片.png

Slave 主要配置:

Redis Slave 也要开启持久化并设置和 master 同样的连接密码, 因为后期 slave 会有提升为 master 的可能,Slave 端切换 master 同步后会丢失之前的所有数据。

一旦某个 Slave 成为一个 master 的 slave, Redis Slave 服务会清空当前 redis 服务器上的所有数据并将 master 的数据导入到自己的内存,但是断开同步关系后不会删除当前已经同步过的数据

实验一: 配置redis主从

yum安装epel源和redis

yum install epel-release -y
yum install -y redis
  1. 主服务器配置:
~]# vim /etc/redis.conf
...
 61 bind 0.0.0.0    <--监控地址
...
 480 requirepass 123    <--redis密码

启动服务

~]# systemctl restart redis
  1. 从服务器配置:
~]# vim /etc/redis.conf
...
 61 bind 0.0.0.0    <--监控地址
...
 265 slaveof 192.168.1.101 6379    <--master IP及端口
...
 272 masterauth 123    <--master的redis密码123
...
 480 requirepass 123    <--redis密码

启动服务

~]# systemctl restart redis

验证连接

[root@server1 ~]# redis-cli
127.0.0.1:6379> AUTH 123
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave    <--
master_host:192.168.1.101    <--
master_port:6379    <--
master_link_status:up    <--
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:155
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

主从复制过程

Redis 支持主从复制分为全量同步和增量同步, 首次同步是全量同步,主从同步可以让从服务器从主服务器备份数据,而且从服务器还可与有从服务器,即另外一台 redis 服务器可以从一台从服务器进行数据同步, redis 的主从同步是非阻塞的,master收到从服务器的 sync(2.8 版本之前是 PSYNC)命令会 fork 一个子进程在后台执行 bgsave 命令,并将新写入的数据写入到一个缓冲区里面, bgsave执行完成之后并生成的将 RDB 文件发送给客户端,客户端将收到后的 RDB 文件载入自己的内存,然后 主redis 将缓冲区的内容在全部发送给 从redis ,之后的同步从服务器会发送一个 offset 的位置(等同于 MySQL 的 binlog 的位置)给主服务器,主服务器检查后位置没有错误将此位置之后的数据包括写在缓冲区的积压数据发送给 redis 从服务器,从服务器将主服务器发送的挤压数据写入内存,这样一次完整的数据同步,再之后再同步的时候从服务器只要发送当前的 offset 位置给主服务器,然后主服务器根据相应的位置将之后的数据发送给从服务器保存到其内存即可。

Redis 全量复制一般发生在 Slave 初始化阶段,这时 Slave 需要将 Master 上的所有数据都复制一份。具体步骤如下:

  1. 从服务器连接主服务器,发送 SYNC 命令;
  2. 主服务器接收到 SYNC 命名后,开始执行 BGSAVE 命令生成 RDB 快照文件并使用缓冲区记录此后执行的所有写命令;
  3. 主服务器 BGSAVE 执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令
  4. 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  5. 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  6. 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
  7. 后期同步会先发送自己 slave_repl_offset 位置, 只同步新增加的数据, 不再全量同步

图片.png

主从同步优化

Redis 在 2.8 版本之前没有提供增量部分复制的功能, 当网络闪断或者 slave Redis 重启之后会导致主从之间的全量同步,即从 2.8 版本开始增加了部分复制的功能。

  1. #是否使用无盘同步 RDB 文件,默认为 no, no 为不使用无盘,需要将 RDB 文件保存到磁盘后再发送给 slave,yes 为支持无盘,支持无盘就是 RDB 文件不需要保存至本地磁盘,而且直接通过 socket 文件发送给 slave。
repl-diskless-sync no
  1. #Master 准备号的 RDB 文件后等等待传输时间
repl-diskless-sync-delay 5
  1. #slave 端详 server 端发生 ping 的时间区间设置,默认为10秒
repl-ping-slave-period 10
  1. #设置超时时间
repl-timeout 60
  1. #是否启用 TCP_NODELAY,如设置成yes,则redis会合并小的 TCP 包从而节约带宽,但会增加同步延迟 (40ms),造成 master 与 slave 数据不一致,假如设置成 no,则 redis master 会立即发送同步数据,没有延迟,前者关注性能,后者关注 redis 服务中的数据一致性。
repl-disable-tcp-nodelay no
  1. #master 的写入数据缓冲区,用于记录自上一次同步后到下一次同步过程中间的写入命令,计算公式:brepl-backlog-size = 允许从节点最大中断时长 * 主实例 offset 每秒写入量,比如 master 每秒最大写入 64mb,最大允许60秒,那么就要设置为64mb*60秒=3840MB(3.8G)
repl-backlog-size 1mb
  1. #如果一段时间后没有 slave 连接到 master,则 backlog size 的内存将会被释放,如果值为0则表示永远不释放这部份内存。
repl-backlog-ttl 3600
  1. #slave 端的优先级设置,值是一个整数,数字越小表示优先级越高,当 master 故障时将会按照优先级来选择 slave 端进行恢复,如果值设置为0,则表示该slave永远不会被选择。
 slave-priority 100
  1. #设置当一个master 端的可用slave少于多少个
#min-slaves-to-write 1
  1. #设置所有 slave 延迟时间都大于多少秒时,master 不接收写操作(拒绝写入)。
#min-slaves-max-lag 20

实验二:主-从-从同步(Slave节点再有Slave)

图片.png

前提注意关闭防火墙、selinux

~]# vim /etc/redis.conf
...
  61 bind 0.0.0.0
...
 480 requirepass 123
...

~]# systemctl restart redis

slave 1

~]# vim /etc/redis.conf
...
 61 bind 0.0.0.0    <--监控地址
...
 265 slaveof 192.168.1.101 6379    <--master IP及端口
...
 272 masterauth 123    <--master的redis密码123
...
 480 requirepass 123    <--redis密码

~]# systemctl restart redis

slave 2

~]# vim /etc/redis.conf
...
  61 bind 0.0.0.0
...
 265 slaveof 192.168.1.102 6379    <--master IP及端口
...
 272 masterauth 123
...
 480 requirepass 123
...

~]# systemctl restart redis

写入数据

]# cat redis-shell.sh
#!/bin/bash
NUM=`seq 1 150`
for i in ${NUM};do
  redis-cli -h 192.168.1.101 -p 6379 -a 123 set key-${i} value-${i}
  echo "key-${i} value-${i} 写入完成"
done
echo "一百个key写入到Redis完成"

#运行脚本
]# bash redis-shell.sh
]# redis-cli
127.0.0.1:6379> AUTH 123
OK
127.0.0.1:6379> KEYS *
...
148) "key-77"
149) "key-63"
150) "key-24"

slave 2

server2 ~]# redis-cli
#密码
127.0.0.1:6379> AUTH 123
OK
#可以看到刚刚写入的150条数据
127.0.0.1:6379> KEYS *
...
148) "key-135"
149) "key-5"
150) "key-144"

slave2

slave手动切换master

#把一个slave节点提升为master
127.0.0.1:6379> SLAVEOF no one
OK

127.0.0.1:6379> SLAVEOF 192.168.1.101 6379
OK
127.0.0.1:6379> CONFIG GET masterauth 123
OK

127.0.0.1:6379> info Replication
# Replication
role:slave
master_host:192.168.1.101
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0    #最近一次与master通信已经过去多少秒
master_sync_in_progress:0    #是否正在与master通信
slave_repl_offset:70841    #当前同步的偏移量
slave_priority:100    #slave 优先级, master故障后值越小越优先同步。
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

常见问题

  1. master密码不对

即配置的 master 密码不对,导致验证不通过俄日无法建立主从同步关系。 20243594-429ae590a8ce50db.webp

  1. Redis版本不一致

不同的redis 版本之间存在兼容性问题,因此各master 和 slave 之间必须保存版本一致。 20243594-cc6912aa900fadc0.webp

  1. 无法远程连接

在开启了安全模式情况下,没有设置bind地址或者密码

# redir-cli -h 192.168.1.103

>192.168.1.103:6379> KEYS *
(error) DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the lookback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 
1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 
2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 
3) If you started the server manually just for testing, restart it with the --portected-mode no option. 
4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.