关于redis集群:独家深度解析redis集群的架构问题附脑洞

7次阅读

共计 6602 个字符,预计需要花费 17 分钟才能阅读完成。

本文首发自 [慕课网](imooc.com),想理解更多 IT 干货内容,程序员圈内热闻,欢送关注 ” 慕课网 ” 及“慕课网公众号”!

作者:一凡 | 慕课网讲师


Redis 是一种开源(BSD 许可)、数据结构存储在内存中的零碎,用作数据库、缓存和音讯队列。Redis 提供了诸如字符串、散列、列表、汇合、带范畴查问的排序汇合、位图、超级日志、天文空间索引和流等数据结构。Redis 内置复制、Lua 脚本、LRU 驱赶、事务和不同级别的磁盘长久化,并通过 Redis Sentinel 和 Redis Cluster 主动分区提供高可用性。

1 集群的劣势

上面是 redis 集群的几个显著劣势。

1.1 伸缩性,数据规模一直增大的时候,容易扩容

单实例模式:只能垂直扩大,增大机器内存的容量;

集群模式:反对垂直扩大,也反对程度扩大,有更好的灵活性,也能够反对更大的容量;

1. 2 高可用,服务故障的状况,影响范畴小

单实例模式:故障转移前 100% 不可用 (slave 转换为 master 之前);

集群模式:故障转移前局部不可用 (集群规模越大,故障影响越小); 

1. 3 高性能,查问和写入的性能 

单实例模式:查问能够扩散在多个 slave,写入却只有一个 master;

集群模式:查问有多个 master 和多个 slave,写入也有多个 master;

2 数据分片,一致性 hash

实现 redis 集群的外围点,是针对数据的分片,这里的一致性 hash 算法就十分要害。

2.1 一般的 hash 算法

node=hash(key)%number

数量变动和 node 程序变动,导致 node 抉择的差异性微小,造成微小的缓存生效。

2.2 一致性 hash

hash(node) 造成虚构节点环,hash(key) 落在虚构节点环,找到对应的 node。

因为 hash(node) 的稳定性,与 node 程序无关。node 变更只影响一小部分数据。

2.3 redis cluster 的 hash slot 算法

关系: cluster > node > slot > key

Redis Cluster 在设计中没有应用一致性哈希(Consistency Hashing),而是应用数据分片引入哈希槽(hash slot)来实现。

一个 Redis Cluster 蕴含 16384(0~16383)个哈希槽,存储在 Redis Cluster 中的所有键都会被映射到这些 slot 中。

集群中的每个键都属于这 16384 个哈希槽中的一个,集群应用公式 slot=CRC16(key)/16384 来计算 key 属于哪个槽,其中 CRC16(key) 语句用于计算 key 的 CRC16 校验和。

依照槽来进行分片,通过为每个节点指派不同数量的槽,能够管制不同节点负责的数据量和申请数。

3 集群元数据的一致性

3.1 比照:集中式存储元数据

依赖内部的集中式存储服务,比方:zookeeper, etcd 等,会减少运维累赘和零碎复杂度。

集中式的益处在于,元数据的读取和更新,时效性十分好,一旦元数据呈现了变更,就立刻更新到集中式的存储中,其它节点读取的时候就能够感知到;不好在于,所有的元数据的更新压力全副集中在一个中央,可能会导致元数据的存储有压力。

3.2 gossip 协定来播送本人的状态以及本人对整个集群认知的扭转

ping / pong 音讯来确认节点的存活和同步全副的集群元数据。

集群元数据,包含:master/slave node 列表和状态, slot 与 node 关系。

每个 master node 每秒会执行 10 次 ping,每次会抉择 5 个最久没有通信的其它节点。

定时查看全副节点,如果发现某个节点通信延时达到了 cluster_node_timeout / 2,那么立刻发送 ping,防止数据交换延时过长。

3.3 减少新节点

命令 CLUSTER MEET <ip> <port> 

向一个节点 node 发送 CLUSTER MEET 命令,能够让 node 节点与 ip 和 port 所指定的节点进行握手(handshake),当握手胜利时,node 节点就会将 ip 和 port 所指定的节点增加到 node 节点以后所在的集群中。

依照 gossip 协定,播送 meet 音讯,全副节点接管新节点。

从新 hash(node),调配和转移相应的 slot 给到新节点。

4 客户端如何调用

4.1 hash slot 信息

当客户端连贯任何一个实例,实例就将哈希槽与实例的映射关系响应给客户端,客户端就会将哈希槽与实例映射信息缓存在本地。

4.2 申请数据

当客户端申请时,会计算出键所对应的哈希槽,在通过本地缓存的哈希槽实例映射信息定位到数据所在实例上,再将申请发送给对应的实例。

4.3 重定向机制

客户端将申请发送到实例上,这个实例没有相应的数据,该 Redis 实例会通知客户端更新本地的哈希槽与映射信息的缓存,将申请发送到其余的实例上。

5 新的节点退出集群 (扩容)

同 3.3 减少新节点的前序步骤是一样的。

这里具体理解下从新扩容时 slot 迁徙和数据。

5.1 每个 slot 的迁徙过程如下所示:

  • 对指标节点发送 cluster setslot {slot_id} importing {sourceNodeId} 命令,指标节点的状态被标记为 ”importing”,筹备导入这个 slot 的数据。
  • 对源节点发送 cluster setslot {slot_id} migrating {targetNodeID} 命令,源节点的状态被标记为 ”migrating”,筹备迁出 slot 的数据。
  • 源节点执行 cluster getkeysinslot {slot_id} {count} 命令,获取这个 slot 的所有的 key 列表 (分批获取,count 指定一次获取的个数),而后针对每个 key 进行迁徙。
  • 在源节点执行 migrate {targetIp} {targetPort} “” 0 {timeout} keys {keys} 命令,把一批批 key 迁徙到指标节点 (redis-3.0.6 之前一次只能迁徙一个 key),具体来说,源节点对迁徙的 key 执行 dump 指令失去序列化内容,而后通过客户端向指标节点发送携带着序列化内容的 restore 指令,指标节点进行反序列化后将接管到的内容存入本人的内存中,指标节点给客户端返回 ”OK”,而后源节点删除这个 key,这样,一个 key 的迁徙过程就完结了。
  • 所有的 key 都迁徙实现后,一个 slot 的迁徙就完结了。
  • 迁徙所有的 slot(应该被迁徙的那些),所有的 slot 迁徙实现后,新的集群的 slot 就重新分配实现了,向集群内所有 master 发送 cluster setslot {slot_id} node {targetNodeId} 命令,告诉他们哪些槽被迁徙到了哪些 master 上,让它们更新本人的信息。

5.2 slot 迁徙的其余阐明

  • 迁徙过程是同步的,在指标节点执行 restore 指令到原节点删除 key 之间,原节点的主线程处于阻塞状态,直到 key 被删除胜利。
  • 如果迁徙过程忽然呈现网路故障,整个 slot 迁徙只进行了一半,这时两个节点依然会被标记为两头过滤状态,即 ”migrating” 和 ”importing”,下次迁徙工具连贯上之后,会持续进行迁徙。
  • 在迁徙过程中,如果每个 key 的内容都很小,那么迁徙过程很快,不会影响到客户端的失常拜访。
  • 如果 key 的内容很大,因为迁徙一个 key 的迁徙过程是阻塞的,就会同时导致原节点和指标节点的卡顿,影响集群的稳定性,所以,集群环境下,业务逻辑要尽可能的防止大 key 的产生。

5.3 slot 编号

无需要求每个 master 的 slot 编号是间断的,只有每个 master 治理的 slot 的数量平衡就能够。

5.4 缩小节点 (缩容)

缩容的过程与扩容相似,只是 slot 和数据从下线的节点内转移到其余的节点上。

6 集群中机器呈现故障

6.1 故障检测,节点生效

如果一个节点认为另外一个节点宕机,那么就是 pfail,主观宕机;

如果超过半数的节点都认为另外一个节点宕机了,那么就是 fail,主观宕机;

6.2 故障转移,节点选举

每个 slave 节点,都依据本人对 master 复制数据的 offset,来设置一个选举工夫,offset 越大(复制数据越多)的从节点,选举工夫越靠前,优先进行选举。

所有的 master node 开始 slave 选举投票,给要进行选举的 slave 进行投票,如果大部分 master node(N/2 + 1)都投票给了某个从节点,那么选举通过,那个从节点能够切换成 master。

从节点执行主备切换,从节点切换为主节点。

7 主从同步以及高可用

redis 的主从同步在 cluster 版本之前就存在了,既能够提供更高的查问效率 (多 slave 能够查问),又能够减少服务的可用性 (master 挂机后能够启用 slave 成为 master)。

7.1 应用主从架构时

将只有一个 Master 和多个隶属用于复制。

所有写入都转到主节点,这会在主节点上产生更多负载。

如果 Master 宕机,整个架构容易呈现 SPOF(单点故障)。

当您的用户群增长时,MS 架构无助于扩大。

所以咱们须要一个过程来在产生故障或敞开的状况下监控 Master,那就是 Sentinel。

7.2 Redis 哨兵

故障转移解决

8 主从同步与数据一致性

8.1 主从同步的实现过程

主从同步分为 2 个步骤:同步和命令流传。

数据同步有 sync 和 psync。

sync 全量同步,性能比拟差;psync 增量同步,速度和实时性好很多。

8.2 全量同步 sync

从服务器对主服务的同步操作,须要通过 sync 命令来实现,以下是 sync 命令的执行步骤:

  • 从服务器向主服务器发送 sync 命令
  • 收到 sync 命令后,主服务器执行 bgsave 命令,用来生成 rdb 文件,并在一个缓冲区中记录从当初开始执行的写命令。
  • bgsave 执行实现后,将生成的 rdb 文件发送给从服务器,用来给从服务器更新数据
  • 主服务器再将缓冲区记录的写命令发送给从服务器,从服务器执行完这些写命令后,此时的数据库状态便和主服务器统一了。

8.3 局部重同步 psync

局部重同步性能由以下 3 局部组成:

  • 主从服务器的复制偏移量
  • 主服务器的复制积压缓冲区
  • 服务器的运行 id(run id)

8.4 心跳检测

当实现了同步之后,主从服务器就会进入命令流传阶段,此时从服务器会以每秒 1 次的频率,向主服务器发送命令:REPLCONF ACK <replication_offset> 其中 replication_offset 是从服务器以后的复制偏移量

发送这个命令次要有三个作用:

  • 检测主从服务器的网络状态
  • 辅助实现 min-slaves 选项
  • 检测命令失落(若失落,主服务器会将失落的写命令从新发给从服务器)

8.5 主从同步总结

发送 SLAVEOF 命令能够进行主从同步,比方:SLAVEOF 127.0.0.1 6379

主从同步有同步和命令流传 2 个步骤

  • 同步:将从服务器的数据库状态更新成主服务器以后的数据库状态(一个耗费资源的操作)
  • 命令流传:当主服务器数据库状态被批改后,导致主从服务器数据库状态不统一,此时须要让主从数据同步到统一的过程

主从同步分首次复制和断线后反复制两种状况

  • 从 2.8 版本开始,在呈现断线后反复制状况时,主服务器会依据复制偏移量、复制积压缓冲区和 run id,来确定执行残缺重同步还是局部重同步
  • 2.8 版本应用 psync 命令来代替 sync 命令去执行同步操作。目标是为了解决同步(sync 命令)的低效操作

问题 1:集群的规模是否无限大,比方:1w 台机器?

答案是否定的,redis 官网给的 Redis Cluster 的规模下限是 1000 个实例。

限度的起因,关键在于实例间的通信开销,集群中的每个节点都保留所有哈希槽与节点对应关系信息(Slot 映射到节点的表),以及本身的状态信息。

参照 3.2gossip 协定播送形式,节点越多,播送风暴对于网络以及服务器压力也就越大。

尽管能够设置播送音讯同步的超时工夫,然而节点增多、超时工夫变长之后,数据一致性的音讯同步延时也会更大,呈现元数据不统一的可能性也会减少。

问题 2:从库的应用,以及如何衡量?

从库的作用,一是进步可用性,当主库宕机之后,能够立刻启用从库作为主库提供服务;一是进步伸缩性,进步了数据查问并发能力,从库提供查问服务就减少了服务资源,更多的节点来反对查问。

因为主从同步存在数据一致性问题,所以在应用从库的过程中,相应的也就会遇到一些问题。

比方:因为从库数据同步慢了,这时候主库宕机了,数据不残缺的从库作为主库,就会呈现数据失落的状况。从库用来查问也有相似问题,实时写入的新数据,同步到从库可能会有延时,在数据没有同步到从库的时候查问从库,也会呈现查问无数据的状况。

所以在应用从库的状况下,须要思考到下面的问题。

面对宕机的时候,数据失落的问题,内存型数据库都会存在的危险,应用 redis 都须要面对这个危险,否则就要就义性能高正数据一致性,redis 数据先长久化再提供服务,这样性能就会降落非常明显了,没法满足内存性数据库的劣势了。

启用从库查问,能够针对一些数据更新的实时性较低,对于脏数据不那么敏感的业务,或者查问量切实太大而能够疏忽局部数据延时的影响。

问题 3:redis 集群化之后,代理的必要性?

代理的性能和稳定性同样是问题所在。

产品的运维难度以及继续的保护,还是官网的 redis cluster 更加牢靠。

有条件的团队,针对 redis cluster 的有余,还会有更深刻的优化,比方咱们本人研发的 tendis。

问题 4:单 key 的百万 qps 限频问题?(待解)

单 key 的频繁更新,因为单个 key 有且只能落地到一个 master 节点的一个 slot 下面,无奈通过减少节点减少 slave 的办法扩容,性能瓶颈就会受限于机器的 CPU/ 内存的读写能力了。

假如单机最高 10w 的写如速度,那么,要实现接口的 100w 的 qps 限频性能,要怎么实现呢?

请输入你的解答。。。

附 - 脑洞:三体人来到地球,要毁灭近半的地球人(待解)

三体人不像灭霸,间接用手套简略粗犷的一个响指就覆灭一半生灵,而是给每个人一个抉择,抉择对的人就有机会生存下来。

这个抉择的办法也特地简略,然而须要开发一套零碎来反对。

那么这套零碎的开发工作就落在了地球人最聪慧的程序员你的头上。

开发好了能够让本人以及家人取得豁免权而生存下来,开发的不好,间接咔嚓。

这个抉择的形容如下

寰球有一个三体人的灯球,默认是燃烧状态。

每个人会有一个三体人的开关,下面会显示以后灯球的状态 (燃烧或者亮起),有两个操作按钮,别离是管制灯球的燃烧和亮起。每个人只有一次抉择机会,两个按钮只能抉择一个按钮,按一次。如果一个按钮都不抉择,不按的话,无论灯球最终状态如何,都是要被毁灭。小孩子或者老人、残疾人,能够由监护人来辅助其实现抉择。

零碎实现的前提条件和需要

前提条件阐明

1 寰球 80 亿人口,必须同时在 1 分钟工夫内实现抉择(三体人的开关,寰球实时状态同步,无工夫偏差,无时延),规定工夫范畴之外无奈操作;

2 三体人提供 1000 台 128 核 256G 内存 1T 磁盘的服务器,三体人的开关与服务器的网络是直连的,没有时延,没有网络开销;

3 寰球 80 亿人,每个人都有一个惟一的从 0 开始自增的数字 ID,与三体人的开关也是一一对应的;

4 每个人的 ID%1000 指向特定服务器,申请零碎提供的接口 /vote

零碎需要

性能,开发这个投票接口 (所有申请只会在这 1 分钟内申请)

/vote?uid=1111&click=1&t=1234143134134134134

参数

uid 长整型,每个人的惟一 ID

click 枚举值,按钮抉择,0 燃烧,1 亮起

t 长整型,操作工夫,单位纳秒

解决

1 在同一个时刻 (同一纳秒),如果有多集体操作,抉择次数多的失效,如果 2 个抉择次数雷同,状态不变。如:燃烧 2 次,亮起 3 次,这个时刻的状态是亮起。

后果数据

1 最终灯球的状态,是燃烧,还是亮起;

2 抉择正确的人 (ID 汇合);

3 抉择谬误的人 (ID 汇合);

4 没有做出抉择的人 (ID 汇合);

最终执行

调用三体人在服务器上安装的零碎程序,实现地球人毁灭打算。

kill uid

调用三体人的零碎程序无延时,等同于内存读取的效率。

要求在 1 分钟工夫内,把抉择谬误的人和没有做出抉择的人毁灭掉。

模仿测试

1 三体人在 1 分钟内导入测试用例,实现 80 亿人的抉择。

2 1 分钟正确执行实现 kill 调用。

如果无奈实现上述工作,失败。

请输入你的解答。。。


欢送关注「慕课网」官网帐号,咱们会始终保持提供 IT 圈优质内容,分享干货常识,大家一起独特成长吧!

本文原创公布于慕课网,转载请注明出处,谢谢合作

正文完
 0