vlambda博客
学习文章列表

深度好文:保姆级教程Redis高可用之主从复制

贴心式服务,手把手教你搭建redis主从复制架构,然后介绍了redis主从复制原理,全量复制和部分复制,最后演示了java代码如何操作redis。希望对你有所帮助。

Redis 主从架构

Redis 支持简单且易用的主从复制功能, 主从复制可以让从服务器成为主服务器的精确复制品。主从复制架构图如下所示:

image-20220323113625838

Redis 主从架构搭建

Redis 集群搭建比较简单,从节点配置直接点信息replicaof <masterip> <masterport>,如果主节点有认证信息可通过 masterauth <master-password> 配置指定。

cd /usr/local/
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
tar -zxvf redis-6.2.6.tar.gz
cd redis-6.2.6/
make
## 到此已经安装完成
## 备份配置文件
cp redis.conf redis.conf_bak
# 创建主从工作目录
mkdir -p replication/6379 # master 节点
mkdir -p replication/6380 # 从节点
mkdir -p replication/6381 # 从节点
# 复制配置文件到主节点工作目录:
cp redis.conf replication/6379/
# 使用vim 命令修改主节点信息:
vim replication/6379/redis.conf
# 修改后台启动
daemonize yes
# redis 运行端口
port 6379 
# pid号写入哪个配置文件
pidfile /var/run/redis_6379.pid
# 指定数据文件的存放位置,因为需要在一台机器启动两个实例,所以必须指定不同的位置,不然会丢失数据
dir /usr/local/redis-6.2.6/replication/6379/
# 注释上允许所有网卡访问,
# bind 127.0.0.1 -::1
# 关闭保护模式
protected-mode no
# 开启 AOF 存储
appendonly yes

按照上述步骤操作以后,master 主节点配置完成,现在可以启动 master。

/usr/local/redis-6.2.6/src/redis-server replication/6379/redis.conf

执行上面的命令,没有任何提示说明启动成功。可以使用客户端连接进行验证。

[root@beifeng redis-6.2.6]# ./src/redis-cli -p 6379
127.0.0.1:6379> set beifeng ok
OK

我们接下来以 6379 实例的配置文件为模板,对两个从节点进行配置。按照以下步骤配置 6380 节点

# 拷贝6379的配置文件到6380实例
cp replication/6379/redis.conf replication/6380/
# 替换6379为6380
sed -i 's/6379/6380/g' replication/6380/redis.conf
vim replication/6380/redis.conf
# 找到 replicaof 配置项,添加如下配置
replicaof 172.16.38.12 6379

启动 6380 从节点

/usr/local/redis-6.2.6/src/redis-server replication/6380/redis.conf

配置 6381 节点

cp replication/6380/redis.conf replication/6381/
sed -i 's/6380/6381/g' replication/6381/redis.conf

启动 6380 从节点

/usr/local/redis-6.2.6/src/redis-server replication/6380/redis.conf

可以使用 redis 客户端连接 master 节点新增数据,然后连接另外两个节点进行验证。

./src/redis-cli -p 6380 # -p 指定端口号
127.0.0.1:6380> info
# Replication
role:slave
master_host:172.16.38.12
master_port:6379
master_link_status:up

至此 redis 主从架构已经完成。是不是 so easy ~ 文末提供配置文件下载路径。

Redis 主从工作原理

如果为 master 配置了一个 slave,不管这个 slave 是否是第一次连上 master,它都会发送一个 PSYNC 命令给 master请求复制数据。

master 收到 PSYNC 命令后,会在后台进行数据持久化通过 bgsave 生成最新的 rdb 快照文件;

持久化期间,master 会继续接收客户端的请求,master 会把可能修改数据集的请求缓存在内存中。

当持久化进行完毕以后,master 会把这份 rdb 文件数据集发送给 slave,slave 会把接收到的数据进行持久化生成 rdb,然后加载到内存。然后,master 在将之前缓存在内存中的命令发送给 slave。

当 master 与 slave 之间的连接由于某些原因而断开时,slave 能够自动重连 master,如果 master 收到了多个 slave 的并发连接请求,master 只会进行一次持久化,而不是一个连接创建一次快照,然后再把这一份持久化的数据发送给多个并发连接的 slave。

主从全量复制流程图

深度好文:保姆级教程Redis高可用之主从复制
image-20220323175056940

数据部分复制

当 master 和 slave 断开重连后,一般都会对整份数据进行复制。但从 Redis2.8 版本开始,Redis 改用可以支持部分数据复制的命令PSYNC 去 master 同步数据,slave 与 master 能够在网络端口重连后只进行部分数据复制。

master 会在其内存创建一个复制数据用的缓存队列,缓存最近一段时间的数据,master 和它所有的 slave 都维护了复制的数据下标 offset 和 master 的进程 id,因此,当网络连接断开后,slave 会继续请求 master 继续进行未完成的复制,从所记录的数据下标开始。

如果 master 进程 id 变化了,或者从节点数据下标 offset 太旧,已经不在 master 的缓存队列里了,那么将会进行一次全量数据的复制。

缓冲区大小修改配置:repl-backlog-size 1mb

深度好文:保姆级教程Redis高可用之主从复制
image-20220324091629437

可以使用 Telnet 连接到 master 节点,然后发送 SYNC 命令观察数据同步。

[root@beifeng redis-6.2.6]# telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
##### 执行sync 观察输出
sync
$203
REDIS0009� redis-ver6.2.6�
redis-bits�@�ctime�v�Qbused-mem�P��repl-stream-db��repl-id(ff2584972b5daa74ebb8c39129e853885d9be94b�
                                                                                                    repl-offset�=�
aof-preamble���ddbeifengokaa/��Gq�*1
$4
ping
*1
$4
ping
*1
$4
ping
*2
$6
SELECT
$1
0
*3
$3
set
$5
hello
$5
world

主从复制风暴

如果有很多从节点,多个从节点同时复制主节点导致主节点压力过大,也就是所谓的主从风暴;不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构。为了缓解主节点压力可以做如下架构,让部分从节点与从节点同步数据。

image-20220324092709631

代码实战

引入 jedis

使用 jedis 驱动操作 redis,创建 maven 工程,引入如下依赖。

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.2.0</version>
</dependency>

基础代码示例

public class JedisTest {
 public static void main(String[] args) {
  JedisPoolConfig poolConfig = new JedisPoolConfig();
  poolConfig.setMaxTotal(20);
  poolConfig.setMaxIdle(10);
  poolConfig.setMinIdle(5);
  JedisPool jedisPool = new JedisPool(poolConfig,"172.16.38.6",6379);
  try (Jedis jedis = jedisPool.getResource()) {
   jedis.set("name""beifeng");
  }
 }
}

上述代码简单演示了如何使用 java 客户端进行操作,后续会有详细介绍。

redis 主从复制是哨兵和集群的基础,希望大家多花时间重点掌握,一定要花时间自己动手实践一遍,实践出真知。