cassandra 之 gossip实现

转自:http://blog.163.com/liaoxiangui@126/blog/static/795696402012123113540670/

1 概述
本文的描述基于cassandra 0.6.3 源代码。
gossip协议解决了在分布式环境中,如何使用最少的网络带宽,达到数据同步的目的。同步的数据包括:集群中有哪些节点以及这些节点的状态。
重点提示:节点只能更新属于自己的状态数据。
在cassandra中,和状态相关的类图的设计见图1。endPointStateMap_存储了本节点已知的节点的状态。状态的数据由2部分组成:心跳状态数据(hbState_)和 应用数据(applicationState_)。
心跳状态数据
■generation_   用来区分是否是宕机后重启,存储在系统表中,每次启动是增加1
■version_      每隔1秒,增加1
应用状态数据
由多个三元组组成。三元组的结构是:<key,state_,version>。具体的数据有:
■磁盘的使用情况(keyis ”LOAD-INFORMATION”)
■节点的生命周期状态(key is ”MOVE”,value is BOOT/NORMAL/LEAVING/LEFT)。


2 实现
2.1 syn消息
1) 从endPointStateMap_获取各个节点的摘要数据(digest),包括本节点
    <addr, heartbeat-generation,max-version>
    addr:节点地址
    generation:从hbState_中获取
    max-version:从applicationState_中获取最大的版本号
2) 把摘要数据打包
限制:数据包的大小限制是1428,一次只发送一个包。为了在数据链路层分片,所以限制了一次send的数据量大小,1428= 1500(MTU) – 20(ipheader len) – 20(tcp header len) – cluster name len(32)。
如果摘要数据大小大于1428,则只发送部分数据。选择哪部分数据? 随机选择,但是本节点的摘要数据一定被包括。
代码参见Gossiper.GossipTimerTask.run()。


2.2 ack消息
收到syn消息后,按照如下流程进行处理
1)检查cluster name
2)根据摘要数据,更新本地为各个节点维护的心跳队列
If 远端generation > 本地generation
    更新心跳队列;
elseif远端generation  == 本地generation &&  远端maxversion > 本地maxversion
    更新心跳队列;
提示:心跳队列用来进行故障探测,具体参见我的文章《cassandra之failure detector》。
3)比较摘要数据和本地数据,生成要返回的摘要数据和状态数据
■生成返回的摘要的数据
if 本地节点没有此节点的数据
    生成摘要数据:<addr, 远端generation,0>
elseif远端generation  > 本地generation
    生成摘要数据: <addr, 远端generation,0>
elseif远端generation == 本地generation&& 远端max-version >本地远端max-version
    生成摘要数据: <addr, 远端generation,本地max-version >
■生成返回的状态数据
应用状态数据
if远端generation  < 本地generation
    生成返回数据:此节点的所有状态数据
elseif远端generation  == 本地generation && 远端max-version < 本地max-version
    生成返回数据:此节点的所有版本号大于远端max-version状态数据。
心跳数据
hbState_设置和本地的一样。
■把待返回的摘要数据和状态数据打包
限制:数据包的大小限制是1428(1500-20-20-clusternamelen),一次只发送一个包。如果待返回的数据大于1428,摘要数据的优先级大于状态数据。在摘要数据中,节点的max-version和摘要数据的差值的绝对值越大,优先级越高。在状态数据中亦然如此。
4) 发送数据包
代码参见GossipDigestSynVerbHandler。


2.3 ack2消息
2.3.1处理ack消息
1)处理ack消息中的状态数据
■更新心跳队列
远端 hbState_ . generation(记为G1) 和 hbState_ . version_(记为V1)
本地hbState_ . generation (记为G2) 和 applicationState_中最大的 version_(记为V2)
if G1 > G2
    更新心跳队列;
elseif G1==G2 && V1>V2
    更新心跳队列;
■更新本地的状态数据
远端 hbState_ . generation(记为G1) 和applicationState_中最大的 version_ (记为V1)
本地hbState_ . generation (记为G2) 和 applicationState_中最大的 version_(记为V2)
if 本地没有此节点的状态数据
    把此节点的状态保存在本地
elseif G1 >  G2
    删除此节点的所有状态数据,把ack消息中此节点的状态数据存储在本地
elseif G1 == G2 &&  V1 > V2
    比较远端的applicationState_ 和 本地applicationState_。若远端数据项的版本号比本地的新,
    这更新本地的数据项目;若远端的数据项在本次不存在,则添加至本地的applicationState_。
2)处理ack消息中的摘要数据
■生成待返回的状态数据
应用状态数据
本地的应用状态数据和摘要数据中的version比较,若大于,这加入至待返回的数据中,
心跳状态数据
hbState_设置和本地的一样。
注意:没有比较generation,因为在远端生成这些数据的时候,已经比较,个人觉得还是比较为好,因为数据是不断变化的。
3)发送在上个步骤中生成的状态数据
需要保证发送的数据不超过1428字节。
代码参见GossipDigestAckVerbHandler。


2.3.2处理ack2消息
同2.3.1 中的步骤1)。
代码参见GossipDigestAck2VerbHandler。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值