Redis 集群有三种模式,分别是主从同步/复制、哨兵模式、Cluster(集群)。本章节将介绍 Redis 的主从复制,主从复制是高可用 Redis 的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对读操作的负载均衡和简单的故障恢复。
Redis 通过持久化特性,保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据。因为持久化会把内存中的数据保存到硬盘上,重启 Redis 会从硬盘上加载数据到内存,恢复数据。但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。
为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。为此,Redis 提供了复制功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他服务器上的数据库中。
在主从复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据(slave)。主数据可以进行读写操作,当写操做导致数据变化时自动将数据同步给从数据库。从数据库一般是只读的,并接收主数据同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。如下图:
主从复制的优点:
(1)主从结构具有读写分离,提高效率、数据备份,提供多个副本等优点
主从复制的缺点:
(1)不具备自动容错和恢复功能,主节点故障,集群则无法进行工作,可用性比较低,从节点升主节点需要人工手动干预
(2)写操作无法进行负载均衡
(3)存储能力受到单机的限制
主从复制主要流程如下:
(1)从节点连接主节点,发送 SYNC 命令,请求同步数据。
(2)主节点收到 SYNC 命令后,启动后台线程,将自己的数据快照写入 RDB 文件,并将这段时间内的所有写命令缓存到内存中,这个时候主节点进入阻塞状态,等待快照文件写入磁盘并发送给从节点。
(3)当主节点的 RDB 文件写入磁盘后,将 RDB 文件发送给从节点。
(4)从节点接收到 RDB 文件后,将 RDB 文件载入内存中,再将主节点缓存的写命令依次执行。
(5)从节点每隔一段时间会发送 PSYNC 命令,请求主节点增量同步数据,主节点将从缓存中的增量命令发送给从节点。
(6)从节点执行增量命令,完成数据同步。
该实例将在单台 Windows 环境服务器下演示 Redis 主从复制的配置,主从复制信息如下:
Master 127.0.0.1:6379 Slave1 127.0.0.1:6378 Slave2 127.0.0.1:6377
注意:下面默认你的 Redis 服务是全新安装的,笔者将给出最简单、最少的配置去开启 Redis 主从复制。
Master 服务器配置,只需要设置密码和端口。当如果你是在不同机器上面部署主从复制,则端口都不需要修改。配置如下:
# 设置端口 port 6379 # 设置 Master 密码,为了安全还是设置一下密码 requirepass "aaaaaa"
下面配置两个从服务器,如下:
如果 Master 服务器没有设置密码,则可以不用配置 masterauth。配置如下:
# 设置端口 port 6378 # 主从复制,使用 replicaof 使一个 Redis 实例成为另一个 Redis 服务器的副本。 # # +------------------+ +---------------+ # | Master | ---> | Replica | # | (receive writes) | | (exact copy) | # +------------------+ +---------------+ # # 1) Redis 复制是异步的,但你可以将主站配置为停止接受写入 # 2) 如果复制链接丢失的时间相对较短,Redis 复制能够与主站进行部分重新同步 # 3) 复制是自动的,不需要用户干预 # # 下面语句表面当前 Redis 实例为 Slave 节点,它从 Master 节点 127.0.0.1:6379 同步数据 replicaof 127.0.0.1 6379 # 如果 Master 通过 requirepass 设置了保护密码,我们可以通过 # masterauth 告诉 Slave 在开始复制同步过程之前使用指定密码进行认证,否则主站会拒绝复制请求 masterauth "aaaaaa"
如果 Master 服务器没有设置密码,则可以不用配置 masterauth。配置如下:
port 6377 replicaof 127.0.0.1 6379 masterauth "aaaaaa"
使用 redis-server.exe redis.windows.conf 命令启动 Redis 服务,启动日志如下:
[9636] 03 Apr 13:01:53.224 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo [9636] 03 Apr 13:01:53.224 # Redis version=5.0.14.1, bits=64, commit=ec77f72d, modified=0, pid=9636, just started [9636] 03 Apr 13:01:53.224 # Configuration loaded _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.14.1 (ec77f72d/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 9636 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' [9636] 03 Apr 13:01:53.242 # Server initialized [9636] 03 Apr 13:01:53.286 * DB loaded from disk: 0.039 seconds [9636] 03 Apr 13:01:53.288 * Ready to accept connections # Slave1 服务连接到 Master [9636] 03 Apr 13:01:59.621 * Replica 127.0.0.1:6378 asks for synchronization [9636] 03 Apr 13:01:59.622 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '79f4f005072ad284bcbb016803009ac3651a9695', my replication IDs are '4644b3e486ba2de4f17119ff02d3d6ca18175256' and '0000000000000000000000000000000000000000') [9636] 03 Apr 13:01:59.622 * Starting BGSAVE for SYNC with target: disk [9636] 03 Apr 13:01:59.686 * Background saving started by pid 6708 [9636] 03 Apr 13:02:00.055 # fork operation complete [9636] 03 Apr 13:02:00.071 * Background saving terminated with success [9636] 03 Apr 13:02:00.128 * Synchronization with replica 127.0.0.1:6378 succeeded # Slave2 服务连接到 Master [9636] 03 Apr 13:02:05.907 * Replica 127.0.0.1:6377 asks for synchronization [9636] 03 Apr 13:02:05.907 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '79f4f005072ad284bcbb016803009ac3651a9695', my replication IDs are '70698914343964c3f04b9d117f95efdc2f8a9e89' and '0000000000000000000000000000000000000000') [9636] 03 Apr 13:02:05.908 * Starting BGSAVE for SYNC with target: disk [9636] 03 Apr 13:02:05.953 * Background saving started by pid 28896 [9636] 03 Apr 13:02:06.341 # fork operation complete [9636] 03 Apr 13:02:06.354 * Background saving terminated with success [9636] 03 Apr 13:02:06.362 * Synchronization with replica 127.0.0.1:6377 succeeded
使用 redis-server.exe redis.windows.conf 命令启动 Redis 服务,启动日志如下:
[38284] 03 Apr 13:01:58.528 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo [38284] 03 Apr 13:01:58.529 # Redis version=5.0.14.1, bits=64, commit=ec77f72d, modified=0, pid=38284, just started [38284] 03 Apr 13:01:58.529 # Configuration loaded _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.14.1 (ec77f72d/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6378 | `-._ `._ / _.-' | PID: 38284 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' [38284] 03 Apr 13:01:58.534 # Server initialized [38284] 03 Apr 13:01:58.547 * DB loaded from disk: 0.012 seconds [38284] 03 Apr 13:01:58.547 * Before turning into a replica, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer. [38284] 03 Apr 13:01:58.547 * Ready to accept connections # 开始和 Master 进行数据同步 [38284] 03 Apr 13:01:58.547 * Connecting to MASTER 127.0.0.1:6379 [38284] 03 Apr 13:01:59.617 * MASTER <-> REPLICA sync started [38284] 03 Apr 13:01:59.617 * Non blocking connect for SYNC fired the event. [38284] 03 Apr 13:01:59.618 * Master replied to PING, replication can continue... [38284] 03 Apr 13:01:59.620 * Trying a partial resynchronization (request 79f4f005072ad284bcbb016803009ac3651a9695:1). [38284] 03 Apr 13:01:59.687 * Full resync from master: 70698914343964c3f04b9d117f95efdc2f8a9e89:0 [38284] 03 Apr 13:01:59.689 * Discarding previously cached master state. [38284] 03 Apr 13:02:00.116 * MASTER <-> REPLICA sync: receiving 569074 bytes from master [38284] 03 Apr 13:02:00.134 * MASTER <-> REPLICA sync: Flushing old data [38284] 03 Apr 13:02:00.148 * MASTER <-> REPLICA sync: Loading DB in memory [38284] 03 Apr 13:02:00.162 * MASTER <-> REPLICA sync: Finished with success
使用 redis-server.exe redis.windows.conf 命令启动 Redis 服务,启动日志如下:
[23216] 03 Apr 13:02:04.904 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo [23216] 03 Apr 13:02:04.906 # Redis version=5.0.14.1, bits=64, commit=ec77f72d, modified=0, pid=23216, just started [23216] 03 Apr 13:02:04.907 # Configuration loaded _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 5.0.14.1 (ec77f72d/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6377 | `-._ `._ / _.-' | PID: 23216 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' [23216] 03 Apr 13:02:04.922 # Server initialized [23216] 03 Apr 13:02:04.939 * DB loaded from disk: 0.016 seconds [23216] 03 Apr 13:02:04.940 * Before turning into a replica, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer. [23216] 03 Apr 13:02:04.942 * Ready to accept connections # 开始和 Master 进行数据同步 [23216] 03 Apr 13:02:04.944 * Connecting to MASTER 127.0.0.1:6379 [23216] 03 Apr 13:02:05.905 * MASTER <-> REPLICA sync started [23216] 03 Apr 13:02:05.905 * Non blocking connect for SYNC fired the event. [23216] 03 Apr 13:02:05.906 * Master replied to PING, replication can continue... [23216] 03 Apr 13:02:05.906 * Trying a partial resynchronization (request 79f4f005072ad284bcbb016803009ac3651a9695:15). [23216] 03 Apr 13:02:05.954 * Full resync from master: 70698914343964c3f04b9d117f95efdc2f8a9e89:14 [23216] 03 Apr 13:02:05.956 * Discarding previously cached master state. [23216] 03 Apr 13:02:06.357 * MASTER <-> REPLICA sync: receiving 569074 bytes from master [23216] 03 Apr 13:02:06.363 * MASTER <-> REPLICA sync: Flushing old data [23216] 03 Apr 13:02:06.367 * MASTER <-> REPLICA sync: Loading DB in memory [23216] 03 Apr 13:02:06.379 * MASTER <-> REPLICA sync: Finished with success
使用 redis-cli 客户端工具连接到 Master 服务,查看主从复制信息,如下:
C:\Users\Administrator>redis-cli 127.0.0.1:6379> auth aaaaaa OK 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 # 下面时两个 slave 服务的信息 slave0:ip=127.0.0.1,port=6378,state=online,offset=98,lag=1 slave1:ip=127.0.0.1,port=6377,state=online,offset=98,lag=0 # 主服务信息 master_replid:70698914343964c3f04b9d117f95efdc2f8a9e89 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:98 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:98
在 Master 服务上面创建一个 master 字符串键,命令如下:
# 在 Master 服务上写入一个 master 键 C:\Users\Administrator> redis-cli 127.0.0.1:6379> set master "hello world" OK 127.0.0.1:6379> # 从 Slave1 中获取 master 键的值 C:\Users\Administrator> redis-cli -p 6378 127.0.0.1:6378> get master "hello world" 127.0.0.1:6378> # 从 Slave2 中获取 master 键的值 C:\Users\Administrator> redis-cli -p 6377 127.0.0.1:6377> get master "hello world" 127.0.0.1:6377>
到这里,Redis 主从复制就介绍完了,如果有问题请留言指正。