草庐IT

微服务中 REST 与消息传递对比

科技狠活与软件技术 2023-03-28 原文

微服务架构是一种既定模式,用于构建由松散耦合模块组成的复杂系统。它是过去几年中最受关注的软件架构趋势之一。将一个大型的、相互依赖的系统分解成许多小的、轻量级的模块,这似乎是一个非常简单的想法,这些模块可以使软件管理更容易。

这里有一个要点:在将整体应用程序分解为小模块之后,应该如何以有意义的方式将它们连接在一起?不幸的是,这个问题没有单一的正确答案,但通常情况下,有几种方法取决于应用程序和个别用例。

微服务中使用的两种常见协议是使用资源 API 的 HTTP 请求/响应和跨多个微服务通信更新时的轻量级异步消息传递。让我们探索这些协议。

通讯类型

微服务可以通过多种不同的通信模式进行通信,每种模式都针对不同的用例。这些类型的通信主要可以分为两个维度。第一个维度定义通信协议是同步的还是异步的:

同步与异步通信第二个维度定义了通信是有一个接收者还是多个接收者:

微服务之间最常见的通信类型是在调用 REST API 时使用同步协议(如 HTTP/HTTPS)的单接收器通信。微服务通常使用消息协议在微服务之间进行异步通信。这种异步通信可能涉及单个接收器或多个接收器,具体取决于应用程序的需要。

表征状态转移

表述性状态传输 (REST) 是一种流行的请求和响应通信架构风格,它可以作为同步通信类型的一个很好的例子。这是基于 HTTP 协议,包含 GET、POST、PUT、DELETE 等动词。在这种通信模式中,调用者等待服务器的响应。

图 1:基于 REST API 的通信

REST 是服务间通信最常用的架构风格,但在涉及微服务架构时,严重依赖这种类型的通信会产生一些负面影响:

  1. 多次往返(延迟) ——客户端通常需要执行多次到服务器的行程以获取客户端所需的所有数据。每个端点指定固定数量的数据,并且在许多情况下,该数据只是客户端填充其页面所需的数据的一个子集。
  2. 阻塞——调用 REST API 时,客户端被阻塞并等待服务器响应。如果应用程序线程正在处理其他并发请求,这可能会损害应用程序性能。
  3. 紧耦合——客户端和服务器需要相互了解。随着时间的推移,它会增加复杂性并降低可移植性。

讯息

消息在遵循异步协议的微服务架构中被广泛使用。在此模式中,服务发送消息而不等待响应,并且一个或多个服务异步处理消息。异步消息传递提供了许多好处,但也带来了幂等性、消息排序、毒消息处理和消息代理的复杂性等挑战,这些消息代理必须具有高可用性。

重要的是要注意异步 I/O 和异步协议之间的区别。异步 I/O意味着调用线程在执行 I/O 操作时不会被阻塞。这是软件设计方面的一个实现细节。异步协议意味着发送方不等待响应。

图 2:基于消息的通信

异步消息传递与同步消息传递相比有一些优势:

  1. 松耦合——消息生产者不需要知道消费者。
  2. 多个订阅者——使用发布者/订阅者 (pub/sub) 模型,多个消费者可以订阅接收事件。
  3. 弹性或故障隔离——如果消费者发生故障,生产者仍然可以发送消息。当消费者从失败中恢复时,消息将被拾取。这在微服务架构中特别有用,因为每个微服务都有自己的生命周期。
  4. 非阻塞——生产者和消费者可以按照自己的节奏发送和处理消息。

尽管异步消息传递有很多优点,但它也有一些折衷:

  1. 与消息传递基础设施的紧密耦合——使用特定的供应商/消息传递基础设施可能会导致与该基础设施的紧密耦合。以后可能很难切换到另一个供应商/消息基础设施。
  2. 复杂性——处理异步消息可能不像设计 REST API 那样容易。必须通过去重或使操作幂等来处理重复的消息。使用异步消息传递很难实现请求-响应语义。要发送响应,需要另一个队列以及关联请求和响应消息的方法。调试也很困难,因为很难确定服务 A 中的哪个请求导致了服务 B 中的错误行为。

异步消息传递已经成熟为多种消息传递模式。这些模式适用于分布式系统的多个部分必须以可靠和可扩展的方式相互通信的场景。让我们来看看其中的一些模式。

发布/订阅模式

发布/订阅模式意味着发布者将消息发送到消息代理上的通道。一个或多个订阅者订阅频道并以异步方式从频道接收消息。当微服务需要向大量消费者广播信息时,此模式很有用。

图 3:发布/订阅模式

发布/订阅模式具有以下优点:

  • 它解耦了需要通信的发布者和订阅者。发布者和订阅者可以独立管理,即使一个或多个订阅者离线也可以管理消息。
  • 增加了可扩展性并提高了发布者的响应能力。发布者可以快速将消息发布到输入通道,然后返回其核心处理职责。消息传递基础设施负责确保将消息传递给感兴趣的订阅者。
  • 它为微服务提供 关注点分离。每个微服务都可以专注于其核心职责,而消息代理处理将消息可靠地路由到多个订阅者所需的一切。

使用这种模式有一些缺点:

  • 发布/订阅模式在发布者传递给订阅者的消息中引入了高度语义耦合。数据结构一旦建立,通常很难改变。要更改消息结构,必须更改所有订阅者以接受更改后的格式。如果订户是外部的,这可能很困难或不可能。
  • 发布/订阅模式的另一个缺点是很难衡量订阅者的健康状况。发布者不知道收听消息的系统的健康状况。
  • 随着发布/订阅系统的扩展,代理通常成为消息流的瓶颈。负载激增会减慢发布/订阅系统的速度,订阅者的响应时间可能会出现峰值。

基于队列的模式

在基于队列的模式中,发送方将消息发布到包含接收方所需数据的队列。队列充当缓冲区,存储消息直到它被接收者检索。接收者从队列中检索消息并按照自己的节奏处理它们。此模式对于使用容易过载的服务的任何应用程序都很有用。

图 4:基于队列的模式

基于队列的模式有以下优点:

  • 它可以帮助最大限度地提高可扩展性,因为队列数量和服务数量都可以扩展以满足需求。
  • 它可以帮助最大限度地提高可用性。生产者或消费者中出现的延迟不会对服务产生直接或直接的影响,即使消费者不可用或处理消息的负载很重,服务也可以继续将消息发布到队列中。

使用这种模式有一些缺点:

  • 当消费者从队列中收到一条消息时,该消息在队列中不再可用。如果消费者未能处理消息,消息将丢失并且可能需要在消费者中回滚。
  • 消息队列不是开箱即用的。我们需要创建、配置和监控它们。当系统扩展时,它可能会导致操作复杂性。

简化消息传递基础架构的关键

异步通信通常通过消息代理进行管理。在为异步通信选择正确的消息传递基础设施时,需要考虑一些因素:

  • 可扩展性——消息代理负载激增时自动扩展的能力
  • 数据持久性——在重启/失败的情况下恢复消息的能力
  • 消费者能力——经纪人是否可以管理一对一和/或一对多消费者
  • 监控——是否具备监控能力
  • 推送和拉取队列——通过消息队列处理推送和拉取传递的能力
  • 安全性——对消息队列和主题进行适当的身份验证和授权
  • 自动故障转移——能够在一个代理发生故障时自动连接到故障转移代理而不影响发布者/消费者

结论

微服务越来越成为设计可扩展和弹性系统的实际方法。微服务之间的所有通信都没有单一的方法。RESTful API 提供请求-响应模型以在服务之间进行通信,而异步消息传递则在不同服务之间提供更具可扩展性的生产者-消费者关系。尽管微服务可以通过消息传递和 REST API 相互通信,但消息传递架构是提高敏捷性和快速移动的理想选择。它们常见于使用微服务的现代应用程序或任何具有解耦组件的应用程序中。

在为您的微服务选择合适的通信方式时,请务必将消费者的需求与一种或多种通信类型相匹配,从而为您的服务提供强大的接口。

有关微服务中 REST 与消息传递对比的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  4. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  5. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  6. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  7. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  8. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  9. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  10. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

随机推荐