当前位置:首页 > 问答 > 正文

Redis集群连接到底是咋回事,过程细节一步步拆解讲给你听

想象一下,Redis集群就像一个有好多家分店的超级大超市,你是一个顾客,想去买一件特定的商品(也就是你想存取的一个数据),你不知道这个商品具体放在哪家分店,你只知道它的名字(也就是数据的key),Redis集群连接的过程,就是你如何找到正确的分店并成功买到东西的整个过程。

第一步:你拿到总店的地址(初始化连接)

你手里不会有一张包含所有分店地址的完整列表,你通常只知道一个或几个分店的地址,这些就是你在代码里配置的“种子节点”地址,你的代码里可能配置了 redis-node1:6379redis-node2:6379,这就像你只知道这个超市在城东和城西有两家店,但你不知道全市到底有多少家。

你的客户端(比如你用Java写的程序)启动后,就拿着这个地址,先去尝试连接其中任意一个节点,比如先连城东店(redis-node1:6379),这个第一次握手,就是为了获取最重要的情报。

第二步:向总店索要“分店地图”(获取集群槽位映射)

连接上城东店之后,你的客户端不会急着说要买什么商品,它会先问这个节点:“喂,把咱们整个超市所有分店的‘货架分布图’给我一份!”

这个“货架分布图”,在Redis集群里叫做 槽位映射(Slot Map),Redis集群把所有的数据(也就是所有可能的key)分成了16384个槽位(slot),可以想象成把整个超市的商品种类分成了16384个类别,每个分店(Redis节点)都负责保管其中一部分槽位对应的商品,城东店负责管理0号到5000号槽位的商品,城西店负责管理5001号到10000号槽位的商品,以此类推。

城东店的店员会很爽快地给你这张“地图”,它包含了所有16384个槽位分别由哪个分店(哪个节点)负责,客户端拿到这份地图后,会立刻在自己内存里缓存起来,这样它就知道任何一件商品(任何一个key)应该去哪个分店找了。

第三步:计算你的商品该去哪家分店(计算Key对应的Slot)

你的程序要执行一个命令了,set userName "张三",客户端不会盲目地把这个命令发给最初连接的城东店,它要先做个计算:商品“userName”应该放在哪个货架(槽位)上呢?

客户端会对这个key(“userName”)执行一个固定的算法(CRC16哈希后再对16384取模),算出来一个介于0到16383之间的数字,假设算出来是5790,它马上翻出自己缓存的那张“地图”一看,5790号槽位归城西店(redis-node2:6379)管。

第四步:直奔正确的分店完成操作(重定向到正确节点)

这个时候,有两种情况:

  1. 理想情况(智能客户端):你用的是一个比较“聪明”的客户端库(比如Java的Lettuce),它自己已经算好了5790属于城西店,所以它压根就不会把 set userName "张三" 这个命令发给城东店,而是直接创建一个新的网络连接,发给了城西店,城西店一看,这个商品正是我管的,没问题,于是成功存下数据,并返回操作成功的信息给你,这是最高效的方式。
  2. 一般情况(需要一次跳转):如果你用的客户端没那么智能,或者它缓存的地图过期了,它可能会先把命令发给一开始连接的城东店,城东店的店员一查自己的账本,发现“userName”这个商品(槽位5790)不归我管,归城西店管,于是它会给你一个回复,这不是一个成功的回复,而是一个“提示条”,上面写着:MOVED 5790 redis-node2:6379,这个“MOVED”错误就是一个友好的指引,告诉你:“客官,您要的东西在城西店,这是地址,您去那儿买。”

一个聪明的客户端在收到这个“MOVED”错误后,会做两件事:第一,根据指引去连接正确的城西店,完成本次操作;第二,更新自己内存里的“地图”,把5790号槽位正确映射到城西店,这样下次再遇到这个槽位的key,就可以直接过去了,不用再问一次路。

第五步:应对突发状况——分店搬家了(处理连接变化)

超市运营中,难免有调整,公司为了平衡客流,把原来城西店管的5001-6000号槽位的商品,全部搬到了新开的城南店去卖,这就是Redis集群的重分片(Resharding)

这时,如果你的客户端缓存的老地图还没更新,它依然会傻乎乎地拿着一个属于5500号槽位的key去找城西店,城西店的店员会告诉你:“不好意思,这部分商品已经搬到城南店了。”但这次它给出的不是“MOVED”提示,而是另一个指令:ASK 5500 redis-node3:6379

“ASK”和“MOVED”有点像,但含义不同。“MOVED”是永久性迁移,意思是“以后这个槽位都归他管了,你更新下地图吧”。“ASK”是临时性迁移,是重分片过程中发生的,意思是“这次你要的东西暂时在我这里搬家的路上,你先去新店(城南店)要,但你的地图暂时还不用改,等全部搬完了会通知你”。

客户端收到“ASK”后,会临时去一次新节点执行命令,但不会更新自己缓存的槽位映射,只有当它之后再次收到“MOVED”指令时,才会更新地图,因为那表示迁移已经彻底完成了。

总结一下全过程:

整个Redis集群连接的核心就是:凭借最初的一两个地址,拿到全局的“槽位地图”,然后通过计算key属于哪个槽位,来精准定位到应该连接的节点。 整个过程的目标就是避免每次操作都要问路,而是让客户端自己变成“活地图”,通过“MOVED”和“ASK”这两种响应机制,灵活地处理集群扩容、缩容等动态变化,保证在店铺不断调整的过程中,你作为顾客最终总能找到正确的商品,这一切都是为了实现Redis集群的核心思想:数据分片和高可用。

Redis集群连接到底是咋回事,过程细节一步步拆解讲给你听