0%

redis主从同步学习

单机Redis的瓶颈

  • 容量瓶颈( 单台Redis提供的容量有限 )
  • QPS瓶颈( 单台Redis能提供的有限 )
  • 机械故障( 单台redis无法保证高可用 )

主从复制的约定

  • 一个master可以有多个slave
  • 一个slave只能用一个master
  • 数据流向是单向的,master到slave (所以要求一般slave是read-only的,不然就无法保证主从一致性了)

主从配置的两种方式

slaveof命令(运行中执行)

例如,机器A的ip为ipA, 机器B的ip为ipB,机器A上的redis作为slave,机器B的redis作为master,如果希望机器A对机器B的redis进行一个主从配置/复制同步的话,那么就在机器A上执行: slaveof ipB:port (机器A的redis执行完该命令之后,会对机器A的redis进行一个清楚,然后进行数据同步)

如果不再让机器A作为机器B的slave的话,可以执行 slaveof no one来断开主从关系(即使断开了主从关系,过去同步的数据依然不会清楚)

配置(启动执行)

可以在配置文件中加入如下命令:

1
2
3
slaveof ip port // 表示作为哪一个节点的从节点
slave-read-only yes // 表示当前从节点是read-only的
masterauth [password] // 如果master有密码的话,那么需要设置master的密码

(ps:在master的配置文件中,requirepass [password] 来设置密码)
(pps: 在redis中,auth password 用于验证身份, info replication查看主从状态)

方式 命令 配置
优点 无需重启 统一配置,方便管理
缺点 不方便管理 需要重启

*Redis主从模式下的几个问题

1. 读写分离

  • 读写分离:读流量分摊到从节点
    在这里插入图片描述

    读写分离的问题:

  • 复制数据延迟(解决延迟代价很高)

  • 读到过期的数据

    redis在清理过期数据时,有一个方式是懒惰删除,即在获取这个key的时候检查是否过期,若过期则删除,而又由于从节点无法主动删除数据(read-only), 所以如果master没有及时把过期数据告诉slave的话可能会造成脏读,redis3.2之后解决了这个问题。

  • 从节点故障

    将从节点上的客户端进行迁移,成本较高。

    2. 主从配置不一致

  • 例如maxmemory不一致,导致主从不一致

    3. 规避全量复制

  1. 第一次全量复制

    第一次全量复制不可能避免(减少分片maxmemory, 在低峰的时候进行)

  2. 节点运行ID不匹配

    redis每次启动时,会有一个run_id,slave会保存master的run_id, 如果master的run_id发生了变化的话,那么就会触发一个全量复制。

  3. 复制积压缓冲区不足

    4. 规避复制风暴


主从复制流程

run_id

Redis每次启动时,都有一个随机ID来标识Redis,这个随机ID就是上面通过info命令查看得到的run_id, 查看master节点上的run_id和偏移量:

1
2
3
4
[root@localhost ~]# redis-cli info server | grep run_id
run_id:7e366f6029d3525177392e98604ceb5195980518
[root@localhost ~]# redis-cli info | grep master_repl_offset
master_repl_offset:0

offset:

偏移量(offset)就是数据写入量的字节数。

在master节点的Redis上写入数据时,master就会记录写了多少数据,并记录在偏移量中。

在master上的操作,会同步到salve机器上,slave上的Redis也会记录偏移量。

当两台机器上的偏移量相同时,代表数据同步完成

偏移量是部分复制很重要的依据

查看Redis的偏移量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
127.0.0.1:6379> info replication    # 查看复制信息
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.81.101,port=6379,state=online,offset=8602,lag=0
master_repl_offset:8602 # 此时192.168.81.100上的偏移量是8602
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:8601
127.0.0.1:6379> set k1 v1 # 向192.168.81.100写入数据
OK
127.0.0.1:6379> set k2 v2 # 向192.168.81.100写入数据
OK
127.0.0.1:6379> set k3 v3 # 向192.168.81.100写入数据
OK
127.0.0.1:6379> info replication # 查看复制信息
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.81.101,port=6379,state=online,offset=8759,lag=1
master_repl_offset:8759 # 写入数据后192.168.81.100上的偏移量是8759
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:8758

master的run_id的改变会触发全量复制

主从的offset相等则说明一致

psync [run_id] [offset]

表示需要让run_id的redis将offset之后的数据同步给当前节点..

全量复制

  • master的全部数据同步到slave
  • master在进行同步期间写的数据也同步到slave

流程:

1. slave -> master:

slave向master发送一个psync ? -1的命令, 因为第一次不知道master节点的run_id和offset,所以传的是?和-1

2. master -> slave:

返回 master 的 run_id 和 offset

3. slave保存master传来的信息

4. master 进行一个bgsave,生成RDB文件

5. master -> slave:

传输RDB文件(全量备份),传输期间会把“write”的信息存到一个buffer中(repl_back_buffer),这部分就是在传输期间会导致不一致的数据,在传输完RDB之后会传输这部分消息

6. master -> slave:

传输buffer中的数据(增量备份)

7. salve清除旧的数据,写入新数据

在这里插入图片描述

全量复制的开销

  1. bgsave的开销 (master)
  2. RDB文件进行网络传输的时间 (master)
  3. slave清空数据(slave)
  4. slave加载RDB数据(slave)
  5. 可能的AOF重写时间 (slave加载完RDB之后,如果开启了AOF,那么会进行一个AOF重写)

部分复制

全量复制开销太大, 在没有必要使用全量复制的时候就可以使用部分复制来做.

部分复制其实还是psync [run_id] [offset] , 通知run_id对应的redis把offset之后的数据都同步过来。。master节点在收到这个指令之后,会去查看能否响应这个offset之后的数据(看这个offset是否在维护的范围内),如果可以响应,那么就将offset后的部分数据同步给slave..

在这里插入图片描述