Redis学习笔记4之做主从复制、读写分离

  • Redis的高并发和快速原因
  • redis高并发瓶颈
  • 如果要redis支撑10万+,要怎么做?
  • 主从架构的核心原理
  • 主从复制断点续传
  • 无磁盘化复制
  • Redis Replication(副本)核心机制
  • Master必须持久化来保障主从架构的数据安全
  • 全量复制
  • 心跳机制
  • 异步复制
  • 搭建一主两从的结构
  • 启动master和2个slave测试
  • 模拟宕机情况
  • Slave宕机
  • Master宕机
  • 手动主备切换步骤:


Redis的高并发和快速原因

  1. redis是基于内存的,内存的读写速度非常快;
  2. redis是单线程的,省去了很多上下文切换线程的时间;
  3. redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。

redis高并发瓶颈

单机的内存限制或网络带宽限制,正常普通笔记本对简单的redis操作命令QPS有上万到几万。
如果有超高并发,比如10万+,同时访问单机redis服务,最终会把redis压垮死。

如果要redis支撑10万+,要怎么做?

单机几乎是不可能,除非你的硬件非常牛逼,redis操作不太复杂。

采用读写分离,对于缓存来做,一般都是用来支撑读高并发,写请求比较少,可能一千到几千每秒

redis sentinel读写分离 redis读写分离实现_redis sentinel读写分离

主从架构的核心原理

官方文档介绍了主要通过3点,来确保slave副本的精准性

  • 当主从连接良好时,主数据库通过向副本发送一系列命令来保持副本更新,以便复制主数据库中由于客户机写入、键过期或驱逐、任何其他操作改变主数据集而产生的对数据集的影响
  • Master和Slave由于网络问题或者master或slave之前通信timeout时,当slave会重新连接master,master会重新同步缺失的数据,如果是第一次连接,会触发一次full resynchronization
  • 当部分重新同步不可能时,slave将要求完全重新同步,其中master需要创建所有数据的快照,将其发送到slave,然后随着数据集的更改继续发送命令流
  • 在full resynchronization时,master会启动一个后台线程,在内存中生成rdb快照,同时也会继续接受新的写命令放在内存,RDB文件生成完成后,master发送给slave,然后slave接受存入本地磁盘,并重新加载数据到内存,然后master会将内存的写命令继续同步给slave

主从复制断点续传

如果复制rdb文件一半网络断开,重新连接上时,会从断开位置开始复制。

  • master和slave都会自身不断的累加offset
  • slave会定时上报自己的offset给master,同时master也会保存slave的offset
    保证两者相互知道他们数据不一致的情况
  • backlog默认大小1M,master复制给slave数据时,也会同步在backlog同步写一份,主要用来全量复制中断后的增量复制
  • 客户端连接后,info server可以查看run ID,如果master重启或数据变化发生run id改变,slave node通过PSYNC发送给master的run id+offset,如果run id改变,master会触发FULLRESYNC runid offset给slave,如果一样就是CONTINUE继续复制

无磁盘化复制

master是在内存中生成RDB文件给slave的,不在再落地自己的本地磁盘
repli-diskless-sync no -yes表示开启无磁盘化复制
repli-diskless-sync-delay 5 -延迟5秒再发送,等待更多的slave连接到master

Redis Replication(副本)核心机制

  • redis采用异步复制,slave node会周期性到主机确认需要复制的数据
  • 一个主机可以有多个副本
  • slave node也可以连接其他的slave node
  • slave node在同步数据时,不会阻塞master node正常工作
  • slave node在同步数据时,也不会阻塞自己的查询数据,他会用旧的数据来提供服务,等复制完成时,需要删除旧数据,加载新数据时,会暂停提供服务
  • slave node主要用来进行横向扩容,做读写分离,提高读QPS

Master必须持久化来保障主从架构的数据安全

官方建议在使用副本机制时,主节点一定要启用持久化配置,不能直接把slave作为master的热备,因为如果master宕机重启后数据是空的,然后可能经过一复制,slave的数据也丢失了。
即使采用了高可用机制把slave node自动接管master node,也是可能存在主机重新启动的速度足以让 Sentinel 无法检测到故障,这样上面描述的故障模式就会发生。
数据安全很重要,如果没有在master开启持久化,就应该禁止master宕机自动重启。

全量复制

repl-timeout=60 # 复制超时时间,超过slave node会认为复制失败
client-output-buffer-limit slave 256M 64M 60 #如果在复制期间,master接收的写命令在内存缓冲区60内超过64M或一次性超过256M,则停止复制,复制失败

心跳机制

redis sentinel读写分离 redis读写分离实现_redis sentinel读写分离_02

异步复制

master每次接到写命令,先在内部写入数据,再异步发送slave node

搭建一主两从的结构

master配置文件

#基本配置
port 6379	# 端口号
bind 192.168.56.10   # 绑定本机的IP地址,只有通过这个网卡才能访问redis服务,之前有误解,以为要配置能访问该服务器的客户端ip
daemonize yes # 后台启动
pidfile /var/run/redis_6379.pid  # 进程文件pid位置
logfile /usr/local/redis/logs/redis_6379.log # 日志文件位置
save 900 1       # RDB文件生成策略:900秒1个Key变化
save 300 10		 # RDB文件生成策略:300秒10个Key变化
save 60 10000	 # RDB文件生成策略:60秒10000个Key变化
dbfilename redis_6379.rdb # rdb文件名
dir /usr/local/redis/data # 文件存放位置
requirepass 123456 # 访问密码

# AOF持久化配置
appendonly yes # 开启AOF持久化配置
appendfilename "appendonly.aof" # AOF文件名字
appendfsync everysec # AOF持久化策略:每秒系统fsync一次把cache的日志写到磁盘文件
no-appendfsync-on-rewrite no # bgrewrite和appendfsync同时发生时的策略:no不是丢数据
auto-aof-rewrite-percentage 100 # 配置rewrite触发策略
auto-aof-rewrite-min-size 64mb # 配置rewrite触发策略

# 副本同步配置
# backlog大小
repl-backlog-size 1mb
# 快照同步的超时时间
repl-timeout 60
# 开启无盘复制
repl-diskless-sync yes
# 无盘复制的延迟默认为5s,是为了等待更多的slave连接
repl-diskless-sync-delay 5
# 是否开启主从节点复制数据的延迟机制
# 当关闭时,主节点产生的命令数据无论大小都会及时地发送给从节点,这样主从之间延迟会变小
# 但增加了网络带宽的消耗。适用于主从之间的网络环境良好的场景
# 当开启时,主节点会合并较小的TCP数据包从而节省带宽。
# 默认发送时间间隔取决于Linux的内核,一般默认为40毫秒。
# 这种配置节省了带宽但增大主从之间的延迟。适用于主从网络环境复杂或带宽紧张的场景
repl-disable-tcp-nodelay no
# 触发快照同步的条件
# 如果增量同步的缓存大于256MB,或者超过60s大于64MB,则触发快照同步
client-output-buffer-limit slave 256mb 64mb 60
# 主从节点进行心跳的时间间隔
repl-ping-slave-period 10

slave配置

port 6379	# 端口号
bind 192.168.56.11   # 绑定本机的IP地址,只有通过这个网卡才能访问redis服务,之前有误解,以为要配置能访问该服务器的客户端ip
daemonize yes # 后台启动
pidfile /var/run/redis_6379.pid  # 进程文件pid位置
logfile /usr/local/redis/logs/redis_6379.log # 日志文件位置
dbfilename redis_6379.rdb # rdb文件名
dir /usr/local/redis/data # 文件存放位置
requirepass 123456 # 访问密码

# 配置主节点
replicaof 192.168.56.10 6379
masterauth 123456  # 访问密码
replica-read-only yes # 副本只读
replica-serve-stale-data yes # 副本处于快照复制期间,是否用旧数据提供服务
min-replicas-to-write 2 # 如果 master 检测到 slave 的数量小于这个配置设置的值,将拒绝对外提供服务,0 代表,无论 slave 有几个都会对外提供服务
min-replicas-max-lag 10 # 如果 master 发现大于等于 ${min-slaves-to-write} 个 slave 与自己的心跳超过此处配置的时间(单位s),就拒绝对外提供服务

redis配置总结参考

启动master和2个slave测试

模拟宕机情况

Slave宕机

如果slave宕机,重新启动后会从新连接上master,同步数据

Master宕机

  1. 把slave提升为master继续服务,在slave运行 slaveof no one或 replicaof no one
  2. 恢复主库前,把 slave 的 rdb 文件备份到 master 上,然后启动master
    按网上的步骤,切换后从库不能写入,set 命令提示
    (error) NOREPLICAS Not enough good replicas to write.
    尝试了一下,在一主两从的结构下,如果主挂了,手动切换slave为主后,不能写入是因为没有足够好的副本
    所以尝试了一主三从,发现手动切换后,可以正常的写入
手动主备切换步骤:
  1. M1 R1 R2 R3,M1挂了
  2. R1执行replicaof no one,提升为主
  3. R2和R3执行 replicaof R1的ip R1的端口,如replicaof 192.168.56.11 6379
  4. 这时就好了。
  5. 如果要恢复M1,需要把R1的RDB文件拷贝到M1,然后再启动M1后,R1,R2,R3都replicaof M1的ip M1的端口