Redis Cluster

陌路散爱 提交于 2019-12-06 03:45:06

Redis Cluster

  • 呼唤集群
  • 数据分布
  • 搭建集群
  • 集群伸缩
  • 客户端路由
  • 集群原理
  • 故障转移
  • 开发运维常见问题

呼唤集群

1. 并发量


2. 数据量


3. 网络流量
解决办法

分布式:简单的认为加机器

集群:规模化需求
  1. 并发量:OPS
  2. 数据量:”大数据”

数据分布

分布式数据库-数据分区

顺序分区和哈希分区
  • 顺序分布

  • 哈希分布(例如节点取模)

数据分布对比
分布方式 特点 典型产品
哈希分布 数据分散度高、键值分布业务无关、无法顺序访问、支持批量操作 一致性哈希Memcache、Redis Cluster、其他缓存产品
顺序分布 数据分散度易倾斜、键值业务相关、可顺序访问、支持批量操作 Big Table、HBase
哈希分布
  • 节点取余分区
  • 一致性哈希分区
  • 虚拟槽分区

  • 多倍扩容

  • 客户端分片:哈希+取余
  • 节点伸缩:数据节点关系变化,导致数据迁移
  • 迁移数量和添加节点数量有关:建议翻倍扩容
一致性哈希

  • 扩容


  • 客户端分片:哈希+顺时针(优化取余)
  • 节点伸缩:只影响邻近节点,但是还是有数据迁移
  • 翻倍伸缩:保证最小迁移数据和负载均衡
虚拟槽分区
  • 预设虚拟槽:每个槽映射一个数据子集,一般比节点数大
  • 良好的哈希函数:例如CRC16
  • 服务端管理节点、槽、数据:例如Redis Cluster

搭建集群-基本架构

单机架构

分布式架构

Redis Cluster架构
  1. 节点
  2. meet
  3. 指派槽
  4. 复制
节点

cluster-enabled yes

meet


所有节点共享消息
指派槽



特性
  1. 复制
  2. 高可用
  3. 分片
Redis Cluster安装
  1. 原生命令安装
  2. 官方工具安装
原生命令安装-理解架构
  1. 配置开启节点

  2. meet
    cluster meet ip port

    12345
    redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7001redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7002redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7003redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7004redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7005
  3. Cluster节点主要配置

  4. 指派槽
    cluster addslots slot [slot …]

    123
    redis-cli -h 127.0.0.1 -p 7000 cluster addslots {0..5461}redis-cli -h 127.0.0.1 -p 7001 cluster addslots {5462..10922}redis-cli -h 127.0.0.1 -p 7002 cluster addslots {10923..16383}
  5. 设置主从
    cluster replicate node-id

    123
    redis-cli -h 127.0.0.1 -p 7003 cluster replicate ${node-id-7000}redis-cli -h 127.0.0.1 -p 7004 cluster replicate ${node-id-7001}redis-cli -h 127.0.0.1 -p 7005 cluster replicate ${node-id-7002}
官方工具Ruby安装
  1. 下载、编译、安装Ruby
  2. 安装rubygem redis
  3. 安装redis-trib.rb
其他

使用redis-trib.rb create 或者 redis-cli create 命令
可视化部署

集群伸缩

  • 伸缩原理
  • 扩容集群
  • 缩容集群
伸缩原理



集群伸缩=槽和数据在节点之间的移动
扩容集群
  • 准备新节点
  • 加入集群
  • 迁移槽和数据
准备新节点

新节点:

  • 集群模式
  • 配置和其他节点同意
  • 启动后是孤儿节点

    12
    redis-server conf/redis-6385.confredis-server conf/redis-6386.conf
加入集群
12
127.0.0.1:6379 > cluster meet 127.0.0.1 6385127.0.0.1:6379 > cluster meet 127.0.0.1 6386


作用
  • 为他迁移槽和数据实现扩容大专栏  Redis Clusteri>
  • 作为从节点负责故障转移
    redis-trib.rb
    1234
    redis-trib.rb add-node new_host:new_port existing_hos:existing_port --slave --master-id <arg>redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000//建议使用redis-trib.rb能够避免新节点已经加入了其他集群,造成故障//新版本使用redis-cli --cluster add-node
迁移槽和数据
  • 槽迁移计划

    1
    //新版本使用redis-cli --cluster reshard
  • 迁移数据

  • 添加从节点
  1. 槽迁移计划

  2. 迁移数据
  3. 对目标节点发送:cluster setslot {slot} importing {sourceNodeId} 命令,让目标节点准备导入槽的数据。
  4. 对源节点发送:cluster setslot {slot} migrating {targetNodeId} 命令,让源节点准备迁出槽的数据。
  5. 源节点循环执行cluster getkeysinslot {slot} {count} 命令,每次获取count个属于槽的键。
  6. 在源节点上执行migrate {targetIp} {targetPort} key 0 {timeout} 命令把指定key迁移。
  7. 重复执行步骤3~4知道槽下所有的键数据迁移到目标节点。
  8. 向集群内所有主节点发送cluster setslot {slot} node {targetNodeId} 命令,通知槽分配给目标节点。

收缩集群
  1. 下线迁移槽
  2. 忘记节点
  3. 关闭节点

下线槽

忘记槽
123
redis-cli > cluster forget {downNodeId}del-node

客户端路由

  • moved重定向
  • ask重定向
  • smart客户端
moved重定向

槽命中

槽不命中:moved异常

ask重定向


moved和ask
  • 两者都是客户端重定向
  • moved:槽已经确定迁移
  • ask:槽还在迁移中
    smart客户端
  • smart客户端原理
  • smart客户端使用:JedisCluster
smart客户端原理:追求性能
  1. 从集群中选一个可运行节点,使用cluster slots初始化槽和节点映射。
  2. 将cluster slots的结果映射到本地,为每个节点创建JedisPool。
  3. 准备执行命令。

执行命令

smart客户端使用:JedisCluster

JedisCluster基本使用

123456789
Set<HostAndPort> nodeList = new HashSet<HostAndPort>();nodeList.add(new HostAndPort(HOST1, PORT1));nodeList.add(new HostAndPort(HOST2, PORT2));nodeList.add(new HostAndPort(HOST3, PORT3));nodeList.add(new HostAndPort(HOST4, PORT4));nodeList.add(new HostAndPort(HOST5, PORT5));nodeList.add(new HostAndPort(HOST6, PORT6));JedisCluster redisCluster = new JedisCluster(nodeList, timeout, poolConfig);redisCluster.command...

使用技巧

  1. 单例:内置了所有节点的连接池
  2. 无需手动借还连接池
  3. 合理设置commons-pool
    整合spring
    springBoot整合redisCluster(redis集群)模式
    注意搭建集群时ip的配置,避免整合客户端时连接失败。
    多节点命令实现
    12345678910
    Map<String, JedisPool> jedisPoolMap = jedisCluster.getClusterNodes();for (Entry<String, JedisPool> entry : jedisPoolMap.entrySet()){    //获取每个节点的Jedis连接    Jedis jedis = entry.getValue().getResource();    //只删除主节点数据    if(!isMaster(jedis)){        continue;    }    //finally close}

批量命令实现
mget mset 必须在一个槽上

  • 四种批量优化的方法
  1. 串行mget

  2. 串行IO

  3. 并行IO

  4. hash_tag

  • 四种方案优缺点分析
方案 优点 缺点 网络IO
串行mget 编程简单、少量keys满足需求 大量keys请求延迟严重 O(keys)
串行IO 编程简单、少量节点满足需求 大量node延迟严重 O(nodes)
并行IO 利用并行特性、延迟取决于最慢的节点 编程复杂、超时定位问题难 O(max_slow(node))
hash_tag 性能最高 读写增加tag维护成本、tag分布易出现数据倾斜 O(1)

故障转移

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


  • 尝试客观下线

  1. 通知集群内所有节点标记故障节点为客观下线
  2. 通知故障节点的从节点触发故障转移流程
故障恢复
  • 资格检查
  1. 每个从节点检查与故障主节点的断线时间
  2. 超过cluster-node-timeout * cluster-slave-validity-factor取消资格
  3. cluster-slave-validity-factor:默认是10
  • 准备选举时间

  • 选举投票

  • 替换主节点

  1. 当前从节点取消复制变为主节点。(slaveof no one)
  2. 执行clusterDelSlot撤销故障主节点负责的槽,并执行clusterAddSlot把这些槽分配给自己。
  3. 向集群广播自己的pong消息,表明已经替换了故障从节点。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!