Docker环境下安装部署Redis Slave

Posted by Lucky Xue on 2020-04-19

本文记录了在Mac上的Docker环境下安装部署Redis主从复制集群并挂载外部配置和数据的操作步骤,Redis 的主从数据是异步同步的,所以分布式的 Redis 系统并不满足「一致性」要求。当客户端在 Redis 的主节点修改了数据后,立即返回,即使在主从网络断开的情况下,主节点依旧可以正常对外提供修改服务,所以 Redis 满足「可用性」。

Redis 保证「最终一致性」,从节点会努力追赶主节点,最终从节点的状态会和主节点的状态将保持一致。如果网络断开了,主从节点的数据将会出现大量不一致,一旦网络恢复,从节点会采用多种策略努力追赶上落后的数据,继续尽力保持和主节点一致。

关注文末的公众号,后台私信获取完整的配置文件。

Redis主从复制配置

1
2
3
4
5
6
7
8
port port # 设置主从节点的端口
pid /var/run/redis-${port}.pid # 通过端口区分主从节点进程
logfile "${port}.log" # 通过端口区分主从节点日志文件
dbfilename dump-${port}.rdb # 通过端口区分主从节点rdb文件
appendfilename "appendonly-${port}.aof" # 通过端口区分主从节点aof文件
slaveof ip port # 从节点附属于主节点的ip和端口
masterauth password # 如果主节点设置了密码认证这时候需要授权从节点密码
slave-read-only yes # 从节点只读
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 指定Redis配置文件目录来启动Redis容器

# 创建redis_master容器服务
~ docker run -p 6379:6379 --privileged=true --name redis_master \
-v /Users/hancaihaoyun/docker/redis/conf:/etc/redis/conf \
-v /Users/hancaihaoyun/docker/redis/data:/data \
-d redis redis-server /etc/redis/conf/redis_master.conf

# 创建redis_slave_1容器服务
~ docker run -p 6380:6380 --privileged=true --name redis_slave_1 \
--link redis_master:master \
-v /Users/hancaihaoyun/docker/redis/conf:/etc/redis/conf \
-v /Users/hancaihaoyun/docker/redis/data:/data \
-d redis redis-server /etc/redis/conf/redis_slave_1.conf

# 创建redis_slave_2容器服务
~ docker run -p 6381:6381 --privileged=true --name redis_slave_2 \
--link redis_master:master \
-v /Users/hancaihaoyun/docker/redis/conf:/etc/redis/conf \
-v /Users/hancaihaoyun/docker/redis/data:/data \
-d redis redis-server /etc/redis/conf/redis_slave_2.conf

设置完主从复制之后,通过docker ps -a查看各个容器的运行状况
然后查看主节点的log,tail -f 6379.log可以看到下面的输出日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1:S 20 Apr 2020 05:47:26.682 * Ready to accept connections
1:S 20 Apr 2020 05:47:26.684 * Connecting to MASTER master:6379
1:S 20 Apr 2020 05:47:26.687 * MASTER <-> REPLICA sync started
1:S 20 Apr 2020 05:47:26.689 * Non blocking connect for SYNC fired the event.
1:S 20 Apr 2020 05:47:26.691 * Master replied to PING, replication can continue...
1:S 20 Apr 2020 05:47:26.693 * Partial resynchronization not possible (no cached master)
1:S 20 Apr 2020 05:47:26.705 * Full resync from master: 9cfc5fe9ae83702ee4c1382ddc9298d4bea9763a:0
1:S 20 Apr 2020 05:47:26.781 * MASTER <-> REPLICA sync: receiving 199 bytes from master
1:S 20 Apr 2020 05:47:26.785 * MASTER <-> REPLICA sync: Flushing old data
1:S 20 Apr 2020 05:47:26.786 * MASTER <-> REPLICA sync: Loading DB in memory
1:S 20 Apr 2020 05:47:26.790 * MASTER <-> REPLICA sync: Finished with success
1:S 20 Apr 2020 05:47:26.793 * Background append only file rewriting started by pid 18
1:S 20 Apr 2020 05:47:26.823 * AOF rewrite child asks to stop sending diffs.
18:C 20 Apr 2020 05:47:26.826 * Parent agreed to stop sending diffs. Finalizing AOF...
18:C 20 Apr 2020 05:47:26.828 * Concatenating 0.00 MB of AOF diff received from parent.
18:C 20 Apr 2020 05:47:26.831 * SYNC append only file rewrite performed
18:C 20 Apr 2020 05:47:26.833 * AOF rewrite: 0 MB of memory used by copy-on-write
1:S 20 Apr 2020 05:47:26.900 * Background AOF rewrite terminated with success
1:S 20 Apr 2020 05:47:26.905 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
1:S 20 Apr 2020 05:47:26.909 * Background AOF rewrite finished successfully

鉴于在同一主机下搭建redis主从集群,只需要完成容器互联来实现容器之间的通信即可,这里采用 docker run命令的–-link选项来建立容器之间的连接。这里介绍一下–link选项的用法,通过–link选项能够进行容器间的安全的交互通信,使用的格式为:name:alias,可在一个docker run命令中重复使用该参数。使用实例如下:

1
docker run --link redis_master:master --name redis_slave_1 redis bash

上例中在redis镜像上启动一个容器,并命名为redis_slave_1,同时将新启动的redis_slave_1容器连接到名为master的容器上。在使用–link选项时,连接通过容器名来确定容器。
通过–link选项来建立容器之间的连接,不但可以避免容器的IP和端口暴露到外网导致的安全问题,还可以防止容器自重启后IP地址发生变化导致的访问的失效,它的原理类似于DNS服务器的与域名和IP地址的映射。当容器的IP地址发生变化时,Docker自动维护映射关系中的IP地址。
如果在配置完毕后启动容器,运行info命令查看到上述信息中connected_slaves的值为0,测试主从复制也没有成功,需要将所有配置文件中的bind 127.0.0.1修改为bind 0.0.0.0,或者直接注释掉bind 127.0.0.1也可以。

1
2
3
4
5
slaveof no one # 在redis_slave_1节点的机器上执行取消主从同步
info replication # 在redis_slave_1节点的机器上查看同步配置信息,发现已经从slave转为master
在redis_master节点的机器上查看同步配置信息,发现connected_slaves:0
slaveof master 6379 # 再次在redis_slave_1节点的机器上执行主从同步
这时候slave节点会清空之前保存的数据,然后从master拉取最新的数据进行全量复制

补充材料

rdb持久化配置

1
2
3
4
5
6
7
8
#save 900 1
#save 300 10
#save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump-${port}.rdb
dir /bigdiskpath

通过save和bgsave生成rdb文件

continuous_deployment

触发机制-不容忽略方式

  • 全量复制
  • debug reload
  • shutdown

aof持久化配置

1
2
3
4
5
6
7
appendonly yes
appendfilename "appendonly-${port}.aof"
appendfsync everysec
dir /bigdiskpath
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

生成aof文件的三种策略对比

continuous_deployment

aof文件会随着时间推移不断变大,当满足一定条件的情况下,redis为了减小aof文件的大小会进行aof重写

continuous_deployment

全量复制开销

  • bgsave时间
  • rdb文件网络传输时间
  • 从节点清空数据时间
  • 从节点加载rdb文件的时间
  • 可能的aof重写时间

部分复制

continuous_deployment

改善fork

  • 优先使用物理机或者高效支持fork操作的虚拟化技术
  • 控制Redis实例最大可用内容:maxmemory
  • 合理配置Linux内存分配策略:vm.overcommit_memory=1
  • 降低fork频率:例如放宽aof重写自动触发时机,不必要的全量复制

改善子进程开销和优化

  • CPU
    开销:rdb和aof文件生成,属于CPU密集型
    优化:不做CPU绑定,不和CPU密集型部署

  • 内存
    开销:fork内存开销,copy-on-write
    优化:echo never > /sys/kernel/mm/transparent_hugepage/enabled

  • 磁盘
    不要和高硬盘负载服务部署在一起:存储服务、消息队列等
    no-appendfsync-on-rewrite = yes
    根据写入量决定磁盘类型:例如ssd
    单机多实例持久化文件目录可以考虑分盘

  • 读写分离可能遇到的问题
    优点是读流量可以分摊到从节点
    复制数据延迟
    读到过期数据
    从节点故障

  • 配置不一致
    例如maxmemory不一致:丢失数据
    列入数据结构优化参数(例如hash:max-ziplist-entries):内存不一致

  • 规避全量复制
    第一次全量复制不可避免,在小主节点上执行,错峰执行
    节点运行id不匹配,主节点重启则运行id变化
    复制积压缓存区不足,网络中断,部分复制无法满足,增大复制缓冲区配置rel_backlog_size,增强网络

  • 规避复制风暴

continuous_deployment

关注【憨才好运】微信公众号,了解更多精彩内容⬇️⬇️⬇️

continuous_deployment