马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
74 redis集群分片之集群是什么
假如主机宕机,那么写操作就被临时中断,后面就要由哨兵进行投票和选举。那么一瞬间如有大量的数据修改,由于写操作中断就会导致数据流失。
由于数据量过大,单个Master复制集难以承担,因此必要对多个复制集进行集群,形成水平扩展。每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,共作用是提供在多个Redis节点间共享数据的步伐集。
75 redis集群分片之集群能干嘛
redis集群是一个提供在多个redis节点间共享数据的步伐集
redsi集群可以支持多个master
左图是一个master,右图是多个master
多个master对外是一个集群整体,里面具体是哪个redis实例提供服务和访问的客户端无关。若三个master中有一个挂了,不要紧,另有另外两个master可以工作。每个master都有对应的从机,假如m1挂了那么s1可以顶上。
redis集群的作用
- Redis集群支持多个Master,每个Master又可以挂载多个Slave
- 由于Cluster自带Sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
- 客户端与Redis的节点连接,不再必要连接集群中所有的节点,只必要任意连接集群中的一个可用节点即可
- 槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系
76 redis集群分片之槽位slot
在 Redis 集群中,密钥空间(Keyspace) 是指 Redis 用来存储所有键的一个逻辑空间。而集群的密钥空间,则是这个概念在 Redis 集群架构中的具体体现,它决定了数据在集群中怎样分布和定位。
分片机制:
- Redis 集群将整个密钥空间分别为 16384 个槽位(slots),编号从 0 到 16383。
- 每个键根据其名字的哈希值被分配到这 16384 个槽位中的某一个槽。
- 每个节点(Redis 实例)负责其中的一部分槽位,这样可以实现数据的分布式存储。
槽位计算方式:
Redis 使用 CRC16 哈希算法计算键的哈希值,然后对 16384 取模,确定该键属于哪个槽。
slot = CRC16(key) % 16384
密钥空间的分别意义:
- 它决定了键值对的物理存储位置。
- 客户端在访问一个键时,可以通过这个槽位快速定位到具体负责这个槽的节点。
redis集群的槽位slot
引入了 哈希槽的概念.
Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。
举个例子,好比当前集群有3个节点,那么:
77 redis集群分片之分片
redis集群的分片
分片是什么
使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集群中的每个Redis实例都被认为是整个数据的一个分片。
怎样找到给定key的分片
为了找到给定key的分片,我们对key进行CRC16(key)算法处置处罚并通过对总分片数目取模。然后,使用确定性哈希函数,这意味着给定的key将多次始终映射到同一个分片,我们可以推断未来读取特定key的位置。
槽位是逻辑单元,分片是物理单元。Redis 通过槽位把键分配到分片上。
假设你有 3 个 Redis 节点(A、B、C)构成一个集群:
- 节点 A:负责槽位 0 ~ 5460
- 节点 B:负责槽位 5461 ~ 10922
- 节点 C:负责槽位 10923 ~ 16383
这 3 个节点就是 3 个分片,每个分片负责一部分 槽位,通过这些槽位将键分布到各个节点上。
| 78 redis集群分片之分片上风
槽位slot和分片的上风
假设系统要扩容,从三主三从变成五主五从。
最大上风,方便扩缩容和数据分派查找
这种布局很易添加或者删除节点,好比假如我想新添加个节点D,并不必要改变所有槽的分布,只必要将部分槽(好比 A 的一部分、B 的一部分)“迁移”到 D 上。好比把 A 的 1000 个槽给 D,B 的 1000 个槽也给 D。假如我想移除节点A.必要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可.由于从一个节点将哈希槽移动到另一个节点并不会停止服务,以是无论添加删除或者改变某个节点的哈希的数目都不会造成集群不可用的状态。
槽位迁移不会造成集群停机
动态数据迁移(Rebalancing)
- 在 Redis 集群中,槽位迁移是在线进行的。
- 当槽从 A 迁移到 D 时,Redis 会逐个 key 从 A 发送到 D(带着 key 的值)。
- 在迁移过程中,假如有客户端访问该 key,Redis 仍旧能处置处罚请求(大概会返回 MOVED 或 ASK 重定向,让客户端重试)。
79 reids集群分片之哈希取余分区算法
slot槽位映射,一般业界有3种解决方案:哈希取余分区、一致性哈希算法分区、哈希槽分区
哈希取余分区
2亿条记载就是2亿个k,v,我们单机不行必须要分布式多机,假设有3台机器构成一个集群,用户每次读写操作都是根据公式:
hash(key)% N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。
长处:
简单粗暴,直接有效,只必要预估好数据规划好节点,比方3台、8台、10台,就能保证一段时问的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处置处罚一部分请求(并维护这些请求的信息),起到负载平衡+分而治之的作用。
缺点:
原来规划好的节点,进行扩容或者缩容就比较贫苦了额,不管扩缩,每次数据变动导致节点有变动,映射关系必要重新进行计算,在服务器个数固定稳定时没有题目,假如必要弹性扩容或故障停机的环境下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key)/?。此时地点经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。
某个redis机器宕机了,由于台数数目变化,会导致hash取余全部数据重新洗牌。
一致性哈希算法
一致性Hash算法背景:一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为相识决分布式缓存数据变动和映射题目,某个机器宕机了,分母数目改变了,自然取余数不OK了。
提出一致性Hash解决方案。目标是当服务器个数发生变动时,尽量镌汰影响客户端到服务器的映射关系
算法构建一致性哈希环
一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有大概哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0=2^32),这样让它逻辑上形成了一个环形空问。
它也是按照使用取模的方法,前面笔记先容的节点取模法是对节点(服务器)的数最进行取模。而一致性Hash算法是对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下图:
整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、 …… 直到2^32-1,也就是说0点左侧的第一个点代表2^32-1,0和2^32-1在零点中方向重合,我们把这个由2^32个点构成的圆环称为Hash环。
支持节点的动态增减而“最小代价”地迁移数据
假设原来你有 3 个节点:A、B、C,分布在环上:
数据 "x" 的哈希值在 A 和 B 之间,那么它就会映射到 B。
假如增长一个新节点 D,映射到 A 和 B 之间:
- 只有 hash 值落在 A 和 D 之间的数据,才会迁移到 D。
- 其他数据仍旧映射到原来的节点上。
只影响局部,不影响全局。
redis服务器IP节点映射
将集群中各个IP节点映射到环上的某一个位置。
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地点的哈希函数计算(hash(ip)),使用IP地点哈希后在环空间的位置如下:
key落到服务器的落键规则
当我们必要存储一个kv键值对时,起首计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,今后位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。
如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。
长处
一致性哈希算法的容错性
假设Node C宕机,可以看到此时对象A、B、D不会受到影响。一般的,在一致性Hash算法中,假如一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是
B、C之间的数据且这些数据会转移到D进行存储。
一致性哈希算法的扩展性
数据量增长了,必要增长一台节点NodeX,X的位置在A和B之问,那收到影响的也就是A到X之问的数据,重新把A到X的数据录入到X上即可,不会导致hash取余全部数据重新洗牌。
缺点
一致性哈希算法的数据倾斜题目
一致性Hash算法在服务节点太少时,容易由于节点分布不匀称而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)题目,比方系统中只有两台服务器:
总结
- 为了在节点数目发生改变时尽大概少的迁移数据
- 将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到临近的存储节点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。
- 长处
- 加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。
- 缺点
- 数据的分布和节点的位置有关,由于这些节点不是匀称的分布在哈希环上的,以是数据在进行存储时达不到匀称分布的效果。
哈希槽分区
一致性哈希算法的数据倾斜题目
什么是哈希槽
哈希槽实质就是一个数组,数组[0,2^14-1]形成hash slot空间。
哈希槽能干什么
解决匀称分配的题目,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。
槽解决的是粒度题目,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射题目,使用key的哈希值来计算所在的槽,便于数据分配
有多少个哈希槽
一个集群只能有16384个槽,编号0-16383(0-2^14-1),这些槽会分配给集群中的所有主节点,分配战略没有要求。
集群会记载节点和槽的对应关系,解决了节点和槽的关系后,接下来就必要对key求哈希值,然后对16384取视,余数是几key就落入对应的槽里。
HASH_SLOT=CRC16(key)mod 16384.以槽为单元移动数据,由于槽的数目是固定的,处置处罚起来比较容易,这样数据移动题目就解决了。
哈希槽的计算
Redis 集群中内置了16384个哈希槽.redis 会根据节点数目大致均等的将哈希槽映射到不同的节点。当必要在Redis集群中放置一个key-value时,redis先对key使用crc16算法算出一个结果然后用结果对16384求余数[CRC16(key)% 16384],这样每个key都会对应一个编号在0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A、B在Node2,key之C落在Node3上
为什么“哈希槽”能帮助实现匀称分布?
1. 槽数宏大于节点数,有助于细粒度平衡
- 有 16384 个槽,但也许只有 3 个节点。
- 可以机动分配槽数来做到负载平衡:好比 5461 个槽一个节点。
- 增长节点时,只必要重新分配槽 → 不必要重新 hash 所有 key。
细粒度的槽控制可以最大水平地做到“平衡”数据分布。
2. 使用好的哈希函数能保证槽分布近似匀称
Redis 使用的是 CRC16(key) % 16384:
- CRC16 是一种分布较匀称的哈希函数;
- 对于大多数 key,它能让结果在 0~16383 之间近似匀称分布。
类比:
假如你用 hash(key) % 3 映射 3 台服务器,hash 函数假如分布不匀称,就大概导致大部分 key 落在某一台服务器上。
而:
- 用 hash(key) % 16384 得到匀称分布的槽;
- 然后把槽“匀称分配”给节点;
- 就间接达到了key 的匀称分布
经典面试题
为什么redis集群的最大槽数是16384个?
Redis集群并没有使用一致性hash而是引入了哈希槽的概念。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。但为什么哈希槽的数目是16384(2^14)个呢?
CRC16算法产生的hash值有16bit,该算法可以产生2^16=65536个值。
换句话说值是分布在0~65535之间,有更大的65536不用为什么只用16384就够?
作者在做mod运算的时间,为什么不mod65536,而选择mod16384?HASH_SLOT=CRC16(key)mod 65536为什么没启用
(1)假如槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于巨大。
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的巨细是:65536÷8÷1024=8kb
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为16384时,这块的巨细是:16384÷8÷1024=2kb
由于每秒钟,redis节点必要发送一定数目的ping消息作为心跳包,假如槽位为65536,这个ping消息的消息头太大了,浪费带宽。
前提:Redis 集群的每个节点必要知道哪些节点负责哪些槽(slot)。这就是为什么在节点之间发送心跳(PING/PONG)时,消息头中会包含该节点负责的槽位信息。
(2)redis的集群主节点数目基本不大概超过1000个。
集群节点越多,心跳包的消息体内携带的数据越多。假如节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数目超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。
(3)槽位越小,节点少的环境下,压缩比来,容易传输
Redis主节点的设置信息中它所负责的哈希槽是通过一张bitmap的情势来保存的,在传输过程中会对bitmap进行压缩,但是假如bitmap的添补率slots/N很高的话(N表现节点数)。bitmap的压缩率就很低。假如节点数很少,而哈希槽数目很多的话,bitmap的压缩率就很低。
85 redis集群分片之不保证强一致性
Redis集群不保证强一致性,这意味着在特定的条件下,Redis集群大概会丢掉一些被系统收到的写入请求命令
什么是“强一致性”?
- 强一致性(Strong Consistency)意味着:一旦系统对外确认写入乐成,所有节点(或客户端)随后读取到的都是这个值,永久不会丢失。
- 而 Redis 集群遵循的是 最终一致性(Eventual Consistency),夸大的是“最终节点状态会一致”,但在中心阶段大概不同步或丢失数据。
Redis 集群中大概丢数据的典型场景
1. 主从复制耽误(Replication Lag)
- Redis 集群采用异步复制:主节点执行写操作后,不会等候从节点确认再响应客户端。
- 假如主节点刚写完数据就宕机:
- 数据还未复制到从节点;
- Redis 集群选了一个从节点晋升为新的主节点;
- 这个新主节点上 大概没有那条写入的数据,就相当于“数据丢失”。
这是一种典型的“已确认但未持久”的写丢失。
2. 脑裂(Split-Brain)或网络分区
- 假如集群节点之间发生网络故障,某些节点无法感知相互状态,大概会:
- 重复选举主节点;
- 有两个主节点接收写入;
- 最后产生数据不一致或写入丢失。
|