在微服务架构的世界中,我们通过一系列服务构建应用。集合中的每项服务都符合以下标准:

  • 松散耦合

  • 可维护和可测试

  • 可以独立部署

微服务架构中的每个服务都解决了应用中的业务问题,或至少支持一个。一个团队对应用中的一个或多个服务负责。

微服务架构可以解锁许多好处。

  • 它们通常更容易构建和维护

  • 服务是围绕业务问题组织的

  • 它们可以提高生产力和速度

  • 它们鼓励自主、独立的团队

这些好处是微服务越来越受欢迎的一个重要原因。但有一些可能会破坏这些好处的坑。如果不小心掉进去了,你将得到一个不断产生技术债的架构。

微服务之间的通信就是一个坑,假如不提前考虑就会造成严重的破坏。

该体系结构的目标是创建松散耦合的服务,并且通信在实现这一目标中起着关键作用。在本文中,我们将重点关注在微服务架构中进行通信的三种方式,每一种都有其自己的利弊和权衡。

HTTP通信

选择服务如何相互通信时,最直接的方式往往是 HTTP。事实上,我们可以提出一个案例,即所有通信渠道都来自这个渠道。但是除此之外,服务之间的 HTTP 调用是服务到服务通信的可行选择。

如果我们的架构中有两个服务,它可能看起来像这样:ServiceA 可以请求并调用 ServiceB 来获取另一条信息。

 1function process(name: string): Promise<boolean> { 2    /** do some ServiceA business logic 3        .... 4        .... 5    */ 6    /** 7     * call ServiceB to run some different business logic 8    */ 9    return fetch('https://service-b.com/api/endpoint')10        .then((response) => {11            if (!response.ok) {12                throw new Error(response.statusText)13            } else {14                return response.json().then(({saved}) => {15                    return saved16                })17            }18        })19}

这是一段很容易理解的适合微服务架构的代码。ServiceA 提供了一个业务逻辑。它运行其代码然后调用 ServiceB 来运行另一个业务逻辑。在这段代码中,第一个服务在返回之前完成等待第二个服务完成。

这里有两个服务之间进行同步的 HTTP 调用。这是一种可行的通信模式,但它确实在两种服务之间建立了耦合。

另一个选择是异步 HTTP。这可能是这样的:

1function asyncProcess(name: string): Promise<string> { 2    /** do some ServiceA business logic 3        .... 4        .... 5    */ 6    /** 7     * call ServiceB to run some different business logic 8    */ 9    return fetch('https://service-b.com/api/endpoint')10        .then((response) => {11            if (!response.ok) {12                throw new Error(response.statusText)13            } else {14                return response.json().then(({statusUrl}) => {15                    return statusUrl16                })17            }18        })19}

这种变化是微妙的。现在, ServiceB 不返回 saved 属性,而是返回一个 statusUrl。这意味着此服务现在正在接收来自第一个服务的请求,并且立即返回一个URL。此 URL 可用来检查请求的进度。

将两种服务之间的通信从同步转换为异步,第一个服务不再停留等待第二个服务完成,然后再返回其工作。

通过这种方法可以使服务彼此隔离,并且耦合松散。

缺点是需要在第二个服务上创建额外的 HTTP 请求,它从外部进行轮询,直到请求完成。这也引入了客户端的复杂性,因为必须检查请求的进度。

但是,异步通信允许服务直接保持松散耦合。

消息通信

另一种通信模式是基于消息的通信。

与HTTP通信不同,所涉及的服务不直接相互通信。相反,服务将消息推送到其他服务订阅的消息代理。这消除了许多与 HTTP 通信相关的复杂性。

它不需要服务知道该如何相互交流,它消除了直接相互调用的服务需求。相反,所有服务都知道消息代理,并且它们将消息推送到该代理。其他服务可以订阅代理中自己关心的消息。

如果我们的应用在 Amazon Web Services 中,可以用简单通知服务(SNS)作为消息代理。现在 ServiceA 可以将消息推送到 ServiceB 监听的 SNS 主题。

 1function asyncProcessMessage(name: string): Promise<string> { 2    /** do some ServiceA business logic 3        .... 4        .... 5    */ 6    /** 7     * send message to SNS that ServiceB is listening on 8    */ 9    let snsClient = new AWS.SNS()10    let params = {11        Message: JSON.stringify({12            'data': 'our message data'13        }),14        TopicArn: 'our-sns-topic-message-broker'15    }1617    return snsClient.publish(params)18        .then((response) => {19            return response.MessageId20        })21}

ServiceB 侦听 SNS 主题上的消息,当收到一个关心的消息时,就会执行它的业务逻辑。

这引入了它自己的复杂性。请注意,ServiceA 不再接收状态 URL 检查进度。这是因为我们只知道消息已经被发送,而不知道 ServiceB 是否已经收到了它。

这可以通过许多不同的方式解决。一种方法是将 MessageId 返回给调用者。可以用它来查询 ServiceB,它将存储它收到的消息的 MessageId。

注意,使用此模式的两个服务之间仍然存在一些耦合。例如,ServiceB 和 ServiceA 必须就消息结构的定义以及其中包含什么达成一致。

事件驱动的通信

最后一种模式是事件驱动模式。这是另一种异步方法,它看起来完全消除了服务之间的耦合。

与消息传递模式不同,事件驱动方法不需要服务必须知道公共消息结构。服务之间的通信通过各个服务产生的事件进行。

此处仍然需要消息代理,因为各个服务会将其事件写入其中。但是与消息方法不同,消费服务不需要知道事件的细节,它们对事件的发生做出反应,而不是产生能会或可能不会传递的信息。

在形式上,这通常被称为“仅事件驱动的通信”。下面的代码和消息传递方法类似,但推送到SNS的事件是通用的。

1function asyncProcessEvent(name: string): Promise<string> { 2    /** do some ServiceA business logic 3        .... 4        .... 5    */ 6    /** 7     * call ServiceB to run some different business logic 8    */ 9    let snsClient = new AWS.SNS()10    let params = {11        Message: JSON.stringify({12            'event': 'service-a-event'13        }),14        TopicArn: 'our-sns-topic-message-broker'15    }1617    return snsClient.publish(params)18        .then((response) => {19            return response.MessageId20        })21}

注意,我们的 SNS 主题消息是一个简单的 event 属性。每个服务都同意以这种格式将事件推送到代理,这使得通信松散耦合。服务可以监听他们关心的事件,并且提供为响应它们而需要运行的逻辑。

此模式使服务的耦合松散,因为事件中不包含任何有效负载。此方法中的每个服务都会响应事件的发生并运行其业务逻辑。在这里,我们通过 SNS 主题发送事件。也可以使用其他事件,例如文件上传或数据库行更新。

结论

这些是基于微服务的架构中所有可能的通信模式吗?当然不是。基于同步和异步模式进行通信的方式还有很多种。

但是这三个突出了支持同步与异步的优缺点。在选择时要考虑耦合因素,但也需要考虑开发和调试的具体情况与注意事项。

原文:https://blog.logrocket.com/methods-for-microservice-communication/

©著作权归作者所有:来自51CTO博客作者mb5ff980b461ced的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 芋道 Spring Boot 消息队列 RocketMQ 入门
  2. 面试官再问我如何保证 RocketMQ 不丢失消息,这回我笑了!
  3. RocketMQ 源码分析 —— 定时消息与消息重试
  4. 假装网络工程师28——MPLS跨AS通信optionC方案2
  5. 分布式链路追踪 SkyWalking 源码分析 —— Agent Remote 远程通
  6. 分布式链路追踪 SkyWalking 源码分析 —— Collector Remote 远
  7. 注册中心 Eureka 源码解析 —— 网络通信
  8. 消息中间件 RocketMQ 源码解析 —— 调试环境搭建
  9. 分布式消息队列 RocketMQ源码解析:事务消息

随机推荐

  1. 挖掘更合适的MVP模式的架构设计
  2. Android上实现仿IOS弹性ListView
  3. android给listview的item设定高度
  4. Android 'showAsAction' in package 'and
  5. android图片特效处理之光晕效果
  6. android 字体&颜色
  7. android junit入门(一) JUNIT测试
  8. 四大布局
  9. Android Studio(六):Android Studio添加注
  10. ADT对应的.android中找不到adb_usb.ini