Redis高可用

一、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的问题

你可能感兴趣的:(nosql,redis)