Redis高可用

62次阅读

共计 2733 个字符,预计需要花费 7 分钟才能阅读完成。

一、reids 集群

1、扩容集群

准备新节点 =》加入集群 =》迁移槽和数据
新节点:

  • 集群模式
  • 配置和其他节点统一
  • 孤立节点

加入集群作用

  • 为它迁移槽和数据实现扩容
  • 作为从节点负责故障转移
    建议使用 redis-trib.rb 能够避免新节点加入其他集群,造成故障
    迁移槽和数据
  • 槽迁移计划
  • 迁移数据
  • 对目标节点发送
  • 添加从节点

步骤

  1. 目标节点准备导入槽
  2. 源节点准备导出槽
  3. 获取 slot 下 count 个键
  4. 批量迁移相关键的数据
  5. 循环迁移键
redis-cli -p 7000 cluster meet 127.0.0.1 7006
redis-trib.rb reshard 127.0.0.1 7000
2、收缩扩容

下线迁移槽
忘记节点:cluster forget downNodeId
关闭节点

redis-trib.rb reshard –from nodeId –to nodeId –slots 1366 127.0.0.1:7000
redis-trib.rb del-node 127.0.0.1:7000 nodeId

3、客户端路由

moved 重定向

  • 发送键命令
  • 计算槽和对应节点
  • 回复 moved
  • 重定向发送命令

槽命中:直接返回
槽命不中:moved 异常
ask 重定向

  • 发送键命令
  • 回复 ask 转向
  • asking
  • 发送命令
  • 响应结果

moved 和 ask:两者都是客户端重定向,moved 槽已经确定迁移,ask 槽还在迁移中
smart 客户端

  • 从集群中选一个可运行节点,使用 cluster slots 初始化槽和节点映射
  • 将 cluster slots 的结果映射到本地,为每个节点创建 JedisPool
  • 准备执行命令

批量优化的方法:
串行 mget,串行 IO,并行 IO,hash_tag

4、故障转移

故障发现:
通过 ping/pong 消息实现故障发现,不需要 sentinel
主观下线和客观下线

主观下线:某个节点认为另一个节点不可用,偏见
客观下线:当半数以上持有槽的主节点都标记某节点主观下线

故障恢复:

资格检查

  • 每个节点检查与故障主节点的断线时间
  • 超过 cluster-node-timeout * cluster-slave-validity-factor 取消资格
  • cluster-slave-validity-factor:默认是 10

准备选举时间

选举投票

替换主节点

  • 当前从节点取消复制为主节点
  • 执行 clusterDelSlot 撤销故障主节点负责的槽,并执行 clusterAddSlot 把这些槽分配给自己
  • 向集群广播自己的 pong 消息,表明已经替换了故障从节点
5、集群完整性

cluster-require-full-coverage 默认为 yes

  • 集群中 16384 个槽全部可用:保证集群完整性
  • 节点故障或者正在故障转移

大多业务无法容忍,cluster-require-full-coverage 建议设置为 no

带宽消耗

  • 官方建议: 1000 个节点
  • PING/PONG 消息
  • 不容忽视的带宽消耗

三个方面:消息发送频率;消息数据量;节点部署的机器规模

避免大集群:避免多业务使用一个集群,大业务可以多集群
cluster-node-timeout:带宽和故障转移速度的均衡
尽量均匀分配到多机器上:保证高可用和带宽

数据倾斜

  • 节点和槽分配不均

redis-trib.rb info ip:port 查看节点,槽,键值分布
redis-trib.rb rebalance ip:port 重新分配槽,节点,键值

  • 不同槽对应键值数量差异较大
  • 包含 bigkey
  • 内存相关配置不一致

请求倾斜

热点 key:重要的 key 或者 bigkey
优化:
避免 bigkey
热键不要使用 hash_tag
当一致性不高时,可用使用本地缓存 + MQ

集群读写分离

只读连接:集群模式的从节点不接受任何读写请求

  • 重定向到负责槽的主节点
  • readonly 命令可以读 连接级别的命令

读写分离:更加复杂

  • 同样的问题:复制延迟 读取过期数据 从节点故障
  • 修改客户端:cluster slaves nodeId

数据迁移
官方迁移工具:redis-trib.rb import
只能从单机迁移到集群
不支持在线迁移:source 需要停写
不支持断点续传
单线程迁移:影响速度

集群和单机

集群限制
key 批量操作支持有限:mget,mset 必须再一个 slot
key 事物和 lua 支持有限:操作的 key 必须在一个节点
key 时数据分区的最小粒度:不支持 bigkey 分区
不支持多个数据库:集群模式下只有一个 db 0
复制只支持一层:不支持树形复制结构

二、reids 缓存成本和收益

1、缓存的受益和成本

受益:

  • 加速读写

通过缓存加速读写速度

  • 降低后端负载

后端服务器通过前端缓存降低负载,业务端使用 Redis 降低后端 Mysql 负载

成本:

  • 数据不一致:

缓存从和数据层有时间窗口不一致,和更新策略有关

  • 代码维护成本

多了一层缓存逻辑

  • 运维成本

使用场景

  • 降低后端负载

对高消耗的 SQL=>join 结果集 / 分组统计结果缓存

  • 加速请求响应

利英 Redis/Memcache 优化 IO 响应时间

  • 大量写合并为批量写

如计数器先 Redis 累加再批量写 DB

2、缓存更新策略
  • LRU/LFU/FIFO 算法剔除
  • 超时剔除
  • 主动更新:开发控制生命周期
建议
低一致性:最大内存和淘汰策略
高一致性 超时剔除和主动更新结合,最大内存和淘汰策略兜底
3、缓存粒度控制
  • 通用性:全量属性更好
  • 占用空间:部分属性更好
  • 代码维护:表面上全量属性更好
4、缓存穿透问题

大量请求不命中
原因:

  • 业务代码自身问题
  • 恶意攻击,爬虫等等

发现:

  • 业务的响应时间
  • 业务本身问题
  • 相关指标 总调用数 缓存层命中数 存储层命中数

解决方案:

  • 缓存空对象

    两个问题:
    需要更多的键
    缓存层和存储层数据短期不一致

  • 布隆过滤器拦截
5、缓存雪崩优化

由于 cache 服务承载大量请求,当 cache 服务器异常 / 脱机,流量直接压向后端组建,造成级联故障

优化方案:
保证缓存高可用性

  • 个别节点,个别机器,甚至是机房
  • 依赖隔离组件为后端限流
  • 提前演练:例如压力测试
6、无底洞优化

优化 IO 的几种方法

  • 命令本身优化:例如慢查询 keys hgetall bigkey
  • 减少网络通信次数
  • 降低接入成本:例如客户端长连接 / 连接池 NIO 等
  • 串行 mget 串行 IO 并行 IO hash_tag
7、热点 key 的重建优化

三个目标

  • 减少重缓存的次数
  • 数据尽可能一致
  • 减少潜在危险

    两个解决

  • 互斥锁
  • 永远不过期

缓存层面:没有设置过期时间
功能层面:为每个 value 添加逻辑过期时间,但发现超过逻辑过期时间后,会使用单独的线程去构建缓存

缓存收益:加速读写,降低后端存储负载
缓存成本 缓存和存储数据不一致性 代码维护成本 运维成本
推荐结合剔除、超时、主动更新三种方案共同完成
穿透问题:使用缓存空对象和布隆过滤器来解决,注意他们各自的使用场景和局限性
无底洞问题:分布式缓存中,有更多的机器不保证有更高的性能
雪崩问题:缓存层高可用,客户端降级 提前演练
热点 key 问题 互斥锁 永远不过期 能够子啊一定程度上解决热点 key 的问题

正文完
 0