redis主从复制(原理及代码详解)

原文并没有把配置过程写的很详细,此文是我亲手配置总结得来。环境centos7 redis-cli 3.2.12

前面是理论部分,后边为配置的实际代码。可以跳过理论直接上代码!

Redis 支持简单且易用的主从复制(master-slave replication)功能, 该功能可以让从服务器(slave
server)成为主服务器(master server)的精确复制品。

以下是关于 Redis 复制功能的几个重要方面:

  • Redis 使用异步复制。 从 Redis 2.8 开始, 从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。

  • 一个主服务器可以有多个从服务器。

  • 不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构。

  • 复制功能不会阻塞主服务器: 即使有一个或多个从服务器正在进行初次同步, 主服务器也可以继续处理命令请求。

  • 复制功能也不会阻塞从服务器: 只要在 redis.conf 文件中进行了相应的设置, 即使从服务器正在进行初次同步, 服务器也可以使用旧版本的数据集来处理命令查询。

    不过, 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 连接请求会被阻塞。

    你还可以配置从服务器, 让它在与主服务器之间的连接断开时, 向客户端发送一个错误。

  • 复制功能可以单纯地用于数据冗余(data redundancy), 也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 比如说, 繁重的 [SORT key BY pattern] [LIMIT offset count] [GET pattern [GET pattern …]] [ASC | DESC] [ALPHA] [STORE destination] 命令可以交给附属节点去运行。

  • 可以通过复制功能来让主服务器免于执行持久化操作: 只要关闭主服务器的持久化功能, 然后由从服务器去执行持久化操作即可。

关闭主服务器持久化时,复制功能的数据安全

当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。 否则的话,由于延迟等问题,部署的服务应该要避免自动拉起。

为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考一下以下会导致主从服务器数据全部丢失的例子:

\1. 假设节点A为主服务器,并且关闭了持久化。 并且节点B和节点C从节点A复制数据

\2. 节点A崩溃,然后由自动拉起服务重启了节点A. 由于节点A的持久化被关闭了,所以重启之后没有任何数据

\3. 节点B和节点C将从节点A复制数据,但是A的数据是空的, 于是就把自身保存的数据副本删除。

在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。 因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。

无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动拉起。

复制功能的运作原理

无论是初次连接还是重新连接, 当建立一个从服务器时, 从服务器都将向主服务器发送一个 SYNC 命令。

接到 SYNC 命令的主服务器将开始执行 BGSAVE , 并在保存操作执行期间, 将所有新执行的写入命令都保存到一个缓冲区里面。

BGSAVE 执行完毕后, 主服务器将执行保存操作所得的 .rdb 文件发送给从服务器, 从服务器接收这个 .rdb 文件, 并将文件中的数据载入到内存中。

之后主服务器会以 Redis 命令协议的格式, 将写命令缓冲区中积累的所有内容都发送给从服务器。

你可以通过 telnet 命令来亲自验证这个同步过程: 首先连上一个正在处理命令请求的 Redis 服务器, 然后向它发送 SYNC 命令, 过一阵子, 你将看到 telnet 会话(session)接收到服务器发来的大段数据(.rdb 文件), 之后还会看到, 所有在服务器执行过的写命令, 都会重新发送到 telnet 会话来。

即使有多个从服务器同时向主服务器发送 SYNC , 主服务器也只需执行一次 BGSAVE 命令, 就可以处理所有这些从服务器的同步请求。

从服务器可以在主从服务器之间的连接断开时进行自动重连, 在 Redis 2.8 版本之前, 断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作, 但是从 Redis 2.8 版本开始, 从服务器可以根据主服务器的情况来选择执行完整重同步还是部分重同步(partial resynchronization)。

部分重同步

从 Redis 2.8 开始, 在网络连接短暂性失效之后, 主从服务器可以尝试继续执行原有的复制进程(process), 而不一定要执行完整重同步操作。

这个特性需要主服务器为被发送的复制流创建一个内存缓冲区(in-memory backlog), 并且主服务器和所有从服务器之间都记录一个复制偏移量(replication offset)和一个主服务器 ID (master run id), 当出现网络连接断开时, 从服务器会重新连接, 并且向主服务器请求继续执行原来的复制进程:

  • 如果从服务器记录的主服务器 ID 和当前要连接的主服务器的 ID 相同, 并且从服务器记录的偏移量所指定的数据仍然保存在主服务器的复制流缓冲区里面, 那么主服务器会向从服务器发送断线时缺失的那部分数据, 然后复制工作可以继续执行。
  • 否则的话, 从服务器就要执行完整重同步操作。

Redis 2.8 的这个部分重同步特性会用到一个新增的 PSYNC master_run_id offset 内部命令, 而 Redis 2.8 以前的旧版本只有 SYNC 命令, 不过, 只要从服务器是 Redis 2.8 或以上的版本, 它就会根据主服务器的版本来决定到底是使用 PSYNC master_run_id offset 还是 SYNC

  • 如果主服务器是 Redis 2.8 或以上版本,那么从服务器使用 PSYNC master_run_id offset 命令来进行同步。
  • 如果主服务器是 Redis 2.8 之前的版本,那么从服务器使用 SYNC 命令来进行同步。
配置
只读从服务器

从 Redis 2.6 开始, 从服务器支持只读模式, 并且该模式为从服务器的默认模式。

只读模式由 redis.conf 文件中的 slave-read-only 选项控制, 也可以通过 CONFIG SET parameter value 命令来开启或关闭这个模式。

只读从服务器会拒绝执行任何写命令, 所以不会出现因为操作失误而将数据不小心写入到了从服务器的情况。

即使从服务器是只读的, DEBUGCONFIG 等管理式命令仍然是可以使用的, 所以我们还是不应该将服务器暴露给互联网或者任何不可信网络。 不过, 使用 redis.conf 中的命令改名选项, 我们可以通过禁止执行某些命令来提升只读从服务器的安全性。

你可能会感到好奇, 既然从服务器上的写数据会被重同步数据覆盖, 也可能在从服务器重启时丢失, 那么为什么要让一个从服务器变得可写呢?

原因是, 一些不重要的临时数据, 仍然是可以保存在从服务器上面的。 比如说, 客户端可以在从服务器上保存主服务器的可达性(reachability)信息, 从而实现故障转移(failover)策略。

主服务器只在有至少 N 个从服务器的情况下,才执行写操作

从 Redis 2.8 开始, 为了保证数据的安全性, 可以通过配置, 让主服务器只在有至少 N 个当前已连接从服务器的情况下, 才执行写命令。

不过, 因为 Redis 使用异步复制, 所以主服务器发送的写数据并不一定会被从服务器接收到, 因此, 数据丢失的可能性仍然是存在的。

以下是这个特性的运作原理:

  • 从服务器以每秒一次的频率 PING 主服务器一次, 并报告复制流的处理情况。
  • 主服务器会记录各个从服务器最后一次向它发送 PING 的时间。
  • 用户可以通过配置, 指定网络延迟的最大值 min-slaves-max-lag , 以及执行写操作所需的至少从服务器数量 min-slaves-to-write

如果至少有 min-slaves-to-write 个从服务器, 并且这些服务器的延迟值都少于 min-slaves-max-lag秒, 那么主服务器就会执行客户端请求的写操作。

你可以将这个特性看作 CAP 理论中的 C 的条件放宽版本: 尽管不能保证写操作的持久性, 但起码丢失数据的窗口会被严格限制在指定的秒数中。

另一方面, 如果条件达不到 min-slaves-to-writemin-slaves-max-lag 所指定的条件, 那么写操作就不会被执行, 主服务器会向请求执行写操作的客户端返回一个错误。

以下是这个特性的两个选项和它们所需的参数:

  • min-slaves-to-write
  • min-slaves-max-lag

详细的信息可以参考 Redis 源码中附带的 redis.conf 示例文件。


废话少说直接上配置的代码步骤

以下的配置几乎都在redis.conf中进行,个别在客户端输入

主机配置

min-slaves-to-write 1    # 1的话就表示将有一个从机连接主服务器,看自己情况而定
min-slaves-max-lag 10	# 默认或自己定都可
requirepass 123456       #从机连接主机的密码,可设可不设,出于安全考虑
bind 116.64.212.111      
bind 0.0.0.0			
protected-mode no      # 关闭保护罩,允许其他服务器连接
systemctl restart redis  #客户端输入,重启加载配置

从机配置

slaveof 192.168.1.1 6379    #添加属于某台主机的从 服务
masterauth 123456       #从服务连接主服的密码(访问主服务器的密码)
slave-read-only yes     #从服务只读,不可在命令行写入数据
systemctl restart redis  #客户端输入,重启加载配置

当然, 你需要将代码中的 192.168.1.16379 替换成你的主服务器的 IP 和端口号。

另外一种方法是调用 SLAVEOF host port 命令, 输入主服务器的 IP 和端口, 然后同步就会开始:

127.0.0.1:6379> SLAVEOF 192.168.1.1 10086
OK
从服务器相关配置关于密码说明

如果主服务器通过 requirepass 选项设置了密码, 那么为了让从服务器的同步操作可以顺利进行, 我们也必须为从服务器进行相应的身份验证设置。同时每次进入主机的redis的客户端时,都要首先输入auth 123456 ,当客户端返回ok后,才可以进行其他操作。

对于一个正在运行的服务器, 可以使用客户端输入以下命令:

config set masterauth <password>

要永久地设置这个密码, 那么可以将它加入到配置文件中:

masterauth <password>

另外还有几个选项, 它们和主服务器执行部分重同步时所使用的复制流缓冲区有关, 详细的信息可以参考 Redis 源码中附带的 redis.conf 示例文件。

最后从机客户端输入info replication 后显示的内容查看是否连接成功:

# Replication
role:slave      # 表示此台服务器是主是从
master_host:39.107.38.62     # 主服务器ip
master_port:6379        # 主服务器端口号
master_link_status:up       # 与主服务器是否连接成功 up为成功 down失败
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:808
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:ea5230cc485f9c6f372b2c89a65613fb075aff8b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:808
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:794
验证是否主服务器写入数据从服务器同步数据

主机存入key为name,value为zhangsan

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zodVmRoO-1593940765257)(redis主从复制/主机.png)]

从机检查是否同步此条数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amUjShvE-1593940765261)(redis主从复制/从机.png)]

没问题,打完收功!
可能遇到的报错:
1. Error condition on socket for SYNC: Connection refused

出现原因

​ redis主服务器绑定了127.0.0.1,跨服务器IP的访问就会失败,只能本机才能访问,外部请求会被过滤。

解决方法:
1. 主服务器绑定ip: bind 39.107.38.62
3. bind 0.0.0.0
2. 注释bind  # 会报下面的错↓
2. '-DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connec

出现原因

​ 处于保护模式,只能本地链接。没有绑定ip 没有设置验证密码。

解决方法:
1. 主服务器绑定ip: bind 39.107.38.62
2. 设置主服务器访问密码:requirepass 12345
3. (error) READONLY You can’t write against a read only replica.

出现原因

​ 从库只可读不可写

解决方法:
1. 设置slave-read-only no # 代表不限于只读
断开主从复制

​ 通过**slaveof **命令建立主从复制关系以后,可以通过slaveof no one断开。

从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。

原文地址: http://redisdoc.com/topic/replication.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值