在Redis复制的基础上(不包括Redis Cluster或Redis Sentinel作为附加层提供的高可用功能),使用和配置主从复制非常简单,能使得 【Redis从服务器】(下文称R)能精确得复制 【Redis主服务器】(下文称M)的内容。 每当 R 和 M 之间的连接断开时, R 会自动重连到 M,并且无论这期间 M 发生了什么, R 都将尝试让自身成为 M 的精确副本。
该系统的运行依靠如下重要的机制:
当一个 M 和一个 R 连接正常时, M 会发送一连串命令流保持对 R 的更新,以便将自身数据集的改变复制给 R,这包括客户端的写入、key 的过期或被逐出等
M、R 断连后,因为网络问题或主从意识到连接超时, R 重新连接上 M 并会尝试进行部分重同步:它会尝试只获取在断开连接期间内丢失的命令流。
当无法进行部分重同步时, R 会请求全量重同步。 这涉及到一个更复杂过程,比如M需创建所有数据的快照,将之发送给 R ,之后在数据集更改时持续发送命令流到 R。
Redis使用默认的异步复制,低延迟且高性能,适用于大多数 Redis 场景。但R会异步确认其从M周期接收到的数据量。
客户端可使用 WAIT 命令请求同步复制某些特定的数据。但WAIT命令只能确保在其他 Redis 实例中有指定数量的已确认的副本:在故障转移期间,由于不同原因的故障转移或是由于 Redis 持久性的实际配置,故障转移期间确认的写入操作可能仍然会丢失。
redis.conf
以避免对磁盘进行持久化,然后连接一个 R ,配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重启的 M 将从一个空数据集开始:如果一个 R 试图与它同步,那么这个 R 也会被清空!无需重启,但是不便于配置管理。
Rof ip port
R-read-only yes
虽然可统一配置,但需重启。
bgsave
,在本地生成一份RDB
则replica就会认为复制失败,可适当调大该参数(对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s)
RDB生成、RDB通过网络拷贝、R旧数据的清理、R aof rewrite,很耗费时间。 如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟。
M 开启一个后台save进程,以便生成一个 RDB 文件。同时它开始缓冲所有从客户端接收到的新的写入命令。当后台save完成RDB文件时, M 将该RDB数据集文件发给 R, R会先将其写入磁盘,然后再从磁盘加载到内存。再然后 M 会发送所有缓存的写命令发给 R。这个过程以指令流的形式完成并且和 Redis 协议本身的格式相同。
当主从之间的连接因为一些原因崩溃之后, R 能够自动重连。如果 M 收到了多个 R 要求同步的请求,它会执行一个单独的后台保存,以便于为多个 R 服务。
默认情况下,M接收SYNC命令后执行BGSAVE,将数据先保存到磁盘,若磁盘性能差,则写入磁盘会消耗大量性能。 因此在Redis 2.8.18时进行改进,可以设置无需写入磁盘直接发生RDB快照给R,加快复制速度。
复制SYNC策略:磁盘或套接字。仅仅接受差异就无法继续复制过程的新副本和重新连接副本需要进行所谓的“完全同步”。 RDB文件从主数据库传输到副本数据库。传输可以通过两种不同的方式进行:1)支持磁盘:Redis主服务器创建一个新过程,将RDB文件写入磁盘。后来,该文件由父进程逐步传输到副本。 2)无盘:Redis主服务器创建一个新进程,该进程将RDB文件直接写入副本套接字,而完全不接触磁盘。使用磁盘支持的复制,在生成RDB文件的同时,只要生成RDB文件的当前子级完成工作,就可以将更多副本排入队列并与RDB文件一起使用。如果使用无盘复制,则一旦传输开始,新的副本将排队,并且当当前副本终止时将开始新的传输。当使用无盘复制时,主服务器在开始传输之前等待一段可配置的时间(以秒为单位),以希望多个副本可以到达并且传输可以并行化。使用慢速磁盘和快速(大带宽)网络时,无盘复制效果更好。 修改配置:
repl-diskless-sync yes (默认no)
在使用 Redis 复制功能时的设置中,推荐在 M 和 R 中启用持久化。 当不可能启用时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重启后自动重新开始复制。
关闭持久化并配置了自动重启的 M 是危险的:
当 Redis Sentinel 被用于高可用并且 M 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, M 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。 任何时候数据安全性都是很重要的,所以如果 M 使用复制功能的同时未配置持久化,那么自动重启进程这项就该被禁用。
用Redis主从同步,写入Redis的数据量太大,没加频次控制,导致每秒几十万写入,主从延迟过大,运维频频报警,在主库不挂掉的情况下,这样大量写入会不会造成数据丢失? 若主从延迟很大,数据会堆积到redis主库的发送缓冲区,会导致主库OOM。
每个 M 也持有一个偏移量,M 将自己产生的复制流发送给 R 时,发送多少个字节的数据,自身的偏移量就会增加多少,目的是当有新的操作修改自己的数据集时,它可据此更新 R 的状态。
复制偏移量即使在没有一个 R 连接到 M 时,也会自增,所以基本上每一对给定的
Replication ID, offset
都会标识一个 M 数据集的确切版本。
R使用psync
从M复制,psync runid offset
M会根据自身情况返回响应信息:
R 连接到 M 时,它们使用 PSYNC 命令来发送它们记录的旧的 M replication ID 和它们至今为止处理的偏移量。通过这种方式, M 能够仅发送 R 所需的增量部分。 但若 M 的缓冲区中没有足够的命令积压缓冲记录,或者如果 R 引用了不再知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, R 会得到一个完整的数据集副本,从头开始。即:
Redis使用复制保证数据同步,以2.8版本为界:
首先是从服务器发生同步操作sync,主服务器执行bgsave生成一个全量RDB文件,然后传输给从服务器。 同时主服务器会把这一过程中执行的写命令写入缓存区。从服务器会把RDB文件进行一次全量加载。 加载完毕后,主服务器会把缓存区中的写命令传给从服务器。从服务器执行命令后,主从服务器的数据就一致了。 这种方式每次如果网络出现故障,故障重连后都要进行全量数据的复制。对主服务器的压力太大,也会增加主从网络传输的资源消耗。
增加部分重同步功能,就是同步故障后的一部分数据,而非全量数据。这种优化在量级非常大的情况下效率提升很明显。
R如果跟M有网络故障,断开连接会自动重连。 M如果发现有多个R都重新连接,仅会启动一个rdb save操作,用一份数据服务所有R。
host
和ip
,但复制流程尚未开始M host和ip配置在 redis.conf
中的 Rof主从节点互相都会发送heartbeat信息。 M默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat。
Redis 2.8开始支持主从复制的断点续传
主从复制过程,若网络连接中断,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。
M和R都要知道各自数据的offset,才能知晓互相之间的数据不一致情况。
M会在内存中维护一个backlog,默认1MB。M给R复制数据时,也会将数据在backlog中同步写一份。
backlog主要是用做全量复制中断时候的增量复制
。
M和R都会保存一个replica offset还有一个M id,offset就是保存在backlog中的。若M和R网络连接中断,R会让M从上次replica offset开始继续复制。但若没有找到对应offset,就会执行resynchronization。
根据host+ip定位M node,是不靠谱的,如果M node重启或者数据出现了变化,那么R node应该根据不同的run id区分,run id不同就做全量复制。 如果需要不更改run id重启redis,可使用:
redis-cli debug reload
M在内存中直接创建RDB,然后发送给R,不会在自己本地持久化。
只需要在配置文件中开启repl-diskless-sync yes
即可.
等待 5s 再开始复制,因为要等更多 R 重连
repl-diskless-sync-delay 5
Redis 的过期机制可以限制 key 的生存时间。此功能取决于 Redis 实例计算时间的能力,但是,即使使用 Lua 脚本更改了这些 key,Redis Rs 也能正确地复制具有过期时间的 key。
为实现功能,Redis 不能依靠主从使用同步时钟,因为这是一个无法解决的问题并且会导致 race condition 和数据不一致,所以 Redis 使用三种主要的技术使过期的 key 的复制能够正确工作:
一旦 R 被提升 M ,它将开始独立过期 key,而不需要任何旧 M 帮助。
Redis 4.0 开始,当一个实例在故障转移后被提升为 M 时,它仍然能够与旧 M 的 R 进行部分重同步。为此,R 会记住旧 M 的旧 replication ID 和复制偏移量,因此即使询问旧的 replication ID,也可以将部分复制缓冲提供给连接的 R 。
但是,升级的 R 的新 replication ID 将不同,因为它构成了数据集的不同历史记录。例如,M 可以返回可用,并且可以在一段时间内继续接受写入命令,因此在被提升的 R 中使用相同的 replication ID 将违反一对复制标识和偏移对只能标识单一数据集的规则。
另外,R 在关机并重新启动后,能够在 RDB 文件中存储所需信息,以便与 M 进行重同步。这在升级的情况下很有用。当需要时,最好使用 SHUTDOWN 命令来执行 R 的保存和退出操作。
参考