redis-8-事务-主从复制
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
1. 事务
1.1 认识
mysql事务特性:原子性,一致性,持久性,隔离性
但是注意体会 Redis 的事务和 MySQL 事务的区别:
• 弱化的原⼦性: redis 没有 “回滚机制”. 只能做到这些操作 “批量执⾏”. 不能做到 “⼀个失败就恢复到初始状态”.
• 不保证⼀致性: 不涉及 “约束”. 也没有回滚,所以可能会不一致. MySQL 的⼀致性体现的是运⾏事务前和运⾏后 , 结果都是合理有效的, 不会出现中间⾮法状态.
• 不需要隔离性: 也没有隔离级别, 因为不会并发执⾏事务 (redis 单线程处理请求) .
• 不需要持久性: 是保存在内存的. 是否开启持久化, 是redis-server ⾃⼰的事情, 和事务⽆关.
redis事务的主要意义,就是为了打包,避免其他客户端的命令,插入进来了
Redis 事务本质上是在服务器上搞了⼀个 “事务队列”. 每次客⼾端在事务中进⾏⼀个操作, 都会把命令先发给服务器, 放到 “事务队列” 中(但是并不会⽴即执⾏)
⽽是会在真正收到 EXEC 命令之后, 才真正执⾏队列中的所有操作.
因此, Redis 的事务的功能相⽐于 MySQL 来说, 是弱化很多的. 只能保证事务中的这⼏个操作是 “连续的”, 不会被别的客⼾端 “加塞”, 仅此⽽已
1.2 事务相关命令
开启事务:MULTI
执行事务:EXEC
放弃当前事务:DISCARD
> multi
OK
> set key 111
QUEUED
> set key2 222
QUEUED
> set key3 333
QUEUED
这个意思就是在服务器的事务队列中,保存了上述请求
如果再开一个客户端,是查询不到这些请求的
> multi
OK
> set key 111
QUEUED
> set key2 222
QUEUED
> set key3 333
QUEUED
> exec
OK
OK
OK
这样就成功了
> multi
OK
> set key4 444
QUEUED
> discard
OK
这个就是表示没有生效了
如果还没执行exec,结果服务器重启了,怎么办呢—》效果就是discard的效果
还有一个watch,命令:监控某个key是否在事务执行之前发生了改变

这样的规则容易产生歧义
可以使用watch来监控
看看这个key在multi和exec之间被外部其他客户端修改了
> watch key
OK
> multi
OK
> set key 222
QUEUED
在其他客户端
> set key 333
OK
回到原来客户端
> watch key
OK
> multi
OK
> set key 222
QUEUED
> exec
null
我们发现exec返回的是null
因为exec在执行事务中的命令的时候,发现key在外部有修改,于是真正执行set key 222的时候,就没有执行
> get key
333
UNWATCH
取消对 key 的监控.
相当于 WATCH 的逆操作.
1.3 watch实现原理
watch的实现,相当于一个乐观锁
乐观锁:预期接下来锁冲突的概率比较低
悲观锁:锁冲突概率比较高
锁冲突概率高和低的话,接下来做的工作是不一样的
redis的watch就是相当于基于版本号这样的机制,来实现了乐观锁


2. 主从复制
在分布式系统中为了解决单点问题,通常会把数据复制多个副本部署到其他服务器,满⾜故障恢复和负载均衡等需求。Redis 也是如此,它为我们提供了复制的功能,实现了相同数据的多个 Redis 副本。复制功能是⾼可⽤ Redis 的基础,哨兵和集群都是在复制的基础上构建的
单点问题:可用性,挂了就没了,服务就没了,并发量有限的
redis的部署方式:主从模式,主动+哨兵模式,集群模式
主从模式:比如有三个redis节点,一个为主,两个为从,从节点要和主节点数据保持一致,主节点的数据复制到从节点
主从模式中,从节点不能修改,只能读取,所以从节点要和主节点保持一致
2.1 解决问题
可用性,并发量
2.2 如何启动多个redis-server
可以在一个主机上运行多个redis-server进程的,但是要保证多个redis-server的端口应该不一样—》可以在启动命令的时候指定,也可以在配置文件中指定
我们这里使用docker来安装
docker run --name my-redis-slave1 -d -p 6380:6379 redis:latest --requirepass "123456"
docker run --name my-redis-slave -d -p 6381:6379 redis:latest --requirepass "123456"
2.3 配置主从复制
参与复制的 Redis 实例划分为主节点(master)和从节点(slave)。每个从结点只能有⼀个主节点,⽽⼀个主节点可以同时具有多个从结点。复制的数据流是单向的,只能由主节点到从节点。配置复制的⽅式有以下三种:
- 在配置⽂件中加⼊ slaveof {masterHost} {masterPort} 随 Redis 启动⽣效。
- 在 redis-server 启动命令时加⼊ --slaveof {masterHost} {masterPort} ⽣效。
- 直接使⽤ redis 命令:slaveof {masterHost} {masterPort} ⽣效
我们来修改配置文件,因为这个是持久化的
注意: 修改配置主要是修改从机的配置. 主机配置不变
但是在容器里面没有配置文件,Docker 最新版本的 Redis 镜像默认不会在容器内部放置一个独立的 redis.conf 配置文件,除非你手动挂载一个进去或者通过环境变量生成。
所以我们只能通过命令的方式来设置了
# 主节点(原命令不变,无需重新启动)
# docker run --name my-redis-master -d -p 6379:6379 redis:latest --requirepass "123456"
# 从节点1:补充 --masterauth 123456
docker run -d -p 6380:6379 --name my-redis-slave1 redis:latest redis-server --slaveof 172.17.0.1 6379 --masterauth 123456 --requirepass 123456
# 从节点2:和从节点1一致
docker run -d -p 6381:6379 --name my-redis-slave2 redis:latest redis-server --slaveof 172.17.0.1 6379 --masterauth 123456 --requirepass 123456


这样就成功了,我们在主节点修改数据,就会自动同步到从节点上了

然后现在就是从节点也不能写数据了
2.4 查看主从结构信息
> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.3,port=6379,state=online,offset=1623,lag=1
slave1:ip=172.17.0.4,port=6379,state=online,offset=1623,lag=0
master_failover_state:no-failover
master_replid:93b8e8d70075dbff05b8684123be8d7b9860e33b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1623
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1623
我们在主节点执行info replication
role:master表示是主节点
connected_slaves表示有两个从节点
主节点修改数据,从节点就要从主节点这里同步修改请求
这里的数据同步不是瞬间完成的,所以offset就是主节点和从节点的同步进度,就是从节点同步到哪里了
lag表示延迟
master_replid是主节点id
master_repl_offset是主节点修改数据到哪里了,和offset一样说明同步了
repl_backlog_active及其后面的配置是积压缓冲区
> info replication
# Replication
role:slave
master_host:172.17.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_read_repl_offset:1693
slave_repl_offset:1693
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:93b8e8d70075dbff05b8684123be8d7b9860e33b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1693
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:1679
这是在从节点上执行
connected_slaves表示从节点的从节点
这些配置都可以在官网上查询
2.5 断开主从结构和修改主从结构
slaveof 命令不但可以建⽴复制,还可以在从节点执⾏ slaveof no one 来断开与主节点复制关系。
例如在 6380 节点上执⾏ slaveof no one 来断开复制。
直接在客户端执行命令就可以了,这样它就不是从节点了,原来得到数据还会保留,但是后续不会同步主节点的数据了
断开复制主要流程:
1)断开与主节点复制关系。
2)从节点晋升为主节点。
从节点断开复制后并不会抛弃原有数据,只是⽆法再获取主节点上的数据变化
通过 slaveof 命令还可以实现切主操作,将当前从节点的数据源切换到另⼀个主节点。执⾏
slaveof {newMasterIp} {newMasterPort} 命令即可
slaveof 127.0.0.1 6380
切主操作主要流程:
1)断开与旧主节点复制关系。
2)与新主节点建⽴复制关系。
3)删除从节点当前所有数据。
4)从新主节点进⾏复制操作
但是这里的6380还是从节点,还是不能写操作
注意这里的修改主从结构是临时性的,重启的话,就不生效了
2.6 主从复制的安全,只读,传输延时
安全性
对于数据⽐较重要的节点,主节点会通过设置 requirepass 参数进⾏密码验证,这时所有的客⼾
端访问必须使⽤ auth 命令实⾏校验。从节点与主节点的复制连接是通过⼀个特殊标识的客⼾端来完
成,因此需要配置从节点的masterauth 参数与主节点密码保持⼀致,这样从节点才可以正确地连接到
主节点并发起复制流程。
只读
默认情况下,从节点使⽤ slave-read-only=yes 配置为只读模式。由于复制只能从主节点到从节
点,对于从节点的任何修改主节点都⽆法感知,修改从节点会造成主从数据不⼀致。所以建议线上不
要修改从节点的只读模式。
但是如果从节点可以修改,主节点是感知不到的—》数据不一致了
传输延迟
主从节点⼀般部署在不同机器上,复制时的⽹络延迟就成为需要考虑的问题,Redis 为我们提供了 repl-disable-tcp-nodelay 参数⽤于控制是否关闭 TCP_NODELAY,默认为 no,即开启 tcp_nodelay 功能,说明如下:
• 当关闭时,主节点产⽣的命令数据⽆论⼤⼩都会及时地发送给从节点,这样主从之间延迟会变⼩,但增加了⽹络带宽的消耗。适⽤于主从之间的⽹络环境良好的场景,如同机房部署。
• 当开启时,主节点会合并较⼩的 TCP 数据包从⽽节省带宽。默认发送时间间隔取决于 Linux 的内核,⼀般默认为 40 毫秒。这种配置节省了带宽但增⼤主从之间的延迟。适⽤于主从⽹络环境复杂的场景,如跨机房部署。

2.7 主从复制的拓扑结构
若干个节点之间,按照啥样的方式来进行组织连接
Redis 的复制拓扑结构可以⽀持单层或多层复制关系,根据拓扑复杂性可以分为以下三种:⼀主⼀从、⼀主多从、树状主从结构。
⼀主⼀从结构
⼀主⼀从结构是最简单的复制拓扑结构,⽤于主节点出现宕机时从节点提供故障转移⽀持,如图所⽰。当应⽤写命令并发量较⾼且需要持久化时,可以只在从节点上开启 AOF,这样既可以保证数据安全性同时也避免了持久化对主节点的性能⼲扰。但需要注意的是,当主节点关闭持久化功能时,如果主节点宕机要避免⾃动重启操作。
如果写数据请求太多,也会给主节点造成一些压力,我们可以关闭主节点的aof,只开启从节点的aof,这样主节点就变快了
但是主节点挂了,不能让它自动重启–》因为自动重启–》没有aof–》数据为空,同步–》从节点也为空
改进:主节点挂了,主节点就要从从节点拉取aof数据,然后在启动
实际开发:读请求远远大于写请求
⼀主多从结构
⼀主多从结构(星形结构)使得应⽤端可以利⽤多个从节点实现读写分离,如图 所⽰。对于
读⽐重较⼤的场景,可以把读命令负载均衡到不同的从节点上来分担压⼒。同时⼀些耗时的读命令可
以指定⼀台专⻔的从节点执⾏,避免破坏整体的稳定性。对于写并发量较⾼的场景,多个从节点会导
致主节点写命令的多次发送从⽽加重主节点的负载。
但是从节点增加—》主节点同步压力太大

树形主从结构
树形主从结构(分层结构)使得从节点不但可以复制主节点数据,同时可以作为其他从节点的主
节点继续向下层复制。通过引⼊复制中间层,可以有效降低住系欸按负载和需要传送给从节点的数据
量,如图 所⽰。数据写⼊节点 A 之后会同步给 B 和 C 节点,B 节点进⼀步把数据同步给 D 和 E 节
点。当主节点需要挂载等多个从节点时为了避免对主节点的性能⼲扰,可以采⽤这种拓扑结构。
缺点就是同步的延时就更大了
2.8 复制流程

1)保存主节点(master)的信息。
开始配置主从同步关系之后,从节点只保存主节点的地址信息,此时建⽴复制流程还没有开始,
在从节点 6380 执⾏ info replication 可以看到如下信息:
master_host: 127.0.0.1
master_port: 6379
master_link_status: down
从统计信息可以看出,主节点的 ip 和 port 被保存下来,但是主节点的连接状态(master_link_status)是下线状态。
2)从节点(slave)内部通过每秒运⾏的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与主节点建⽴基于 TCP 的⽹络连接。如果从节点⽆法建⽴连接,定时任务会⽆限重试直到连接成功或者⽤⼾停⽌主从复制。
3)发送 ping 命令。连接建⽴成功之后,从节点通过 ping 命令确认主节点在应⽤层上是⼯作良好的。如果 ping 命令的结果 pong 回复超时,从节点会断开 TCP 连接,等待定时任务下次重新建⽴连接。
4)权限验证。如果主节点设置了 requirepass 参数,则需要密码验证,从节点通过配置 masterauth参数来设置密码。如果验证失败,则从节点的复制将会停⽌。
5)同步数据集。对于⾸次建⽴复制的场景,主节点会把当前持有的所有数据全部发送给从节点,这步操作基本是耗时最⻓的,所以⼜划分称两种情况:全量同步和部分同步,后面重点介绍。
6)命令持续复制。当从节点复制了主节点的所有数据之后,针对之后的修改命令,主节点会持续的把命令发送给从节点,从节点执⾏修改命令,保证主从数据的⼀致性。
2.9 replicationid的作用
数据同步 psync—》一般不需要我们手动执行,redis服务器会自动执行,从节点负责执行psync
Redis 使⽤ psync 命令完成主从数据同步,同步过程分为:全量复制和部分复制。
• 全量复制:⼀般⽤于初次复制场景,Redis 早期⽀持的复制功能只有全量复制,它会把主节点全部
数据⼀次性发送给从节点,当数据量较⼤时,会对主从节点和⽹络造成很⼤的开销。
• 部分复制:⽤于处理在主从复制中因⽹络闪断等原因造成的数据丢失场景,当从节点再次连上主节
点后,如果条件允许,主节点会补发数据给从节点。因为补发的数据远⼩于全量数据,可以有效避
免全量复制的过⾼开销。
PSYNC replicationid offset
如果 replicationid 设为 ? 并且 offset 设为 -1 此时就是在尝试进⾏全量复制.
如果 replicationid offset 设为了具体的数值, 则是尝试进⾏部分复制.
replicationid 是主节点生成的,主节点启动的时候生成,同一个主节点每次重启的replicationid 都不一样,从节点可以获取replicationid ,表示从哪个主节点获取同步数据。因为后面可能是多主,所以replicationid 要指定好
- replicationid/replid (复制id)
主节点的复制 id. 主节点重新启动, 或者从节点晋级成主节点, 都会⽣成⼀个 replicationid. (同⼀个节
点, 每次重启, ⽣成的 replicationid 也会变化).
从节点在和主节点建⽴连接之后, 就会获取到主节点的 replicationid.
通过 info replication 即可看到 replicationid
replicationid所以就是主节点的id
> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.3,port=6379,state=online,offset=1623,lag=1
slave1:ip=172.17.0.4,port=6379,state=online,offset=1623,lag=0
master_failover_state:no-failover
master_replid:93b8e8d70075dbff05b8684123be8d7b9860e33b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1623
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1623
master_replid2这个就是一个备份的效果,一般用不上,如果A主挂了,B从可能就变为主节点了,所以后面从节点就通过master_replid2来记录旧的master_replid,目的是为了以后有一天让B又变成A的从节点—》这个要手动干预,但是哨兵机制可以自动完成
关于 master_replid 和 master_replid2
每个节点需要记录两组 master_replid . 这个设定解决的问题场景是这样的:
⽐如当前有两个节点 A 和 B, A 为 master, B 为 slave.
此时 B 就会记录 A 的 master_replid.
如果⽹络出现抖动, B 以为 A 挂了, B ⾃⼰就会成为主节点. 于是 B 给⾃⼰分配了新的 master_replid.
此时就会使⽤ master_replid2 来保存之前 A 的 master_replid.
• 后续如果⽹络恢复了, B 就可以根据 master_replid2 找回之前的主节点.
• 后续如果⽹络没有恢复, B 就按照新的 master_replid ⾃成⼀派, 继续处理后续的数据
2.10 offset的作用
主节点和从节点都会维护这个偏移量
主节点这个偏移量就是说修改到哪里了,就是说修改命令占有字节,offset就是所有修改操作的总的字节数
从节点的offset就是说自己同步到哪里了
如果主从的offset,就OK了
参与复制的主从节点都会维护⾃⾝复制偏移量。主节点(master)在处理完写⼊命令后,会把命令的
字节⻓度做累加记录,统计信息在 info replication 中的 master_repl_offset 指标中
127.0.0.1:6379> info replication
# Replication
role:master
...
master_repl_offset:1055130
从节点(slave)每秒钟上报⾃⾝的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量,
127.0.0.1:6379> info replication
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=1055214,lag=1
从节点在接受到主节点发送的命令后,也会累加记录⾃⾝的偏移量。统计信息在 info replication 中的
slave_repl_offset 指标中:
127.0.0.1:6380> info replication
# Replication
role:slave
...
slave_repl_offset:1055214
通过对⽐主从节点的复制偏移量,可以判断主从节点数据是否⼀致。
replid + offset 共同标识了⼀个 “数据集”.
如果两个节点, 他们的 replid 和 offset 都相同, 则这两个节点上持有的数据, 就⼀定相同
2.11 全量复制和部分复制

1)从节点发送 psync 命令给主节点,replid 和 offset 的默认值分别是 ? 和 -1.
2)主节点根据 psync 参数和⾃⾝数据情况决定响应结果:
• 如果回复 +FULLRESYNC replid offset,则从节点需要进⾏全量复制流程。
• 如果回复 +CONTINEU,从节点进⾏部分复制流程。
• 如果回复 -ERR,说明 Redis 主节点版本过低,不⽀持 psync 命令。从节点可以使⽤ sync 命令进⾏
全量复制。
• psync ⼀般不需要⼿动执⾏. Redis 会在主从复制模式下⾃动调⽤执⾏.
• sync 会阻塞 redis server 处理其他请求. psync 则不会.
全量复制–》第一次复制,或者不方便部分复制
全量复制是 Redis 最早⽀持的复制⽅式,也是主从第⼀次建⽴复制时必须经历的阶段。
部分复制:大部分数据都是一致的
2.12 全量复制流程

1)从节点发送 psync 命令给主节点进⾏数据同步,由于是第⼀次进⾏复制,从节点没有主节点的运⾏ ID 和复制偏移量,所以发送 psync ? -1。
2)主节点根据命令,解析出要进⾏全量复制,回复 +FULLRESYNC 响应。
3)从节点接收主节点的运⾏信息进⾏保存。比如replyid
4)主节点执⾏ bgsave 进⾏ RDB ⽂件的持久化。为了是传输rdb到从节点,而且rdb是二进制文件,比aof文本文件传输消耗带宽小,而且rdb不是实时的,所以要重新生成rdb
5)从节点发送 RDB ⽂件给从节点,从节点保存 RDB 数据到本地硬盘。
6)主节点将从⽣成 RDB 到接收完成期间执⾏的写命令,写⼊缓冲区中,等从节点保存完 RDB ⽂件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照 rdb 的⼆进制格式追加写⼊到收到的 rdb ⽂件中. 保持主从⼀致性。
7)从节点清空⾃⾝原有旧数据。
8)从节点加载 RDB ⽂件得到与主节点⼀致的数据。
9)如果从节点加载 RDB 完成之后,并且开启了 AOF 持久化功能,它会进⾏ bgrewrite 操作,得到最近的 AOF ⽂件。
通过分析全量复制的所有流程,我们会发现全量复制是⼀件⾼成本的操作:主节点 bgsave 的时间,RDB 在⽹络传输的时间,从节点清空旧数据的时间,从节点加载 RDB 的时间等。所以⼀般应该尽可能避免对已经有⼤量数据集的 Redis 进⾏全量复制。
2.13 全量复制的无硬盘模式
有磁盘复制 vs ⽆磁盘复制(diskless)
默认情况下, 进⾏全量复制需要主节点⽣成 RDB ⽂件到主节点的磁盘中, 再把磁盘上的 RDB⽂件通过发送给从节点.
Redis 从 2.8.18 版本开始⽀持⽆磁盘复制. 主节点在执⾏ RDB ⽣成流程时, 不会⽣成 RDB ⽂件到磁盘中了, ⽽是直接把⽣成的 RDB 数据通过⽹络发送给从节点. 这样就节省了⼀系列的写硬盘和读硬盘的操作开销.
2.14 关于runid和repid
runid
> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.4,port=6379,state=online,offset=2547,lag=0
slave1:ip=172.17.0.5,port=6379,state=online,offset=2547,lag=1
master_failover_state:no-failover
master_replid:0c27c4c8bdffc82a185162fbcf178f586774356a
master_replid2:93b8e8d70075dbff05b8684123be8d7b9860e33b
master_repl_offset:2547
second_repl_offset:1246
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1246
repl_backlog_histlen:1302
这个可以看到repid
> info server
# Server
redis_version:8.0.3
redis_git_sha1:00000000
redis_git_dirty:1
redis_build_id:d4cb0aa008da4ca9
redis_mode:standalone
os:Linux 6.6.87.2-microsoft-standard-WSL2 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:12.2.0
process_id:1
process_supervised:no
run_id:4d470e99825acc7e6fa0dc1d285e53efc2b9be09
tcp_port:6379
server_time_usec:1770445162856580
uptime_in_seconds:976
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:8837482
executable:/data/redis-server
config_file:
io_threads_active:0
listener0:name=tcp,bind=*,bind=-::*,port=6379
这个可以看到run_id
这两个长度相同,格式也类似
主从节点的repid是一样的
主从的runid是不一样的,各自都不相同,每个节点都是不一样的
一次runid标识一次redis的运行,每次redis的运行,runid都是不一样的
所以runid和主从复制是没有关系的
repid和offset共同标识了一个数据的复制进度
repid就是复制数据的来源
offset是复制的进度
2.15 部分复制流程
就是大部分数据一样,少部分数据不一致的时候进行部分复制
部分复制主要是 Redis 针对全量复制的过⾼开销做出的⼀种优化措施,使⽤ psync replicationId offset 命令实现。当从节点正在复制主节点时,如果出现⽹络闪断或者命令丢失等异常情况时,从节点会向主节点要求补发丢失的命令数据,如果主节点的复制积压缓冲区存在数据则直接发送给从节点,这样就可以保持主从节点复制的⼀致性。补发的这部分数据⼀般远远⼩于全量数据,所以开销很⼩。整体流程如图所⽰。
1)当主从节点之间出现⽹络中断时,如果超过 repl-timeout 时间,主节点会认为从节点故障并终端复制连接。
2)主从连接中断期间主节点依然响应命令,但这些复制命令都因⽹络中断⽆法及时发送给从节点,所以暂时将这些命令滞留在复制积压缓冲区中。
3)当主从节点⽹络恢复后,从节点再次连上主节点。
4)从节点将之前保存的 replicationId 和 复制偏移量作为 psync 的参数发送给主节点,请求进⾏部分复制。
5)主节点接到 psync 请求后,进⾏必要的验证。随后根据 offset 去复制积压缓冲区查找合适的数据,并响应 +CONTINUE 给从节点。
6)主节点将需要从节点同步的数据发送给从节点,最终完成⼀致性
复制积压缓冲区
复制积压缓冲区是保存在主节点上的⼀个固定⻓度的队列,默认⼤⼩为 1MB,当主节点有连接的从节点(slave)时被创建,这时主节点(master)响应写命令时,不但会把命令发送给从节点,还会写⼊复制积压缓冲区
由于缓冲区本质上是先进先出的定⻓队列,所以能实现保存最近已复制数据的功能,⽤于部分复制和复制命令丢失的数据补救。复制缓冲区相关统计信息可以通过主节点的 info replication 中:
根据统计指标,可算出复制积压缓冲区内的可⽤偏移量范围:[repl_backlog_first_byte_offset,repl_backlog_first_byte_offset + repl_backlog_histlen]。这个相当于⼀个基于数组实现的环形队列. 上述区间中的值就是 "数组下标
如果当前从节点需要的数据, 已经超出了主节点的积压缓冲区的范围, 则⽆法进⾏部分复制, 只能全量复制了.
2.16 实时复制
全量复制:从节点刚刚链接上
部分复制:全量复制的额特殊情况
主从节点在建⽴复制连接后,主节点会把⾃⼰收到的 修改操作 , 通过 tcp ⻓连接的⽅式, 源源不断的传输给从节点. 从节点就会根据这些请求来同时修改⾃⾝的数据. 从⽽保持和主节点数据的⼀致性.
另外, 这样的⻓连接, 需要通过⼼跳包的⽅式来维护连接状态. (这⾥的⼼跳是指应⽤层⾃⼰实现的⼼跳,⽽不是 TCP ⾃带的⼼跳).
1)主从节点彼此都有⼼跳检测机制,各⾃模拟成对⽅的客⼾端进⾏通信。
2)主节点默认每隔 10 秒对从节点发送 ping 命令,判断从节点的存活性和连接状态。
3)从节点默认每隔 1 秒向主节点发送 replconf ack {offset} 命令,给主节点上报⾃⾝当前的复制偏移
量。
如果主节点发现从节点通信延迟超过 repl-timeout 配置的值(默认 60 秒),则判定从节点下线,断开复制客⼾端连接。从节点恢复连接后,⼼跳机制继续进⾏。
2.17 总结
主从复制解决的问题:
单点问题.
-
单个 redis 节点, 可⽤性不⾼.
-
单个 redis 节点, 性能有限.
主从复制的特点: -
Redis 通过复制功能实现主节点的多个副本。
-
主节点⽤来写, 从节点⽤来读. 这样做可以降低主节点的访问压⼒.
-
复制⽀持多种拓扑结构,可以在适当的场景选择合适的拓扑结构。
-
复制分为全量复制, 部分复制和实时复制
-
主从节点之间通过⼼跳机制保证主从节点通信正常和数据⼀致性。
主从复制配置的过程: -
主节点配置不需要改动.
-
从节点在配置⽂件中加⼊ slaveof 主节点ip 主节点端⼝ 的形式即可.
主从复制的缺点: -
从机多了, 复制数据的延时⾮常明显.
-
主机挂了, 从机不会升级成主机. 只能通过⼈⼯⼲预的⽅式恢复或者redis哨兵机制(替换主节点)
2.18 关于从节点何时晋升为主节点
- 从节点主动和主节点断开连接
slaveof no none
这个时候从节点就能够晋升为主节点
3.主节点挂了,这个时候从节点不会晋升为主节点,只能人工来操作,哨兵机制就是可以主动晋升
总结
更多推荐


所有评论(0)