资讯专栏INFORMATION COLUMN

从RocketMQ我们学到了什么之NameServer

wangbjun / 2402人阅读

摘要:故事中的下属们,就是消息生产者角色,屋子右面墙根那块地就是消息持久化,吕秀才就是消息调度中心,而你就是消息消费者角色。下属们汇报的消息,应该叠放在哪里,这个消息又应该在哪里才能找到,全靠吕秀才的惊人记忆力,才可以让消息准确的被投放以及消费。

微信公众号:IT一刻钟
大型现实非严肃主义现场
一刻钟与你分享优质技术架构与见闻,做一个有剧情的程序员
关注可了解更多精彩内容。问题或建议,请公众号留言。

在很久很久以前,人们之间的通信方式就是面对面交谈,你说一句,我听一句,虽然简单可靠,但是弊端也很大。
比如,当你成为一个军队的首领,每个属下一有情况就立刻向你汇报,一个还好,但当你的属下有几十个几百个的时候,他们每天不分时间不看场合,都在叽叽喳喳和你汇报情况,那你可能什么都听不到,而且脑袋都要炸掉了。这个时候,你说停,都给我停下,要汇报情况的,去门口排队,一个一个的来,这个就叫做流量削峰,一群人不要一拥而上,都乖乖给我排队去。
然后你就一个接一个的听,听了整整24个小时,实在困的不行,寻思着这样不行呀,如此下去可能就要天妒英才了,于是你又说,来人,发笔和纸,都把要汇报的消息写在纸上,写完后告诉吕秀才,然后听吕秀才的指示,沿着屋里右面墙根,按照指示的位置叠放整齐,汇报的人就可以退下该做啥做啥去吧,等我休息一下,再来看你们的汇报内容,这就叫做异步处理,你终于可以由自己掌控消息获取的进度了,美滋滋的去睡觉了。
而汇报的人把内容写在纸上,叠放好,就可以退下自己做自己该做的事情,而不是一直在门口等待汇报,这个就叫做解耦。
削峰,异步,解耦。这就是消息队列最常用的三大场景。
故事中的下属们,就是消息生产者角色,屋子右面墙根那块地就是消息持久化,吕秀才就是消息调度中心,而你就是消息消费者角色。下属们汇报的消息,应该叠放在哪里,这个消息又应该在哪里才能找到,全靠吕秀才的惊人记忆力,才可以让消息准确的被投放以及消费。

消息调度中心是今天的主角

在RocketMQ里,就有一个角色和吕秀才的作用一样,叫做NameServer,它是整个分布式消息调度的总控制,是RocketMQ的灵魂之所在,倘如没有了它,RocketMQ会分崩离析无法工作。
那么,它是怎么工作的呢?
我们先来看一张RocketMQ物理架构图:

乱如蜘蛛丝?不要害怕,换句话说,先忘掉这张图吧。

我们来类比一下现实生活,有一个人想要给另外一个人寄快件,那么就需要先由这个人在网上查询有哪些邮局,然后选择其中一个邮局,把快件投递给它,再由邮局配送到目标人。

需要完成这一整个业务流程,首先需要将邮局自身的信息注册到卫星网络上,卫星负责信息的调度,这样发件人就知道有哪些邮局可以选择,收件人通过卫星网络知道快件到了哪个邮局,可以联系邮局沟通适合的配送时间,而邮局则负责接收配送存储快件。
类比RocketMQ简线图就是如下:

Producer:消息⽣产者,⽤于向消息服务器发送消息,就是图中的寄件人。
NameServer:路由注册中⼼,就是图中的卫星。
Broker:消息存储服务器,就是图中的邮局。
Consumer:消息消费者,不是今天的重点,图中未标出,就是收件人。

由此可见,NameServer作为分布式消息队列的协调者,具有信息路由注册与发现的作用。

路由注册

邮局在竣工后,需要与卫星联网,将自己纳入卫星网络管理中,这样就相当于对外宣布,我这个邮局开始运营了,可以收发邮件快递了。
邮局并网之后,如何让卫星持续并及时感知这个邮局在线以及邮局自身信息的调整,使卫星可以随时协调这个邮局呢?这个时候就需要邮局定时向卫星发一条信息:
“哔哔哔————我是邮局C,编号SHC,地址XXXXX,归属中国上海集群,在线,此时此刻2019年3月15日13点21秒”
卫星接收到消息后,拿个小本本记录下来:
“邮局B,BJB,北京,2019年3月15日13点10秒,活着...”
“邮局A,BJA,北京,2019年3月15日13点15秒,活着...”
“邮局C,SHC,上海,2019年3月15日13点21秒,活着...”
......

上面这个故事,就讲述了NameServer路由注册的基本原理。
NameServer就相当于卫星,内部会维护一个Broker表,用来动态存储Broker的信息。
而Broker就相当于邮局,在启动的时候,会先遍历NameServer列表,依次发起注册请求,保持长连接,然后每隔30秒向NameServer发送心跳包,心跳包中包含BrokerId、Broker地址、Broker名称、Broker所属集群名称等等,然后NameServer接收到心跳包后,会更新时间戳,记录这个Broker的最新存活时间。
NameServer在处理心跳包的时候,存在多个Broker同时操作一张Broker表,为了防止并发修改Broker表导致不安全,路由注册操作引入了ReadWriteLock读写锁,这个设计亮点允许多个消息生产者并发读,保证了消息发送时的高并发,但是同一时刻NameServer只能处理一个Broker心跳包,多个心跳包串行处理。这也是读写锁的经典使用场景,即读多写少。

路由剔除

忽然有一天,邮局C的机房进老鼠了,咬断电源线宕机了,而卫星不知道邮局C业务故障了,依旧将带有邮局C的邮局表信息传给寄件人(生产者),寄件人联系邮局C发送快件,但是邮局C机房宕机,业务暂停,处于瘫痪状态,自然也就无法接收快件了。
另一方面,因为快件未能被邮局C收入,也就无法将快件转交给收件人,顾客们久久等不到自己的快件,纷纷投诉,为此邮局C的管理层备受责难。
于是邮政总局技术部开始研究讨论,怎么让卫星可以感知到邮局“失联了”,从而自动排除故障邮局,将其负责的业务交付给其他正常的邮局处理,这样就不会因为某一个邮局出现问题,而导致这个邮局所管辖的部分业务无法处理。
大家众说纷纭,最后敲定了一个方案,让卫星每隔一段时间扫描邮局信息表,如果发现某个邮局上报信息时间与当时扫描时间之间的差值超过了某个预设的阈值,就判定这个邮局“失联了”,将此邮局信息从邮局表中剔除。这样寄件人查询到的邮局表里都是正常营业的邮局信息。
新功能上线运营后,效果不错,大家再也不用担心因为某个邮局故障而导致业务停滞,又过上了泡茶报纸的生活。

这个故事同样在RocketMQ中上演。
正常情况下,如果Broker关闭,则会与NameServer断开长连接,Netty的通道关闭监听器会监听到连接断开事件,然后会将这个Broker信息剔除掉。
异常情况下,NameServer中有一个定时任务,每隔10秒扫描一下Broker表,如果某个Broker的心跳包最新时间戳距离当前时间超多120秒,也会判定Broker失效并将其移除。

细心的人会发现一个问题,NameServer在清除失活Broker之后,并没有主动通知生产者,生产者每隔30秒会请求NameServer并获取最新的路由表,那么就意味着,消息生产者总会有30秒的延时,无法实时感知Broker服务器的宕机。所以在这个30秒里,生产者依旧会向失活Broker发送消息,那么消息发送的高可用性如何保证呢?
要解决这个问题得首先谈一谈Broker的负载策略,消息发送队列默认采用轮询机制,消息发送时默认选择异常重试机制来保证消息发送的高可用。当Broker宕机后,虽然消息发送者无法第一时间感知Broker 宕机,但是当消息生产者向Broker发送消息返回异常后,消息生产者会选择另外一个Broker上的消息队列,这样就规避了发生故障的Broker,结合重试机制,巧妙实现消息发送的高可用,同时由于不需要NameServer通知众多不固定的生产者,也降低了NameServer实现的复杂性。

在降低NameServer实现复杂性方面,还有一个设计亮点就是NameServer之间是彼此独立无交流的,也就是说NameServer服务器之间在某个时刻的数据并不会完全相同,但是异常重试机制使得这种差异不会造成任何影响。

路由发现

天上的卫星是有限的,不易变的,而地上的寄件人是繁多的,易变的。所以寄件人想要知道有哪些邮局,很明显最适合的方式是向卫星发请求,拉取邮局表信息,而不是等卫星给每个人推送。
所以在RocketMQ中,NameServer是不主动推送会客户端的,而是由客户端拉取主题的最新路由信息。

CAP理论

NameServer作为注册和发现中心,是整个分布式消息队列调度的灵魂,谈及到分布式,就逃不开CAP理论,C是Consistency,A是Availability,P是Partiton Tolerance,对于分布式架构,网络条件不可控,出现网络分区是不可避免的,因此必须具备分区容错性,那么NameServer就是在AP还是CP中选择了,由于NameServer之间相互独立,很明显,是一个AP设计。

之所以替换掉Zookeeper

ZooKeeper为分布式应用程序提供协调服务。那为什么RocketMQ要自己造轮子,开发集群的管理程序呢?因为ZooKeeper的功能很强大,包括自动Master选举等,RocketMQ的架构设计决定了它不需要进行Master选举,用不到这些复杂的功能,只需要一个轻量级的元数据服务器就足够了。
中间件对稳定性要求很高,RocketMQ的NameServer只有很少的代码,容易维护,所以不需要再依赖另一个中间件,从而减少整体维护成本。

学到了什么?

1.长连接编程模型⾥⼼跳的实现原理
2.多线程编程中读写锁的经典使⽤⽅式
3.追求简单⾼效⼜可靠的实现⽅式

说在后面的话

想要研究NameServer源代码的,请点击链接:https://github.com/MrChiu/Roc...
里面附有我标注的注释,易于通读代码


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73801.html

相关文章

  • RocketMQ我们学到什么NameServer

    摘要:故事中的下属们,就是消息生产者角色,屋子右面墙根那块地就是消息持久化,吕秀才就是消息调度中心,而你就是消息消费者角色。下属们汇报的消息,应该叠放在哪里,这个消息又应该在哪里才能找到,全靠吕秀才的惊人记忆力,才可以让消息准确的被投放以及消费。 微信公众号:IT一刻钟大型现实非严肃主义现场一刻钟与你分享优质技术架构与见闻,做一个有剧情的程序员关注可了解更多精彩内容。问题或建议,请公众号留言...

    Arno 评论0 收藏0
  • rocketmqproducer解析

    摘要:所以基于目前的设计,建议关闭自动创建的功能,然后根据消息量的大小,手动创建。如果发送消息,返回结果超时,这种超时不会进行重试了如果是方法本身耗时超过,还未来得及调用发送消息,此时的超时也不会重试。 先来看下producer核心的类设计,如下图: showImg(http://pbdqyl9hh.bkt.clouddn.com/rocketmq/producer%E7%B1%BB%E5%...

    luodongseu 评论0 收藏0
  • 高并发异步解耦利器:RocketMQ究竟强在哪里?

    摘要:它是阿里巴巴于年开源的第三代分布式消息中间件。是一个分布式消息中间件,具有低延迟高性能和可靠性万亿级别的容量和灵活的可扩展性,它是阿里巴巴于年开源的第三代分布式消息中间件。上篇文章消息队列那么多,为什么建议深入了解下RabbitMQ?我们讲到了消息队列的发展史:并且详细介绍了RabbitMQ,其功能也是挺强大的,那么,为啥又要搞一个RocketMQ出来呢?是重复造轮子吗?本文我们就带大家来详...

    tainzhi 评论0 收藏0
  • 深度解析RocketMQ Topic的创建机制

    摘要:当接收到消息后,会在方法中调用方法,将的信息塞进缓存中,并且会定时发送心跳将发送给进行注册。这也说明了当用集群模式去创建时,集群里面每个的的数量相同,当用单个模式去创建时,每个的数量可以不一致。 微信公众号「后端进阶」,专注后端技术分享:Java、Golang、WEB框架、分布式中间件、服务治理等等。 老司机倾囊相授,带你一路进阶,来不及解释了快上车! 我还记得第一次使用rocket...

    gself 评论0 收藏0
  • SpringBoot RocketMQ 整合使用和监控

    摘要:前提通过前面两篇文章可以简单的了解和安装,今天就将和整合起来使用。然后我运行之前的整合项目,查看监控信息如下总结整篇文章讲述了与整合和监控平台的搭建。 showImg(https://segmentfault.com/img/remote/1460000013232432?w=1920&h=1277); 前提 通过前面两篇文章可以简单的了解 RocketMQ 和 安装 RocketMQ...

    Jacendfeng 评论0 收藏0

发表评论

0条评论

wangbjun

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<