Redis:06-集群:复制

Redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

配置

在复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据库(slave)。主数据库可以进行读写操作,当写操作导致数据变化是会自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。

在Redis中使用复制功能非常容易,只需要在从数据库的配置文件中加入“slaveof 主数据库地址 主数据库端口” 即可,主数据库无需进行任何配置。

使用 info replication 可以查看 主从信息,如下:

//to do

除了在配置文件设置slaveof 参数,还可以命令行参数或运行时使用 slaveof 命令修改。

redis 启动时命令行参数

redis-server -port 6380 --slaveof 127.0.0.1 6379

使用 slaveof 命令

slaveof 127.0.0.1 6379

原理

了解Redis复制的原理对日后运维有很大的帮助,包括如何规划节点,如何处理节点故障等。

当一个从数据库启动后,会向主数据库发送sync命令。同时主数据库接收到sync命令后会开始在后台保存快照(即rdb持久化的过程),并将保存快照期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。以上过程称为复制初始化,复制初始化结束后,主数据库每当收到写命令就会将命令同步给从数据库,从而保证主数据库数据一致。

当主从数据库之间的连接断开重连后,Redis2.6以及之前的版本会重新进行复制初始化(即主数据库重新保存快照并传送给从数据库),即使从数据库可以仅有几条命令没有收到,主数据库也必须要将数据库里的所有数据重新传送给从数据库。这使得主从数据库断线重连后的数据恢复过程效率很低下。Redis2.8版的一个重要改进就是断线重连能够支持有条件的增量数据传输,当从数据库重新连接上主数据库后,主数据库只需要将断线期间执行的命令传送给从数据库,从而大大提高Redis复制的实用性。

读写分离

通过复制可以实现读写分离,以提高服务器的负载能力。在一些场景中(如电商网站),读的频率大于写,当单机的Redis无法应付大量的读请求时(尤其是较耗资源的请求,如sort命令等)可以通过复制功能建立多个从数据库节点,主数据库只进行写操作,而从数据库负责读操作。

从数据库持久化

另一个相对耗时的操作时持久化,为了提高性能,可以通过复制功能建立一个额(或若干个)从数据库,并在从数据库中启用持久,同时在主数据库禁用持久化。当从数据库崩溃重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。

当主数据库崩溃时,情况就稍显复杂了。手工通过从数据库数据恢复主数据库数据时,需要严格按照以下两步进行。

  1. 在从数据库中使用slaveof no one 命令将从数据库提升成主数据库继续服务。
  2. 启动之前崩溃的主数据库,然后使用slaveof 命令将其设置成新的主数据库的从数据库,即可将数据同步回来。

注意: 当开启复制且主数据库关闭持久化功能时,一定不要使用supervisor以及类似的进程管理工具另主数据库崩溃后自动重启。同样当主数据库所在的服务器因故关闭时,也要避免直接重新启动,这是因为当主数据库重新启动后,因为没有开启持久化功能,所以数据库中所有数据都被清空,这时从数据库依然会从主数据库中接收数据,使得所有从数据库也被清空,导致从数据库的持久化失去意义。

无硬盘复制

前面介绍的Redis复制的工作原理时介绍复制是基于RDB方式的持久化实现的,即主数据库端在后台保存RDB快照,从数据库端则接收并载入快照文件。这样的实现优点是可以显著地简化逻辑,复用已有的代码,但是缺点也很明显。

  1. 当主数据库禁用RDB快照时(即删除了所有的配置文件中的save语句),如果执行了复制初始化操作,Redis依然会生成RDB快照,所以下次启动后主数据库会以该快照恢复数据。因为复制发生的时间不能确定,这使得恢复的数据可能是任何时间点的。
  2. 因为复制初始化时需要在硬盘中创建RDB快照文件,所以如果硬盘性能很慢(如网络硬盘)时这一过程会对性能产生影响。

因此从2.8.18版本开始,Redis引入了无硬盘复制选项,开启该选项时,Redis在于从数据库进行复制初始化时将不会讲快照内容存储到硬盘上,而是直接通过网络发送给从数据库,避免了硬盘的性能瓶颈。

在配置文件中使用如下配置来开启(默认是不开启的):

repl-diskless-sync yes

增量复制

前面复制的原理中提到当主从数据库连接断开后,从数据库会发送sync命令来重新进行一次完整复制操作。这样即使断开期间数据库的变化很小(甚至没有),也需要将数据库中的所有数据重新快照并传送一次。这种实现方式显然不太理想。Redis2.8版本最重要的更新之一就是实现了主从断线重连的情况下的增量复制。

增量复制是基于如下3点实现的:

  1. 从数据库会存储主数据库的运行ID(run id)。每个Redis运行实例均会拥有一个唯一的运行ID,每当实例重启后,就会自动生成一个新的运行ID。
  2. 在复制同步阶段,主数据库每将一个命令传递给从数据库时,都会同时把该命令存放到一个积压队列(backlog)中,并记录下当前积压队列中存放的命令的偏移量。
  3. 同时,从数据库接收到主数据库传来的命令时,会记录下该命令的偏移量。

这3点是实现增量复制的基础。当主从连接准备就绪后,从数据库会发送一条sync命令来告诉主数据库可以开始吧所有数据同步过来了。而2.8版本之后,不再发送sync命令,取而代之的是发送 psync 命令,格式为 “psync 主数据库的运行 ID 断开前最新的命令偏移量”。主数据库收到 psync命令后,会执行以下判断来决定此次重连是否可以执行增量复制。

  1. 首先主数据库会判断从数据库从数据库传来的运行ID是否和自己运行ID相同。这一步骤的意义子啊与确保从数据库之前确实是和自己同步的,以免从数据库拿到错误的数据。
  2. 然后判断从数据库最后同步成功的命令偏移量是否在积压对了中给,如果在则可以执行增量复制,并将积压队列中相应的命令发送给从数据库。

如果此次重连不满足增量复制的条件,主数据库会进行一次全部同步。

2.8版本的主数据库也可以正常地和旧版本的从数据库同步(通过接收sync命令),同样2.8版本的从数据库也可以与旧版本的主数据库同步(通过发送sync命令)。唯一需要设置的就是积压队列的大小了。

积压队列本质上是一个固定长度的循环队列,默认情况下积压队列的大小为1MB,可以通过配置文件的 repl-backlog-size 选项来调整。与积压队列相关的另一个配置选项是 repl-backlog-ttl 即当所有从数据库与主数据库断开连接后,经过多久时间可以释放积压队列的内存空间,默认时间是1小说。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章