一站式学习Redis, 从入门到高可用分布式实践-10-深入redis cluster

本章针对redis cluster的集群伸缩、请求路由、故障转移等方面进行分析说明

  1. 集群伸缩原理

    集群伸缩 = 槽和数据在节点之间的移动

  2. 扩容集群

  • 准备新节点
    集群模式、配置和其它节点统一、启动后是孤儿节点
redis-server redis-8006.conf
redis-server redis-8007.conf
  • 加入集群
cluster meet ip 8006
cluster meet ip 8007

加入集群后观察集群配置
cluster nodes
加入集群的作用: 为他迁移槽和数据,实现扩容;作为从节点负责故障转移
加入集群的第2中方法(推荐),redis-cli命令:
redis-cli add-node new_host:new_port existing_host:existing_port --slave --master-id
redis-cli add-node ip:8006 ip:8007
建议使用redis-cli能够避免新节点已经加入了其它集群,造成故障

  1. 迁移槽和数据
  • 槽迁移计划
  • 迁移数据

    迁移数据完整流程图

    迁移数据伪代码
  1. 集群扩容演示
    启动两台实例
redis-server redis-8006.conf
redis-server redis-8007.conf

加入到cluster中

redis-cli -p 8000 cluster meet ip 8006
redis-cli -p 8000 cluster meet ip 8007

主从分配
redis-cli -p 8007 cluster replicate 4bc81058b7051845c5xxx46c4f14e57fd
此时查看集群状态
redis-cli -p 8006 cluster nodes
可以看到8006 master节点还没有负责任何的槽

  1. 使用redis-cli迁移槽数据
    redis-cli --cluster reshard ip:8000
    提示:How many slots do you want to move (from 1 to 16384)? 4096
    提示:What is the receiving node ID? 4bc81058b7051845cxxxxa046c4f14e57fd
    提示:Source node #1: all
    提示:Do you want to proceed with the proposed reshard plan (yes/no)? yes
    迁移成功,查看集群状态
    redis-cli -p 8006 cluster nodes
    整个迁移的过程中对客户端来说是无痛的,相当强大!

  2. 收缩集群

  • 迁移槽
    redis-cli --cluster reshard ip 8006
  • 让集群中其它节点忘记该节点
    切记,要先下线从节点:(如果先下主节点,会触发故障转移,所以先下从节点,在下主节点)
    redis-cli --cluster del-node ip:8000 317e195ac96xxxxxa69ff28db82c782
    redis-cli --cluster del-node ip:8000 4bc81058b7xxxxx5cx046c4f14e57fd
    查看集群状态
    redis-cli -p 8000 cluster nodes
    发现8006、8007已经不在集群当中了,至此,缩容完成
  1. moved重定向
  • 获取键所在的槽命令
    redis-cli -p 8000 cluster keyslot name
    cluster keyslot name
  1. ASK重定向
  • moved和ask的区别
    两者都是客户端重定向、moved槽已经确定迁移、ask槽还在迁移中
  1. smart客户端实现原理
  • smart客户端的目标:追求性能
    从集群中选取一个可运行节点,使用cluster slots初始化槽和节点映射
    将cluster slots的结果映射到本地,为每个节点创建redisPool
    准备执行命令
  1. redis-py-cluster使用
    安装:pip install redis-py-cluster
    基本使用
from rediscluster import RedisCluster

# 需要至少一个节点进行集群发现,建议使用多个节点
startup_nodes = [
    {"host": "ip", "port": "8000"},
    {"host": "ip", "port": "8001"},
    {"host": "ip", "port": "8002"},
    {"host": "ip", "port": "8003"},
    {"host": "ip", "port": "8004"},
    {"host": "ip", "port": "8005"},
]

# 链接redis集群
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)

# 设置获取值
rc.set("yuwen", 80)
ret = rc.get("yuwen")

print(ret)

使用技巧:
单例:内置了所有节点连接池
无序手动借还连接池

  1. 批量操作优化
  • 串行mset、mget(性能差一些,需要n次的网络时间)
  • 串行IO
  • 并行IO
  • hash_tag
    四种方案优缺点:
  1. 故障发现
  • redis sentinel一样也分为主观下线和客观下线
  • 通过ping/pong消息实现故障发现,不依赖于sentinel
    主观下线的基本流程

    客观下线:
    当半数以上持有槽的主节点都标记某节点主观下线
    客观下线的两个操作:通知集群内的所有节点标记故障节点为客观下线,通知故障节点的从节点触发故障转移流程
  1. 故障恢复
  • 资格检查

  • 准备选举时间

  • 选举投票

  • 替换主节点

  1. 故障模拟
  • 执行 kill -9 节点模拟宕机
  • 观察客户端故障恢复时间
  • 观察各节点日志

redis cluster开发运维常见为题

  1. 集群完整性

  2. 带宽消耗

    节点带宽的优化:

  3. pubsub(广播)
    集群中发布订阅会存在问题,当集群中的一个节点进行发布消息的时候,所有与其它节点都会订阅到该消息,加重了带宽压力
    限订阅
    redis-cli -p 8001 subscribe cluster_p
    在发布
    redis-cli -h ip -p 8005 publish cluster_p "afdslfdas"

  4. 集群倾斜目录

  5. 数据倾斜
    节点和槽分配不均
    查看每个主节点分配的槽的数量:redis-cli -p 8000 cluster nodes | grep master
    不同槽对应键值数量差异较大
    CRC16正常情况下比较均匀,可能存在hash_tag
    包含bigkey
    例如大字符串,几百万的hash或者set等,查找大字符串:redis-cli -p 8000 --bigkeys
    优化数据结构
    内存相关配置不一致

  6. 请求倾斜

  • 热点key: 重要的key或者bigkey
  • 优化:避免bigkey,热键不要用hash_tag,当一致性不高时,可以用本地缓存+MQ
    如何使用hash_tag
    set name{sankuan} zhangsan
    set name{sankuan} lisi
    所有指定为{sankuan}这个hash_tag指定的槽里
  1. 集群读写分离
  • 只读连接:集群模式下的从节点不接受任何读写请求
    重定向到负责槽的主节点
    readonly命令可以读:连接级别命令
    也就是说在集群模式下的从节点中,不会执行读取命令,读取命令也会直接跳转到对应的主节点去执行读的操作
    如果想在从节点执行读的命令,可以执行readonly
  • 集群读写分离

    尽量不要在集群模式下使用读写分离,否则成本太高、问题也会比较多
  1. 数据迁移
  • 离线/在线迁移
  1. 集群VS单机
  • 集群限制
    key批量操作支持有限:例如mget、mset必须在一个slot里
    key事务和Lua支持有限:操作的key必须在一个节点
    key是数据分区的最小粒度:不支持bigkey分区
    不支持多个数据库:在集群模式下只有一个db 0
    复制只支持一层,不支持树形复制结构
  1. 思考分布式redis不一定好?

  2. 本章总结

posted @ 2022-04-23 15:08  专职  阅读(81)  评论(0编辑  收藏  举报