主从架构原理
-
首先是主从库建立连接、协商同步的过程,具体的从库向主库发送 psync 命令,代表要进行数据同步;psync 中包含了主库的 runID(Redis 启动时生成的随机 ID,初始值为:
?
)和复制进度 offset(设为-1,代表第一次复制)两个参数,主库接收到 psync 命令会,会用 FULLRESYNC 命令返回给从库,包含两个参数:主库 runID 和复制进度 offset;其中 FULLRESYNC 代表的全量复制,会将主库所有的数据都复制给从库; -
待从库接收到数据后,在本地完成数据加载,具体的主库执行 bgsave 命令,生成 RDB 文件,然后将文件发给从库,从库接收到 RDB 文件后,首先清空当前数据,然后再加载 RDB 文件;这个过程主库不会被阻塞,仍然可以接受请求,如果存在写操作,刚刚生成的 RDB 文件中是不包含这些新数据的,此时主库会在内存中用专门的 replication buffer 记录 RDB 文件生成后所有的写操作;
-
最后,主库会把 replication buffer 中的修改操作发给从库,从库重新执行这些操作,就可以实现主从库同步了。
Redis 单节点安装
本次测试版本为redis-7.0.8
所有的搭建都需要提前安装redis,此处可以使用Yum或者Docker 镜像的方式安装
#如果有依赖问题可以提前安装下面的依赖包库
[root@web01 redis]# yum -y install gcc gcc-c++ make autoconf libtool-ltdl-devel gd-devel freetype-devel libxml2-devel libjpeg-devel libpng-devel openssh-clients openssl-devel curl-devel bison patch libmcrypt-devel libmhash-devel ncurses-devel binutils compat-libstdc++-33 elfutils-libelf elfutils-libelf-devel glibc glibc-common glibc-devel libgcj libtiff pam-devel libicu libicu-devel gettext-devel libaio-devel libaio libgcc libstdc++ libstdc++-devel unixODBC unixODBC-devel numactl-devel glibc-headers sudo bzip2 mlocate flex lrzsz sysstat lsof setuptool system-config-network-tui system-config-firewall-tui ntsysv ntp pv lz4 dos2unix unix2dos rsync dstat iotop innotop mytop telnet iftop expect cmake nc gnuplot screen xorg-x11-utils xorg-x11-xinit rdate bc expat-devel compat-expat1 tcpdump sysstat man nmap curl lrzsz elinks finger bind-utils traceroute mtr ntpdate zip unzip vim wget net-tools
[root@web01 redis]# wget http://download.redis.io/releases/redis-7.0.8.tar.gz
[root@web01 redis]# tar xf redis-7.0.8.tar.gz
[root@web01 redis]# make && make install
#建议使用PREFIX指定安装目录,后续多台集群方便统一维护以及后续脚本编写
#PREFIX=/opt/redis
前台启动测试
先启动测试,检查是否有版本依赖或其它端口冲突等问题,后续统一调整配置文件
[root@web01 redis-7.0.8]# redis-server redis.conf --port 6379
20186:C 15 Mar 2023 01:32:13.854 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
20186:C 15 Mar 2023 01:32:13.854 # Redis version=7.0.8, bits=64, commit=00000000, modified=0, pid=20186, just started
20186:C 15 Mar 2023 01:32:13.854 # Configuration loaded
20186:M 15 Mar 2023 01:32:13.854 * Increased maximum number of open files to 10032 (it was originally set to 1024).
20186:M 15 Mar 2023 01:32:13.854 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 7.0.8 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 20186
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
20186:M 15 Mar 2023 01:32:13.855 # Server initialized
20186:M 15 Mar 2023 01:32:13.855 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
20186:M 15 Mar 2023 01:32:13.856 * Ready to accept connections
不修改配置文件的方式,后台直接启动
[root@web01 redis-7.0.8]# nohup redis-server redis.conf --port 6379 &
#redis.conf可以单独指定其它文件
检查启动进程是否正常,可以连接
[root@web01 redis-7.0.8]# netstat -lntup|grep 6379
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 20201/redis-server
tcp6 0 0 ::1:6379 :::* LISTEN 20201/redis-server
[root@web01 redis-7.0.8]# ps -ef|grep redis
root 20201 15634 0 01:49 pts/0 00:00:00 redis-server 127.0.0.1:6379
检查是否可以正常写入
[root@web01 redis-7.0.8]# redis-cli -p 6379
127.0.0.1:6379> KEYS *
(empty array)
127.0.0.1:6379>
主从复制配置文件对应参数解释如下
- slaveof <masterip> <masterport> # 复制选项,slave复制对应的master;
- masterauth <master-password> # 如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。masterauth就是用来配置master的密码,这样可以在连上master后进行认证;
- slave-serve-stale-data yes # 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续响应客户端的请求。2) 如果slave-serve-stale-data设置为no,除去INFO和SLAVOF命令之外的任何请求都会返回一个错误”SYNC with master in progress”;
- slave-read-only yes # 作为从服务器,默认情况下是只读的(yes),可以修改成NO,用于写(强烈不建议);
- repl-diskless-sync no # 是否使用socket方式复制数据。目前redis复制提供两种方式,disk和socket。如果新的slave连上来或者重连的slave无法部分同步,就会执行全量同步,master会生成rdb文件。有2种方式:disk方式是master创建一个新的进程把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave。socket是master创建一个新的进程,直接把rdb文件以socket的方式发给slave。disk方式的时候,当一个rdb保存的过程中,多个slave都能共享这个rdb文件。socket的方式就的一个个slave顺序复制。在磁盘速度缓慢,网速快的情况下推荐用socket方式;
- repl-diskless-sync-delay 5 # diskless复制的延迟时间,防止设置为0。一旦复制开始,节点不会再接收新slave的复制请求直到下一个rdb传输。所以最好等待一段时间,等更多的slave连上来;
- repl-ping-slave-period 10 # slave根据指定的时间间隔向服务器发送ping请求。时间间隔可以通过 repl_ping_slave_period 来设置,默认10秒;
- repl-timeout 60 # 复制连接超时时间。master和slave都有超时时间的设置。master检测到slave上次发送的时间超过repl-timeout,即认为slave离线,清除该slave信息。slave检测到上次和master交互的时间超过repl-timeout,则认为master离线。需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时;
- repl-disable-tcp-nodelay no # 是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。默认是no,即使用tcp nodelay。如果master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。但是这也可能带来数据的延迟。默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes;
- repl-backlog-size 5mb # 复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。这样在slave离线的时候,不需要完全复制master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状态。缓冲区的大小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。没有slave的一段时间,内存会被释放出来,默认1m;
- repl-backlog-ttl 3600 # master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒;
- slave-priority 100 # 当master不可用,哨兵会根据slave的优先级选举一个master。值越小优先级越高。但0,永远不会被选举;
- min-slaves-to-write 3 # redis提供了可以让master停止写入的方式,如果配置了min-slaves-to-write,健康的slave的个数小于N,mater就禁止写入。master最少得有多少个健康的slave存活才能执行写命令。这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。设置为0是关闭该功能;
- min-slaves-max-lag 10. # 延迟小于min-slaves-max-lag秒的slave才认为是健康的slave;
- - 设置1或者min-slaves-to-write设置为0,表示禁用这个特性;
主从架构
如果从库的实例过多,对于主库来说有一定的压力,主库会频繁 fork 子进程以生成 RDB 文件,fork 这个操作会阻塞主线程处理正常请求,导致响应变慢,Redis 采用了主-从-从的模式,可以手动选择一个从库,用来同步其他从库的数据,以减少主库生成 RDB 文件和传输 RDB 文件的压力;
主从搭建
主机名 | 节点 | IP | 注 | |
---|---|---|---|---|
web-01 | master | 192.168.31.70 | ||
web-02 | slave | 192.168.31.71 | ||
web-03 | slave | 192.168.31.72 |
接下来先配置Master节点配置
这里是redis.conf
配置文件,主从部分只介绍主从的相关配置,后续会添加哨兵和集群模式的搭建及相对应的配置
- 本次的配置文件将slave节点设为只读,禁止写入数据
- 设置redis密码为123123
- 采用aof持久化存储
- 日志存储/opt/redis.log
- 配置文件后台启动
bind 0.0.0.0
protected-mode yes
requirepass 123123 #密码
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/opt/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay yes
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
#aof持久化相关配置
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
#存储目录
dir /opt/
#同步策略
appendfsync always
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
min-slaves-to-write 0
min-slaves-max-lag 10
启动redis master,写入数据
#因为直接设置了后台进程,所以不需要手动让进程后台运行
[root@web-01 redis-7.0.8]# redis-server redis.conf
#连接redis
[root@web01 redis-7.0.8]# redis-cli -p 6379
#redis已经设置密码了,所以需要登陆密码
127.0.0.1:6379> auth 123123 #输入密码
127.0.0.1:6379> KEYS *
1) "abc"
2) "age"
3) "stu"
127.0.0.1:6379> get abc
"name"
127.0.0.1:6379>
目前我们执行info replication
只能看到master自己
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:135b31657c35b82c753e69b638cc0c49956aa56a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
Redis从库搭建
从slave配置
#所有从节点,只需要添加一行下面的配置就可以
replicaof 192.168.31.70 6379
masterauth 123123
slave-read-only yes
#Redis masterIP masterPort
#Redis password
#slave-read-only 从库开启只读
步骤如下
[root@web02 redis-7.0.8]# cp redis.conf{,.bak_2023-03-15}
[root@web02 redis-7.0.8]# >redis.conf
[root@web02 redis-7.0.8]# vim redis.conf
#配置复制master,另外添加下面一行
replicaof 192.168.31.70 6379
masterauth 123123
slave-read-only yes
slave节点启动测试
[root@web-03 redis-7.0.8]# redis-server redis.conf
[root@web-03 redis-7.0.8]# tail -f /opt/redis.log
11331:S 15 Mar 2023 04:07:21.171 * Creating AOF incr file temp-appendonly.aof.incr on background rewrite
11331:S 15 Mar 2023 04:07:21.171 * Background append only file rewriting started by pid 11337
11337:C 15 Mar 2023 04:07:21.174 * Successfully created the temporary AOF base file temp-rewriteaof-bg-11337.aof
11337:C 15 Mar 2023 04:07:21.175 * Fork CoW for AOF rewrite: current 4 MB, peak 4 MB, average 4 MB
11331:S 15 Mar 2023 04:07:21.272 * Background AOF rewrite terminated with success
11331:S 15 Mar 2023 04:07:21.272 * Successfully renamed the temporary AOF base file temp-rewriteaof-bg-11337.aof into appendonly.aof.3.base.rdb
11331:S 15 Mar 2023 04:07:21.272 * Successfully renamed the temporary AOF incr file temp-appendonly.aof.incr into appendonly.aof.3.incr.aof
11331:S 15 Mar 2023 04:07:21.288 * Removing the history file appendonly.aof.2.incr.aof in the background
11331:S 15 Mar 2023 04:07:21.288 * Removing the history file appendonly.aof.2.base.rdb in the background
11331:S 15 Mar 2023 04:07:21.290 * Background AOF rewrite finished successfully
##########################################
[root@web-03 redis-7.0.8]# redis-cli
127.0.0.1:6379> KEYS *
1) "abc"
2) "stu"
3) "age"
127.0.0.1:6379> set nnn abc #开启slave节点只读
(error) READONLY You can't write against a read only replica.
127.0.0.1:6379>
当我们2台slave节点都启动完毕后,我们这master节点执行info replication
就可以看到slave节点信息
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.31.71,port=6379,state=online,offset=308,lag=0
slave1:ip=192.168.31.72,port=6379,state=online,offset=308,lag=0
master_failover_state:no-failover
master_replid:eba1048b441dc364697f924d8725d729f0ffe36d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:308
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:308
主从架构缺点
主从模式缺点: 当master节点down掉,slave节点无法进行写入,只可以进行只读。主节点由于故障下线了,从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作。并且还有一个问题就是当master节点down后,从节点没有数据同步,当master节点持久化丢失后,redis slave节点也将会删除持久化数据重新进行同步
[…] Redis 二进制主从搭建及原理 […]
[…] […]