Redis槽指派那事儿,怎么做到集群扩展不卡顿,真挺有意思的
- 问答
- 2025-12-24 02:54:49
- 2
我记得第一次了解到Redis集群的槽指派时,心里就想,这不就是个高级点的分片嘛,但后来仔细一琢磨,它那个设计,尤其是怎么在增加机器的时候让数据搬家还不影响线上服务,这事儿确实挺有意思的,一点也不死板。
(来源:Redis官方文档关于集群数据分片的核心概念)Redis集群不是简单地把数据随便分到几个机器上就完事了,它弄了一个固定大小的“聚会厅”,这个厅里有16384个座位,每个座位就是一个“槽”,你可以把每个键值对数据想象成一位客人,每位客人通过一个算法(CRC16校验和再对16384取模)被分配到一个固定的座位上,这个座位号码是0到16383之间的一个数,而集群里的每个主节点,就像是被分配了负责管理这个大厅里的一部分连续座位,一个三节点的集群,可能节点A管0到5000号座位,节点B管5001到10000号,节点C管10001到16383号,这样一来,任何一个键过来,我都能立刻算出它应该坐在哪个座位,然后就知道该去找哪个节点要数据了,这就避免了需要一个大管家来记录所有客人在哪的麻烦,每个节点自己心里都有本账,知道整个大厅的座位是怎么分配的。

最精彩的部分来了:怎么给这个大厅扩容,比如再加一个节点D,而且不让聚会中断呢?(来源:Redis集群规范中关于重分片的部分)这个过程的巧妙之处在于,它不是一下子把所有数据都搬过去,而是“一个座位一个座位地搬”。
集群的老大会告诉新节点D:“嘿,你以后要负责管理一部分座位了,比如从3000号到6000号。” 它也会通知原来管着这片区域的节点A和节点B,关键点来了:从通知下达的那一刻起,整个集群对于这3000到6000号座位的“管理权”就进入了一个非常有意思的过渡状态。

具体是这样玩的:假设我现在要搬3000号这个座位上的所有客人(数据),集群会先给节点A(原管理者)和节点D(新管理者)下一个命令,这个命令的核心意思是:以后所有对3000号座位的新增、修改操作(写命令),都会在节点A上执行,但同时,节点A会把这个命令本身也转发给节点D,让节点D也跟着执行一遍。 你看,这就好比是,客人还在原来的座位上坐着,但如果有服务员要给他上新的酒水(写数据),就会同时给原座位和新座位都上一份,保证两边是完全一样的。
在这个转发机制运行的同时,一个数据迁移的过程在后台悄悄地开始了,节点A会把自己内存里所有属于3000号座位的客人(键值对),一批一批地搬送到节点D的空座位上,因为是后台操作,所以对前端的性能影响可以降到很低,就像搬家公司在深夜帮你搬大件家具,不影响你白天正常生活。
当3000号座位上的所有客人都被安全搬运过去,并且在一段时间内,通过命令转发机制,两个节点上的数据已经保持绝对同步了之后,集群老大就会正式宣布:“好了,从现在开始,3000号座位归节点D全权负责了!” 这个切换是瞬间完成的,之后,所有针对3000号座位的请求,无论是读还是写,都会直接指向节点D,节点A那里关于3000号座位的数据,就可以被清掉了。
就这样,集群对3000号到6000号之间的每一个座位,都重复一遍上述的“建立转发 -> 后台迁移 -> 切换权责”的过程,因为是一个槽一个槽地迁移,所以整个集群在扩容期间始终是可以提供服务的,对于不涉及正在迁移的槽的请求,完全不受影响;对于正在迁移的槽的请求,因为有了那个巧妙的命令转发机制,也能得到正确的处理,客户端最多可能感觉到一点点延迟,但绝不会出现数据错乱或者服务不可用的情况。
你说这事儿有意思吧?它没有用什么高深莫测的黑科技,就是用一个“双写”的中间状态,平滑地解决了数据迁移的难题,这就像给一列高速行驶的火车换轮子,它不是猛地刹停,而是让新轮子先在旁边跟着转,同步上速度后,再稳稳地把车体承托过去,这种务实又精巧的设计思路,才是真正让人拍案叫绝的地方。

本文由颜泰平于2025-12-24发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/67292.html
