Redis主从复制

主从复制

  • 官方文档:redis.io/docs/latest...
  • 极简概括:将一个主Redis服务器的数据复制到其它从Redis服务器的过程。
  • 角色:
    • 主节点(Master):负责处理客户端的写(或者读)请求,并将写操作同步到从节点。
    • 从节点(Slave):负责处理客户端的读请求,并将主节点发送过来的数据更新数据复制到本地。
  • 解决问题:
    • 容灾备份:主节点发生故障,从节点有对应的数据备份。
    • 负载均衡:当单个Redis节点扛不住时,利用读写分离的特性,多个Redis从节点分摊主节点读的压力。
  • 适用场景:读多写少大流量的服务端应用。
  • 优点:
    • 数据备份。
    • 负载均衡。
    • 有一定的容灾性:当主节点和从节点之间的由于网络问题断开,从服务器会重新连接并尝试继续进行部分重新同步。当部分重新同步不可行时,复制副本将要求完全重新同步。 +非阻塞: Redis主从复制是在主节点上非阻塞的。这意味着当一个或多个从节点执行初始同步或部分重新同步时,主服务器将继续响应客户端的请求。
    • Redis主从复制在从节点上,基本也是非阻塞的,大key情况除外。
    • 支持级联架构:Redis从节点也可成为其它实例的主节点,形成级联架构。
    • 低耦合容灾:当Redis主节点挂掉时,从节点还能维持基本的读操作。
    • 进度同步:不同从节点可能存在着不同的进度,Redis有自动纠正偏移量的机制,使其每个节点保持同一进度。
  • 缺点:
    • 多台机器不可避免的增加运维成本,
    • 受网络隔离和Redis本身的特性,无法保证主从强一致性,极端情况下,主节点活从节点挂掉,就会导致不一致。
    • 高并发或有大key的前提下,不可避免的出现主从复制延迟问题。
    • 若主节点挂掉,Redis主从功能本身缺少从节点自动升级为主节点的策略,因此出现了哨兵模式。

相关命令或配置

  • 命令(Redis服务停止前一直生效,适用于不停机热配置)
    • info replication:查看主从节点的状况。
    • slaveof 主库IP 主节点端口:在从节点配置主节点。
    • slaveof no one:让Redis不做任何节点的从节点。
  • 配置(持久化配置):
    • replicaof 主库IP 主库端口:在从节点配置主节点。
    • masterauth 主节点密码:在从节点配置主节点密码。

一主二从实操

  • 误区:Redis主从不比MySQL,Redis只需要在从库上配置主库就可以了。
  • 环境:CentOS7.6,配置了3台可正常运行Redis的服务,且保证每个Redis实例可远程连接(同一局域网、防火墙、端口放行、远程连接权限配置到位)。192.168.0.180(主)、192.168.0.181(从1)、192.168.0.182(从2)。
  • 内存问题:3个系统占内存,在虚拟机上将每个系统内存配置到256MB,Linux轻松启动。
sh 复制代码
在从节点1和从节点2上分别进行配置
vim /usr/local/redis/etc/redis.conf
配置IP和端口
replicaof 192.168.0.180 6379
配置密码
masterauth 123456

之后重启redis


测试:
主节点上执行set a a
两台从节点上get a发现都能获取到值。

若在从节点上设置值,会有如下错误:
(error) READONLY You can't write against a read only replica.

此时主节点执行info replication,会得到如下结果:
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.0.182,port=6379,state=online,offset=2736,lag=1
slave1:ip=192.168.0.181,port=6379,state=online,offset=2736,lag=1
master_replid:9aaf7cbbcfb924c8a793e1b69f0597a57768844b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2736
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2736

注释:
Replication是注释。
connected_slaves:表示从节点数量
slave0和slave1:描述两个从节点的基本信息。
master_replid: 主服务器的复制 ID
master_replid2: 用于支持部分同步复制的第二复制 ID
master_repl_offset: 主服务器的复制偏移量,复制的进度。
repl_backlog_active: 启用复制 backlog 功能
repl_backlog_size: 复制 backlog 的大小为1048576字节
repl_backlog_first_byte_offset: 复制 backlog 中第一个字节的偏移量
repl_backlog_histlen: 复制 backlog 的历史长度为2736字节

backlog
复制积压缓冲区,当主节点有连接的slave时创建,主节点响应写请求时,会先写到自己的backlog buffer中。
可以简单的理解为,避免数据改动一个字节就频繁同步从节点,而是积累到一定的批次做缓冲。

从节点执行得到如下结果
# Replication
role:slave
master_host:192.168.0.180
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:518
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:f1f768608ae81b330bb152f69a4a624bf3a9657e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:518
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:518


role:slave: 表示这是一个从节点。
master_host:192.168.0.180: 指定了主节点的IP地址。
master_port:6379: 指定了主节点的端口号。
master_link_status:up: 表示从节点与主节点的连接状态为正常(已连接)。
master_last_io_seconds_ago:3: 上次与主节点进行IO操作的时间,这里是3秒前。
master_sync_in_progress:0: 没有正在进行的同步操作。
slave_repl_offset:518: 从节点当前复制偏移量为518。
slave_priority:100: 从节点的复制优先级为100。
slave_read_only:1: 从节点设置为只读模式(read-only)。
connected_slaves:0: 连接的从节点数为0,即没有其他从节点连接到这个从节点。
master_replid:f1f768608ae81b330bb152f69a4a624bf3a9657e: 主节点的复制ID。
master_replid2:0000000000000000000000000000000000000000: 第二复制ID。
master_repl_offset:518: 主节点当前复制偏移量为518。
second_repl_offset:-1: 第二复制偏移量为-1。
repl_backlog_active:1: 复制后备日志(repl backlog)处于激活状态。
repl_backlog_size:1048576: 复制后备日志的大小为1048576字节(1MB)。
repl_backlog_first_byte_offset:1: 复制后备日志的第一个字节偏移量为1。
repl_backlog_histlen:518: 复制后备日志历史长度为518。

一主一从再一从实操

可以理解为爹子孙三代。 这个用法与一主二从没有什么区别,可以接着一主二从的基础上,在从节点2上临时设置slave of 192.168.0.181 6379(从1为从2主节点)即可。 注意密码问题,由于命令行不支持masterauth命令,所以可能需要在从节点配置文件中先把主节点密码设置到位。

编程语言调用的绑定问题

  • 以PHP为例,读写调用主或者从服务器,是由PHP控制的,不是由Redis主节点控制的(Redis主节点就没有从节点的配置)。
  • PHP Redis扩展虽然提供了丰富的Redis Client API,但是没有专门应对主从的解决方案。因此原生开发,读写操作调用那台服务器,是由开发者自定义控制,而不是PHP的内部实现。 例如:
php 复制代码
$redis_master = new Redis();
$redis_master->connect('192.168.0.180', 6379);
$redis_master->auth('123456');

$redis_slave = new Redis();
$redis_slave->connect('192.168.0.181', 6379);

$redis_master->set('k', 'v');
print_r($redis_master->get('k'));

如果是从库写,也会报如上一样的错误:
Fatal error: Uncaught RedisException: READONLY You can't write against a read only replica. in E:\Host\test\t1.php:10 Stack trace: #0 E:\Host\test\t1.php(10): Redis->set('k', 'v') #1 {main} thrown in E:\Host\test\t1.php on line 10

对于Laravel框架:

php 复制代码
config/database.php中的redis段,添加
'slave' => [
    'client' => 'predis',
    'host' => 'your_slave_redis_host',
    'password' => 'your_slave_redis_password',
    'port' => 6379,
    'database' => 0,
],

使用主节点
Redis::connection('default')->set('key', 'value');
使用从节点
Redis::connection('slave')->get('key');

从节点数据覆盖问题

经过实测,若一个redis实例被做为从节点,那么原先的老数据会被清空,这可能会造成数据丢失。

主从节点进度不一致问题

Redis的特性,主从复制性能不会差,除非遇到大key。所以这里讨论的是,从节点1和主节点进度相同,从节点2和主节点进度不同的问题。 可以模拟从节点2挂掉,直接关停从节点2,主节点多写几个key,从节点1正常同步。此时启动从节点2,经过实测,发现进度得到了同步。 这意味Redis会自动处理进度不一致的问题,达到的是最终一致性。

主节点挂掉后从节点的状态

经过实测,从节点不会自动变成主节点,从节点上的数据可以正常读取,仍旧不能写入。 比较好的一点是,虽然数据层,从节点强依赖主节点,但是主节点挂掉后,从节点没有挂掉,勉强使用。 此时从节点不进行任何操作,若主节点恢复,则整个主从架构正常运行。

单线程下却可以异步复制的思考

官网有说:Redis主从复制的内部过程,是异步进行的(异步非阻塞,高性能)。由于Redis是单线程,通俗讲就是同时只能执行一个任务,却进行了异步实现,这个问题值得理解。

通过查阅资料,得知单线程异步是通过事件循环机制来处理。 单线程环境下:当一个异步操作被启动后,程序会继续执行其它任务,但异步操作的结果或者状态变化会被放入事件队列中,等待事件循环处理。当事件循环处理到该事件时,会调用相应的回调函数来处理操作的结果或者状态变化。在这种情况下,不需要额外创建新的线程。

按照我的理解,通俗讲,整个过程就是一个循环机制,不停的循环,获取事件队列上的数据,一是可以让待执行的异步任务再下一轮循环中去执行,二是可以再本次循环中执行同步的任务,直到任务为空从而停止,不需要额外现成的依赖。

从节点备份的不可靠因素

纯缓存模式下:主节点崩溃,但是服务器设定了一些运维策略,可以自动重启进程。但Redis主节点启动时,将以空数据集重新启动。其它从节点缓存的数据,也将会被销毁。

所以: 复制与不带持久性配置的master一起使用时,应该禁用实例的自动重启。 或者,做好主节点的AOF与RDB配置。

RDB:配置save '',并注释掉其它save项。 AOF:配置appendonly no 可修改为纯缓存模式,亲测确实会丢失数据。

相关推荐
鸠摩智首席音效师3 分钟前
MySQL ERROR 1114 (HY000): The table is full
数据库·mysql
数据大魔方7 分钟前
【期货量化实战】豆粕期货量化交易策略(Python完整代码)
开发语言·数据库·python·算法·github·程序员创富
森旺电子19 分钟前
Linux指令快速记忆
linux·运维·服务器
Codeking__27 分钟前
Redis的value类型介绍——zset
数据库·redis·缓存
muddjsv29 分钟前
SQLite3 核心命令全解析 (从入门到精通)
数据库
思茂信息30 分钟前
CST电动汽车EMC仿真(三)——初探轴电压
运维·服务器·单片机·嵌入式硬件·cst·电磁仿真·天线仿真
難釋懷33 分钟前
认识NoSQL
数据库·nosql
xiaolyuh12333 分钟前
Redis 核心业务流程
java·redis·spring
亿坊电商36 分钟前
利于SEO优化的CMS系统都有哪些特点?
前端·数据库
阿阿阿安36 分钟前
MySQL(一)数据库风险操作场景总结
数据库·mysql