使用NATS的轻量级云原生消息传递

在为云构建应用程序时,我们通常会付出很多努力来分解整体,并将应用程序构建为小型,容器化的工作负载,这些工作负载遵循云原生应用程序的12(或15)个因素。 由于我们的注意力集中在代码库的内部,我们经常将有关消息传递的讨论和设计留在积压中。

消息传递是任何大规模分布式系统的中枢神经系统。 无论我们是在进行事件源还是更简单的工作调度模型,消息传递都是使一切正常运行的粘合剂。 没有它,我们精彩的分布式系统就会停顿下来。

那么,我们如何为应用程序选择消息代理或消息传递体系结构? 令人感到不知所措,已经有大量选项可用,每天都有新选项出现。

在复杂性和规模的尽头,我们有了Kafka 。 Kafka通常被称为分布式日志存储。 假定发布到Kafka主题的消息将保留一段时间,并且使用消费者组的概念允许消息在同一服务的多个实例之间平均分配。 它非常强大,但随之而来的是巨大的责任。 Kafka难以维护,并且对于任何希望熟练掌握该技术的团队来说都具有陡峭的学习曲线。

另一个非常常见的选择是RabbitMQ (或者实际上是任何符合AMQP的经纪人)。 Rabbit的重量大大减轻,但是Rabbit没有使用唯一的消费者组的概念,而是采用了让客户使用队列的简单方法。 如果客户端不确认消息,则它将返回队列以供其他消息处理。 这种体系结构产生了一些细微的差别,例如允许允许两个工人接收相同调度的较小的时间窗口,等等。

即使像Redis这样的不以消息代理人身份收费的应用程序也支持发布/订阅消息传递。 如您所见,围绕消息代理的产品和服务列表非常庞大且不胜枚举。

这些产品中的每一个都有其亮点和发光的地方。 Kafka在具有持久性消息日志的大规模消息流和聚合方案中展示了其真正的实力。 Rabbit在需要更简单的发布/订阅功能以及在消息代理程序范围之外需要强制的工作幂等性的环境中蓬勃发展。 如果您所有的邮件客户端也都在与Redis进行缓存,并且您不需要保留邮件,则Redis甚至可能是一个很好的选择。

如果我想真正接受“中枢神经系统”的想法,但又不希望其他解决方案的所有开销怎么办? 如果我想既可以进行传统的发布/订阅,又可以进行请求/回复,甚至可以进行分散聚会,同时又能保持轻巧轻巧,该怎么办? 这是更适合NATS的地方。

NATS是一个基于简单但功能强大的内核而构建的快速,开源的消息传递系统。 该服务器使用基于文本的协议,因此,尽管有许多特定于语言的客户端库,但是您可以从字面上telnet到NATS服务器并发送和接收消息。 NATS被设计为始终在线,已连接并准备接受命令。 如果您足够大,可以知道“ 拨号音 ”是什么,那么值得一提的是,NATS文档喜欢在设计中使用这种类比。

为了了解在NATS上构建应用程序的感觉,让我们逐步介绍几个常见的用例。

在最简单的发布/订阅模型中,我们有一个发布者,它向主题发出消息(尽管您可能更熟悉主题一词)。 对有关该主题的消息感兴趣的任何一方都订阅它。 然后 NATS将保证最多一次交货。 这意味着可以保证从单个发布者发送的邮件可以按顺序到达,但是不能在多个发布者之间保留订单。 我将把“全局消息排序”兔子洞的讨论保存在以后的博客文章中,因为辩论可能持续数天。

假设我们正在构建一个进行面部识别的视频分析系统。 随着分析器在大量媒体上取得进步,我们希望将该进展发布给任何有兴趣的人。

由于NATS是文本协议,因此您只需发出如下命令即可:

  PUB分析进度55 
{“哈希”:“ abc56fghe”,id:12,进度:32,面孔:78}
+确定

我们告诉NATS主题( analysis.progress )和内容长度(55字节)。 然后,换行符在实际数据之前和之后。 如果一切顺利,NATS会给我们+OK答复。 这与某些消息代理使用的一些复杂甚至专有的二进制协议形成了鲜明的对比。 当我们可以轻松地使用POSTman插件调试RESTful服务时,会感到这种感觉,就像我只能远程登录到NATS服务器时的感觉一样。

要进行订阅,我们创建一个具有唯一主题标识符的订阅(主题ID对我的连接而言是私有的):

  SUB分析进度50 

这意味着主题ID 50表示对analysis.progress的预订。 然后,每个订户都会收到一条消息,如下所示:

 味精分析进展50 55 
{“哈希”:“ abc56fghe”,id:12,进度:32,面孔:78}

与出版物一样,仅通过简单的换行符/回车键组合将有效负载与元数据分开。 每个MSG协议消息都包含主题ID和原始消息的内容长度。

为了与其他经纪人进行比较,在某些情况下,我们必须编写管理脚本来提前创建主题,然后才能启动我们的服务。 Kafka和Rabbit一样,需要明确创建的主题,而Redis和NATS则允许您即时创建频道和主题(它们各自的术语)。

事实证明,按需创建主题的能力是启用请求-答复语义的关键。

当我们进行RESTful服务调用时,我们向服务发出HTTP请求,然后获得答复,这就是使用传统的同步请求-响应模式。

在许多消息传递系统中,请求-答复模式通常很困难,或者需要一些非常尴尬和沉重的折衷方案。 使用NATS,请求答复是一个相当简单的操作,其中涉及在发布消息时提供“答复”主题。

这是在基于NATS的请求-答复情况下发生的细目,在该情况下,我们要询问出现特定人物的视频列表。 这里要记住的重要一件事是,我们不知道我们在询问什么信息。 我们正在做的只是发布我们对答案的渴望,而这取决于系统能否满足我们的要求。 这种松散的耦合功能令人难以置信,它使我们拥有极大的灵活性,可以随着时间的推移升级和增强系统,而无需发布“ stop the world”。

  1. 发布者订阅主题,例如vididentify.reply
  2. 然后,发布者发送关于诸如vididentify.inquiry类的主题的消息,并包含“回复”主题的名称: vididentify.reply
  3. 发布者然后等待一些时间来接收单个响应
  4. 发布者取消订阅他们对vididentify.reply主题的兴趣
  5. 发布者相应地处理响应

为了防止多个相同类型的并发请求相互踩踏,并确保处理该请求的任何代码仅对负责该消息的单个请求发布者进行答复,每个请求的“答复”主题都是唯一的,通常GUID后缀。 例如,我们可能会发布视频标识查询请求,如下所示:

  PUB vididentify.inquiry vididentify.reply.1b807ae3-bc12-42ab-b667-ccbd6c677745 25 
{“ person_id”:4237249}
+确定

这种复杂性几乎总是由特定语言的客户处理的。 例如, Go客户端完全隐藏了回复主题的创建:

  nc,err:= nats.Connect(* urls) 
如果err!= nil {
log.Fatalf(“无法连接:%v \ n”,错误)
}推迟nc.Close()
//获取有效载荷... msg,err:= nc.Request(“ vididentify.inquiry”,
[] byte(有效载荷),100 *次。毫秒)

这将发布一个请求,并等待100毫秒以内答复。 Go库正在向开发人员隐藏回复主题的详细信息。 它还隐藏了对回复主题的订阅和取消订阅。 如果您使用的库没有为您实现此功能,则创建一个可以实现此功能的包装器非常容易。

在分散收集模式中,单个发布者同时向未知数量的订户发布有关主题的消息。 假定所有侦听器都将开始工作。 然后,发布者等待一些或所有订阅者的答复,然后以某种方式汇总结果。

假设我有几千架无人机组成了我的包裹递送设备。 有人要求提供包裹,我想选择我要使用的无人机。 以“旧方法”做事,我可以遍历已知的所有无人机列表,在缓慢且可能不可靠的网络上逐一询问每个无人机,然后在完成此循环后,我终于可以根据剩余电池做出决定,重量和当前位置。 这很慢,容易出错,而且效率极低。

为了解决这个问题,我们可以使用散布聚集 。 我将在package.auction主题上发布一条消息,如下所示:

  PUB包。拍卖.d5e979a1-bf54-4baf-abdc-c91d451898c5.replies(内容长度) 
{“ pkg_weight”:12.5,“ dest_address”:{...},“ priority”:“ A”}
+确定

请注意,我们仍在使用唯一的回复主题。 这使机队中的所有侦听无人机都可以答复此特定的拍卖请求,而不会干扰同时处理的任何其他拍卖请求。

那些没有收到消息的人显然不是好的接送人,那些没有在我们预期的超时时间内未答复的人也不是。 消息可能像这样返回:

  MSG拍卖。d5e979a1-bf54-4baf-abdc-c91d451898c5。回复50(内容长度) 
{“ drone_id”:12345,“ est_batt_remaining”:12.34,“ capacity”:30,...}

然后,我们可以收集在超时时间内收到的所有结果,并根据无人机电池的寿命,位置,容量以及在降落结束时可能还剩下多少电池,从答复中做出决定。

使NATS如此强大的不是其复杂性,而是其简单性 。 我特别喜欢简洁的优雅(日语是kotan的意思 ),NATS很好地体现了这一点。 通过保持底层协议的简单性,关注性能和云原生的可靠性,我们可以构建各种真正强大的消息传递模式,而不必费力地笨拙地使用功能或在大型产品中承担大量未使用的功能。

希望本文能激发您不仅对NATS有所了解,而且能以敏锐的眼光评估您的消息代理所需要的复杂程度。 如果您想尝试使用NATS,则可以获取gnatsd docker镜像并开始使用它。


公开声明:这些观点是作者的观点。 除非在本帖子中另有说明,否则Capital One不与任何提及的公司有关联或认可。 使用或显示的所有商标和其他知识产权均为其各自所有者的所有权。 本文为©Capital One 2018。