众所周知周知,疫情仍然在全球各地肆虐。据最新数据统计,截至北京时间 2020-05-28,全球累计确诊 5698703 例,累计死亡 352282 例,累计治愈 2415237 例。

从上面的统计数据,我们可以看出,新冠病毒在人与人之间的传播是极其高效的,且影响范围广。如果我们把「新冠病毒」想象成一小段数据,将「人与人之间传播」想象成数据交换,那么,我们可以得出结论,在不考虑免疫系统和人为干预等一些因素,经过反复迭代,数据(新冠病毒)可以被发送(感染)到每个节点(人)上。

这个就是今天要介绍的 Gossip 协议,该协议早在 1987 年就被发表在 ACM 上的论文《Epidemic Algorithms for Replicated Database Maintenance》中。当时主要用在分布式数据库系统中各个副本节点间同步数据。

Gossip 协议简介

Gossip 协议分为 Push-based 和 Pull-based 两种模式,具体工作流程如下:

Push-based 的 Gossip 协议:

  • 网络中的某个节点随机选择N个节点作为数据接收对象

  • 该节点向其选中的N个节点传输相应数据

  • 接收到数据的节点对数据进行存储

  • 接收到数据的节点再从第一步开始周期性执行

Pull-based 的 Gossip 协议,正好相反:

  • 集群内的所有节点,随机选择其它 k 个节点询问有没有新数据

  • 接收到请求的节点,返回新数据

如何实现 Gossip

这边简单分析下 HashiCorp 公司的 Serf 的核心库 Memberlist。这家公司研发了 Consul(基于 raft 实现的分布式存储)、Vagrant(声明式虚拟机编排)等优秀的产品。最近由于中美矛盾升级,也陷入到了舆论的漩涡中,爆出禁止在中国使用他们的产品的传闻。不过,这是题外话。

Memberlist 这个 Golang 的代码库,基于 Gossip 协议,实现了集群内节点发现、 节点失效探测、节点故障转移、节点状态同步等。

其核心实现的大致如下:

  • newMemberlist():初始化 Memberlist 对象,根据配置监听 TCP/UDP 端口,用于之后通信。这边需要注意一点,虽然是基于 Gossip 协议实现的,但是并不是所有信息都采用 Gossip 进行数据交换。比如节点加入集群的时候,为了尽快的让集群内所有节点感知到,采用遍历当前已知的所有节点并通过 TCP 连接发送并接收数据的方式,来确保跟所有节点完成数据交换。

  • gossip():Memberlist 对象启动之后,会定期使用 Gossip 协议,随机选择集群内的节点,采用 UDP 传输方式发送当前节点状态以及用户自定义的数据。

  • pushPull():还会定期随机选择一个节点,通过 TCP 传输方式与其做全量数据交换,加速集群内数据一致性收敛。

  • probe():还会定期轮训集群内的一个节点,通过 UDP 方式发送心跳探测包,做到节点感知。

深入 Gossip 核心代码

发送端处理流程:

  • 周期性地随机选择 m.config.GossipNodes 个节点,然后广播正在等待发送的信息

// Create a gossip ticker if needed
if m.config.GossipInterval > 0 && m.config.GossipNodes > 0 {
t := time.NewTicker(m.config.GossipInterval)
go m.triggerFunc(m.config.GossipInterval, t.C, stopCh, m.gossip)
m.tickers = append(m.tickers, t)
}

// gossip is invoked every GossipInterval period to broadcast our gossip
// messages to a few random nodes.
func (m *Memberlist) gossip() {
defer metrics.MeasureSince([]string{“memberlist”, “gossip”}, time.Now())

// Get some random live, suspect, or recently dead nodes
m.nodeLock.RLock()
kNodes := kRandomNodes(m.config.GossipNodes, m.nodes, func(n *nodeState) bool {if n.Name == m.config.Name {return true}switch n.State {case StateAlive, StateSuspect:return falsecase StateDead:return time.Since(n.StateChange) > m.config.GossipToTheDeadTimedefault:return true}
})
m.nodeLock.RUnlock()// ...for _, node := range kNodes {// Get any pending broadcastsmsgs := m.getBroadcasts(compoundOverhead, bytesAvail)if len(msgs) == 0 {return}addr := node.Address()if len(msgs) == 1 {// Send single message as isif err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, msgs[0]); err != nil {m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err)}} else {// Otherwise create and send a compound messagecompound := makeCompoundMessage(msgs)if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, compound.Bytes()); err != nil {m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err)}}
}

}
接收端:

  • 接收数据报文,然后解析报文信息,并将信息记录下来

// packetListen is a long running goroutine that pulls packets out of the
// transport and hands them off for processing.
func (m *Memberlist) packetListen() {
for {
select {
case packet := <-m.transport.PacketCh():
m.ingestPacket(packet.Buf, packet.From, packet.Timestamp)

    case <-m.shutdownCh:return}
}

}

func (m *Memberlist) ingestPacket(buf []byte, from net.Addr, timestamp time.Time) {
// …

// See if there's a checksum included to verify the contents of the message
if len(buf) >= 5 && messageType(buf[0]) == hasCrcMsg {crc := crc32.ChecksumIEEE(buf[5:])expected := binary.BigEndian.Uint32(buf[1:5])if crc != expected {m.logger.Printf("[WARN] memberlist: Got invalid checksum for UDP packet: %x, %x", crc, expected)return}m.handleCommand(buf[5:], from, timestamp)
} else {m.handleCommand(buf, from, timestamp)
}

}

Gossip 协议的优缺点

看了 Memberlist 的实现,难免会有这样的疑问,为什么要使用 Gossip 协议,直接在集群内广播不香么?接下来,我们可以通过 Gossip 协议的优缺点来分析,使用 Gossip 协议的意义。

优点:

  • 协议简单,实现起来很方便

  • 扩展性强,可以允许集群内节点任意增加或者减少,新增节点最终会与其他节点一致

  • 去中心化,节点之间是完全对等的

  • 最终一致性

缺点:

  • 数据同步延迟,因为只保证最终一致性,所以会出现某个时间点,部分节点数据不同步的情况

  • 传输数据冗余,相同数据在节点间会反复被传输

今天对 Gossip 的协议就简单介绍到这里,如果有同学对内容感兴趣,可以回复评论,我们私下多多探讨和交流。

参考资料

https://en.wikipedia.org/wiki/Gossip_protocol

https://github.com/hashicorp/serf

https://github.com/hashicorp/memberlist

https://zhuanlan.zhihu.com/p/41228196

https://www.jianshu.com/p/de7b026f4997

从新冠疫情出发,漫谈 Gossip 协议相关推荐

  1. Python小白的数学建模课-B6. 新冠疫情 SEIR 改进模型

    传染病的数学模型是数学建模中的典型问题,常见的传染病模型有 SI.SIR.SIRS.SEIR 模型. SEIR 模型考虑存在易感者.暴露者.患病者和康复者四类人群,适用于具有潜伏期.治愈后获得终身免疫 ...

  2. 复盘2020全球旅游业:新冠疫情巨大冲击下的艰难复苏

    2020年是不同寻常的一年,由于全球遭遇新冠疫情的巨大冲击,扰乱了全球人的节奏.同时也给各行各业带来了巨大冲击,首当其冲的是全球旅游行业,尤其是航空.游轮.全球旅游等可以说是一片哀嚎.好的一面是中国旅 ...

  3. SSM新冠疫情服务系统 计算机专业毕设源码49727

    摘  要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题.针对疫情服务管理等问题, ...

  4. Gossip协议详解

    起源 Gossip protocol 也叫 Epidemic Protocol (流行病协议),是基于流行病传播方式的节点或者进程之间信息交换的协议..Gossip protocol在1987年8月由 ...

  5. 信息如何实现病毒式传播?一文看懂Gossip协议

    来源 | 架构之美 责编 | 寇雪芹 头图 | 下载于视觉中国 起源 Gossip protocol 也叫 Epidemic Protocol (流行病协议).Gossip protocol在1987 ...

  6. Python小白的数学建模课-B5. 新冠疫情 SEIR模型

    传染病的数学模型是数学建模中的典型问题,常见的传染病模型有 SI.SIR.SIRS.SEIR 模型. 考虑存在易感者.暴露者.患病者和康复者四类人群,适用于具有潜伏期.治愈后获得终身免疫的传染病. 本 ...

  7. 关于Gossip协议的几个问题

    本文来说下Gossip 协议的几个问题 文章目录 概述 Gossip是什么 原理 图解 发送消息 可扩展性 失败容错 健壮性 本文小结 概述 Gossip是一种去中心化.容错并保证最终一致性的协议.它 ...

  8. 冯扬文:新冠疫情下国际航运市场趋势分析

    冯扬文:新冠疫情下国际航运市场趋势分析 一.目前国际海运市场表现 (一)国际集装箱运价持续上涨,运力需求旺盛 2020年下半年以来,市场一直处于缺舱.缺箱.运价上涨的状态.仔2021年下半年曾出现持续 ...

  9. 新冠疫情防控背后有哪些鲜为人知的技术?

    1. 前言 从2019年末从武汉市发现新冠肺炎病毒确诊病例开始,到现在已经有两年多的时间了.在这两年中,从最初的恐慌变得自信,从开始的逃离疫区.抢购物资.扎堆就医,到现在配合流调.主动检测.积极接种疫 ...

最新文章

  1. servlet 访问项目
  2. python少儿编程 在线课程-石家庄Python人工智能编程
  3. python zip
  4. Python之 sklearn:sklearn.preprocessing中的StandardScaler函数的简介及使用方法之详细攻略
  5. EL之RF(随机性的Bagging+DTR):利用随机选择属性的bagging方法解决回归(对多变量的数据集+实数值评分预测)问题
  6. 一个简单的Map Iterator性能测试
  7. C语言与Java的对比,你想好选谁了吗?
  8. coverage.py - python 单元测试覆盖率统计工具
  9. CentOS_7 安装MySql5.7
  10. 熊猫多模式站群-开发日志
  11. 蔡高厅老师 - 高等数学阅读笔记 - 07 - 函数的微分 - 微分中值定理 罗尔、拉格朗日中值定理 (31、32、33、34、35)
  12. 【C语言】在线OJ题 BC72-BC87-牛客网编程初学者入门训练
  13. gitee中打开的index.html中图片不显示_typora + gitee + zsh 实现全免费个人云笔记
  14. 《OpenGL编程指南》收藏的学习网址
  15. 吃饭,睡觉,打豆豆任务二
  16. 20189218 2018-2019-2 《密码与安全新技术专题》第7周作业
  17. 计算机调整亮度是哪个好,电脑屏幕亮度怎么调 电脑屏幕亮度怎么调对眼睛最好...
  18. c语言的编写程序--最简单的算术题
  19. 欢聚时代YY/测试实习面试
  20. 创建html自定义标签,如何为htm创建自定义标签

热门文章

  1. 循环基础-第一个while循环
  2. Hystrix Dashboard的使用与常见问题总结
  3. 设计模式之_Strategy_01
  4. SpringBoot 数据验证错误处理
  5. KDE Applications 19.04 发布,包含大量更新
  6. css3-11 如何实现2D动画
  7. FFmpeg使用遇到问题记录
  8. myeclipse maven 创建 web项目
  9. Lync-技巧-2.启用-用户-启用-语音-设置-线路URI
  10. C++对自定义结构体变量排序