redis 优化系列(六)高可用集群 Redis Cluster 的认识
一、redis 哨兵+主从的问题
假设我们在一台主从机器上配置了 200G 内存,但是业务需求是需要 500G 的时候,主从结构+哨兵可以实现高可用故障切换+冗余备份,但是并不能解决数据容量的问题,用哨兵,redis 每个实例也是全量存储,每个 redis 存储的内容都是完整的数据,浪费内存且有木桶效应。
为了最大化利用内存,可以采用 cluster 集群,就是分布式存储。即每台 redis 存储不同的内容。
Redis 分布式方案一般有两种:
①、客户端分区方案:优点是分区逻辑可控,缺点是需要自己处理数据路由、高可用、故障转移等问题,比如在 redis2.8 之前通常的做法是获取某个 key 的 hashcode,然后取余分布到不同节点,不过这种做法无法很好的支持动态伸缩性需求,一旦节点的增或者删操作,都会导致 key 无法在 redis 中命中。
②、代理方案:优点是简化客户端分布式逻辑和升级维护便利,缺点是加重架构部署复杂度和性能损耗,比如 twemproxy、Codis
③、Redis 官方为我们提供了专有的集群方案:Redis Cluster,它非常优雅地解决了 Redis 集群方面的问题,部署方便简单,因此理解应用好 Redis Cluster 将极大地解放我们使用分布式 Redis 的工作量。
二、Redis Cluster
1、简介
Redis Cluster 是 Redis 的分布式解决方案,在 3.0 版本正式推出,有效地解决了 Redis 分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用 Cluster 架构方案达到负载均衡的目的。
架构图:
在上面这个图中,每一个蓝色的圈都代表着一个 redis 的服务器节点。它们任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点,对其进行存取和其他操作。
Redis 集群提供了以下两个好处:
①、将数据自动切分到多个节点的能力。
②、当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力,拥有自动故障转移的能力。
2、redis cluster VS replication + sentinel 如何选择?
如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个 G,单机足够了。
Replication:一个 mater,多个 slave,要几个 slave 跟你的要求的读吞吐量有关系,结合 sentinel 集群,去保证 redis 主从架构的高可用性,就可以了。
redis cluster:主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用 redis cluster。
3、Redis Cluster 集群中的数据分布是如何进行的?
什么是数据分布?数据分布有两种方式,顺序分区和哈希分区。
分布式数据库首先要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集。
顺序分布就是把一整块数据分散到很多机器中,如下图所示。
顺序分布一般都是平均分配的。
哈希分区:
如下图所示,1~100 这整块数字,通过 hash 的函数,取余产生的数。这样可以保证这串数字充分的打散,也保证了均匀的分配到各台机器上。
哈希分布和顺序分布只是场景上的适用。哈希分布不能顺序访问,比如你想访问 1~100,哈希分布只能遍历全部数据,同时哈希分布因为做了 hash 后导致与业务数据无关了。
4、数据倾斜与数据迁移跟节点伸缩
顺序分布是会导致数据倾斜的,主要是访问的倾斜。每次点击会重点访问某台机器,这就导致最后数据都到这台机器上了,这就是顺序分布最大的缺点。
但哈希分布其实是有个问题的,当我们要扩容机器的时候,专业上称之为“节点伸缩”,这个时候,因为是哈希算法,会导致数据迁移。
5、哈希分区方式
因为 redis-cluster 使用的就是哈希分区规则所以分析下几种分区形式
5.1、节点取余分区
使用特定的数据(包括 redis 的键或用户 ID),再根据节点数量 N,使用公式:hash(key)%N 计算出一个 0~(N-1)值,用来决定数据映射到哪一个节点上。即哈希值对节点总数取余。
缺点:当节点数量 N 变化时(扩容或者收缩),数据和节点之间的映射关系需要重新计算,这样的话,按照新的规则映射,要么之前存储的数据找不到,要么之前数据被重新映射到新的节点(导致以前存储的数据发生数据迁移)
实践:常用于数据库的分库分表规则,一般采用预分区的方式,提前根据数据量规划好分区数,比如划分为 512 或 1024 张表,保证可支撑未来一段时间的数据量,再根据负载情况将表迁移到其他数据库中。
5.2、一致性哈希
一致性哈希分区(Distributed Hash Table)实现思路是为系统中每个节点分配一个 token,范围一般在 0~232,这些 token 构成一个哈希环。数据读写执行节点查找操作时,先根据 key 计算 hash 值,然后顺时针找到第一个大于等于该哈希值的 token 节点
上图就是一个一致性哈希的原理解析。
假设我们有 n1~n4 这四台机器,我们对每一台机器分配一个唯一 token,每次有数据(图中黄色代表数据),一致性哈希算法规定每次都顺时针漂移数据,也就是图中黄色的数 据都指向 n3。
这个时候我们需要增加一个节点 n5,在 n2 和 n3 之间,数据还是会发生漂移(会偏移到大于等于的节点),但是这个时候你是否注意到,其实只有 n2~n3 这部分的数据被漂移,其他的数据都是不会变的,这种方式相比节点取余最大的好处在于加入和删除节点只影响哈希环中相邻的节点,对其他节点无影响
缺点:每个节点的负载不相同,因为每个节点的 hash 是根据 key 计算出来的,换句话说就是假设 key 足够多,被 hash 算法打散得非常均匀,但是节点过少,导致每个节点处理的 key 个数不太一样,甚至相差很大,这就会导致某些节点压力很大
实践:加减节点会造成哈希环中部分数据无法命中,需要手动处理或者忽略这部分数据,因此一致性哈希常用于缓存场景。
*5.3、虚拟槽分区*(目前在 redis 集群中 数据存储和读取常用的方式就是这种 槽 的方式)*
虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot)。这个范围一般远远大于节点数,比如 Redis Cluster 槽范围是 0~16383(也就是 16384 个槽。redis 集群规定了 16384 个槽,这些槽将会平均分配给不同的 redis 节点)。槽是集群内数据管理和迁移的基本单位(也就是说 数据是存储在槽中,而槽被分配在了不同的 redis 节点中)。采用大范围槽的主要目的是为了方便数据拆分和集群扩展。每个节点会负责一定数量的槽,具体看下图所示。
当前集群有 5 个节点,每个节点平均大约负责 3276 个槽。由于采用高质量的哈希算法,每个槽所映射的数据通常比较均匀,将数据平均划分到 5 个节点进行数据分区。Redis Cluster 就是采用虚拟槽分区,下面就介绍 Redis 数据分区方法。
上图步骤大概执行如下(数据写入):
①、redis 根据所给定的 key 进行 CRC16 算法之后 算出一个结果,然后 再对该结果 进行 16384 取模(即 对该结果进行 16384 求余数),得到一个槽。
这样每个 key 都会对应一个编号在 0---16383 之间的槽号码,redis 会根据节点数量大致均等的原则将哈希槽映射到不同的节点上。比如有 3 个 redis 节点,把 16384 分成 3 段,每个节点承担一段范围的哈希槽。
**注意:**这里是对 16384 进行取模,上图中那个 CRC16(key)&16383 写错了 正确公式为:CRC16(key)%16384
②、再根据所得的槽位数,获得这个槽所在的 redis 节点(假设是 Z 节点)。
③、连接 Z 节点,将该 key 保存到 Z 这台 redis 节点上。
数据读取也是同理,都是根据 key 得到槽,根据槽得到该槽所在的 redis 节点,然后连接该 redis 节点进行数据读取操作。
每当 key 访问过来,Redis Cluster 会计算哈希值是否在这个区间里。它们彼此都知道对应的槽在哪台机器上,这样就能做到平均分配了。
redis-cluster 集群方面有一些限制:
Redis 集群相对单机来说,在功能上存在一些限制,需提前了解,在使用时做好规避。限制如下: key 批量操作支持有限。如 mset、mget 等。
总结 redis 主从、哨兵、集群的概念:
【redis 主从】:
是备份关系, 我们操作主库,数据也会同步到从库。 如果主库机器坏了,从库可以上。就好比你 D 盘的片丢了,但是你移动硬盘里边备份有。
【redis 哨兵】:
哨兵保证的是 HA(高可用),保证特殊情况故障自动切换,哨兵盯着你的“redis 主从集群”,如果主库死了,它会告诉你新的老大是谁。
哨兵:主要针对 redis 主从中的某一个单节点故障后,无法自动恢复的解决方案。(哨兵 保证 redis 主从的高可用)
【redis 集群】:
集群保证的是高并发,因为多了一些兄弟帮忙一起扛。同时集群会导致数据的分散,整个 redis 集群会分成一堆数据槽,即不同的 key 会放到不不同的槽中。
集群主要针对单节点容量、高并发问题、线性可扩展性的解决方案。
集群:是为了解决 redis 主从复制中 单机内存上限和并发问题,假如你现在的服务器内存为 256GB,当达到这个内存时 redis 就没办法再提供服务,同时数据量能达到这个地步写数据量也会很大,容易造成缓冲区溢出,造成从节点无限的进行全量复制导致主从无法正常工作。
版权声明: 本文为 InfoQ 作者【乌龟哥哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/11ba8b4e4786efe5cce945c6f】。文章转载请联系作者。
评论