Redis学习笔记4之做主从复制、读写分离
- Redis的高并发和快速原因
- redis高并发瓶颈
- 如果要redis支撑10万+,要怎么做?
- 主从架构的核心原理
- 主从复制断点续传
- 无磁盘化复制
- Redis Replication(副本)核心机制
- Master必须持久化来保障主从架构的数据安全
- 全量复制
- 心跳机制
- 异步复制
- 搭建一主两从的结构
- 启动master和2个slave测试
- 模拟宕机情况
- Slave宕机
- Master宕机
- 手动主备切换步骤:
Redis的高并发和快速原因
- redis是基于内存的,内存的读写速度非常快;
- redis是单线程的,省去了很多上下文切换线程的时间;
- redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。
redis高并发瓶颈
单机的内存限制或网络带宽限制,正常普通笔记本对简单的redis操作命令QPS有上万到几万。
如果有超高并发,比如10万+,同时访问单机redis服务,最终会把redis压垮死。
如果要redis支撑10万+,要怎么做?
单机几乎是不可能,除非你的硬件非常牛逼,redis操作不太复杂。
采用读写分离,对于缓存来做,一般都是用来支撑读高并发,写请求比较少,可能一千到几千每秒
主从架构的核心原理
官方文档介绍了主要通过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,则停止复制,复制失败
心跳机制
异步复制
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),就拒绝对外提供服务
启动master和2个slave测试
模拟宕机情况
Slave宕机
如果slave宕机,重新启动后会从新连接上master,同步数据
Master宕机
- 把slave提升为master继续服务,在slave运行 slaveof no one或 replicaof no one
- 恢复主库前,把 slave 的 rdb 文件备份到 master 上,然后启动master
按网上的步骤,切换后从库不能写入,set 命令提示
(error) NOREPLICAS Not enough good replicas to write.
尝试了一下,在一主两从的结构下,如果主挂了,手动切换slave为主后,不能写入是因为没有足够好的副本
所以尝试了一主三从,发现手动切换后,可以正常的写入
手动主备切换步骤:
- M1 R1 R2 R3,M1挂了
- R1执行replicaof no one,提升为主
- R2和R3执行 replicaof R1的ip R1的端口,如replicaof 192.168.56.11 6379
- 这时就好了。
- 如果要恢复M1,需要把R1的RDB文件拷贝到M1,然后再启动M1后,R1,R2,R3都replicaof M1的ip M1的端口