该文章为知识总结的文章,如果是初学者,建议先从专栏学习:Redis专栏
文章目录
一、容灾策略
1. 如何配置RDB持久化机制
redis.conf文件,也就是/etc/redis/6379.conf,去配置持久化
save 900 1
save 300 10
save 60 10000
每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting,快照
也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成
save可以设置多个,就是多个snapshotting检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件
2. RDB持久化机制的工作流程
(1)redis根据配置自己尝试去生成rdb快照文件
(2)fork一个子进程出来
(3)子进程尝试将数据dump到临时的rdb快照文件中
(4)完成rdb快照文件的生成之后,就替换之前的旧的快照文件
dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照
3. AOF持久化的配置
AOF持久化,默认是关闭的,默认是打开RDB持久化
appendonly yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓
打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写入os cache的,然后每隔一定时间再fsync一下
而且即使AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为aof数据比较完整
可以配置AOF的fsync策略,有三种策略可以选择,一种是每次写入一条数据就执行一次fsync; 一种是每隔一秒执行一次fsync; 一种是不主动执行fsync
-
always: 每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢,那就只能这样了
-
everysec: 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万的,但是可能会失去一秒的数据
-
no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了
# appendfsync always
appendfsync everysec
# appendfsync no
4. AOF rewrite
redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉。
redis中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在redis内存中
所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,到很大很大。
所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致
no-appendfsync-on-rewrite no
当进行rewrite操作时,涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,设置成no意思就是接受阻塞,而设置成yes则相当于将appendfsync设置为no,将可能丢失30s的数据
如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes;如果应用系统无法忍受数据丢失,则设置为no。
在redis.conf中,可以配置rewrite策略
auto-aof-rewrite-percentage 100 # 增长超过100%的比例
auto-aof-rewrite-min-size 64mb # 最小的重写大小
每一次rewrite之后会记住当前文件的大小,当文件大小超过一定比例时就会进行rewrite
比如说上一次AOF rewrite之后,是128mb
然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite
但是此时还要去跟min-size,64mb去比较,256mb > 64mb,才会去触发rewrite
重写的过程:
-
redis fork一个子进程
-
子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
-
redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
-
子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
-
用新的日志文件替换掉旧的日志文件
5. AOF破损文件的修复
如果redis在append数据到AOF文件时,机器宕机了,可能会导致AOF文件破损
用redis-check-aof --fix命令来修复破损的AOF文件,就是删除那些破损的命令
6. AOF和RDB同时工作
- RDB和AOF 重写同一时间只会执行一个
- 同时有RDB snapshot文件和AOF日志文件,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整
7. 企业级的备份策略
RDB中每隔一分钟更改的数据量为多少需要根据业务需求改变
博主设置的为
save 60 1000
AOF一定要打开,fsync磁盘刷新策略使用everysec,重写策略采用就是超过100%,最小大小设置为16mb
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 16mb
然后设置定时任务每天和每个小时都做一个备份,然后每天都将备份上传到云服务器上
备份也可以避免上线出现的BUG,比如12点上线了代码,发现代码有bug,导致代码生成的所有的缓存数据,写入redis,全部错了找到一份11点的rdb的冷备,然后按照上面的步骤,去恢复到11点的数据
二、读写分离
单机Redis最高不超过10万QPS,一般情况下,大量的请求都是读请求
1. redis replication主从复制过程
千万不能关闭主节点的持久化,否则一旦重启主节点,数据将是空,然后将全部的从节点也变成空
当启动一个slave node的时候,它会发送一个PSYNC命令给master node
如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次全量复制
全量复制
- master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。
- 如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。
异步同步
- 当给一个主节点写一条数据的时候,会直接返回给客户端写入成功,然后在异步的把这个命令同步给从节点
断点续传
- 如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
无磁盘化同步
- master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了
repl-diskless-sync yes # 开启无磁盘化,默认是false
repl-diskless-sync-delay 5 # 等待一定时长再开始复制,因为要等更多slave重新连接过来,默认等待5秒
过期key处理
- slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。
2. 主从搭建
从节点
修改绑定的IP地址
bind 0.0.0.0
配置从节点
slaveof 192.168.xxx.xxx 6379
强制读写分离
slave-read-only yes
- 开启了只读的redis slave node,会拒绝所有的写操作,这样可以强制搭建成读写分离的架构
集群安全认证
masterauth redis-pass # master连接口令
主节点
修改绑定的IP地址
bind 0.0.0.0
集群安全认证
requirepass redis-pass # master上启用安全认证
读写分离架构的测试
- 先启动主节点,eshop-cache01上的redis实例
- 再启动从节点,eshop-cache02上的redis实例
使用命令查看各个节点状态
redis-cli -a redis-pass
info replication
3. 快速压测
redis-3.2.8/src
./redis-benchmark -h eshop-cache01
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)
根据你自己的高峰期的访问量,在高峰期,瞬时最大用户量会达到10万+,-c 100000,-n 10000000,-d 50
三、哨兵配置
1. 解决异步复制和脑裂导致的数据丢失
min-slaves-to-write 1 # 从服务器的数量少于1个,或者小于1个从服务器的延迟(lag)值都小于等于10秒时
min-slaves-max-lag 10 # 允许丢失多长时间的数据量
-
要求至少有一个slave数据复制和同步的延迟不能超过10秒
-
如果说一旦所有的slaves,数据复制和同步的延迟都超过了10秒钟,或者当前连接的slave数少于1,那么这个时候,master将会变成只读
上面两个配置可以减少异步复制和脑裂导致的数据丢失
(1)减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟所有的slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据
2. 配置经典三节点哨兵
哨兵的配置文件在sentinel.conf
-
每一个哨兵都可以去监控多个maser-slaves的主从架构
-
因为可能你的公司里,为不同的项目,部署了多个master-slaves的redis主从集群
-
相同的一套哨兵集群,就可以去监控不同的多个redis主从集群
-
你自己给每个redis主从集群分配一个逻辑的名称
类似这种配置,来指定对一个master的监控,给监控的master指定的一个名称,因为后面分布式集群架构里会讲解,可以配置多个master做数据拆分
核心配置:
sentinel down-after-milliseconds mymaster 60000 # 哨兵主管认为的宕机时间(60s)
sentinel failover-timeout mymaster 180000 # 一台机器故障转移超时时间(180s)
sentinel parallel-syncs mymaster 1 # 故障转移每次转移几台机器
上面的三个配置,都是针对某个监控的master配置的,给其指定上面分配的名称即可
上面这段配置,就监控了两个master node
这是最小的哨兵配置,如果发生了master-slave故障转移,或者新的哨兵进程加入哨兵集群,那么哨兵会自动更新自己的配置文件
sentinel monitor master-group-name hostname port quorum
quorum的解释如下:
- 至少多少个哨兵要一致同意,master进程挂掉了,或者slave进程挂掉了,或者要启动一个故障转移操作
- quorum是用来识别故障的,真正执行故障转移的时候,还是要在哨兵集群执行选举,选举一个哨兵进程出来执行故障转移操作
- 假设有5个哨兵,quorum设置了2,那么如果5个哨兵中的2个都认为master挂掉了; 2个哨兵中的一个就会做一个选举,选举一个哨兵出来,执行故障转移; 如果5个哨兵中有3个哨兵都是运行的,那么故障转移就会被允许执行
down-after-milliseconds
- 超过多少毫秒跟一个redis实例断了连接,哨兵就可能认为这个redis实例挂了
parallel-syncs
-
新的master别切换之后,同时有多少个slave被切换到去连接新master,重新做同步,数字越低,花费的时间越多
-
假设你的redis是1个master,4个slave
-
然后master宕机了,4个slave中有1个切换成了master,剩下3个slave就要挂到新的master上面去
-
这个时候,如果parallel-syncs是1,那么3个slave,一个一个地挂接到新的master上面去,1个挂接完,而且从新的master sync完数据之后,再挂接下一个
-
如果parallel-syncs是3,那么一次性就会把所有slave挂接到新的master上去
failover-timeout
- 执行故障转移的timeout超时时长
配置sentinal
mkdir /etc/sentinal
mkdir -p /var/sentinal/5000
mkdir -p /var/log/sentinal/5000
cp /var/sentinal/5000/26379.log /var/log/sentinal/5000/5000.log
cp /usr/local/redis/redis-3.2.8/sentinel.conf /etc/sentinal/5000.conf
vi /etc/sentinal/5000.conf
详细配置
port 5000
bind 0.0.0.0
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
daemonize yes # 配置成后台进程
logfile /var/log/sentinal/5000/5000.log
sentinel auth-pass mymaster redis-pass # 配置主节点的密码
启动哨兵
redis-sentinel /etc/sentinal/5000.conf
连接哨兵查看状态
redis-cli -h 127.0.0.1 -p 5000
info sentinel # 展示基本信息
日志里会显示出来,每个哨兵都能去监控到对应的redis master,并能够自动发现对应的slave
哨兵之间,互相会自动进行发现,用的就是之前说的pub/sub,消息发布和订阅channel消息系统和机制
3. 常用命令
增加sentinal,会自动发现
删除sentinal的步骤
- 停止sentinal进程
SENTINEL RESET * # 在所有sentinal上执行,清理所有的master状态
slave的永久下线
SENTINEL RESET mymaster # 让master摘除某个已经下线的slave
四、Redis-cluster集群配置
1. redis cluster的重要配置
-
cluster-enabled <yes/no>:开启集群
-
cluster-config-file <filename>:这是指定一个文件,供cluster模式下的redis实例将集群状态保存在那里,包括集群中其他机器的信息,比如节点的上线和下限,故障转移,不是我们去维护的,给它指定一个文件,让redis自己去维护的
-
cluster-node-timeout <milliseconds>:节点存活超时时长,超过一定时长,认为节点宕机,master宕机的话就会触发主备切换,slave宕机就不会提供服务
2. 编写配置文件
port 7001
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7001.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7001.pid
dir /var/redis/7001
logfile /var/log/redis/7001.log
bind 192.168.31.187
appendonly yes
3. 准备环境
准备启动脚本并启动
mkdir -p /etc/redis-cluster
mkdir -p /var/log/redis
mkdir -p /var/redis/7001
mkdir -p /var/redis/7002
cd /etc/init.d
cp redis_6379 7001_redis
cp redis_6379 7002_redis
vi 7001_redis
vi 7002_redis
./7002_redis start
./7002_redis start
4. 创建集群
wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
tar -zxvf ruby-2.3.1.tar.gz
./configure -prefix=/usr/local/ruby
make && make install
cd /usr/local/ruby/ruby-2.3.1
cp bin/ruby /usr/local/bin
cp bin/gem /usr/local/bin
wget http://rubygems.org/downloads/redis-3.3.0.gem
gem install -l ./redis-3.3.0.gem
gem list --check redis gem
cp /usr/local/redis-3.2.8/src/redis-trib.rb /usr/local/bin
redis-trib.rb create --replicas 1 192.168.31.187:7001 192.168.31.187:7002 192.168.31.19:7003 192.168.31.19:7004 192.168.31.227:7005 192.168.31.227:7006
redis-trib.rb check 192.168.31.187:7001
5. 添加删除节点
添加
redis-trib.rb add-node 192.168.31.227:7007 192.168.31.187:7001
redis-trib.rb reshard 192.168.31.187:7001
# 迁移slot到一个node的id
删除
先用resharding将数据都移除到其他节点,确保node为空之后,才能执行remove操作
redis-trib.rb del-node 192.168.31.187:7001 bd5a40a6ddccbd46a0f4a2208eb25d2453c2a8db