redis分布式架构cluster(一)

redis分布式架构cluster(一)

优势:解决单机的内存,并发,流量瓶颈

一、数据分布理论

  1. redis cluster 的数据分布规则:
    哈希–虚拟槽分区

  2. 集群功能限制
    a. 批量操作例如mget、mset只支持在一个槽中的keys,只支持多key在同一节点的事务功能
    b. 不支持多数据库空间,仅一个库 db 0
    c. 复制结构只支持一层,不能嵌套树状复制结构

  3. 常见的分区理论:
    顺序分区、哈希分区

  4. 哈希分区方法:
    节点取余分区:当节点数量变化时,需要重新计算映射关系,数据要迁移(常用于数据库分表方案,表的数量已固定),可用翻倍扩容来避免全量的数据迁移,只迁50%。
    一致性哈希分区:节点变化只影响在哈希环中相邻的节点,会造成部分数据无法命中的情况,较适用于缓存场景,会造成数据负载不均衡,需要增加或者减少一倍的节点。节点少的时候影响范围更大。
    虚拟槽分区 :所有的键按照哈希函数映射到0~16383的槽内,每个节点负责维护一部分槽和所映射的键值数据。

二、集群搭建

流程:

  1. 修改配置文件,cluster相关内容
    clusert-enabled yes 等

  2. 启动6个以上redis-server节点,指定配置文件,不然就会自动创建一个新的
    redis-server conf/redis-6379.conf

  3. 节点握手,在任意节点执行
    cluster meet ip port

  4. 将槽均匀分配到n个节点,分配槽后集群在线
    cluster addslots{0…5461}
    cluster addslots{5462…10922}
    cluster addslots{10923…16383}

  5. 设置主从关系,在从节点上执行
    cluster replicate nodeid
    ps:nodeid可以通过cluster nodes的第一列获得

几个知识点:

  1. redis-server集群初始化时有一个节点id,是不会改变的;而运行id,每次重启会改变;
  2. 集群模式的redis除了自己的配置文件外,还有一份集群配置文件,redis自动维护,不要手动修改;

三、节点通信

  1. 通信协议
    gossip协议

  2. 节点定时任务
    每秒随机选取5个节点找出最久没有通信的节点发送ping消息,
    每秒执行10次,间隔一秒。每100ms如果发现节点最近一次接受pong消息大于cluster_node_timeout/2,立刻发送ping消息

  3. 消息数据量
    主要是消息头(2k)和消息体(与节点数量息息相关)

几个运维建议:

  1. 当带宽资源紧张时,可以适当调大cluster_node_timeout
  2. 集群数量并不是越多越好

四、集群扩缩容

槽和数据在节点之间的迁移

1、集群扩容

  1. 新节点安装好redis-server,参数配置同其他几台
  2. 加入集群,再集群里的任意一个节点执行
    cluster meet 127.0.0.1 6385
    经过一段时间的通信后就加入集群了

redis-trib.rb工具,可以实现为集群添加新节点命令,也可以直接添加为从节点(正式环境建议使用,避免发生新节点已经加入别的集群导致的集群合并,数据错乱)
redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6379 --slave --master-id
redis-trib.rb add-node 新节点ip:port 旧节点ip:port

  1. 迁移槽和数据(redis-trib.rb)
    槽迁移过程中集群可以正常提供读写服务
    redis-trib.rb reshard host:port --from --to --slots --yes --timeout --pipline

host:port 集群内任意节点地址
–from 指定源节点id,可写多个逗号分隔
–to 目标节点只有一个
–slots 需要迁移槽的总数量
–yes 是否需要用户输入yes确认后再执行reshard
–timeout 每次migrate操作的超时时间,默认为6w ms;
–pipline 控制每次批量迁移键的数量,默认为10

  1. 迁移后建议使用redis-trib rebalance检查节点之间槽的均衡性
    redis-trib rebalance ip:port

  2. 给该节点添加从节点
    集群模式下,slaveof不可用,要使用cluster replicate {masternodeid}

2、集群缩容

  1. 迁移槽
    把下线节点的槽均匀迁移至其他几个节点,需要执行多次redis-trib.rb reshard

  2. 忘记节点
    cluster forget {downnodeid} 执行后会有60s内禁用该节点通信,需要在60s内将所有节点都禁用。比较麻烦且容易失败。
    redis-trib.rb del-node {host:ip} {downnodeid}
    实现了安全下线的功能:判断是否已经没有槽,是否有从节点,从节点迁移到拥有从节点最少的主节点上。

五、请求路由

1. moved重定向
返回key所对应的槽:cluster keyslot key

2. 自动重定向(由客户端完成)
redis-cli -p6379 -c

3. 计算槽
根据键的有效部分,使用CRC16函数计算散列值,再对16383取余数。
键的有效部分的定义:当有{}时,按照{}里的内容;没有时则为完整key

4. ask重定向
当集群slots正在迁移,会出现ask重定向,不知道什么时候会结束,是个暂时的重定向

5. smart客户端
dummy(傀儡客户端):随机连上集群的一个,根据moved重定向信息再次发起请求

smart客户端:客户端维护slot–>node的映射关系,moved重定向用来维护本地的映射关系

  1. 初始化时先选择一个运行节点,初始化槽和节点的映射关系,使用cluster slot命令完成
  2. 执行键命令
  • 计算slot并根据slot缓存获得目标节点,发送命令
  • 如果出现连接错误,使用随机链接重新执行键命令,每次命令重试对redirections参数减1
  • 捕获到moved重定向错误,使用cluster slots命令更新slots缓存
  • 重复执行上述3步,直至命令执行成功或者redirections<=0,抛出异常
  1. 抛出JedisConnectionException异常可能的原因:
    Jedis连接节点发生socket错误;
    所有命令/Lua脚本读写超时抛出;
    JedisPool连接池获取可用Jedis对象超时抛出;

redis集群支持故障转移,故障从发现到转移需要一定的时间,节点宕机期间所有指向这个节点的命令都会触发随机重试,每次收到moved重定向后会调用JedisClusterInfoCache类的renewslotcache方法。

获得写锁之后再执行cluster slots命令初始化缓存,由于集群所有的键命令都需要调用getslotspool方法计算槽对应的节点,内部要求读锁。读写锁互斥,从而所有的请求都会造成阻塞。即cluster slots风暴

cluster slots风暴
现象:

  1. 重试机制导致io通信放大问题
  2. 个别节点操作异常导致频繁的更新slots缓存,多次调用cluster slots命令,集群架构越庞大,问题越严重
  3. 频繁触发更新本地slots缓存操作,内部使用了写锁,阻塞对集群所有键命令的调用

建议升级到jedis 2.8.2以上,会减少调用cluster slots命令,减少更新slots缓存次数,且优化写锁阻塞和不必要的并发调用

你可能感兴趣的:(redis,redis,缓存,数据库)