前言

Redis有三种集群模式,第一个就是主从模式,第二种“哨兵”模式,第三种是Cluster集群模式,第三种的集群模式是在Redis 3.x以后的版本才增加进来的,这一篇来说一下Redis第一种集群模式:主从集群模式。
主从模式,可以是树状的,从服务属于多台主服务,且从服务也可以有从服务。

主从复制工作原理


Redis主从(Master%26Slave)模式 - 图1

  1. 从数据库连接主数据库,发送SYNC命令;
  2. 主数据库接收到SYNC命令后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  3. 主数据库BGSAVE执行完后,向所有从数据库发送快照文件,并在发送期间继续记录被执行的写命令;
  4. 从数据库收到快照文件后丢弃所有旧数据,载入收到的快照;
  5. 主数据库快照发送完毕后开始向从数据库发送缓冲区中的写命令;
  6. 从数据库完成对快照的载入,开始接收命令请求,并执行来自主数据库缓冲区的写命令;(从数据库初始化完成)
  7. 主数据库每执行一个写命令就会向从数据库发送相同的写命令,从数据库接收并执行收到的写命令(从数据库初始化完成后的操作)
  8. 出现断开重连后,2.8之后的版本会将断线期间的命令传给重数据库,增量复制。
  9. 主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。Redis 的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

    优点

  • 同一个Master可以同步多个Slaves。
  • Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
  • Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
  • Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
  • 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
  • Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

    缺点

  • Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。

  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  • Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。
  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。

    环境搭建

    这篇为了方便只装了一台虚拟机,然后用三个端口区分三个redis,一主二从
    1. redis-master 192.168.100.100 6379
    2. redis-slave1 192.168.100.100 6380
    3. redis-slave2 192.168.100.100 6381
    master节点正常启动不用管
    配置和安装见Redis安装单机版

    复制配置文件

    1. [root@redis-master redis-6.2.4]# cp redis.conf redis-slave1.conf
    2. [root@redis-master redis-6.2.4]# cp redis.conf redis-slave2.conf

    修改从节点配置文件

    两个从节点的端口分别配置为6380和6381,密码和主节点一样。
    从节点配置默认为只读模式。
    1. # slave1位6380 slave2位6381
    2. port 6380
    3. # 主节点地址和端口
    4. replicaof 127.0.0.1 6379
    5. # 主节点密码
    6. masterauth anin
    :::info 注意,之前版本的redis,配置为slaveof,新版本改为replicaof。 :::

    启动

    1. [root@redis-master redis-6.2.4]# redis-server ../redis.conf
    2. [root@redis-master redis-6.2.4]# redis-server ../redis-slave1.conf
    3. [root@redis-master redis-6.2.4]# redis-server ../redis-slave2.conf

    查看启动

    1. [root@redis-master redis-6.2.4]# ps -ef|grep redis
    2. root 3307 1 6 17:08 ? 00:10:48 redis-server 0.0.0.0:6379
    3. root 3396 1 0 17:46 ? 00:00:06 redis-server 0.0.0.0:6381
    4. root 3424 1 0 17:53 ? 00:00:05 redis-server 0.0.0.0:6380
    5. root 3431 3333 0 17:55 pts/1 00:00:00 redis-cli -p 6380 -a anin
    6. root 3500 1839 0 20:04 pts/0 00:00:00 grep --color=auto redis

    检查是否连接上了

    在主节点连接上redis-cli,使用info replication命令查看节点信息。
    1. [root@redis-master redis-6.2.4]# redis-cli -a anin
    2. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    3. 127.0.0.1:6379> info replication
    4. # Replication
    5. role:master
    6. connected_slaves:2
    7. slave0:ip=127.0.0.1,port=6381,state=online,offset=11592,lag=0
    8. slave1:ip=127.0.0.1,port=6380,state=online,offset=11592,lag=0
    9. master_failover_state:no-failover
    10. master_replid:cbfb2b6489fed27427dd540e2a2acd3eef684da8
    11. master_replid2:0000000000000000000000000000000000000000
    12. master_repl_offset:11592
    13. second_repl_offset:-1
    14. repl_backlog_active:1
    15. repl_backlog_size:1048576
    16. repl_backlog_first_byte_offset:1
    17. repl_backlog_histlen:11592
    可以看到,该节点的角色为master,连接从节点的数量为2。

    检测从节点

    ```shell [root@redis-master src]# redis-cli -p 6380 -a anin 127.0.0.1:6380> set kk dd (error) READONLY You cant write against a read only replica. 127.0.0.1:6380> info replication

    Replication

    role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:6 master_sync_in_progress:0 slave_repl_offset:13006 slave_priority:100 slave_read_only:1 replica_announced:1 connected_slaves:0 master_failover_state:no-failover master_replid:cbfb2b6489fed27427dd540e2a2acd3eef684da8 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:13006 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:13006
  1. 可以看到从节点是不能写入的。
  2. <a name="wV49S"></a>
  3. ### 故障迁移
  4. 这其中是有问题,比如如果主节点挂了,这咋整呢?<br />还能咋的啊,当然选择**人工干预**啦。咱在其他的从节点中再手动选择一个主节点,然后让其他节点变成新的主节点的从节点。
  5. <a name="zD3nm"></a>
  6. #### 模拟主库故障
  7. ```shell
  8. [root@redis-master redis-6.2.4]# ps -ef|grep redis
  9. root 3307 1 4 17:08 ? 00:10:51 redis-server 0.0.0.0:6379
  10. root 3396 1 0 17:46 ? 00:00:08 redis-server 0.0.0.0:6381
  11. root 3424 1 0 17:53 ? 00:00:08 redis-server 0.0.0.0:6380
  12. root 3431 3333 0 17:55 pts/1 00:00:00 redis-cli -p 6380 -a anin
  13. root 3531 1839 0 21:04 pts/0 00:00:00 grep --color=auto redis
  14. [root@redis-master redis-6.2.4]# kill -9 3307

从库查看连接信息

我们发现主节点链接状态为down了。

  1. 127.0.0.1:6380> info replication
  2. # Replication
  3. role:slave
  4. master_host:127.0.0.1
  5. master_port:6379
  6. master_link_status:down
  7. master_last_io_seconds_ago:-1
  8. master_sync_in_progress:0
  9. slave_repl_offset:16506
  10. master_link_down_since_seconds:31
  11. slave_priority:100
  12. slave_read_only:1
  13. replica_announced:1
  14. connected_slaves:0
  15. master_failover_state:no-failover
  16. master_replid:cbfb2b6489fed27427dd540e2a2acd3eef684da8
  17. master_replid2:0000000000000000000000000000000000000000
  18. master_repl_offset:16506
  19. second_repl_offset:-1
  20. repl_backlog_active:1
  21. repl_backlog_size:1048576
  22. repl_backlog_first_byte_offset:1
  23. repl_backlog_histlen:16506

原从库6380升级为主库

我们看到6380的角色成为了主节点。

  1. 127.0.0.1:6380> slaveof no one
  2. OK
  3. 127.0.0.1:6380> info replication
  4. # Replication
  5. role:master
  6. connected_slaves:0
  7. master_failover_state:no-failover
  8. master_replid:a2e82c9f0a654e86c3f996787f5d0d65fe7cb484
  9. master_replid2:cbfb2b6489fed27427dd540e2a2acd3eef684da8
  10. master_repl_offset:16506
  11. second_repl_offset:16507
  12. repl_backlog_active:1
  13. repl_backlog_size:1048576
  14. repl_backlog_first_byte_offset:1
  15. repl_backlog_histlen:16506

更改6381从库的主库链接信息

我们可以看到6381已经成功链接到了6380新的主节点上。

  1. 127.0.0.1:6381> slaveof 127.0.0.1 6380
  2. OK
  3. 127.0.0.1:6381> info replication
  4. # Replication
  5. role:slave
  6. master_host:127.0.0.1
  7. master_port:6380
  8. master_link_status:up
  9. master_last_io_seconds_ago:3
  10. master_sync_in_progress:0
  11. slave_repl_offset:16506
  12. slave_priority:100
  13. slave_read_only:1
  14. replica_announced:1
  15. connected_slaves:0
  16. master_failover_state:no-failover
  17. master_replid:a2e82c9f0a654e86c3f996787f5d0d65fe7cb484
  18. master_replid2:cbfb2b6489fed27427dd540e2a2acd3eef684da8
  19. master_repl_offset:16506
  20. second_repl_offset:16507
  21. repl_backlog_active:1
  22. repl_backlog_size:1048576
  23. repl_backlog_first_byte_offset:1
  24. repl_backlog_histlen:16506

验证

此时我们在新升级的主节点6380上写入数据,发现他已经有了写入的权限,并且在6381上也成功同步新增加的数据。

  1. 127.0.0.1:6380> set testkv kv
  2. OK
  1. 127.0.0.1:6381> keys *
  2. 1) "k1"
  3. 2) "hash3"
  4. 3) "set1"
  5. 4) "f3"
  6. 5) "hash1"
  7. 6) "{f4}:config"
  8. 7) "k2"
  9. 8) "zset1"
  10. 9) "set2"
  11. 10) "f1"
  12. 11) "f4"
  13. 12) "hash2"
  14. 13) "pf1"
  15. 14) "k3"
  16. 15) "hash4"
  17. 16) "testkv"
  18. 17) "f2"

结束

其实redis的主从模式很简单,在实际的生产环境中是很少使用的,我也不建议在实际的生产环境中使用主从模式来提供系统的高可用性,之所以不建议使用都是由它的缺点造成的,在数据量非常大的情况,或者对系统的高可用性要求很高的情况下,主从模式也是不稳定的。虽然这个模式很简单,但是这个模式是其他模式的基础,所以必须深刻的理解,对其他模式的学习才会有帮助作用。