redis源码分析(八):集群--cluster

redis源码分析(八):集群--cluster

redis集群我们可以使用sentinel的模式(详情点击这里),这个模式有几个缺点

  • 1.sentinel是用来监控redis的,这个进程本该对客户端隐藏,但是sentinel模式下,master如果down了,某个slave成为master后,客户端无法感知,因此需要客户端还需要连接sentinel来获取master的地址。
  • 2.sentinel部署方式本质还是一主多从的模式,master的压力比较大。

redis官方还提供了另一种集群的方式 -- cluster, 一个集群中数据根据其key的哈希值被分别存储到 0 ~ 16383个槽中(slot)。每个槽均要被唯一添加到集群master节点中,在所有槽都被添加以后,集群的状态才会变成可用。

集群搭建

如果需要启用cluster集群的话,需要更改配置如下:

port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes

拷贝6份可执行程序到不同文件夹,从node1到node6,端口范围7001~7006,编写脚本startup.sh以便调试,内容如下:

pkill redis-server

cd node1
./redis-server ./redis.conf &
cd ..

cd node2
./redis-server ./redis.conf &
cd ..

cd node3
./redis-server ./redis.conf &
cd ..

cd node4
./redis-server ./redis.conf &
cd ..

cd node5
./redis-server ./redis.conf &
cd ..

cd node6
./redis-server ./redis.conf &
cd ..

编写cleanup.sh来清除节点信息和数据

rm ./*/nodes.conf
rm ./*/*.aof

启动一个干净的集群集合以后。

我们通过一下操作来创建一个简单的集群。1.连接各节点,2.分配槽 3.用cluster nodes 获取到各节点的名称,然后用cluster replicate设置各个slave的master节点。


1. redis-cli -p 7001 

> cluster meet 127.0.0.1 7002

> cluster meet 127.0.0.1 7003

> cluster meet 127.0.0.1 7004

> cluster meet 127.0.0.1 7005

> cluster meet 127.0.0.1 7006



2. redis-cli -h 127.0.0.1 -p 7001 cluster addslots {0..5461}

   redis-cli -h 127.0.0.1 -p 7002 cluster addslots {5462..10922}

   redis-cli -h 127.0.0.1 -p 7003 cluster addslots {10923..16383}


3. redis-cli -p 7004 //重复三次
> cluster replicate $MasterName


用redis-cli -c 来连接集群服务端,每次写操作,如果key映射出来的槽不是这个节点处理的,他会返回一条MOVED错误和应该接收这条写命令的master节点信息。客户端需要重定向到这个地址去写入数据。

流程分析

接下来我们就可以将代码附加到其中一个程序开始观察整个流程了。

redis启动时除了监听port端口以外,还启动了port+10000的端口,用于集群服务各进程间互联,每个客户端连接的socket处理读事件的函数是clusterReadHandler。

集群的命令

集群模式下有个重要的命令"cluster",下面解析几个重要的:

  • cluster meet $host $port 与其他集群的节点建立链接。

  • cluster info 查看当前集群的简略信息。

  • cluster nodes 查看当前的节点信息。

  • cluster addslots/delslots $slot1 $slot2 ... $slotn 添加(删除)槽到当前节点。可以使用 redis-cli -h $host -p $port cluster addslots {$begin..$end} 来批量添加的连续end-begin个槽,(进入了客户端内后敲不行)。注意同一个槽不能重复添加。

  • cluster flushslots 删除当前所有的槽。

  • cluster setslot $slot migrating $targetName 将$slot槽从本节点迁移到目标节点,节点名称为每个节点的runid。

  • cluster setslot $slot importing $sourceName 将$slot槽从源节点迁移到本节点,为上条的逆操作。

  • cluster keyslot $key 计算$key应该被放到哪个槽中。

  • cluster replicate $targetName 设置当前节点为slave,并从对应的master中复制数据,注意slave有旧数据或被分配了槽会操作失败。

这里有一个小插曲,(测试的时候发现还没有调用addslots来添加槽,有的节点就凭白无故多了几个固定的槽,后来跟了代码发现是该节点aof文件没有清除,导致了节点启动的时候读取数据并加给自己了槽。)

集群的时间事件。

集群的时间事件处理函数是clusterCron。我们看看它都干了什么。

1.连接集群内的其他未连接上的服务进程,调用"cluster meet $ip $port"时,会新建一个集群节点放入“server.cluster->nodes”,在下次时间周期到来时连接port+10000端口,并设置读事件处理函数为clusterReadHandler,注意到这个和本地监听的集群端口处理函数是同一个。首次连接,给其发送meet命令(断线重连,直接发ping)。

2.每十次事件循环执行一次,随机ping五个集群内的其他进程。

3.断开连接超时的链接,在下个周期会重连。

4.由slave来统计各个master上的slave数量。如果当前有master下的slave都挂了,且当前的集群保存最多slave的master上有大于2个的slave,那么可以分一个slave给那个"光杆司令"master。具体的迁移处理函数是clusterHandleSlaveMigration,具体算法就是对比各个slave的runid字符串,如果自身的最小,则开始迁移

5.如果主节点挂了(超半数节点认为他挂了),而且当前节点是它的slave,那么此时开始发送一个故障转移授权请求。

6.故障转移,如果当前节点是slave,对应的master挂了且获得了故障转移权限,则开始故障转移,将自身升级为master,继承原master的槽,并通知其他节点自己升级了。此时如果原master又启动了,发现纪元比新的master小,只能降级为slave。

对集群中其他节点发来消息的处理

处理函数是上文提及的clusterReadHandler,我们直接看调用到的核心函数clusterProcessPacket。

1.处理ping和meet消息,均返回pong,将新消息的数据更新到本节点。注意到在所有ping,pong,meet消息中,均会去尝试携带二者(自己和对方)之外节点的gossip信息,特别是状态信息。这个机制保证了,在有限的时间内,所有节点均可以meet each other。

2.如果有从节点的master发生了变更,修改本地数据。如果有master的槽信息发生了变化,更新之。

3.异常处理--(如果有master重启可能会发生。)如果对方是master,且本节点记录的master中,管理的槽和对方有重复。则通知纪元较小的修正;同理,接收到了CLUSTERMSG_TYPE_UPDATE请求,如果本节点的纪元较小,也需更新本节点的槽信息。

4.解析对方节点A的gossip信息,如果gossip中的目标节点B的状态是疑似下线或者已下线,将A添加节点B的failedlist中。如果大多数节点都认为这个节点下线了,那么我们将其从疑似下线转变为下线。

5.假设master A下线了,其slave会发起一个故障转移的授权请求,只有master有投票权。所有接受到该消息的master节点如果确定A确实下线了,那么投B一票。投票的过程和sentinel选举新的master的过程类似,都是基于纪元累增,胜出的slave将执行故障转移。

只是略读了一下代码,大致理清楚了其中的业务处理和故障处理流程,master挂了各节点会怎么做? slave挂了各节点会怎么做?

但是集群涉及到多个节点共同合作,细节很多,比如数据一致性的问题。自己脑袋确实不够用了,先写到这里吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345