一、 为什么需要主从分离---单节点redis的问题
- 单机故障
如果发生机器故障,例如磁盘损坏,主板损坏等,未能在短时间内修复好,客户端将无法连接redis。
当然如果仅仅是redis节点挂掉了,可以进行问题排查然后重启,姑且不考虑这段时间对外服务的可用性,那还是可以接受的。
而发生机器故障,基本是无济于事。除非把redis迁移到另一台机器上,并且还要考虑数据同步的问题。
- 单机故障
- 容量瓶颈
假如一台机器是16G内存,redis使用了12G内存,而其他应用还需要使用内存,假设我们总共需要60G内存要如何去做呢,是否有必要购买64G内存的机器?
- 容量瓶颈
- QPS瓶颈
redis官方数据显示可以达到10w的QPS,如果业务需要100w的QPS怎么去做呢?
关于容量瓶颈和QPS瓶颈是redis分布式需要解决的问题,而机器故障就是高可用的问题了。
- QPS瓶颈
二、主从复制的用途
- 1、读写分离
Redis实例划分为主节点(master)和从节点(slave)。默认 情况下,主节点负责写操作,从节点负责读操作 - 2、容灾备份
三、常见拓扑结构
1.一主一从
从节点也是可以对外提供服务的,主节点是有数据的,从节点可以通过复制操作将主节点的数据同步来,并且随着主节点数据不断写入,从节点数据也会做同步的更新。整体起到的就是数据备份的效果。
应对高并发时的一种解决方法 ----- 关闭 主节点的aof
- 关注主节点的aof
- 只开启从节点的aof
重启服务时,先在从节点断开slaveof no one与主节点的复制关系,再重启主节点。防止复制主节点导致从节点数据丢失
2.一主多从
- 一主多从结构(又称为星形拓扑结构)使得应用端可以利用多个从节点 实现读写分离(见图6-5)。
- 对于读占比较大的场景,可以把读命令发送到 从节点来分担主节点压力。
- 同时在日常开发中如果需要执行一些比较耗时的 读命令,如:keys、sort等,可以在其中一台从节点上执行,防止慢查询对 主节点造成阻塞从而影响线上服务的稳定性。
- 对于写并发量较高的场景,多个从节点会导致主节点写命令的多次发送从而过度消耗网络带宽,同时也加重了主节点的负载影响服务稳定性。
3.树状主从结构
- 树状主从结构(又称为树状拓扑结构)使得从节点不但可以复制主节点数据,同时可以作为其他从节点的主节点继续向下层复制。
- 通过引入复制中间层,可以有效降低主节点负载和需要传送给从节点的数据量。
- 数据写入节点A后会同步到B和C节点,B节点再把数据同步到D和E节 点,数据实现了一层一层的向下复制。
- 当主节点需要挂载多个从节点时为了 避免对主节点的性能干扰,可以采用树状主从结构降低主节点压力。
四、配置方式
1.建立连复制
1.1修改redis.conf
# 配置主节点的IP和端口号
slaveof 127.0.0.1 8000
# 从节点只做读的操作,保证主从数据的一致性
slave-read-only yes
1.2redis-server启动命令
redis-server --slaveof {masterHost}{masterPort}
1.3redis-cli中直接使用命令
slaveof {masterHost}{masterPort}
注意:
slaveof本身是异步命令,执行slaveof命令时,节点只保存主节点信息后 返回,后续复制流程在节点内部异步执行。
1.4 info replication命令 查看复制状态信息
2. 断开复制
slaveof no one
断开后的主要流程
1)断开与主节点复制关系。
2)从节点晋升为主节点。
注意
- 从节点断开复制后并不会抛弃原有数据,只是无法再获取主节点上的数据变化。
- 切换主节点后的从节点会清空之前所有的数据,线上人工操作时小心slaveof在错 误的节点上执行或者指向错误的主节点。
传输延迟
主从节点一般部署在不同机器上,复制时的网络延迟就成为需要考虑的 问题,Redis为我们提供了repl-disable-tcp-nodelay参数用于控制是否关闭 TCP_NODELAY,默认关闭,说明如下:
- 当关闭时,主节点产生的命令数据无论大小都会及时地发送给从节 点,这样主从之间延迟会变小,但增加了网络带宽的消耗。适用于主从之间 的网络环境良好的场景,如同机架或同机房部署。
- 当开启时,主节点会合并较小的TCP数据包从而节省带宽。默认发送 时间间隔取决于Linux的内核,一般默认为40毫秒。这种配置节省了带宽但 增大主从之间的延迟。适用于主从网络环境复杂或带宽紧张的场景,如跨机 房部署。
五、复制过程步骤
从节点执行 slaveof 命令
从节点只是保存了 slaveof 命令中主节点的信息,并没有立即发起复制
从节点内部的定时任务发现有主节点的信息,开始使用 socket 连接主节点
连接建立成功后,发送 ping 命令,希望得到 pong 命令响应,否则会进行重连
如果主节点设置了权限,那么就需要从节点必须配置masterauth参数进行权限验证;如果验证失败,复制终止。
权限验证通过后,进行数据同步,这是耗时最长的操作,主节点将把所有的数据全部发送给从节点。
-
当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来,主节点就会持续的把写命令发 送给从节点,保证主从数据一致性。
六、数据同步
上面说的复制过程,其中有一个步骤是“同步数据集”,这个就是现在讲的‘数据间的同步’。同步过程分为『全量同步』与『部分同步』
- 全量复制:
一般用于初次复制场景,Redis早期支持的复制功能只有全 量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会 对主从节点和网络造成很大的开销。 - 部分复制:
用于处理在主从复制中因网络闪断等原因造成的数据丢失 场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据 给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过 高开销。
当使用复制功能时,尽量采用2.8以上版本的Redis。
1.redis 同步有 2 个命令:
sync 和 psync,前者是 redis 2.8 之前的同步命令,后者是 redis 2.8 为了优化 sync 新设计的命令。我们会重点关注 2.8 的 psync 命令。
2.psync 命令需要 3 个组件支持:
- 主从节点各自复制偏移量
参与复制的主从节点都会维护自身的复制偏移量。
主节点在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在 info replication 中的 masterreploffset 指标中。
从节点每秒钟上报自身的的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量。
从节点在接收到主节点发送的命令后,也会累加自身的偏移量,统计信息在 info replication 中。
通过对比主从节点的复制偏移量,可以判断主从节点数据是否一致。
- 主节点复制积压缓冲区
复制积压缓冲区是一个保存在主节点的一个固定长度的先进先出的队列。默认大小 1MB。
这个队列在 slave 连接是创建。这时主节点响应写命令时,不但会把命令发送给从节点,也会写入复制缓冲区。
他的作用就是用于部分复制和复制命令丢失的数据补救。通过 info replication 可以看到相关信息。
- 主节点运行 ID
每个 redis 启动的时候,都会生成一个 40 位的运行 ID。
运行 ID 的主要作用是用来识别 Redis 节点。如果使用 ip+port 的方式,那么如果主节点重启修改了 RDB/AOF 数据,从节点再基于偏移量进行复制将是不安全的。所以,当运行 id 变化后,从节点将进行全量复制。也就是说,redis 重启后,默认从节点会进行全量复制。
如果在重启时不改变运行 ID 呢?
可以通过 debug reload 命令重新加载 RDB 并保持运行 ID 不变。从而有效的避免不必要的全量复制。
他的缺点则是:debug reload 命令会阻塞当前 Redis 节点主线程,因此对于大数据量的主节点或者无法容忍阻塞的节点,需要谨慎使用。一般通过故障转移机制可以解决这个问题。
- 流程说明:从节点发送 psync 命令给主节点,runId 就是目标主节点的 ID,如果没有默认为 -1,offset 是从节点保存的复制偏移量,如果是第一次复制则为 -1.
主节点会根据 runid 和 offset 决定返回结果:
如果回复 +FULLRESYNC {runId} {offset} ,那么从节点将触发全量复制流程。
如果回复 +CONTINUE,从节点将触发部分复制。
如果回复 +ERR,说明主节点不支持 2.8 的 psync 命令,将使用 sync 执行全量复制。
到这里,数据之间的同步就讲的差不多了,篇幅还是比较长的。主要是针对 psync 命令相关之间的介绍。
七、全量复制
全量复制是 Redis 最早支持的复制方式,也是主从第一次建立复制时必须经历的的阶段。触发全量复制的命令是 sync 和 psync。
redis 2.8 之前使用 sync 只能执行全量不同,2.8 之后同时支持全量同步和部分同步。
发送 psync 命令(spync ? -1)
主节点根据命令返回 FULLRESYNC
从节点记录主节点 ID 和 offset
主节点 bgsave 并保存 RDB 到本地
主节点发送 RBD 文件到从节点
从节点收到 RDB 文件并加载到内存中
主节点在从节点接受数据的期间,将新数据保存到“复制客户端缓冲区”,当从节点加载 RDB 完毕,再发送过去。(如果从节点花费时间过长,将导致缓冲区溢出,最后全量同步失败)
从节点清空数据后加载 RDB 文件,如果 RDB 文件很大,这一步操作仍然耗时,如果此时客户端访问,将导致数据不一致,可以使用配置slave-server-stale-data 关闭.
从节点成功加载完 RBD 后,如果开启了 AOF,会立刻做 bgrewriteaof。
以上加粗的部分是整个全量同步耗时的地方。
注意:
如过 RDB 文件大于 6GB,并且是千兆网卡,Redis 的默认超时机制(60 秒),会导致全量复制失败。可以通过调大 repl-timeout 参数来解决此问题。
无盘复制
为了降低主节点磁盘开销,Redis支持无盘复制,生成 的RDB文件不保存到硬盘而是直接通过网络发送给从节点,通过repl- diskless-sync参数控制,默认关闭。无盘复制适用于主节点所在机器磁盘性 能较差但网络带宽较充裕的场景。注意无盘复制目前依然处于试验阶段,线 上使用需要做好充分测试。
八、部分复制
当从节点正在复制主节点时,如果出现网络闪断和其他异常,从节点会让主节点补发丢失的命令数据,主节点只需要将复制缓冲区的数据发送到从节点就能够保证数据的一致性,相比较全量复制,成本小很多。
步骤如下:
当从节点出现网络中断,超过了 repl-timeout 时间,主节点就会中断复制连接。
主节点会将请求的数据写入到“复制积压缓冲区”,默认 1MB。
当从节点恢复,重新连接上主节点,从节点会将 offset 和主节点 id 发送到主节点
主节点校验后,如果偏移量的数后的数据在缓冲区中,就发送 cuntinue 响应 —— 表示可以进行部分复制
主节点将缓冲区的数据发送到从节点,保证主从复制进行正常状态。
九、心跳
主从节点在建立复制后,他们之间维护着长连接并彼此发送心跳命令。
心跳的关键机制如下:
中从都有心跳检测机制,各自模拟成对方的客户端进行通信,通过 client list 命令查看复制相关客户端信息,主节点的连接状态为 flags = M,从节点的连接状态是 flags = S。
主节点默认每隔 10 秒对从节点发送 ping 命令,可修改配置 repl-ping-slave-period 控制发送频率。
从节点在主线程每隔一秒发送 replconf ack{offset} 命令,给主节点上报自身当前的复制偏移量。
主节点收到 replconf 信息后,判断从节点超时时间,如果超过 repl-timeout 60 秒,则判断节点下线。
注意:为了降低主从延迟,一般把 redis 主从节点部署在相同的机房/同城机房,避免网络延迟带来的网络分区造成的心跳中断等情况。
十、异步复制
主节点不但负责数据读写,还负责把写命令同步给从节点,写命令的发送过程是异步完成,也就是说主节点处理完写命令后立即返回客户端,并不等待从节点复制完成。
异步复制的步骤很简单,如下:
主节点接受处理命令
主节点处理完后返回响应结果
对于修改命令,异步发送给从节点,从节点在主线程中执行复制的命令。
总结
- 缺点:
1.由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
2.当主机宕机之后,将不能进行写操作,需要手动将从机升级为主机,从机需要重新制定master
- 简单总结:
一个master可以有多个Slave
一个slave只能有一个master
数据流向是单向的,只能从主到从