Redis
主从复制
一、当新数据进入Redis时,如果内存不足怎么办
- Redis使用内存存储数据时,执行前都会调用freeMemoryIfNeedled()检测内存是否充足,如果内存不满足新加入数据的最低存储要求,Redis要临时删除一写数据为当前指令清理存储空间,清除数据的策略称为逐出算法
- 逐出数据的过程不是100%清理出足够的空间,如果不成功反复执行,如果达不到存储要求,抛出异常,设置MaxMemory为物理内存的百分之50~60
二、主从复制
2.1、同步阶段
-
同步阶段master说明
-
如果master的数据量过大,数据同步阶段应该避开流量高峰期,避免早场master阻塞,影响业务正常运行。
-
复制缓冲区大小设定不合理,导致数据溢出,如果全量复制周期太长,部分复制时发现数据已经存在丢失现象,那么必然会进行第二次的全量复制,导致slave进入死循环
-
通过 real-blocklog-size ?mb
-
master单机内存占用内存的比例不应该过大建议50 - 70,百分之30 - 50 的内存用于bgsave和创建复制缓冲区
-
-
同步阶段savle说明
-
避免slave全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭期间对外服务
-
Slave-server-table-date yes|no
-
数据同步阶段,master发送给slave信息可以理解为master是slave的一个客户端,主动向slave发送命令
-
多个slave同时对master请求数据同步,master发送的RDB文件过多,回对带宽造成巨大冲击,如果master带宽不足,因此数据同步需要根据业务需求,适量错峰
-
2.2、复制阶段
-
命令传播阶段的部分复制
- 命令传播阶段出现了断网现象
- 网络闪断闪连,忽略
- 短时间网络中断,部分复制
- 产时间网络中断,全量复制
- 命令传播阶段出现了断网现象
-
部分复制三个要素
- 服务器的运行ID(RUN id)
- 每个服务器运行时的身份识别码,一台服务器可以生成多个id
- id由40位字符组成,随机16进制字符
- 运行id被用于在服务器之间进行传输,识别身份。如果想两次操作均对于一个服务器执行,必须每次操作携带对应的运行id,方便识别
- 运行id在每台服务器启动时自动生成,master在首次连接slvae时,会将自己的运行ID发送给slave,slave保存次id,通过info server命令,可以查看节点的run id
- 主服务器的复制积压缓冲区
- 由偏移量和字节值组成
- 通过offset区分不同的slave当前传播数据传播的差异,master记录已发送的信息对应的offset,slave记录已接受的信息对应的offser
- 缓冲区是一个FIFO的队列,由于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,保存在缓冲区中,缓冲区的默认大小为1M,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,新元素会被放入队列
- 主从服务器的复制偏移量
- 通过偏移量来判断,master向slave发送的数据是通过全量复制还是部分复制
- 服务器的运行ID(RUN id)
2.3、工作流程
- 首先slave发送一个指令
psync? -1 由于不知道和所以发送的数据为?和-1 - master收到指令之后,执行bgsave生成RDB文件,记录当前的复制偏移量,发送给slave和,发送+FULLRESYNC runid offset,通过Socket发送RDB文件给slave
- slave收到 +FULLRESYNC,保存master的runid和offset,清空当前的slave的数据,通过Socket接受RDB文件,恢复RDB数据
- 在全量复制的时候主机可能正在进行写操作,写入操作会影响offset,slave会一直发送指令(心跳机制),所以使用了积压缓冲区存入数据,当全量复制完成之后,接下来进行部分复制
- slave发送指令
psyncrunid offset ,master接收到指令之后,判断runid是否于master匹配,判断offset是否匹配复制缓冲区- 如果runid或offset有一个不满足就会执行全量复制
- 如果runid或offset校验通过,offset与offset相同则忽略
- 如果不相同则发送+CONTINUE offset,通过offset发送复制缓冲区中offset到offset的数据
- slave收到+CONTINUE指令,保存master的offset,接收到信息后执行bgwriteaof,恢复数据
三、心跳机制
-
进入命令传播阶段,master和slave间进行信息交换,使用心跳机制进行维护,实现保持双方在线
- master心跳内部指令:PING
- 周期:由real-ping-slave-period决定,默认10s
- 作用:判断slave是否在线
- 查询:INFO replication 获取slave最后一次连接时间间隔,lag项维持在0,1视为正常
- slave心跳任务
- 内部指令:REPLCONF ACK(offset)
- 周期:1s
- 作用1:汇报slave自己的复制偏移量,获取最新的数据变更指令
- 作用2:判断master是否在线
- master心跳内部指令:PING
-
心跳阶段注意事项
-
当slave多数掉线,或延迟过高,master为了保障数据的稳定性,将拒绝所有信息同步操作
-
Min-slaves-to-write 2
Min-slave-max-lag 8
- slave数量少于2个,或者将所有slave的延迟都大于等于8s,强制关闭master写功能,停止数据同步
-
slave数量由slave发送REPLCONF ACK命令做确认
-
slave延迟由slave发送REPLCONF ACK命令确认
-
四、主从复制的常见问题
4.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-id master_repl_offset = real-offset
- 通过INFO命令可以查看信息
- 作用:本机保存上次runid,重启后恢复该值,使所有slave认为还是之前的master
4.2、频繁的全量复制2
- 问题现象:网络环境不佳,出现网络中断,slave不断提供服务
- 问题原因:复制缓冲区过小,断网后slave的offset越界,触发全量复制
- 最终结果:slave反复进行全量复制
- 解决方案,修改复制缓冲区大小
repl-blacklog-size ?mb
- 建议设置如下
- 测算从master到slave的重连平均时长second
- 获取master平均每秒产生写命令数量总量write_size_per_second
- 最优复制缓冲区空间 = 2 * second * write_size_per_second
4.3、频繁的网络中断
- 问题现象:master的cpu占用过高或slave频繁断开链接
- 问题原因
- slave每一秒发送REPLCONF ACK命令到master
- 当slave接到了慢查询(keys * ,hgetall等),会大量占用cpu
- master每一秒调用复制定时函数replicationCron(),对比slave发现长时间没有进行响应
- 最终结果:master各种资源(输出缓冲区,带宽,链接等)被严重占用
- 解决方案:通过设置合理的超时时间,确认是否释放slave
repl-timeout seconds
- 该参数定义了超时时间的阈值默认60s,超过改时间,释放slave
4.4、频繁的网络中断2
- 问题现象:slave和master断开链接
- 问题原因:
- master发送ping指令频率较低
- master设定超市时间较短
- ping指令在网络中存在丢包
- 解决方案
- 提高ping指令发送的频率
repl-ping-slave-preiod seconds
- 超时时间repl-time的时间至少是ping指令频率的5-10倍,否则slave容易判定超时
4.5、数据不一致
- 问题描述:多个slave获取相同数据不同步
- 问题原因:网络信息不同步,数据发送有延迟
- 解决方案:
- 优化主从间的网络环境,通常放置在同一个机房部署,如使用阿里云服务器时要注意此现象
- 监控主从节点延迟通过offset判断,如果slave延迟过大,展示屏蔽程序对该slave的数据访问
slave-serve-stale-date yes|no
- 开启后仅响应info、slaveof等少数命令(慎用,除非对数据一致性要求非常高)
哨兵模式
一、定义
哨兵(sentinel)是一种分布式系统,用于对主从的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master,哨兵也是多个进行监控
- 监控
- 不断地检查master和slave是否正常运行
- master存活检测、master与slave运行情况监测
- 告知:当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知
- 自动鼓胀转移:断开master与slave的连接,选取一个slave作为master,将其他slave连接新的master,并告知客户端新的服务器地址
- 哨兵也是一台redis服务器,不提供相关服务,通常哨兵的数量为单数
二、配置
- 设置哨兵监听的主服务器信息,sentinel_number表示参与投票的哨兵数量
Sentinel monitoer master_name master_host master_port master_number
- 设置判定服务器宕机时长,该设置该控制是否进行主从切换
Sentinel down-after-milliseconds master_name million_seconds
- 设置故障切换的最大超时时长
sentinel failover_timeout master_name million_seconds
- 设置主从切换后,同时进行数据同步的slave数量,数值越大,要求网络资源越高,数值越小,同步时间越长
Sentinel parallel-syncs master_name sync_slave_number
三、工作原理
主动切换
- 哨兵在进行主从切换过程中经历三个阶段
- 监控
- 通知
- 故障转移
- 阶段一:用于同步各个节点的状态信息
- 获取各个sentinel的状态(是否在线)
- 获取master的状态
- master属性
- runid
- role:master
- 各个slave的详细信息
- master属性
- 获取所有slave的状态(根据master中的slave信息)
- slave信息
- runid
- role:slave
- master_host,master_port
- offset
- ...
- slave信息
- 阶段二:通过发送hello指令,实现信息同步
- 阶段三:
- 如果哨兵一直向机器发送hello,但是机器挂掉了,机器上会标记"flags:SRI_S_DOWN",之后哨兵之间会通知机器挂掉,然后所有哨兵都会发送hello去判断,在终端中,
+sDOWN表示一台哨兵认为一个机器挂掉了,+oDown表示所有的哨兵都认为机器挂掉了 - 哨兵们之间进行投票,最终得票多的哨兵就会成为头头,如果失败就会loop,直到选取成功。
- 服务器列表中挑选备用master
- 不在线的
- 响应慢的
- 与原master断开时间久的
- 优先原则
- 优先级
- offset
- runid
- 发送指令sentinel
- 向新的master发送slaveof no one
- 向其他slave发送slaveof 新masterIP端口
- 如果哨兵一直向机器发送hello,但是机器挂掉了,机器上会标记"flags:SRI_S_DOWN",之后哨兵之间会通知机器挂掉,然后所有哨兵都会发送hello去判断,在终端中,
问题解决
一、缓存预热
- 问题排查
- 请求数量较高
- 主从之间数据量吞吐量较大,数据同步操作频度较高
- 前置准备工作
- 日常例行统计数据访问记录,统计访问频度较高的热点数据
- 利用LRU数据删除策略,构建数据留存队列
- 准备工作:
- 将统计结果中的数据分类,根据级别,redis优先加载级别高的热点数据
- 利用分布式服务器同时进行数据读取,提速数据加载过程
- 热点数据主从同时预热
- 实施:
- 是用脚本程序固定触发数据预热过程
- 如果条件允许,使用了CDN内容分发网络,效果会更好
- 小结:缓存预热就是系统启动前,提前将相关数缓存数据直接加载到缓存系统。避免用户在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据。
二、缓存雪崩
-
数据库服务器崩溃(1)
- 系统运行平稳过程中,忽然数据库连接量激增
- 应用服务器无法及时处理请求
- 大量408,500页面出现
- 客户反复刷新页面获取数据
- 数据库崩溃
- 重启应用服务器无效
- redis服务器崩溃
- redis集群崩溃
- 重启数据库后再次被瞬间流量放倒
-
问题排查
- 在一个较短的时间内,缓存中较多的key集中过期
- 此周期内请求访问过期的数据,redis未命中,redis向数据库中获取数据
- 数据库同时接收到大量的请求无法及时处理
- reids大量请求被挤压,开始出现超时现象
- 数据库流量激增,数据库崩溃
- 重启后仍然对缓存中无数据可用
- redis服务器资源被严重占用,redis服务器崩溃
- redis集群呈现崩塌,集群瓦解
- 应用服务器无法及时得到数据库响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
- 应用服务器,redis,数据库全部重启,效果不理想
-
解决方案(道)
- 更多的页面静态化处理
- 构建多级缓存架构
- nginx缓存+redis缓存+ehcache缓存
- 检测Mysql验证耗时业务进行优化
- 对数据库的瓶颈排查:例如超时查询,耗时较高事务等
- 灾难预警机制
- 监控redis服务器性能指标
- CPU占用、使用率
- 内存容量
- 查询平均响应时间
- 线程数
- 监控redis服务器性能指标
- 限流、降级
- 短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步开放
-
解决方案(术)
- LRU和LFU切换
- 数据有效期策略调整
- 根据业务数据有效期进行分类措施,A类90min,B类80min,C类70min
- 过期时间使用固定时间+随机值的形式,稀释集中到期的key的数量
- 超热数据使用永久key
- 定期维护(自动+人工)
- 对即将过期数据做访问量分析,确认是否掩饰,配合访问量统计,做热点数据的延时
-
加锁
-
小结:缓存雪崩就是瞬间过期数量太大,导致对数据库服务器造成压力,如果能有效避免过期时间集中,可以有效解决雪崩现象的出现(约40%),配合其他策略一期使用,并监控服务器的运行数据,根据运行记录做快速调整
三、缓存击穿
- 数据库服务器崩溃(2)
- 系统平稳运行过程中
- 数据库连接量瞬间激增
- redis服务器无大量key过期
- redis内存平稳,无波动
- redis服务器cpu正常
- 数据库崩溃
- 问题排查
- redis某个key过期了,该key访问量巨大
- 多个数据请求从服务器直接压道redis后,均未命中
- redis在短时间内发起了大量对数据库中同一数据的访问
- 解决方案(术)
- 预先设定
- 以电商为例,每个商检根据店铺等级,指定若干款主打商品,在购物节期间,加大此类信息key的过期时长
- 现场调整
- 监控访问量,对自然流量激增的数据延长过期时间或设置为永久key
- 后台刷新数据
- 启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失
- 二级缓存
- 设置不同的失效时间,保障不会被同时淘汰
- 加锁
- 分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎用
- 预先设定
四、性能监控指标
-
性能指标:perfromance
-
响应请求的平均时间
-
Latency
-
平均每秒处理请求总数量
-
Instantaneous_ops_per_sec
-
缓存查询命中率
-
Hit_rate(calculated)
-
-
内存指标:Memory
-
当前内存使用量
-
Used_memory
-
内存碎片率(关系碎片整理)
-
Mem_fragmentation_ratio
-
为避免内存溢出删除key的总数量
-
Evicted_keys
-
基于阻塞操作(BLPOP等)影响的客户端数量
-
Blocked_clients
-
-
基本活动指标:Basic_activity
-
当前客户端连接总数
-
Connected_clients
-
当前连接slave总数
-
Connected_slaves
-
最后一次主从信息交换距现在的秒数
-
Master_last_io_seconds_ago
-
key的总数
-
Keyspace
-
-
持久性指标:Persistence
-
当前服务器最后一次RDB持久化的时间
-
rdb_last_save_time
-
当前服务器最后一次RDB持久后数据变化总量
-
rdb_changes_since_last_save
-
-
错误指标:Error
-
被拒绝连接的客户端总数
-
Rejected_connections
-
key未命中的总次数
-
Keyspace_misses
-
主从断开的秒数
-
Master_link_down_since_seconds
-
五、监控方式
- 工具
- Cloud Insight Redis
- Prometheus
- Redis—stat
- redis—faina
- RedisLive
- zabbix
- 命令
- benchmark
- redis-cli
- monitor
- slowlog