“
从产生伊始,各类微服务就需要以不同的方式进行彼此通信。
有些人喜欢使用 HTTP REST APIs,但是他们可能会碰到自身的队列问题;有些人则倾向使用诸如 RabbitMQ 之类旧的消息队列,然而他们不得不考虑扩容和运营等相关问题。
因此以 Kafka 为核心的架构应运而生,它旨在解决上述两方面的问题。
在本文中,我们将和您讨论 Apache Kafka 是如何改进过去在微服务中,所用到的 HTTP REST API 和消息队列架构,以及它是如何进一步扩展自己的服务能力。
两大阵营的故事
第一大阵营是指:通信被通过调用诸如 HTTP REST API、或远程过程调用(Remote Procedure Calls,RPC)等其他服务的形式来直接处理。
第二大阵营则借用了面向服务的架构(Service-Oriented Architecture,SOA)的企业服务总线(Enterprise Service Bus)的概念,使用某个负责与其他服务进行通信的消息队列(如 RabbitMQ),作为消息代理来实现各种操作。
此法虽然能够给通信免去逐个服务直接进行“交流”的负载,但是在网络中增加了额外“一跳(hop)”的成本。
使用 HTTP REST APIs 的微服务
HTTP RESTAPIs 是一种在服务之间进行 RPC 的流行方式。它的主要好处在于简化了初始化设置,并提升发送消息的相对效率。
然而,这种模式需要其实现者考虑队列之类的问题,以及如何应对传入请求的数量超过该节点容量的问题。
例如:假设您有一个服务长链,其中的一个 preceding(先导)超过了节点的处理容量。
那么我们就需要对该服务链中的所有 preceding 服务进行相同类型的背压处理(back pressure handling,译者注:系统自适应地降低源头或者上游的发送速率),以应对该问题。
此外,这种模式要求所有的单个 HTTP REST API 服务都具备高可用性。而在那些由各种微服务所组成的长管道(pipeline)中,没有一个微服务可以承受失去其所有组件的“损失”。
因此,只要在给定组中至少一个进程仍在正常运行,那么这种通信就仍然可以运作。
当然,我们通常需要在这些微服务的前端配置负载均衡模块。同时,由于不同的微服务需要知道哪里能够通过调用来实现通信,因此服务发现(service discovery)模块也往往是必须的。
这种模式的优点之一在于:延时非常低。由于在给定的请求路径上,几乎省去了中间人的角色,因此,诸如 Web 服务器和负载平衡之类的组件,都经得起实战的“检验”,并具有高性能。
可见,对于不同 RPC 类型的微服务而言,我们需要处理它们之间的普通依赖性,因此它们往往会很快变得相当复杂,并最终影响、甚至拖慢开发的进程。
如今,业界也推出了一些新的解决方案。例如 Envoy 代理,它使用的是服务网格(service mesh)来解决此类问题。
虽然该模式解决了诸如负载均衡和服务发现等问题,但是相对于简单且直接的 RPC 调用而言,我们系统的整体复杂程度还是增加了不少。
如下图所示,许多公司起初可能只有几个微服务需要相互通信,而随着其系统的逐渐“成长”,相互之间的调用关系和通信渠道会最终变得像一碗意大利面那些错综复杂。
消息队列
构建微服务之间通信的另一种方式是:基于消息总线或消息队列系统的使用。
以前那些旧的面向服务架构将这种方式称为企业服务总线(ESB)。通常情况下,它们需要用 RabbitMQ 或 ActiveMQ 作为消息代理(message brokers)。
消息代理作为集中式的消息服务,能够方便所有与之相连的微服务进行彼此通信。
同时,借助消息服务的排队处理机制和高可用性,各个服务之间的通信也能够得以保障。
例如:有了消息队列的支持,各种消息能够被有序地接收到,以便系统进行后期处理。
而不会在出现请求峰值,且超过了处理容量的极限时,系统直接丢弃后续的队列。
然而,许多消息代理都已经明确地告知用户:它们在集群环境中,对于消息的传递和持久性的处理能力缺少可扩展性,甚至有所限制。
对于消息队列而言,另一个值得专注的地方是:它们在错误发生时的处理方式。
例如:系统在消息传递过程的可靠机制,是能够至少保证一次呢?还是最多也只能保证有一次?
当然,其语义的选择,则完全依赖于消息队列的实现。也就是说,您必须熟悉自己所选用的消息传递、及其相配的语义规则。
此外,将消息队列添加到现有系统的架构中,势必会增加有待操作和维护的新组件。
同时为了发送各类消息,而在网络中新增“一跳”,也将会给网站产生一些额外的延时与等待。
客观地说,该模式通过对各种消息队列系统,采用集中式的访问控制列表(Access Control Lists,ACL),从而简化了各类安全事项。
即:这种集中式管控方式统一地运用各种规则,限定了谁可以读取和写入什么样的消息。
集中式通信的另一个好处是:网络安全。例如:过去所有的微服务都采用的是彼此自行通信的方式。
而采用消息代理之后,您可以将所有的连接都经由消息队列服务来进行中转,通过类似防火墙的规则设定,来滤除掉其他微服务之间的直接联络,进而减少了被攻击面。
以 Kafka 为中心的优势
由 LinkedIn 创建的 Apache Kafka 是一个开源的事件流平台。与过去旧的消息队列系统截然不同的是:它具有将发送者与接收者完全分离的能力。也就是说,发送者并不需要知道谁将会去接收其发送的消息。
在其他许多消息代理系统中,它们必须事先知道谁会去读取所发的消息。这多少阻碍了我们将一些新的未知用例添加到传统的排队系统之中。
而在使用 Apache Kafka 时,各种消息被发送者写入一个被称为 topic(主题)的日志式数据流里,他们完全没有必要去关心谁、或那些应用将会真正地去读取该消息。
因此,这留给了新的用例去根据自己的新用途,考虑如何处置 Kafka 的相关 topic 内容的发挥空间。
对于 Kafka 而言,它不但不会去理会各种发送消息的具体载荷,还会让消息以任意方式进行序列化。
因此,大多数用户还是会使用 JSON、AVRO、或 Protobufs 来实现其数据格式上的序列化。
另外,您也可以轻松地通过设置 ACL,来限制各种 producers(生产者)和 consumers(消费者)能够对系统中的哪些 topic 进行读取或写入,以便您实现对所有消息的集中式安全控制。
因此,您会经常看到 Kafka 被作为一种 firehose 式数据管道,用来接收潜在的超大量数据。
例如:Netflix 公司就声称,他们正在使用 Kafka 来处理每天二万亿条消息的体量。
值得注意的是,Kafka 的 consumers 具有一个重要的特性:随着消息负载的增加,Kafka 的 consumers 会根据故障和容量需求的增多而发生变化,此时 Kafka 会自动地重新平衡各个 consumers 之间的处理负荷。
可见,开发者从需要保证微服务内部的高可用性,转移到了 Apache Kafka 服务本身。
相应地,Kafka 这种能够处理流数据(streaming data)的运营能力,也将其从一个消息系统发展成为了一个流数据平台。
而且可喜的是,Apache Kafka 的使用虽然给网络新增了额外的“一跳”,但是它作为各种请求的微服务通信总线,却没有增加(或者说降低了)任何延时。
总之,上述提到的低延时、自动扩容、集中管理、以及成熟的高可用性,都让 Apache Kafka 在微服务的通信开发中能够脱颖而出,为您可能用到的各种流数据实时分析创造了稳定的运行环境。
作者:Hannu Valtonen,陈峻编译
编辑:陶家龙、孙淑娟
领取专属 10元无门槛券
私享最新 技术干货