【问题标题】:Microservices asynchronous response微服务异步响应
【发布时间】:2020-02-06 22:33:30
【问题描述】:

我看到很多博客说,由于 rabbitmq 的异步特性,使用 rabbitmq 可以提高微服务的性能。

在这种情况下,我不明白 http 响应是如何发送给最终用户的,我将在下面更清楚地阐述我的问题。

  1. 用户向微服务1(面向用户的服务)发送http请求

  2. microservice1 将其发送到 rabbitmq,因为它需要来自 microservice2 的一些服务

  3. microservice2接收到请求处理它并将响应发送给rabbitmq

  4. 微服务1收到rabbitmq的响应

现在如何将此响应发送到浏览器? microservice1 会等到收到rabbitmq 的响应吗? 如果是,那么它是如何变成异步的??

【问题讨论】:

    标签: spring-boot rabbitmq microservices


    【解决方案1】:

    您还可以使用事件并使整个流程异步。在这种情况下,微服务 1 创建一个表示用户请求的事件,然后立即将请求的创建响应返回给用户。然后,您可以在请求完成处理后通知用户。

    我推荐 Ben Stopford 写的设计事件驱动系统一书。

    【讨论】:

    • 你能解释一下在请求完成后通知用户的方法吗?
    • 当请求被处理后,可以创建一个新事件来通知服务。然后可以通过服务器推送通知用户。
    【解决方案2】:

    我会再看看你的架构。一般来说,对于微服务——尤其是必须同步的面向用户的微服务,让ServiceA 必须调用ServiceB 是一种反模式(反过来,它可能会调用ServiceC 等等...) 以返回响应。这种情况表明这些服务是紧密耦合的,这使得它们很脆弱。例如:如果ServiceB 在您的示例中出现故障或过载,ServiceA 也会因自身没有故障而下线。因此,可能会出现以下一种或多种情况:

    • 在包含整个域的外观背后部署相关服务 - 让客户端与外观同步交互,并让外观处理与幕后的多个服务的对话。
    • 使用 MQTT 或 AMQP 在 ServiceB 中添加/更改数据时发布数据,并让 ServiceA 订阅以获取所需内容,这样它就可以在不显式调用其他服务的情况下满足用户请求
    • 考虑将ServiceAServiceB 合并到一个可以处理请求而无需进行外部调用的服务中

    您还可以将 HTTP 请求从客户端发送到服务,将应用程序状态设置为 waiting 或类似的,并让消费应用程序从总线订阅 eventSuccesseventFail 集成消息。这个想法的要点是你让菊花链服务(我也不喜欢它)轮流工作,无论哪个服务“完成”了这项工作,都会发布一个集成事件,让任何正在倾听的人知道。您甚至可以通过初始请求传递 webhook URI,让服务在完成时直接回调应用程序(或使用 SignalR、gRPC 或...)

    我们使用 RabbitMQ 的方式是实时集成服务,以便每个服务始终拥有它需要自行响应的信息。以您的示例为例,在我们的世界中,ServiceB 在数据更改时发布事件。 ServiceA 只关心并订阅这些事件的一小部分(通常只有一个或两个事件数据字段),但它会在几秒钟内(通常更少)知道 B 何时发生变化并且它拥有所有响应请求所需的信息。每个服务根本不知道存在哪些其他服务,它只知道它关心的(并且符合合同的)事件时不时到达并且需要关注它们。

    【讨论】:

      【解决方案3】:

      好问题,我们一一讨论

      同步行为:

      • 客户端发送 HTTP 或任何请求并等待响应 HTTP。

      异步行为:

      客户端发送请求,有另一个线程在套接字上等待响应。一旦响应到达,就会通知原始发送者(通常使用类似回调的结构)。

      现在我们可以谈谈阻塞与非阻塞调用

      当您使用 spring rest 时,每个调用都会启动新线程并等待响应并阻塞您的网络,而非阻塞调用所有调用都通过单线程进行,并且 pushback 将返回响应而不阻塞网络。

      现在来回答你的问题

      使用rabbitmq提高微服务的性能是由于 rabbitmq 的异步特性。

      ,性能取决于您的 TPS 命中率,而 rabbitmq 不会提高性能。

      消息传递为您提供两种不同类型的消息传递模型

      • 同步消息
      • 异步消息传递

      使用消息传递,您将获得松散耦合和容错。

      • 如果您的应用程序需要阻塞调用,例如需要响应,否则无法移动使用 Rest
      • 如果您可以在没有得到响应的情况下工作,请继续使用非阻塞
      • 如果您想设计您的应用程序,请使用消息传递。

      简而言之,您希望如何构建应用程序的架构风格,性能取决于可扩展性。

      您可以将您的应用与休息和消息传递以及非阻塞与消息传递相结合。

      在您的场景中,微服务 1 可能会使用 rest 模板或 Web 客户端和/或消息队列来阻止调用其他 api,一旦获得响应,就会将 rest json 调用返回到您的 Web 应用程序。

      【讨论】:

        【解决方案4】:

        这是个好问题。要回答这个问题,您必须想象服务器一次运行一个线程。通过 RestTemplate 向微服务发出请求是一个阻塞请求。用户点击网页上的一个按钮,这会触发你在 microservice1 中的 spring-boot 方法。在该方法中,您向微服务 2 发出请求,微服务 1 会阻塞等待响应。

        该线程正忙于等待 microservice2 完成请求。线程并不昂贵,但在非常繁忙的服务器上,它们可能是一个限制因素。

        RabbitMQ 允许 microservice1 将消息排队到 microservice2,然后释放线程。当 microservice2 处理消息并提供响应时,您的接收消息将由系统(spring-boot / RabbitMQ)触发。同时线程池中的那个线程可以用来处理其他用户的请求。当 RabbitMQ 响应到来时,线程池使用一个未使用的线程来处理请求的剩余部分。

        实际上,您正在使运行微服务1 的服务器在更多时间拥有更多可用线程。只有在服务器负载过重时才会出现问题。

        【讨论】:

        • '当 RabbitMQ 响应到来时,线程池使用一个未使用的线程来处理请求的剩余部分。' 这如何实现?难道我们不能在服务 1 中有一个运行 kafka/rabbitmq 消费者的专用线程吗?
        • 按照约定实现。使用 spring-boot,它通过包含依赖项、配置和方法注释来实现。你不会编写代码来实现这一切。您只需在定义 RabbitMQMessageReceiver / MessageListenerAdapter bean 时看到您的方法被调用。
        猜你喜欢
        • 2017-10-10
        • 2019-02-08
        • 2018-11-02
        • 2022-06-18
        • 2021-08-19
        • 1970-01-01
        • 1970-01-01
        • 2021-07-24
        • 2018-07-15
        相关资源
        最近更新 更多