redis提供的是单主复制功能,而不是多主复制功能(一个主服务器可以有多个从服务器,但是一个从服务器只能有一个主服务器)

在默认情况下,处于复制模式的主服务器可读可写,而从服务器则只能执行读操作

对于开启了复制功能的主从服务器,主服务器在每次执行写操作后,都会与所有的从服务器进行数据同步

18.1 REPLICAOF:将服务器设置为从服务器

1
replicaof host port 
  • 从服务器原有数据被清空,被主服务器数据取代
  • 可以通过配置的方式设置从服务器: redis-server --port 10086 --replicof 127.0.0.1 6379 表示启动一个监听10086端口的redis服务器,它是127.0.0.1:6379的从服务器(副本)
  • 使用 replicaof no one 取消复制 ,从服务器的数据会保留

18.2 ROLE:查看服务器角色

  • 主服务器执行ROLE命令
    • master 复制偏移量 数组:从服务器1的ip 从服务器1的port 从服务器1的复制偏移量 从服务器2的ip 从服务器2的port 从服务器2的复制偏移量 ...
  • 从服务器执行ROLE命令
    • slave 主服务器ip 主服务器port 与主服务器的连接状态 从服务器当前的复制偏移量
    • 连接状态有6种状态:
      • none 未建立链接
      • connect 正在握手
      • connecting 主从服务器成功建立连接
      • sync 正在进行数据同步
      • connected 主从服务器已经进入在线更新状态
      • unknown 主从服务器连接状态未知

18.3 数据同步

执行replicaof命令后,主从服务器执行操作如下:

  1. 主服务器执行BGSAVE命令,生成一个 RDB 文件,并使用缓冲区存储起在BGSAVE之后执行的所有命令
  2. 当RDB文件创建完毕,主服务器会通过套接字将RDB文件传送给从服务器
  3. 从服务器载入RDB文件
  4. 主服务器发送执行BGSAVE后的命令给从服务器
  5. 从服务器应用这些后续的命令,完成同步 完成同步后,后续每当主服务器执行完一个写命令,它就会将相同的命令(或者有相同效果的写命令)同步给从服务器

为了提高数据同步操作的执行效率,如果主服务器在接收到replicaof命令之前已经完成了一次RDB创建操作,并且它的数据库在创建RDB文件之后没有发生任何变化,那么主服务器将直接向从服务器发送已有的RDB文件

如果在主服务器创建RDB文件期间,有多个从服务器请求同步,那么主服务器将把这些请求放入一个队列,等RDB文件创建后发送给所有的这些请求的从服务器,避免重复生成RDB文件

18.3.1 部分同步

当因故障下线的从服务器重新上线时,如果重新进行全量复制同步,那么在从服务器只是短暂下线这种情形下是十分浪费资源的

redis从2.8版本开始使用新的重同步功能取替代原来的同步功能:

  • 当一个服务器称为主服务器时,它将把每个写命令记录到一个特定长度的先进先出的队列中
  • 重新上线的从服务器会先在该队列中进行检查,以此进行判断是部分更新,还是全量更新。
  • 这个队列的默认大小1MB,其配置选项为 repl-backlog-size

18.4 无须硬盘的复制

  • reids从2.8.18 引入无须硬盘的复制特性
  • 启用这个特性后,主服务器在接收到replicaof命令时将不在本地创建RDB文件,而是会fork一个子进程,然后由子进程通过套接字的方式直接将RDB文件写入到从服务器
  • 通过配置repl-diskless-sync yes 开启

18.5 降低数据不一致情况出现的概率

为了尽可能的降低数据不一致的出现概率,redis从2.8版本开始引入两个配置选项:

  • min-replicas-max-lag <seconds>
  • min_replicas-to-write <numbers>

用户设置了这两个配置选项之后,主服务器只会在从服务器的数量大于等于min_replicas-to-write选项的值,并且这些从服务器与主服务器最后一次成功通信的间隔不超过min-replicas-max-lag选项的值时才会执行同步操作

18.6 可写的从服务器

从redis2.6版本开始,从服务器在默认情况下只允许执行读命令。

如果尝试对从服务器进行写操作,将返回错误

可以通过配置replica-read-only no关闭

启示:在从服务器上进行耗费资源的计算

18.7 脚本复制

redis提供两种不同的脚本复制模式:

  • 脚本传播模式(whole script replication)
  • 命令传播模式 (script effect replication)

18.7.1 脚本传播模式

处于脚本模式的主服务器会将被执行的脚本及其参数(也就是EVAL命令本身)复制到AOF文件以及从服务器中

因为带有副作用的函数在不同的服务器上运行可能产生不同的效果,从而导致主从服务器不一致,所以在这一模式下执行的脚本必须是纯函数(使得对于同相同的数据集,相同的脚本以及参数必须产生相同的效果)

为了保证脚本的纯函数性质,redis对处于脚本传播模式的lua脚本设置了一下限制:

  • 脚本不能访问lua的时间模块、内部状态或除了给定参数之外的其他外部信息
  • 在redis命令中,存在一部分带着随机性质的命令,需要避免使用这些命令。这些命令为spop, srandmember, scan, sscan, zscan, hscan, randomkey, lastsave, pubsub, time。如果脚本在执行这些命令后,尝试继续执行写命令,那么redis将拒接执行该命令并返回一个错误。
  • 当用户在脚本中sinter, sunion, sdiff, smembers, hkeys, hvals, keys这7个会以随机顺序返回结果元素的命令时,为了消除随机性质,lua环境在返回这些命令的结果之前会先对结果中包含的元素进行排序,以此来保证命令返回的元素总是有序的 (萌新疑惑???)
  • redis会确保每个被执行的脚本都拥有相同的随机数生成种子(这意味着所有脚本在默认情况下产生的伪随机数列都将相同)

18.7.2 命令传播模式

处于命令传播模式的主服务器会将执行脚本产生的所有写命令用事务包裹起来,然后将事务复制到AOF文件以及从服务器中

[todo]

18.7.3 选择性命令传播

[todo]

18.7.4 模式的选择

判断方法:

  • 如果脚本的体积不大,执行的计算页不多,但却会产生大量的命令调用,那么使用脚本传播模式可以有效的节约网络资源
  • 相反,如果一个脚本的体积非常大,执行的计算非常多,但只会产生少量命令调用,那么使用命令传播模式可以重用已有的计算结果来节约计算资源以及网络资源

脚本模式就是 只传递脚本不传递参数 命令模式就是 传递脚本且包含每一个参数 这样理解? (书写得太烂了,让人看起来难受) [todo]