redis replication -> 主从架构 -> 读写分离 -> 水平扩容支撑读高并发
redis 采用异步方式复制数据到 slave 节点,不过 redis2.8 开始,slave node 会周期性地确认自己每次复制的数据量;
注意点:
1. 如果采用了主从架构,那么建议必须开启 master 的持久化,不建议用 slave 作为 master 的数据热备。因为如果你关掉 master 的持久化,可能在 master 出现故障宕机重启的时候数据是被清空的,然后可能一经过复制, slave node 的数据也丢了。
2. 此外,master 的各种备份方案,也需要做。万一本地的所有文件丢失了,从备份中挑选一份 rdb 去恢复 master,这样才能确保启动的时候,是有数据的,即使采用了高可用机制,slave node 可以自动接管 master node,但也可能 sentinel 还没检测到 master failure,master node 就自动重启了,还是可能导致上面所有的 slave node 数据被清空。
从 redis2.8 开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。
master node 会在内存中维护一个 backlog,master 和 slave 都会保存一个 replica offset 还有一个 master run id,offset 就是保存在 backlog 中的。如果 master 和 slave 网络连接断掉了,slave 会让 master 从上次 replica offset 开始继续复制,如果没有找到对应的 offset,那么就会执行一次 resynchronization。
如果根据 host+ip 定位 master node,是不靠谱的,如果 master node 重启或者数据出现了变化,那么 slave node 应该根据不同的 run id 区分。
无磁盘化复制:master 在内存中直接创建 RDB,然后发送给 slave,不会在自己本地落地磁盘了。只需要在配置文件中开启 repl-diskless-sync yes 即可。
过期 key 处理:slave 不会过期 key,只会等待 master 过期 key。如果 master 过期了一个 key,或者通过 LRU 淘汰了一个 key,那么会模拟一条 del 命令发送给 slave。
鉴于之前做过安装讲解,这里就直接脚本运行了
[root@localhost ~]# vi redis.sh
#!/bin/bash
##判断网络环境
ping www.baidu.com -c 3 -i 0.2
if [[ $? = 0 ]]
then
echo "网络正常"
else
echo "网络异常,请检查网络"
fi
wget https://download.redis.io/releases/redis-5.0.10.tar.gz
##安装编译环境
yum -y install gcc-c++ gcc make
tar zxvf redis-5.0.10.tar.gz -C /opt
cd /opt/redis-5.0.10/
make
make PREFIX=/usr/local/redis install
##执行配置脚本
cd /opt/redis-5.0.10/
cd utils/
echo -e "\n\n\n\n\/usr\/local\/redis\/bin\/redis-server\n\n" | ./install_server.sh
ln -s /usr/local/redis/bin/* /usr/local/bin/
##备份配置文件
cp -p /etc/init.d/redis_6379 /etc/init.d/redis_6379bak
## service管理服务
mv /etc/init.d/redis_6379 /etc/init.d/redis
sed -i '2a#chkconfig: 2345 90 25' /etc/init.d/redis
chkconfig --add redis
[root@localhost ~]# chmod +x redis
[root@localhost ~]# ./redis.sh
[root@localhost ~]# vim /etc/redis/6379.conf
# bind 127.0.0.1 //70行,注释掉bind监听地址,注释后默认监听所有
protected-mode no //第80行,yes改为no,关闭保护模式,在保护模式下会拒绝所有外来请求
repl-backlog-size 1mb //第414行,设置backlog的大小
##backlog是一个缓冲区,在slave端失连时存放要同步到slave的数据,因此当一个slave要重连时,经常是不需要完全同步的,执行局部同步就足够了。backlog设置的越大,slave可以失连的时间就越长。但是会占用内存空间,因此根据实际工作环境需要进行修改
[root@localhost ~]# service redis restart ##重启生效
Stopping ...
Redis stopped
Starting Redis server...
[root@localhost ~]# vi /etc/redis/6379.conf
# bind 127.0.0.1 //70行,注释掉bind监听地址,注释后默认监听所有
protected-mode no //第80行,yes改为no,关闭保护模式,在保护模式下会拒绝所有外来请求
replicaof 192.168.10.10 6379 //287行,配置slave数据同步源(即master)的 ip 及 端口号
replica-read-only yes //第325行,开启slave的只读功能,默认开启
[root@localhost ~]# scp -p /etc/redis/6379.conf root@192.168.10.30:/etc/redis/6379.conf ##因为两台slave的配置相同,因此可以通过scp的方式将这台redis的配置发送过去,重启服务
[root@localhost ~]# service redis restart
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
4.1 master 写入数据
[root@localhost ~]# redis-cli -h 192.168.10.10 ##登入主服务器master
192.168.10.10:6379>
192.168.10.10:6379> set name zhangsan ##写入数据
OK
192.168.10.10:6379> get name
"zhangsan"
4.2 slave 查看验证
[root@localhost ~]# redis-cli -h 192.168.10.20 ##salve1 查看数据,同步成功
192.168.10.20:6379> keys *
1) "name"
192.168.10.20:6379> get name
"zhangsan"
192.168.10.20:6379>
[root@localhost ~]# redis-cli -h 192.168.10.30 ##slave2 查看数据 ,同步成功
192.168.10.30:6379> keys *
1) "name"
192.168.10.30:6379> get name
"zhangsan"
192.168.10.30:6379>
注意点:哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。
在进行主备切换的时候,会有两种导致数据丢失的情况:
在配置文件中修改如下两条配置
[root@localhost ~]# vi /etc/redis/6379.conf
min-slaves-to-write 1 ##最小slave数为1,表示至少有1台slave
min-slaves-max-lag 10 ##数据复制和同步的延迟不能超过 10 秒
多少情况下 哨兵+主从构 成高可用群集,基于上面的主从部署,我们在添加哨兵群集,实现高可用
[root@localhost ~]# find / -name sentinel.conf ##哨兵模式有个模板配置文件,在编译安装的源码目录下
/opt/redis-5.0.10/sentinel.conf
[root@localhost ~]# cp -p /opt/redis-5.0.10/sentinel.conf /etc/redis/ ##将其拷贝到/etc/redis目录下
[root@localhost ~]# cd /etc/redis/
[root@localhost redis]# ls
6379.conf sentinel.conf
[root@localhost redis]# vim /etc/redis/sentinel.conf
port 26379 //21 行,监听端口号
daemonize yes //26行,开启守护进程
pidfile /var/run/redis-sentinel.pid //31行,PID文件位置
logfile "/var/log/sentinel.log" //36行,日志文件位置
dir /var/lib/redis/sentinel //65行,指定工作目录
sentinel monitor mymaster 192.168.10.10 6379 2 //84行,指定监控的 master 地址及端口号
#---------------插入下面两条优化配置------------------------#
min-slaves-to-write 1 ##最小slave数为1,表示至少有1台slave
min-slaves-max-lag 10 ##数据复制和同步的延迟不能超过 10 秒
[root@localhost ~]# mkdir -p /var/lib/redis/sentinel ##创建配置文件中指定的工作目录
----------因为三台哨兵节点的配置相同,因此将配置文件scp过去,在创建工作目录即可----------------
[root@localhost ~]# scp -p /etc/redis/sentinel.conf root@192.168.10.50:/etc/redis/sentinel.conf
[root@localhost ~]# scp -p /etc/redis/sentinel.conf root@192.168.10.60:/etc/redis/sentinel.conf
----------------------------------------------------------------------------------------
[root@localhost ~]# redis-sentinel /etc/redis/sentinel.conf ##redis-sentinel命令指定配置文件,开启哨兵模式
[root@localhost ~]# netstat -anpt |grep 26379 ##查看端口状态
tcp 0 0 0.0.0.0:26379 0.0.0.0:* LISTEN 8155/redis-sentinel
sentinel myid b8968ce4b0af03b99b387b2e8d2880e23e1c8673 //84行,自动分配密文ID
……省略部分
######并且在文件结尾部分会自动生成下列信息,指明slav地址及其他两台哨兵地址及ID密文
protected-mode no
sentinel known-replica mymaster 192.168.10.20 6379
sentinel known-replica mymaster 192.168.10.30 6379
sentinel known-sentinel mymaster 192.168.10.60 26379 0cca768420585707028ca7371c266472692dcac8
sentinel known-sentinel mymaster 192.168.10.40 26379 8322b2583d5af36eeb93ae3a810c6ec7846037fd
sentinel current-epoch 0
[root@localhost ~]# redis-cli -p 26379
127.0.0.1:26379> info
# Server
redis_version:5.0.10 ##version号
redis_git_sha1:00000000
……省略部分
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.10.10:6379,slaves=2,sentinels=3 ##可以查看到监控的 master ip,以及salve的个数,哨兵的个数
4.1 关闭master服务器,模拟故障
[root@localhost ~]# redis-cli
192.168.10.10:6379> shutdown ##关闭master
4.2 进入哨兵客户端查看主从信息
[root@localhost ~]# redis-cli -p 26379
127.0.0.1:26379> info
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.10.30:6379,slaves=2,sentinels=3 ##已经完成了故障转换,主服务器master变为192.168.10.30(原为192.168.10.20)
127.0.0.1:26379>
4.3 在新master上写入数据测试
[root@localhost ~]# redis-cli -h 192.168.10.30
192.168.10.30:6379> info ##查看节点信息
# Replication
role:master ##角色类型是 master
connected_slaves:2 ##连接两个slave
slave0:ip=192.168.10.20,port=6379,state=online,offset=57725,lag=1
slave1:ip=192.168.10.10,port=6379,state=online,offset=57711,lag=1
192.168.10.30:6379> set score 89 ##可以写入数据,已经不是slave的只读状态了
OK
192.168.10.30:6379> get score
"89"
4.4 在另一台仅存的slave上测试主从
[root@localhost ~]# redis-cli -h 192.168.10.20
192.168.10.20:6379> keys * ##可以查看的新master上插入的键值,确认主从故障切换成功
1) "score"
2) "name"
192.168.10.20:6379> get score
"89"
4.5 查看哨兵节点配置文件末尾信息
[root@localhost ~]# vim /etc/redis/sentinel.conf
protected-mode no
sentinel known-replica mymaster 192.168.10.20 6379
sentinel known-replica mymaster 192.168.10.10 6379 ##配置文件自动修改,将192.168.10.10(原master)降级为slave
sentinel known-sentinel mymaster 192.168.10.60 26379 0cca768420585707028ca7371c266472692dcac8
sentinel known-sentinel mymaster 192.168.10.40 26379 8322b2583d5af36eeb93ae3a810c6ec7846037fd
sentinel current-epoch 1
4.6 重新开启原master(192.168.10.10)进行主从复制验证
[root@localhost ~]# service redis start
Starting Redis server...
[root@localhost ~]# redis-cli -h 192.168.10.10
192.168.10.10:6379> keys * ## 宕机间在新master上写入的数据也被同步过来了
1) "name"
2) "score"
192.168.10.10:6379> get score
"89"
192.168.10.10:6379> set ABC 123 ## 再次开启后不会切换回master,不再具有写的权限
(error) READONLY You can't write against a read only replica.
注意点:在配置监控master时指定了quorum数量,若sentinel哨兵群集发生故障,存活的哨兵服务器数量少于quorum数量,那么哨兵群集将失效。不能再进行故障切换