目录
Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步
主从模式介绍
作用
- 数据冗余:主从复制实现数据热备份,是持久化之外的数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速故障恢复。
- 负载均衡:在主从复制基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务
(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是
在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。 - 读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,
同时可根据需求的变化,改变从库的数量; - 高可用:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用基础
工作原理
- 连接并发送 SYNC 命令:从库通过执行
SLAVEOF 10.0.0.31 6379
命令连接到主库,并发送 SYNC 命令给主库。 - 生成并发送 RDB 快照:主库接收到 SYNC 命令后,会立即触发 BGSAVE 命令,在后台生成 RDB 快照,并将该快照发送给从库。
- 应用 RDB 快照:从库接收并应用 RDB 快照,更新自身的数据。
- 同步新操作:主库将生成快照期间的新操作记录下来,并陆续发送给从库。
- 正常运行:完成上述步骤后,主从复制集开始正常工作。
- 命令传播:之后,主库发生的任何新操作都会自动以命令形式发送给从库,以保持数据同步。
- 查看复制信息:所有与复制相关的信息都可以通过
INFO
命令查询,即使重启任何节点,主从关系依然存在。 - 处理断开重连:如果主从关系断开,从库的数据不会受损。在重新连接后,从库发送 PSYNC 命令给主库。
- 增量同步:主库只会将从库缺失的数据部分同步给从库,以快速恢复主从架构的同步状态。
全量同步
Redis 全量复制通常发生在从节点初始化阶段,此时从节点需要将主节点上的所有数据复制一份。具体步骤如下:
- 连接并发送 SYNC 命令:从节点连接到主节点,并发送 SYNC 命令请求全量同步。
- 生成 RDB 文件:主节点接收到 SYNC 命令后,执行 BGSAVE 命令生成 RDB 文件,并使用缓冲区记录此后执行的所有写命令。
- 发送快照文件:主节点 BGSAVE 执行完毕后,向所有从节点发送生成的快照文件。在此期间,主节点继续记录新的写命令。
- 从节点载入快照:从节点收到快照文件后,丢弃所有旧数据,并载入新的快照。
- 发送缓冲区写命令:主节点发送完快照文件后,开始向从节点发送缓冲区中记录的写命令。
- 从节点同步命令:从节点完成快照的载入后,开始接收并执行来自主节点缓冲区中的写命令。
增量同步
Redis 增量复制指的是当从节点初始化后正常工作时,将主节点发生的写操作同步到从节点的过程。具体步骤如下:
- 建立复制连接:从节点与主节点建立复制连接。
- 发送 PSYNC 命令:从节点通过发送 PSYNC 命令请求进行增量同步。
- 增量复制过程:在增量复制过程中,主节点每执行一个写操作,就会将相同的写命令发送给从节点,从节点接收并执行这些写命令。
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
**需要注意: **如果多个Slave断线了,需重启时,因为只要Slave启动,就会发送sync请求和主机全量同步,当多个同时出现的时候,可能会导致Master IO剧增宕机
主库是否要开启持久化?
1)为了缓解主redis服务器写磁盘压力带来的开销,可以配置让主redis不将将数据持久化到磁盘,
而是通过连接让一个配置的从redis服务器及时的将相关数据持久化到磁盘,不过这样会存在一个问题,
就是主redis服务器一旦重启,因为主redis服务器数据为空,这时候通过主从同步可能导致从redis
服务器上的数据也被清空;
2)主库要开持久化,主redis服务器写磁盘压力带来的开销,重启数据不会丢失。
生产环境中,建议开启master库持久化功能,避免因主库意外重启而导致缓存丢失。举个例子,master库有1w条数据,replica库在某一时刻仅有9k数据,还有1k数据未来得及同步master库时,master库意外重启导致KEY为0,此时replica库同步master库数据会将replica库已有的9k缓存数据删除以达到和master库同步的目的
主从搭建过程
主机规划
操作系统 | IP | 主机名 | 关系 | CPU/内存 | 版本 |
---|---|---|---|---|---|
麒麟信安3.3 | 10.0.0.31 | redis1 | 主 | 2核+2G | 6.2.6 |
麒麟信安3.3 | 10.0.0.32 | redis2 | 从 | 2核+2G | 6.2.6 |
麒麟信安3.3 | 10.0.0.33 | redis3 | 从 | 2核+2G | 6.2.6 |
下载redis
wget http://download.redis.io/releases/redis-6.2.6.tar.gz
安装依赖
yum -y install gcc automake autoconf libtool make
关闭防火墙
1.#闭防火墙、selinux、dnsmasq/NetworkManager
systemctl disable --now firewalld
systemctl disable --now dnsmasq
systemctl disable --now NetworkManager
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/sysconfig/selinux
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
#检查
grep ^SELINUX= /etc/selinux/config
编译安装redis
tar xf redis-6.2.6.tar.gz
mv redis-6.2.6 /usr/local/redis
cd /usr/local/redis
make
所有主机配置环境变量
#/usr/local/redis/src
cat>>/etc/profile<<'EOF'
export PATH=/usr/local/redis/src:$PATH
EOF
tail -1 /etc/profile
source /etc/profile
echo $PATH
所有主机创建Redis的数据存储目录
mkdir /data/6379/ -p
所有主机创建配置文件
- 31配置文件
cat > /data/6379/redis.conf <<EOF
port 6379
bind 10.0.0.31 127.0.0.1
daemonize yes
pidfile /data/6379/redis.pid
loglevel notice
logfile "/data/6379/redis.log"
dbfilename dump.rdb
dir /data/6379
requirepass 123
masterauth 123
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
- 32 配置文件
cat > /data/6379/redis.conf <<EOF
port 6379
bind 10.0.0.32 127.0.0.1
daemonize yes
pidfile /data/6379/redis.pid
loglevel notice
logfile "/data/6379/redis.log"
dbfilename dump.rdb
dir /data/6379
requirepass 123
masterauth 123
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
- 33配置文件
cat > /data/6379/redis.conf <<EOF
port 6379
bind 10.0.0.33 127.0.0.1
daemonize yes
pidfile /data/6379/redis.pid
loglevel notice
logfile "/data/6379/redis.log"
dbfilename dump.rdb
dir /data/6379
requirepass 123
masterauth 123
# 配置RDB持久化策略
save 900 1
save 300 10
save 60 10000
# 配置AOF持久化
appendonly yes
appendfsync everysec
EOF
启动redis
redis-server /data/6379/redis.conf
netstat -lantup | grep 6379
- 脚本管理
#!/bin/bash
REDIS_CONFIG_PATH=/data/6379/redis.conf
choice=$1
start(){
echo "开始启动redis"
PID=$(ps -ef | grep redis-server | grep -v grep | wc -l)
if [ $PID -eq 0 ]; then
/usr/local/redis/src/redis-server $REDIS_CONFIG_PATH
sleep 2
echo "redis启动成功"
else
echo "redis已启动"
fi
}
stop(){
echo "开始停止redis"
PID=$(ps -ef | grep redis-server | grep -v grep | wc -l)
if [ $PID -eq 1 ]; then
redis-cli -h 127.0.0.1 -p 6379 -a 123 shutdown
sleep 2
echo "redis停止成功"
else
echo "redis已停止"
fi
}
case "$choice" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "请输入正确的格式: sh $0 {start|stop|restart}"
;;
esac
使用system管理
cat >/usr/lib/systemd/system/redis.service<<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/redis/src/redis-server /data/6379/redis.conf --supervised systemd
ExecStop=/usr/local/redis/src/redis-cli shutdown
Type=notify
User=root
Group=root
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now redis.service
systemctl status redis.service
netstat -lantup | grep 6379
启动警告处理
echo '511' > /proc/sys/net/core/somaxconn
echo never > /sys/kernel/mm/transparent_hugepage/enabled
ulimit -SHn 65535
echo "* - nofile 65535" >>/etc/security/limits.conf #永久生效
开启主从
以"31"实例为主库,以"32"实例和"33"实例为从库。
从库开启主从
- 32从库执行
redis-cli -h 10.0.0.32 -p 6379 -a 123 SLAVEOF 10.0.0.31 6379
- 33从库执行
redis-cli -h 10.0.0.33 -p 6379 -a 123 SLAVEOF 10.0.0.31 6379
主库查看主从信息
[服务未授权][root@redis1 6379]# redis-cli -p 6379 -a 123 INFO REPLICATION
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.32,port=6379,state=online,offset=770,lag=0
slave1:ip=10.0.0.33,port=6379,state=online,offset=770,lag=0
master_failover_state:no-failover
master_replid:66003cae539c0cfa8239c8c4580a7a2561cfa1a9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:770
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:770
从库查看主从信息
[服务未授权][root@redis2 ~]# redis-cli -p 6379 -a 123 INFO REPLICATION
# Replication
role:slave
master_host:10.0.0.31
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_read_repl_offset:854
slave_repl_offset:854
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:66003cae539c0cfa8239c8c4580a7a2561cfa1a9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:854
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:854
验证主从配置是否生效
- 在"redis31"实例主库创建测试数据
[服务未授权][root@redis1 6379]# redis-cli -p 6379 -a 123
127.0.0.1:6379>
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name jiajia
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379>
- 在"31"实例和"32"实例从库查看数据是否同步
[服务未授权][root@redis2 ~]# redis-cli -p 6379 -a 123
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name
"jiajia"
127.0.0.1:6379> get age
"18"
127.0.0.1:6379>
[服务未授权][root@redis3 ~]# redis-cli -p 6379 -a 123
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name
"jiajia"
127.0.0.1:6379> get age
"18"
127.0.0.1:6379>
redis主从复制默认是读写分离的,即:
主节点上可以读写操作;从节点上只能进行读操作,不能写数据
主从切换
- 停止主节点master的redis
[服务未授权][root@redis1 6379]# redis-cli -p 6379 -a 123 shutdown
[服务未授权][root@redis1 6379]# netstat -lntup | grep 6379
- 将从节点slave32实例的redis设成主redis
这条命了只是临时将该节点设置为主节点;当redis重启后,就会失效;可以登录redis,通过info信息查看!
redis-cli -a 123 -h 127.0.0.1 -p 6379 slaveof NO ONE
变为主redis后,slave就可以进行写入操作了
10.0.0.32:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:a5764bd08d52ee8956b96047fa56363765e570c4
master_replid2:66003cae539c0cfa8239c8c4580a7a2561cfa1a9
master_repl_offset:3658
second_repl_offset:3659
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:3658
10.0.0.32:6379> set name xiaomin
OK
10.0.0.32:6379> get name
"xiaomin"
10.0.0.32:6379>
- 原来的主redis恢复正常了,要重新切换回去
原来的主节点恢复了,发现只有一个从节点33。另一个从节点32在31节点故障期间临时变为主节点
[服务未授权][root@redis1 6379]# netstat -lntup | grep 6379
[服务未授权][root@redis1 6379]# systemctl start redis
[服务未授权][root@redis1 6379]# netstat -lntup | grep 6379
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 14896/redis-server
tcp 0 0 10.0.0.31:6379 0.0.0.0:* LISTEN 14896/redis-server
[服务未授权][root@redis1 6379]# redis-cli -p 6379 -a 123
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.33,port=6379,state=online,offset=14,lag=1
master_failover_state:no-failover
master_replid:01c66d4f28fe9bfa4b4320d68e412807174f6407
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
127.0.0.1:6379>
那么现在要重新将主节点切换回去。步骤如下:
登录临时切换的主节点32
[服务未授权][root@redis2 ~]# redis-cli -a 123 -h 10.0.0.32 -p 6379
10.0.0.32:6379> set num 100
OK
10.0.0.32:6379> save
OK
10.0.0.32:6379>
将现在的主redis(即32节点,临时设置的主节点)/data/6379/目录下文件和dump.rdb文件拷贝覆盖到原来主redis的根目录(覆盖前将原来主redis下的持久化文件备份下)
31节点备份
[服务未授权][root@redis1 6379]# cd /data/6379/
[服务未授权][root@redis1 6379]# ls
appendonly.aof dump.rdb redis.conf redis.log redis.pid
[服务未授权][root@redis1 6379]# mkdir buckup
[服务未授权][root@redis1 6379]# cp appendonly.aof dump.rdb buckup/
32节点拷贝覆盖到31
rsync -e "ssh -p22" -avpgolr /data/6379/dump.rdb 10.0.0.31:/data/6379
rsync -e "ssh -p22" -avpgolr /data/6379/appendonly.aof 10.0.0.31:/data/6379
重启原来的主redis(即31节点)
[服务未授权][root@redis1 6379]# systemctl restart redis
在现在的主redis(即32节点)中切换(或者直接重启该节点的redis,因为redis.conf文件中已经配置了;如果不想重启redis,就使用下面的命令)
[服务未授权][root@redis2 6379]# redis-cli -a 123 -h 127.0.0.1 -p 6379 slaveof 10.0.0.31 6379
登录到原来的master节点查看(31节点)
10.0.0.31:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.33,port=6379,state=online,offset=182,lag=1
slave1:ip=10.0.0.32,port=6379,state=online,offset=182,lag=0
master_failover_state:no-failover
master_replid:049068be0a73b1d6958c091388eb7a60e7500850
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:182
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:182
10.0.0.31:6379> keys *
1) "num"
2) "age"
3) "name"
10.0.0.31:6379> get num
"100"
10.0.0.31:6379>
注意事项
如果使用主从复制,那么要确保你的master激活了持久化,或者确保它不会在当掉后自动重启,原因:
- slave是master的完整备份,因此如果master通过一个空数据集重启,slave也会被清掉。
- 在配置redis复制功能的时候,如果主数据库设置了密码,需要在从数据的配置文件中通过masterauth参数设置主数据库的密码,这样从数据库在连接
- 主数据库时就会自动使用auth命令认证了。相当于做了一个免密码登录。(我上面的例子中没有设置密码)
解除主从关系
32 解除主从关系
[服务未授权][root@redis2 ~]# redis-cli -p 6379 -h 10.0.0.32 -a 123 SLAVEOF NO ONE
OK
33 解除主从关系
[服务未授权][root@redis3 ~]# redis-cli -p 6379 -h 10.0.0.33 -a 123 SLAVEOF NO ONE
OK
31 master节点查看主从关系,可以看到connected_slaves数量为0
[服务未授权][root@redis1 6379]# redis-cli -p 6379 -a 123 -h 10.0.0.31 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:049068be0a73b1d6958c091388eb7a60e7500850
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:756
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:756
标签:10.0,主从复制,部署,Redis,redis,6379,repl,master,节点
From: https://www.cnblogs.com/Unstoppable9527/p/18348909