服务集成时需避免的两个错误

划重点

  • 影响系统可靠性的关键因素。
  • 采用存储转发(Store and forward)交换模式保持系统的可用性。
  • 同步消息传递(Synchronous messaging)中的延迟所产生的影响,以及需要避免它的原因。
  • 使用链接服务(Linked Services)模式的异步通信。
  • 在代理协议或 API (如 JMS)中的各种应答模式,以及为何要使用它们。

简介

随着面向服务架构(下文简称 SOA,Service Oriented Architecture)的出现,企业通过将业务功能分解为多重服务 [1],它们迅速地从整体应用程序设计(Monolithic application design)过渡到了异构设计(Heterogeneous design)。在将这些服务集成起来之时,企业架构师应当小心,因为劣质的服务集成将会导致一团乱麻的结局。很多时候,企业假定仅采用如企业服务总线(下文简称 ESB,Enterprise Service Bus)和微服务这样的模式就能避免出现混乱的局面 [2],并且能够提供一个可行的解决方案。当它被 “部分地” 完成时,很不幸这些模式并不能解决某些隐藏的挑战。危险的是,在开发和部署的初始化阶段,它们通常不会被注意到,但是当系统在生产环境中工作时,它们就会出现。等我们意识到后果,为时已晚。本文旨在详细阐述其中的一些挑战,并明确指出,我们可以采取哪些措施来避免这些挑战。

服务集成的挑战

在采用 SOA 时,我们通常使用 ESB 作为集成服务之间的主干基础设施 [3]。当然,现在用微服务作为 ESB 的替代品 [4] 这种方法突然就火起来了,然而,美国资讯公司高德纳的副总裁、杰出分析师 Anne Thomas 并不赞同 [5]。依我看来,过度的规模化服务会对网络开销产生负面影响,同时也会使系统的调试以及故障查找变得困难。因此,谨慎地使用微服务是明智的(除非服务粒度更大能为业务带来巨大的好处)。然而,本文目的是要详细说明这些设计模式所能解决的挑战的范围,并揭示一些它们没有解决的隐藏的挑战。

如文章 [1] 所述,Restful API 的使用数一直呈指数式增长。因此,本文中使用的示例将主要阐明应用 ESB 完成的 Restful API 集成,并揭示一些仅通过 ESB 无法解决的隐藏挑战。

下面演示了一个使用 ESB 完成的简单服务链(Service chaining)示例。用户在 ESB 中调用代理服务,此时 ESB 的作用是将两个服务 —— 订单处理服务(下文简称 OPS,Order Processing Service)与订单交付服务(下文简称 ODS,Order Delivery Service)—— 将它们链接起来,并向用户提供响应。

图1. 披萨外卖系统
图2. 披萨外卖消息流

下表对比了用户通过使用 ESB 在服务之间集成(而非让服务直接彼此对话,即点对点的方式)所获得的好处。

特性

点对点

ESB

虚拟化/可用性

实现起来很复杂,每个客户端需要自己实现服务的编排/连接逻辑。

ESB 代理将 OPS 与 ODS 之间的链接虚拟化。则用户只需要调用 ESB 中的一个服务来获得预期的响应。

可扩展性

假设 OPS 服务是安全的,作为先决条件的服务需要在传入的请求中附加一个安全令牌。为获得一个安全令牌,用户授权服务(下文简称 UAS,User Authorization Service)应在 OPS 之前被调用。若有数百万客户端正调用 OPS,则这百万客户都必须修改他们的实现,以在 OPS 调用之前,先与 UAS 进行沟通。

客户端与服务编排/链接的复杂性并不紧密耦合。因此改变 ESB 中的配置就足以体现这一更改。

容错性

当服务之间是紧密耦合的,这会导致其中某一个服务出错时整个系统都会陷入危险之中。直接通信的情况下,在自动伸缩(Auto scaling)环境中进行容错处理以及负载均衡是很复杂的。

ESB 允许集中管理服务的编排/链接。因此,容错处理、节点自动伸缩的动态发现也可被集中管理。降低了用户/客户端开发的复杂性。

上表罗列出了采用 ESB 比起点对点的服务集成所具有的主要优势。然而仅仅采用 ESB 并不能解决所有挑战。下一节将评估那些仅使用 ESB 不能解决的挑战。

观察图 1 与图 2 中的例子。考虑在某个时间段内使用 ESB 服务的数百万用户的使用情况。OPS 或 ODS 能够以相同的速度处理这些 ESB 接收到的用户请求吗?

如前所述,ESB 通常被视为企业中的主干,这就意味着它应能够处理高数量的请求负载。请求负载通常以每秒事务数(下文简称 TPS,Transactions Per Second)进行度量。在机构中实现的服务(OPS 或 ODS)可能不会被设计为能与 ESB 相同的 TPS 速率来处理请求。实际上,那会有什么问题呢?正如 [6] 中所述,由于出现故障或系统过载,服务或系统可能无法完成交付。如果 ESB 以相同的 TPS 速率将请求路由到 OPS 或 ODS,此时若服务不能承受该速率,那么这些服务将超载,并且无法交付响应。服务中的错误将会导致 ESB 从用户端接收到的请求被丢失。

因此,采取积极主动的措施防止服务过载是至关重要的,为确保系统不会崩溃,我们应采取应对措施保证通信链路是更加可靠的(无消息丢失),所以若 ESB 接收了来自用户的请求,它应确保所有服务之间的信息能够交付(可靠性)。

下一节我们将聚焦于如何使 ESB 之间的通信链路能够可靠地进行,并采取应对措施防止服务(OPS 和 ODS)过载。

可靠通信

实现可靠通信的一个传统的方法是使用 WS-ReliableMessaging(可靠消息传输,这是一种数据传输协议)。然而,随着 Restful api [1] 的发展,这一方法也随之发展起来,因为 WS-ReliableMessaging 是特定于 Web 服务的。在文章 [7] 中,Marc 还讨论了如何从传输层中提取可靠性,以及是否有必要将其与业务语义(Business semantic)结合起来。然而,依我看,只有当系统中的所有服务都是在内部实现时,这种方法才能适用。对于大多数企业来说,并非是内部实现的情况。迁移到 SOA 的一个主要目的是使得系统具有可扩展性,以便在内部实现的服务和(或者)第三方服务(或 API 供应商)公开的服务之间能够重用以及互用。由于组织机构不能影响外部服务供应商遵守特定的业务语义,因此可靠性不应该与业务应用级别紧密耦合。因此采用一个更通用(取决于它们的业务语义)的机制来实现系统可靠性是必须的。

Message-Broker(消息中介)是一种中介模式,它能解除消息发送方与接收方之间的耦合。大多数 ESB 供应商都支持对消息代理(下文简称 MB,Message Broker)的集成(通过诸如 JMS 这样的协议实现)。下一节将重点讨论如何将 ESB 和 MB 模式组合在一起,从而在通过 ESB 链接的服务之间实现更可靠的通信链路(即实现零消息丢失)。同时也会详细说明 MB 将如何发挥作用,以提供控制消息通过 ESB 路由到服务(OPS 与 ODS)时的 TPS 速率的方法(即节流),以防止服务过载。

请求速率控制

MB 围绕着几个消息传递概念。主要基于队列(点对点)与主题(发布/订阅)。这些概念的设计是为了解开时间和空间之间耦合 [8]。因此,如果发送方将给定的消息插入到队列中,代理者将确保将消息传递给它的接收方。若接收方在消息发送时是不可用的,代理将保有消息直到接收方的状态变为可用为止。让我们回顾之前的披萨外卖系统例子,在这个情景下 ESB 是如何截取 MB 的。我们的目的是说明如何添加 MB 而不会对服务(OPS 和 ODS)造成负面影响,如图 3 和图 4 所示。

图3. 通过 ESB 存储与转发
图4. 存储与转发消息流

正如上面的消息流简图(图 4)所示:

  1. 客户端发送订单信息到 ESB。
  2. ESB 接收 HTTP 消息,并通过代理 API (JMS)重发布消息到 MB 的一个队列中(OPSQ)。
  3. 存储的消息由 ESB 以可控的速度从 OPSQ 中消费出去(比如每三十秒一次)。一旦消息被消费,则相应地代理者会从队列中将其删除。
  4. 被消费的消息由 ESB 发送到 OPS 中(通过执行 JMS 到 HTTP 的协议转换)。
  5. 当 OPS 作出响应时,响应消息有 ESB 发布到 ODSQ 队列中。
  6. 此时经过与 3、4 步骤相同的动作,则消息就以可控的速率被传递到 ODS 中。

现在我们看看使用 MB 的优点与缺点。

优点:

  • 该方法适用于任何服务的实现,例如 Web 服务以及 Restful。
  • 如果服务无法承受传入的 TPS 速率,消息将被保持在队列或主题中。这将确保实现消息的保证交付,并且服务可以以控制的 TPS 速率使用消息。
  • 加入 MB 时,不会对服务实现(OPS 和 ODS)产生负面影响。因此,当与第三方 API 集成并实现可靠性时,这种方法更加敏捷。

缺点:

  • 添加代理意味着消息会经过一个额外的层。参阅图 2 与图 4,这一点就非常明显了。当代理被加入时,消息会经过两个额外的层(OPSQ 与 ODSQ)。

消息经过的层数(网络跃点)越多,它将为客户端带来更高的延迟以接收响应 [9]。此外,如果服务是以较低的TPS速率(节流)消费,则对客户端响应延迟的影响会更高。

下一节我们将重点阐明响应延迟的增加如何会对客户端产生不利影响。

响应延迟的副作用

依据所使用的操作系统(简称 OS,Operating System),客户端保持连接的超时时间大概在 20 秒到 75 秒之间变化。对于上述例子,若发送方(客户端)阻塞等待以接收从代理服务发送来的响应(即以同步的方式),则代理服务需要在 20 秒内向客户端发送响应。否则发送方将会超时,并认定事务失败了(但它可能并没有失败)。及时发送方未及时进行通知,消息也会被所有服务(OPS 以及 ODS)进行处理。因此,假设事务失败,发送方将再次尝试发送相同的消息,这将会导致不一致。

我们需要采取一些应对措施来避免这些不一致。现实情况是,系统不应假定它总是能在超时之前将消息传递给调用者或发送方,因为响应时间可能是主观的,特别是当服务以控制的速度使用消息,并且消息需要通过多个网络跳变实现可靠性时。因此对于发送方来说,从同步(阻塞)通信方式转变为异步(非阻塞)通信方式是最有利的。

异步通信

对比起基于 RPC 的同步通信,使用异步通信有优点亦有缺点 [9]。正如文章 [9] 中所阐述的那样,与同步通信不同,异步通信只会使发送方在更短的时间内被阻塞。

参考图 4 中的例子,我们可以在消息发布到消息代理之后直接让 ESB 给客户端响应,而不是在调用每个服务(如 OPS 与 ODS)之后再响应。这种方法将会给发送方缩短响应延迟。然而,这其中有些许灰色地带需要我们解决。

  1. 当消息正被服务(OPS,ODS)处理时,若发生了一个错误,发送方要如何收到通知?或者说订单状态要如何更新?
  2. 如文章 [9] 中描述,异步通信不像同步通信那样,默认情况下,它对于发送方并不提供将信息成功交付到目的地的保证。在这种情形下,发送方要如何保证成功地处理所下的订单?

下一节中,将会介绍以上两种情况要如何去解决。

链接服务模式

链接服务 [10] 是一种服务设计模式,它为发送方/客户端定义了一种机制,以发现能够确定正在被处理的请求状态的相关服务。这种模式主要指定在给发送方的响应消息中包含超链接,以便发送方以后可以引用这些链接来跟踪请求的状态。除了适应异步通信之外,服务所有者还可以在响应消息中为服务调用者(发送方)提供超链接。按照这种方法,发送方可以使用这些链接来确定订单交付的状态,或者在处理消息时可能发生的任何错误情况。

下图展示了发送方如何能够与服务异步地通信(使用链接服务模式)。

图5. 异步消息

如图 5 所示:

  1. 客户端发送订单消息到 ESB。
  2. ESB 接收 HTTP 消息并且通过代理 API(如 JMS)重发布消息到 MB 的一个队列(OPSQ)中。
  3. 一旦消息发布到队列中,ESB 就给客户端发送响应。这一响应包含了一个超链接,它允许客户端引用并追踪订单状态。
  4. 在此基础上,消息流类似于第 1 节中描述的步骤 3-6。

交付担保以及事务

发送消息时不需要确认(即发即弃模式)时,会有消息丢失的风险,因为发送消息的网络或系统有可能是错误的或不可靠的。若通过 ESB 向代理(OPSQ)发布的 JMS 消息没有到达队列,此时会出现什么问题呢?

由于发送方会在将消息放置到队列后成功接收消息时被通知,在向发送方发送接收响应之前,必须同 MB 验证消息是否已成功地放入队列。并且,在删除队列消息之前,总是确认(Acknowledgement)其被接收方成功地消费是必要的。

当 MB 成功地接收消息到队列时,它会向调用者发送一个发布者确认消息,当接收到该消息的消费者发送一个确认消息时,MB 将从队列中删除一条消息。JMS 在默认情况下 [11],确认模式是 AUTO_ACKNOWLEDGE,则当消费者(ESB)接收到消息时会对其进行确认。

会影响披萨外卖系统的潜在风险是,在从队列中消费了一个消息后,OPS 返回一个错误状态,或者完全无响应。由于 ESB 默认情况下将 OPSQ 设置为 AUTO_ACKNOWLEDGE 模式,因此消息在被 ESB 消费后将立即从队列中丢弃。整个想法是确保 OPS 和 ODS 能成功地接收到消息,ESB 接收消息并不会保证将消息传递给相关的服务(OPS、ODS)。

JMS 中,可以使用的一个选项是 CLIENT_ ACKNOWLEDGEMENT 模式。这个模式允许消费者显式地进行确认或回滚消息,而不是当接收到消息时自动确认。通过这种方式,如果 OS 或 ODS 服务抛出错误,则使用者(ESB)可以回滚消息并重放消息,直到消息被传递。MB 则会确保消息被保留到 ESB 确认它为止。关于确认模式的更多详细信息可以参考文章 [12]

图6. 消息流

如图 6 所示:

  1. 客户端发送订单消息给 ESB。
  2. ESB 接收 HTTP 消息,并通过一种代理 API(如 JMS)重发布该消息到 MB 的一个队列(OPSQ)中。
  3. ESB 等待代理确认接收到消息并已经将其加入 OPSQ 中。
  4. 一旦得到确认,ESB 就发送确认响应(Confirmation response)给客户端。
  5. ESB 使用 CLIENT_ACKNOWLEDGE 模式从队列中查找消息。(这就确保消息不会被丢弃直至客户端发送一个确认或拒绝消息)
  6. ESB 将请求发送到 OPS。若 OPS 发送一个成功响应,则 ESB 确认该消息并通知 OPSQ 从队列中删除消息。如果状态为错误,则 ESB 发送一个拒绝消息到 OPSQ,告知它需要进行回滚,使得消息不会被丢弃,而是准备再次使用(重播)。
  7. 当从 ODSQ 中进行消费而发送一个消息到 ODS 时,以上步骤同样适用。

总结

总的来说,诸如 ESB 这样的模式在集成异构服务时能给我们带来很多好处。然而仅仅采用 ESB 无法解决系统面临的所有集成挑战。通过 ESB 进行编排/链接的服务,它们处理输入的请求的 TPS 速率可能无法与 ESB 从用户端接收请求的速率等同。这就导致服务可能会过载,于是系统会崩溃并且交付失败。消息代理(MB)可以用于控制服务消费消息的速率,从而确保可靠性。同时,使用 MB 不会对服务的实现造成任何负面影响,因此它适合于确保内部和第三方服务/API 的可靠性。在使用 MB 实现可靠性并控制服务间的速率时,会对响应延迟产生成比例的影响。响应延迟的增加会造成不一致(由于客户端会超时)。因此,为避免这些不一致,考虑使用异步通信比用同步通信有更多优势。对比同步通信,异步通信能使响应延迟变低,然而与同步通信不同的是,它不会隐式地为调用者提供一种方式来识别被处理的请求的状态,也不隐式地保证消息的传递。我们可以通过显式地使用服务设计模式(例如链接服务模式与适当的确认模式)来弥补这些缺口。

腾讯云分布式微服务来啦!

腾讯分布式微服务TSF围绕应用和微服务的PaaS平台,提供服务全生命周期管理能力和数据化运营支持,提供多维度应用、服务、机器的监控数据,助力服务性能优化;拥抱 Spring Cloud 开源社区技术更新和K8s容器化部署。

(详见 https://cloud.tencent.com/product/tsf

本文的版权归 StoneDemo 所有,如需转载请联系作者。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SDNLAB

SDN实战团分享(三十一):Nutanix超融合之架构设计

超融合平台 针对于超融合的概念有着不同的理解,因为组件不同(虚拟化、网络等)而理解不同。然而,核心的概念如下:天然地将两个或多个组件组合到一个独立的单元 中。在...

3367
来自专栏Golang语言社区

Go 语言构建高并发分布式系统实践

你知道互联网最抢手的技术人才有哪些吗?最新互联网职场生态报告显示,最抢手的十大互联网技术人才排名中Go语言开发人员位居第三,从中不难见得,Go语言的渗透率越来越...

3899
来自专栏Java技术交流群809340374

最新鲜的美团现场面试41题(三面技术+HR面):Redis+Kafka+分布式

互联网特别是电商平台,阿里双11秒杀、还有12306春运抢票、以及平时各种节假日抢购活动等,都是典型的高并发场景。

1460
来自专栏架构师之路

典型数据库架构设计与实践 | 架构师之路

本文,将介绍数据库架构设计中的一些基本概念,常见问题以及对应解决方案,为了便于读者理解,将以“用户中心”数据库为例,讲解数据库架构设计的常见玩法。 一、用户中心...

3765
来自专栏Golang语言社区

Go 语言构建高并发分布式系统实践

你知道互联网最抢手的技术人才有哪些吗?最新互联网职场生态报告显示,最抢手的十大互联网技术人才排名中Go语言开发人员位居第三,从中不难见得,Go语言的渗透率越来越...

3034
来自专栏Golang语言社区

Go 语言构建高并发分布式系统实践

你知道互联网最抢手的技术人才有哪些吗?最新互联网职场生态报告显示,最抢手的十大互联网技术人才排名中Go语言开发人员位居第三,从中不难见得,Go语言的渗透率越来越...

3724
来自专栏高性能服务器开发

11 一种高性能网络游戏服务器架构设计

网络游戏的结构分为客户端与服务器端,客户端采用2D绘制引擎或者3D绘制引擎绘制游戏世界的实时画面,服务器端则负责响应所有客户端的连接请求和游戏逻辑处理,并控制...

1452
来自专栏EAWorld

任务和调度:理解批量处理的关键设计

一、背景 1.1.什么是批量处理 1.2.批量处理拥有广泛的使用场景 1.3.批量处理需要良好的架构设计 二、批量处理中的关键设计 2.1从SpringBat...

3959
来自专栏QQ会员技术团队的专栏

大规模 codis 集群的治理与实践

本文将从方案选型、整体架构、自动化接入、数据迁移、高可用、运营实践等方面详细介绍我们在生产环境中的实践情况。

8352
来自专栏云技术

性能超前,详解腾讯云新一代Redis缓存数据库

当前内存数据库发展迅速,用户对于存储系统的要求也越来越高,为了满足各类业务场景的需要,腾讯云设计了新一代的内存数据库,不但保留了原来系统的高性能,高可用等特性,...

52416

扫码关注云+社区