redis亿级缓存设计方案

  随着业务发展企业数据蓬勃增长,需要缓存数据也越来越大,传统的单机缓存方案肯定无法支持。那如何设计一套分布式缓存来满足亿级数据缓存?

   一、哈希取余分区

  2亿条记录就是2亿个key,我们单机不行必须要分布式多机器,假设有3台机器构成一个集群,用户每次读写操作都是根据公式hash(key)%N台机器数,计算出哈希值,用来决定数据映射到哪一台节点上。

   优点: 简单粗暴,直接有效,只需要预估好数据规划的好节点,例如3台、8台、10台就能保证一段时间数据支撑,使用hash算法计固定的一部分请求落地同一台服务器上,这样服务器固定处理一部分请求(并维护这些请求信息)起到了负载均衡+分而治之的作用。

  缺点:规划好的节点进行扩容或者缩容就比较麻烦了,不管扩缩每次数据变动导致节点变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化,hash(key)%3就变成hash(key)/? 此时地址经过取余的运算结果将发生很大变化,根据公式获取的服务器数也会变得不可控。由于台数量变化 会导致hash取余全部数据重新洗牌。

  二、一致性哈希算法分区

  一致性哈希算法背景

  一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动问题和映射问题,某个机器宕机 分母数量改变了 自然取余数不变。一致性哈希算法解决了哈希算法的问题。当服务器的数量发生变化,尽量只对部分服务器产生影响。

  一致性Hash算法是对2^{32}取模,会产生0 ~2^{32}-1的值 这些值构成一个hash空间。将它们顺序排列且首尾相连,构成一个环形空间(Hash环)。

    将服务器的IP或主机名作为关键字进行哈希取模,这样每台机器在哈希环上就有一个位置。假如4个服务器节点A、B、C、D,使用IP地址求哈希再取模,再Hash环上的位置如下:

   对数据进行哈希取模,这样每台机器在哈希环上就有一个位置。从此位置沿环顺时针“行走”,遇到的第一服务器,就是数据储存目标服务器 假设有Object A、Object B、Object C、Object D四个数据对象,经过哈希取模计算后,在Hash环空间上的位置如下。根据一致性Hash算法分区,数据A会被定位到Node A上,B被定位到Node B上,C被定位到Node C上,D被定位到Node D上

   优点:加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。例如增加一台服务器节点NodeX,X的位置在A和B之间,那受到影响的也就是A到X之间的数据,重新把A到X的数据录入到X上即可供正确读取数据。

   缺点:数据分布和节点的位置有关,因为这些节点不是均匀分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果,很容易导致数据倾斜

  三、Redis哈希槽分区

  Redis 集群中内置了 16384(2^14) 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。使用哈希槽的好处就在于可以方便的添加或移除节点。当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。

   redis哈希槽为什么是16384个?

  1、如果槽位是65536(2^16),发送心跳消息头达到8K发送的心跳包过于庞大。

  在消息头中最点空间的是myslots(cluster_slots/8),当槽位为65536时 这块的大小是65536/8=8192即8KB,因为每秒钟 redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536 这个ping的消息头太大 导致浪费带宽,同时带来网络阻塞

  2、redis的集群主节点数据基本不可能超过1000个。

  集群节点越多,心跳包的消息体内携带的数据越多,如果节点超过1000个 会导致网络拥堵,因此redis作者不建议redis cluster节点数量超过1000个,那么对于节点数在1000以内的redis cluster集群,16384槽位已够用了没有必要拓展到65536个。

  3、槽位越小,节点少的情况下,压缩比高 容易传输。

  redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是bitmap的填充率slots/N很高的话(N表示节点数),bitmap的压缩率就很低,如果节点数很少 而哈希槽数量很多的话bitmap压缩率就很低。

  优点:1、解耦数据和节点之间的关系,例如:数据的读写只要计算出槽号就可以,节点的扩容和收缩只要重新均衡分配槽区间即可;故简化了节点扩容和收缩难度  

                  2、节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区和数据

                  3、支持节点、槽、键之间的映射查询,用于数据路由、在线伸缩等场景,数据和槽号是绑在一起的通过槽号找到节点

  缺点:槽位的转移和分派,Redis集群是不会自动进行的,而是需要人工配置的

posted @ 2022-09-12 11:07  Crazier  阅读(808)  评论(0编辑  收藏  举报