Redis的补充

382 阅读14分钟

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发送的数据是通过全量复制还是部分复制

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发送指令 psync runid 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是否在线
  • 心跳阶段注意事项

    • 当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的详细信息
    • 获取所有slave的状态(根据master中的slave信息)
      • slave信息
        • runid
        • role:slave
        • master_host,master_port
        • offset
        • ...
  • 阶段二:通过发送hello指令,实现信息同步
  • 阶段三:
    • 如果哨兵一直向机器发送hello,但是机器挂掉了,机器上会标记"flags:SRI_S_DOWN",之后哨兵之间会通知机器挂掉,然后所有哨兵都会发送hello去判断,在终端中,+sDOWN表示一台哨兵认为一个机器挂掉了,+oDown表示所有的哨兵都认为机器挂掉了
    • 哨兵们之间进行投票,最终得票多的哨兵就会成为头头,如果失败就会loop,直到选取成功。
    • 服务器列表中挑选备用master
      • 不在线的
      • 响应慢的
      • 与原master断开时间久的
      • 优先原则
        • 优先级
        • offset
        • runid
    • 发送指令sentinel
      • 向新的master发送slaveof no one
      • 向其他slave发送slaveof 新masterIP端口

问题解决

一、缓存预热

  • 问题排查
    • 请求数量较高
    • 主从之间数据量吞吐量较大,数据同步操作频度较高
  • 前置准备工作
    • 日常例行统计数据访问记录,统计访问频度较高的热点数据
    • 利用LRU数据删除策略,构建数据留存队列
  • 准备工作:
    • 将统计结果中的数据分类,根据级别,redis优先加载级别高的热点数据
    • 利用分布式服务器同时进行数据读取,提速数据加载过程
    • 热点数据主从同时预热
  • 实施:
    • 是用脚本程序固定触发数据预热过程
    • 如果条件允许,使用了CDN内容分发网络,效果会更好
  • 小结:缓存预热就是系统启动前,提前将相关数缓存数据直接加载到缓存系统。避免用户在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据。

二、缓存雪崩

  • 数据库服务器崩溃(1)

    • 系统运行平稳过程中,忽然数据库连接量激增
    • 应用服务器无法及时处理请求
    • 大量408,500页面出现
    • 客户反复刷新页面获取数据
    • 数据库崩溃
    • 重启应用服务器无效
    • redis服务器崩溃
    • redis集群崩溃
    • 重启数据库后再次被瞬间流量放倒
  • 问题排查

    • 在一个较短的时间内,缓存中较多的key集中过期
    • 此周期内请求访问过期的数据,redis未命中,redis向数据库中获取数据
    • 数据库同时接收到大量的请求无法及时处理
    • reids大量请求被挤压,开始出现超时现象
    • 数据库流量激增,数据库崩溃
    • 重启后仍然对缓存中无数据可用
    • redis服务器资源被严重占用,redis服务器崩溃
    • redis集群呈现崩塌,集群瓦解
    • 应用服务器无法及时得到数据库响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
    • 应用服务器,redis,数据库全部重启,效果不理想
  • 解决方案(道)

    • 更多的页面静态化处理
    • 构建多级缓存架构
      • nginx缓存+redis缓存+ehcache缓存
    • 检测Mysql验证耗时业务进行优化
      • 对数据库的瓶颈排查:例如超时查询,耗时较高事务等
    • 灾难预警机制
      • 监控redis服务器性能指标
        • CPU占用、使用率
        • 内存容量
        • 查询平均响应时间
        • 线程数
    • 限流、降级
      • 短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步开放
  • 解决方案(术)

    • 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