Redis集群
主从复制
相关文档
简介
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。
主从复制的作用主要包括:
数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
工作流程
主从复制过程大体可以分为三个阶段:
建立连接阶段(即准备阶段)
数据同步阶段
命令传播阶段
阶段1:建立连接阶段工作流程
步骤:
slave端设置master的地址与端口,通过slaveof ip port与master相互连接,在slave端保存master相应的信息
建立socket连接,用于master与slave端传递信息
slave周期性的对master发送ping命令(定时器任务),保证master在线
如果master设置了密码,进行身份验证
slave将端口信息发送给master,master保存slave的端口信息
状态:
slave:保存master的地址与端口
master:保存slave的端口
总体:之间创建了连接的socket
主从连接方式
方式一:客户端发送指令
slaveof
方式二:启动服务器时携带参数
redis-server --slaveof
方式三:服务器配置*
slaveof
断开连接方式:
slaveof no one
阶段2:数据同步阶段工作流程
步骤:
slave发送psync2指令,请求master同步数据
master创建RDB同步数据
slave恢复RDB同步数据
slave向master请求部分同步数据
slave恢复部分同步数据
状态:
slave:具有master端全部数据,包括RDB过程接收的数据
master:保存slave当前数据同步的位置
总体:之间完成了数据克隆
说明
master:
master:
- 如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行
- 复制缓冲区大小设定不合理,会造成数据溢出。如进行全量复制周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态。
repl-backlog-size 1mb
- master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执行bgsave命令和创建复制缓冲区
slave:
- 为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务
slave-serve-stale-data yes|no
- 数据同步阶段,master发送给slave信息可以理解为master是slave的一个客户端,主动向slave发送命令
- 多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果master带宽不足,因此数据同步需要根据业务需求,适量错峰
- slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间节点即是master,也是slave。注意使用树状结构时,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟较大,数据一致性变差,应谨慎选择
部分复制的三个核心要素
服务器的运行id
概念:服务器的运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id
组成:运行id由40位字符组成,是一个随机的十六进制字符
作用:运行id被用于在服务器间进行传输,识别身份
实现方式:运行id在每台服务器启动时自动生成,master在首次连接slave时,会将自己的运行id发送给slave,slave保存此id,通过info Server命令,可以查看节点的runid
复制缓冲区
概念:复制缓冲区,又名复制积压区,是一个先进先出的队列,用于存储服务器执行的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区中(默认大小1M)
组成:偏移量、字节值
作用:用于保存master收到的所有指令(仅影响数据变更的指令)
数据来源:当master接收到主客户端的指令时,除了将指令执行,会将该指令存储到缓冲区中
复制偏移量
概念:一个数字,描述复制缓冲区中的指令字节位置
分类:
master复制偏移量:记录发送给所有slave的指令字节对应的位置(多个)
slave复制偏移量:记录slave接收master发送过来的指令字节的位置(一个)
数据来源:
master:发送一次记录一次
slave端:接收一次记录一次
作用:信息同步,对比master与slave的差异,当slave断线后,恢复数据使用
心跳机制
进入命令传播阶段,master与slave之间需要进行信息交换,采用心跳机制实现双方连接保持在线
-
master心跳:
指令:PING
周期:由repl-ping-slave-period决定,默认为10秒
作用:判断slave是否在线
查询:INFO replication //获取slave最后一次连接的时间间隔,lag项维持在0或1视为正常
-
slave心跳:
指令:REPLCONF ACK {offset}
周期:1秒
-
作用:
向master汇报自己所复制的偏移量,判断是否一致,不一致则获取新的数据变更指令
判断master是否在线
心跳阶段注意事项
- 当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步操作
min-slaves-to-write 2
min-slaves-max-lag 10
注:slave数量小于2或是所有slave的延迟都大于10秒时,强制关闭slave的写功能,停止数据同步
- slave数量和延迟由slave发送REPLCONF ACK命令确认
阶段3:数据同步与命令传播阶段的工作流程
授权访问
master:
配置文件中:
require
执行时:
config set requirepass
config get requirepass
slave:
配置文件中:
masterauth
启动时:
redis-cli -a
执行时:
auth
主从复制常见问题
频繁的全量复制
频繁的全量复制1
-
条件:伴随着系统运行,master的数据量会越来越大,一旦master重启,runid将发生变化,会引起slave的全量复制操作
内部优化调整方案:
master内部创建master_replid变量,使用runid相同的策略生成,长度41位,并发送给所有slave
-
在master关闭时执行 shutdown save,进行RDB持久化,将runid与offset保存到RDB文件中
repl-id repl-offset
通过redis-check-rdb命令可以查看该信息
-
master重启后加载RDB文件,恢复数据
重启后,将RDB文件保存到repl-id与repl-offset加载到内存中
master_repl_id = repl master_repl_offset = repl-offset
通过info命令可以查看该信息
作用:本机保存上次runid,重启后恢复该值,使所有slave认为还是之前的master
频繁的全量复制2
条件:网络环境不佳,出现网络中断,slave不提供服务
出现原因:复制缓冲区过小,断网后slave的offset越界,触发全量复制
解决方案:
- 修改复制缓冲区大侠
repl-backlog-size
建议设置如下:
- 测算冲master到slave的重连平均时长second
- 获取maser平均每秒产生写命令数据总量write_size_per_second
- 最优复制缓冲区空间 = 2 * second * write_size_per_second
频繁的网络中断
频繁的网络中断1
条件:master的CPU占用过高或slave频繁断开连接
-
出现原因:
slave每1秒发送REPLCONF ACK命令到master
当slave接收到了慢查询(key *,hgetall等)时,会占用大量CPU性能
master每1秒调用复制定时函数replicationCron()时,比对slave发现长时间未响应
解决方案:
- 设置合理的超时时间,确认是否释放slave
repl-timeout //该参数定义了超时时间的阈值(默认60秒),超过该值,释放slave
频繁的网络中断2
条件:slave与master断开
-
出现原因:
master发送ping指令的频度较低
master设定超时时间较短
ping指令在网络中存在丢包
解决方案:
- 提高ping指令的发送频度
注意:超时时间repl-timeout的时间至少是ping指令频度的5-10倍,否则slave很容易判定超时
数据不一致
条件:多个slave获取相同数据不同步
出现原因:网络信息不同步,数据发送有延迟
解决方案:
优化主从间的网络环境,通常放置在同一个机房部署,如果使用云服务器要注意此现象
监控主从节点延迟(通过offset)判断,如果slave延迟过大,暂时屏蔽程序对该slave的数据访问
slave-serve-stale-data yes|no
//开启后仅响应info、slaveof等少数命令(慎用,除非对数据一致性要求很高)
哨兵模式
简介
哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。
作用
-
监控
不断的检查master和slave是否正常运行
master存活检测、master与slave运行情况检测
-
通知(提醒)
当被监控的服务器出现问题时,向其他(哨兵间、客户端)发送通知
-
自动故障转移
断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的master的地址
注意:哨兵也是一台redis服务器,只是不提供数据服务,并且通常哨兵配置数量为单数
配置哨兵
通过配置文件配置,配置后使用命令启动
- 配置文件
[root@localhost redis-4.0.6]# cat sentinel.conf | grep -v "#" | grep -v "^$"
port 26379
dir /tmp
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
----------------------------------------------------------------------------
以上分别为:
端口号
路径
监控的master 地址 端口号 哨兵认定数量
连接未响应时长
重设master后同时同步数量
认定下线时间(毫秒)
- 启动命令
redis-sentinel sentinel-端口号.conf
- 连接命令
redis-cli -p 端口号
注意:在服务启动后哨兵的配置文件会发生改变
工作原理
阶段一:监控阶段
-
用于同步各个节点的状态信息
获取各个sentinel的状态(是否在线)
-
获取master的状态
-
master属性
runid
role:master
各个slave的详细信息
-
-
获取所有slave的状态(根据master中的slave信息)
-
slave属性
runid
role:slave
master_host、master_port
offset
......
-
-
工作内容:
第一个sentinel与master进行连接后,发送info指令
建立长期cmd连接,sentinal同时保存所有哨兵状态,master中记录redis实例信息
通过master中的slave信息与其中的slave进行连接并发送info指令
第二个sentinel进入,与master连接发送info指令,发现master端的sentinels中有信息
与第一个sentinel建立连接并同步信息,互相发送ping命令保证对方在线,并于master建立cmd连接
通知阶段
- 工作内容:由其中一个sentinel通过建立的cmd连接获取主从机的工作状态,获取到信息并且与相互连接的其他sentinel之间进行信息同步。
故障转移阶段
- 故障转移阶段引起原因:
其中一台sentinel多次获取master状态失败
将master中标记为SRI_S_DOWN(主观下线)
在sentinel之间传播,表示发现master掉线
其他sentinel连接master
连接失败的sentinel在sentinel之间表示发现master掉线
连接失败的sentinel占sentinel总数超过一半时,将master标记为SRI_O_DOWN(客观下线),确定master掉线
- 选出sentinel担任处置工作:
所有的sentinel同时对其余的sentinel发送一条指令(SENTINEL is-master-down-by...),其中包含:下线的ip、下线的端口、竞选次数、runid
-
通过循环的投票机制,选出一台sentinel担任处置工作
- 投票机制:每个sentinel均是投票者也是参选者,例如:当前有五台sentinel,其中4台sentinel会同时向剩余的一台sentinel发送自己的信息,剩余这台的sentinel会将自己的票投给信息最先到达的sentinel,最后通过所有投票情况选出获得票数最多的sentinel。
-
通过投票机制产生的sentinel从服务器列表中选择出备选的master
-
担任master的选择方式:
在线的
响应速度快的
与原master断开时间短的
-
优先原则:
优先级
offset
runid
-
-
发送指令
向新的master发送slaveof no one,表示与master断开连接
向其他slave发送slaveof 新master的IP 端口,使其他slave与新master产生主从关系
集群
集群简介
集群架构
- 集群就是使用网络将若干台计算机连接到一起,并且提供同一的管理方式,使其对外呈现单机的服务效果
集群作用
分散单台服务器的访问压力,实现负载均衡
分散单台服务器的存储压力,实现可扩展性
降低单台服务器宕机带来的灾难性的影响
Redis集群结构设计
数据存储设计
Redis会将所有的服务器的存储空间等分切割为16384份,切割后的每一个空间称之为一个槽
当需要存储数据时,首先将该数据通过RCR16(循环冗余校验)生成的值与16384取模,得到结果
按照key计算得到的结果,存储至对应的槽中
当有新的服务器加入或是有服务器退出时,已存在服务器将自己的槽位分享给新机器或是退出服务器将其所持有的槽位分享给剩余机器
集群内部通讯设计
当搭建好集群后,所有服务器将会建立连接互相通信,记录各个库中槽的编号数据
当有数据进入,如果第一次访问到的计算机直接命中,则返回数据
-
如果所需存储数据不在第一次访问的计算机中,则返回所在计算机位置,通过该位置访问获取数据
结论:最多两次可以命中数据
集群搭建
-
- 配置文件
cluster-enabled yes|no //启动cluster集群,称为集群中的一个节点
cluster-config-file //启动配置文件位置
cluster-node-time //超时时间,单位为毫秒数
cluster-migartion-barrier //master连接slave的最小数量
- 启动集群方式
redis-trib.rb create --replicas 数字 master的ip:port ... slave的ip:port ...
//replicas用于指定内部结构,数字表示一个master对应几个slave
- 连接至集群方式
redis-cli -c //以集群方式启动客户端
- 主从下线与主从切换
- 当从机下线后,对应的主机发送信息标记从机下线
- 主机下线后,从机多次连接失败,进行故障转移,产生新的master,并标记原有master状态为fail,当原先master上线,自动转换为slave
cluster节点操作命令
cluster nodes //查看集群节点信息
cluster replicate //切换主节点
cluster meet ip:port //新增主节点
cluster forget //忽略一个没有solt的节点
cluster failover //手动故障转移
企业级解决方案
缓存预热
现象
服务器启动后迅速宕机
问题排查
请求数量较高
主从之间数据吞吐量较大,数据同步操作频度较高
解决方案
前置准备工作:
日常例行统计数据访问记录,统计访问频度较高的热点数据
如果热点数据量较大,利用LRU数据删除策略,构建数据留存队列(手工维护或storm+kafka等)
启动前准备工作:
将统计结果中的数据分类,根据级别,redis优先加载级别较高的热点数据
利用分布式多服务器同时进行数据读取,提速数据加载过程
实施:
使用脚本程序固定触发数据预热过程
如果条件允许,使用CDN(内容分发网络)
总结
缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统,从而避免在用户请求的时候,先查询数据库,然后再将数据缓存到redis的问题。用户直接查询事先被预热的数据。
缓存雪崩
现象
系统平稳运行过程中,忽然数据库连接量激增
应用服务器无法及时处理请求
用户访问时返回408、500等错误页面
客户反复刷新页面,请求量继续增大
数据库崩溃
应用服务器崩溃
重启服务器后无效
Redis服务器崩溃
Redis集群崩溃
重启库数据后再次被瞬间浏览击倒
问题排查
在一个较短的时间内,缓存中较多的key集中过期
此周期内请求访问过期的数据,redis未命中,便向数据库获取数据
数据库同时接收到大量的请求无法及时处理
Redis大量请求被积压,开始出现超时现象
数据库流量激增,导致数据库崩溃
重启数据库后Redis缓存中仍然无数据可用
Redis服务器资源被严重占用,服务器崩溃
Redis集群崩溃瓦解
应用服务器无法及时得到数据响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
应用服务器、redis、数据库全部重启,效果不理想
解决方案
道(针对问题如何设计):
对页面内容进行更多的静态化处理
构建多级缓存架构,如:Nginx缓存+Redis缓存+ehcache缓存
检测Mysql严重耗时业务进行优化(对数据库的拼劲排查:例如超时查询、耗时较高事务等)
-
灾难预警机制
监控Redis服务器性能指标
CPU占用率、CPU使用率
内存容量
查询平均响应时间
线程数
-
限流、降级
短时间范围内牺牲一些用户体验,限制一部分请求访问,降低应用服务器压力,待业务低俗运转后再逐步开放访问
术(针对问题如何解决):
LRU与LFU切换
-
数据有效期策略调整
根据业务有效期进行分类错峰(不同品类不同过期时间)
过期时间使用固定时间+随机值的形式,稀释集中到期的key的数量
超热数据使用永久key
-
定期维护(自动+人工)
对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据延时
加锁(慎用)
总结
缓存雪崩就是瞬间过期数据量太大,导致对数据库服务器造成压力。如能够有效避免过期时间集中,可以有效解决雪崩现象的出现(约40%),配合其他策略一起使用,并监控服务器的运行数据,根据运行记录做快速调整。
缓存击穿
现象
系统平稳运行
数据库连接量瞬间激增
Redis服务器无大量key过期
Redis内存平稳,无波动
Redis服务器CPU正常
数据库出现崩溃
问题排查
Redis中某个key过期,该key的访问量巨大
多个对于该数据的请求从服务器直接压到Redis中,均未名中
Redis在短时间内发起了大量对数据库中同一数据的访问
解决方案
术:
预先设计:对于热点数据的key预先设定更长的过期时常
现场调整:监控访问量,对自然流量激增的数据延长过期时间或设置永久性key
后台刷新数据:启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失
二级缓存:设置不同的失效时间,保障不会被同时淘汰
加锁:分布式锁,防止被击穿,但也要注意性能瓶颈(慎重)
总结
缓存击穿就是单个高热数据过期的瞬间,数据访问量较大,未名中redis后,发起了大量对统一数据的数据库访问,导致对数据库服务器造成压力。应对策略应该在业务数据分析与预防方面进行,配合运行监控与即时调整策略,毕竟单个key的过期监控难度较高,配合雪崩处理策略即可。
缓存穿透
现象
系统平稳运行过程中
应用服务器流量随时间增量较大
Redis服务器命中率随时间逐步降低
Redis内存平稳无压力
Redis服务器CPU占用激增
数据库服务器压力激增
数据库崩溃
问题排查
获取的数据在数据库中也不存在,数据库查询未得到对应数据
Redis获取到null数据未进行持久化,直接返回
重复出现访问不存在的数据
出现黑客攻击服务器
解决方案
术:
缓存null:对于查询结果为null的数据进行缓存(长期使用,定时清理),设定短时限(30-60s,最多5分钟)
-
白名单策略
提前预热各种分类数据id对应bitmaps,id作为bitmaps的offset,相当于设置数据白名单。当正常加载时放行,加载异常数据时直接拦截(效率偏低)
使用布隆过滤器
-
实时监控:实时监控redis命中率(业务正常范围时,通常会有一个波动值)与null数据的占比
非活动时段波动:通常检测3-5倍,超过5倍纳入重点排查对象
活动时段波动:通常检测10-50倍,超过50倍纳入重点排查对象
-
key加密
问题出现后,临时启动防灾业务key,对key进行业务层传输加密服务,设定校验程序,对key进行校验,不满足校验则驳回数据访问
总结
缓存穿透访问了不存在的数据,跳过了合法数据的redis数据缓存阶段,每次都对数据库进行访问,导致对数据库服务器造成压力。通常此类数据的出现量是一个较低的值,当出现此类情况以毒攻毒,并及时报警。应对策略应在临时预案防范多做文章。
无论是黑名单还是白名单,都是对整体系统的压力,警报解除后需要尽快移除。
性能指标监控
监控指标
性能指标:Performance(响应时间、每秒处理请求数、缓存命中率)
内存指标:Memory(已使用内存、内存碎片率、由于最大内存策略被移除key的数量、阻塞操作导致阻塞的量)
基本活动指标:Basic activity(客户端连接数、Slave数量、最近一次主从交互后的秒数、数据库中key值的总数)
持久性指标:Persistence(最后一次持久化到磁盘的时间戳、最后一次持久化后的数据库更改数)
错误指标:Error(达到最大连接数后拒绝的连接数、key的未命中次数、主从断开的时间)