一、reids集群
1、扩容集群
准备新节点 =》 加入集群 =》 迁移槽和数据
新节点:
- 集群模式
- 配置和其他节点统一
- 孤立节点
加入集群作用
- 为它迁移槽和数据实现扩容
- 作为从节点负责故障转移
建议使用redis-trib.rb能够避免新节点加入其他集群,造成故障
迁移槽和数据 - 槽迁移计划
- 迁移数据
- 对目标节点发送
- 添加从节点
步骤
- 目标节点准备导入槽
- 源节点准备导出槽
- 获取slot下count个键
- 批量迁移相关键的数据
- 循环迁移键
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的问题
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。