Redis深刻系列-0x017:Redis同步

概述

基础的Redis同步使用很是简单,配置主从同步可让从节点彻底复制节点。无论主节点发生任何事,从节点会在连接断开以后自动重连。redis

这个机制工做使用了三台机子:数据库

  • 当主节点和从节点链接的很好的时候,主节点经过发送主节点上接收并执行的命令流到从节点,从而保证从节点更新:客户端写、key过时或者回收等。
  • 当主从节点之间的链接断开,好比网络问题或者主从节点以为超时,从节点将从新连接而且尝试部分从新同步:这意味着他将从新同步在断开连接以后流中的命令。
  • 当部分从新同步失败之后,从节点将会请求一个彻底同步,这降火执行一个更加复杂的操做,主节点须要建立一个当前数据的镜像,发送给从节点,而且在数据集发生改变的时候继续发送命令流。

Redis默认使用高性能高延迟的异步复制,这是大部分Redis使用场景的天然复制模式。从节点按期异步的从主节点获取大量的数据。缓存

能够在客户端使用WAIT命令来请求同步复制确认的数据。然而WATI命令只能确保指定数量的数据被复制到其余实例:数据写入依旧会在故障转移或者因故障转移的致使的缘由中丢失,取决于Redis持久化配置。你能够查看Sentinel或者Redis Cluster文档查看更多关于高可用和故障转移的信息。接下来的文档主要归纳Redis简单的数据同步的一些基本的特征。安全

接下来是一些关于Redis同步很重要的事实:网络

  • Redis使用异步复制,从节点异步的从主节点获取大量的数据。
  • 一个主节点能够有多个从节点
  • 从节点能够接受其余从节点的链接,在链接不少从节点到同一个主节点以外,从节点也能够链接到其余从节点,相似级联的方式。从Redis 4.0之后,全部的子从节点都将从主节点收到相同的复制流。
  • Redis同步在主节点是非堵塞的。这意味着主节点能够继续处理请求,当一个或者多个从节点作初始化数据同步或者增量同步的时候。
  • 同步在从节点也是非堵塞的。若是你在配置文件中配置好了,在从节点初始化同步的时候可使用旧版本的数据集去响应请求。除此以外,你也能够配置Redis从节点在复制流来的的时候返回一个错误给客户端,在初始化同步的时候,旧的数据集将被删除,行的数据必须被加载。从节点将会在这个短暂时间窗口堵塞正在进来的链接(这将在巨大的数据集上花费长达许多秒的时间)。从Redis 4.0开始,删除就数据将会在另外一个线程进行,可是加载新的初始化数据集依旧会在主线程执行,而且堵塞从节点。
  • 为了拥有多个从节点去处理只读请求(好比O(N)的慢查询操做能够由从节点分担),同步是可伸缩的,也是安全可靠的。
  • 避免主节点将全部数据集写入磁盘产生的损耗也是由办法的:一个典型的技术是经过配置不让主节点持久化数据到磁盘,而后配置从节点去作这件事,或者开始AOF。可是这个操做要很是当心,由于重启住节点将清空数据集:若是此时从节点去同步它,将会让从节点也清空。

当主节点的持久化关闭的时候,安全的同步数据

若是使用Redis同步,强烈建议在主节点和从节点都打开持久化。若是这由于担忧延迟致使磁盘缓慢,实例应该经过修改配置,避免在重启的时候自动重启。
为了更好的理解在持久化关闭的时候,自动重启是很是危险的,检查下面数据数据从主节点和从节点都消失的模式:并发

  • 咱们设置节点A做为主节点,关闭持久化,节点B和C从A处同步数据。
  • 节点A奔溃,然而他有自动重启系统,他将会自动重启。然而,由于持久化关闭,因此主节点将会以空数据集重启。
  • 节点B和C依旧从节点A复制数据,可是由于A是空的,因此他们也会将本身的数据同步为空。

Redis Sentinel用来作高可用的时候,主节点上将会关闭持久化,同时也关闭自动重启。好比主节点能够快速重启,快到Sentinel都来不及捕捉错误因此上面归纳的失败的模式就发生了。less

任什么时候候数据安全都是重要的是,当主节点使用同步并关闭持久化的时候,自动重启也要被关闭异步

Redis同步是怎么工做的

每个Redis主节点有一个同步ID,是一个巨大的位随机字符串标记数据集。同时主节点也为发送到从节点的同步流提供一个增加偏移量,为了让从节点更新数据集状态。同步偏移量即便在没有从节点;连接的时候也会增加,因此每一次都将产生一对:性能

Replication ID, offset

标记主机数据集精确的版本
当从节点链接到主节点的时候,他们使用PSYNC命令发送他们目前为止执行的旧的同步ID和偏移量。这种方式下,主节点能够值发送增加部分,然而,若是主节点没有足够的日志备份,或者从节点使用了一个过去的同步ID,主节点没法找到他,就会发生全量同步:这种状况下,从节点将会获得一个完成的数据复制集,重新开始。
更多全量同步工做的方式:
主节点开始一个后台进程保存数据,产生一个RDB文件。同时开始缓存从客户端来的全部写命令。当后台保存进程完成,主节点将会把数据文件发送给从节点,他保存在磁盘中,而后加载到内存。主节点也会立刻发送缓存命令到从节点。这将会以Redis协议自己相同的命令流格式完成。
你能够足迹经过telnet尝试。在服务店正在执行一些工做的时候链接Redis端口并发送SYNC命令。你能够看到大部分的传输而且主节点收到的全部命令都会telnet中打印出来。事实上SYNC是一个旧的协议,不在新的Redis实例上使用,可是依旧向后兼容的:他不容许从新增量同步,因此PSYNC用来代替他。ui

  • 就像已经说过的,从节点在主从节点由于某些断开的时候自动从新链接。若是主节点同时接到多个从节点同步请求,他只会启动一个单独的线程去服务他们。

无盘同步

正常状况下,一个全量同步须要建立一个RDB文件,而后从磁盘中读取这个文件,再发送给从节点。

然而磁盘读取是很是慢的,这将给主节点形成很是大的压力。Redis 2.8.18之后支持无盘同步。在这种设置下,子进程能够直接经过网络发送RDB给从节点,从而避免使用磁盘当作中间存储。

配置

配置Redis同步是很简单的,添加如下命令到配置文件就能够了:

slaveof 192.168.1.1 6379

固然你必须使用你主节点的IP和端口覆盖192.168.1.1 6379参数。当你使用SLAVEOF命令的时候,主节点就会开始同步数据到从节点

固然还有一些参数用来开启同步日志,让主节点加载到内存中去执行增量同步。能够查看Redis发行版中的redis.conf文件查看更新信息。

无盘同步可使用repl-diskless-sync配置参数开启。延迟传输从而等待更多子节点连接主节点可使用repl-diskless-sync-delay配置参数控制。更多栗子请查阅发行版中的redis.conf文件。

只读的从节点

Read-only slave
Redis 2.6开始,从节点支持只读模式,而且这是默认开启的。这个行为能够用slave-read-only来控制,能够在redis.conf修改,也可使用CONFIG SET来设置。

只读的本身诶单拒绝全部的写命令,因此不可能写入从节点,由于会发生错误。这并不觉得这这个特性是为了在不被信任的网络和客户端中暴露本身,由于管理命令,好比像DEBUGCONFIG之类的依旧可使用。固然,只读实例的安全性能够经过在redus.conf中的rename-command禁用命令来提高。

你可能会想为何要容许只读的从节点实例能够被改成可写的。这些写入的数据将会被主节点再次同步数据的时候删除,这里有几个合理的用户场景来讲明为何要短暂的在可写从节点存储数据。

好比统计慢Set或者Sorted Set操做,并存储他们到本地,这是一个可写从节点很常见的用户场景

然而,要记住,4.0之前的可写从节点没办法作到key的过时时间设置,这意味着,若是你使用EXPIRE或者其余命令去设置一个key最大的TTL,这个key将会泄露,你将没法使用读命令找到他,你将会在key的统计中看到他,而且他依旧占据着内存。因此,在一般状况下可写从节点使用TTL将会致使问题(4.0版本之前)。

Redis 4.0 RC3和更新的版本彻底解决了这个发生在key写入超过63个数据库的问题(可是默认状况下Redis实例只有16个数据库),而且如今可写从节点能够像主节点同样驱逐过时的key

一样须要记住的是从Redis4.0之后,从节点写入的数据只存在本地,不会传播到链接到该子节点的子从节点,子从节点接收到的同步流将会和最高的主节点发送给中间节点如出一辙。下面是栗子:

A ---> B ---> C

即便B是可写的,C也不会看到B写入的数据,只会看到A中的数据

设置从节点链接主节点时候的验证

若是你的主节点经过requirepass配置属性设置了密码,设置从节点使用密码同步也是很是简单的:
使用redis-cli链接从节点,输入:

config set masterauth <password>

为了永远记住他,添加到配置文件中:

masterauth <password>

只有N个从节点连接的时候才容许写入

Redis 2.8之后,能够设置主节点只有在有N台从节点连接的时候能够写入请求。

然而,由于Redis使用的是异步复制,因此没有办法保证从节点确实收到的给定的写入请求,纵游一个窗口期的数据丢失。
接下来是解释这个特性是如何工做的:
This is how the feature works:

  • 从节点每秒钟都会ping主节点,告知它全部的复制流工做了。
  • 主节点会记住从每一个从节点收到的最新的ping
  • 用户能够给从节点配置一个在等于从节点的数量的最低值和不超过最高值之间的延迟

若是至少有N个从节点,若是少于延迟M秒,则写入将被接受。
你可能以为经最大努力保证数据安全的机制,虽然数据一致性没法保证,可是至少只是几秒的时间窗口内丢失数据。一般状况下范围数据丢失可比无范围数据丢失好多了。
若是条件不知足,主节点将会返回一个错误,而且写入请求将不被接受
下面是这个特性的两个配置参数:

min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

查看更多信息,能够查阅打包在Redis发行版中的redis.config

How Redis replication deals with expires on keys

Redis同步是如何解决key的过时的

Redis过时容许key有一个有限的生存时间。这种特性依赖于实例多时间的控制,从节点正确的复制key和过时,就是这些keylua修改过。

为了实现这种特性,Redis不能信任主节点和从节点时钟同步的能力,由于这没法解决这个问题而且还会致使静态条件和数据集分离,因此Redis使用三个主要技术来保证过时key的同步:

  • 从节点不让key过时,而是等待主节点让key过时。当主节点让一个key过时(或者由于LRU被移除),它同步发往全部从节点的DEL命令。
  • 然而,由于只有主节点才执行过时操做,有些时候,从节点在内存中还保存这逻辑上已通过期的key,由于这时候主节点没法提供一个DEL命令。为了解决这个问题,从节点只用它本身的逻辑时钟报告说这个key不存在,而且只供读操做,并不去影响数据集的一致性(而后新的命令就会从主节点来)。这种方式下,从节点就避免了逻辑上过时的key还存在的问题。在真实的团推中,一个用从节点抓取的HTML片断将会避免返回已经比指望存在时间多的缓存。
  • Lua脚本执行的时候,key将不会过时,当Lua脚本执行的时候,概念上来说,主节点的时间是中止的。因此一个key在脚本执行期间,要么存在,要么不存在。这防止key在脚本运行中间的时候过时,这也是为了发送相同的脚本到全部的从节点,保证了对数据集的影响是一致的。

当一个从节点晋升为主节点,他将会开始独立的过时key,不须要旧的主节点的任何帮助。

DockerNAT中配置同步

当使用Docker或者其余容器技术作端口转发或网络地址转换的时候,Redis同步有一些须要额外注意,特别是使用Redis Sentinel或者其余系统时,主节点INFOROLE命令须要输出并扫描,用来发现从节点地址。

问题在ROLE命令,和同步章节的INFO输出,当发送请求到主节点实例的时候,使用NAT的环境可能和从节点实例逻辑地址不一样(能够用来链接从节点的那个地址)。

一样的,从节点将会被以配置文件中配置的监听的端口列出,这可能会和转发的端口不一样,要注意端口可能被重映射。

为了解决这个问题,从Redid 3.2.2开始,强制要求从节点声明一个任意的IP和端口给主节点。这两个配置指定是:

slave-announce-ip 5.5.5.5
slave-announce-port 1234

这被记录在Redis发行版的redis.conf文件中。

INFOROLE命令

有两个命令提供了不少关于主节点和从节点当前的同步参数。一个是INFO。若是这个命令被以INFO replication的方式调用,则只显示和同步紧密相关的信息。另外一个更加计算机友好的命令是ROLE,提供了主节点和从节点同步的状态,同步偏移,列出已链接的从节点等。

Redis 4.0之后支持重启和故障转移后的增量从新同步,当一个实例在故障转之后提高为主节点,他依旧能够从旧的主节点那边执行增量从新同步。为了作到这一点,从节点记住了从前的主节点的的同步ID和偏移,因此,能够提供部分的记录去链接从节点,尽管他们请求的是旧的同步ID。

然而,晋升的从及诶单提供的新的同步ID将会不一样,由于他构建了一个不一样的数据集历史。好比,有时候,主节点能够返回可使用而且能够继续接受写入,因此在晋升的从节点使用相同的同步ID将会破坏规则,即一个同步ID和偏移对只标记一个数据集。
此外,当优雅关闭或者重启的时候,从节点能够存储从主节点同步必须的信息到RDB文件中。这对升级颇有用,当必须的时候,最好在从节点使用SHUTDOWN命令去执行一个保存-退出操做。

相关文章
相关标签/搜索