微服务的三种通信方法

更新日期: 2019-07-31阅读: 2.2k标签: 通信

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

  • 松散耦合
  • 可维护和可测试
  • 可以独立部署

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

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

  • 它们通常更容易构建和维护
  • 服务是围绕业务问题组织的
  • 它们可以提高生产力和速度
  • 它们鼓励自主、独立的团队

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

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

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


HTTP通信

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

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

function process(name: string): Promise<boolean> {
    /** do some ServiceA business logic
        ....
        ....
    */
    /**
     * call ServiceB to run some different business logic
    */
    return fetch('https://service-b.com/api/endpoint')
        .then((response) => {
            if (!response.ok) {
                throw new Error(response.statusText)
            } else {
                return response.json().then(({saved}) => {
                    return saved
                })
            }
        })
}

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

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

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

function asyncProcess(name: string): Promise<string> {
    /** do some ServiceA business logic
        ....
        ....
    */
    /**
     * call ServiceB to run some different business logic
    */
    return fetch('https://service-b.com/api/endpoint')
        .then((response) => {
            if (!response.ok) {
                throw new Error(response.statusText)
            } else {
                return response.json().then(({statusUrl}) => {
                    return statusUrl
                })
            }
        })
}

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

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

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

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

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


消息通信

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

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

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

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

function asyncProcessMessage(name: string): Promise<string> {
    /** do some ServiceA business logic
        ....
        ....
    */
    /**
     * send message to SNS that ServiceB is listening on
    */
    let snsClient = new AWS.SNS()
    let params = {
        Message: JSON.stringify({
            'data': 'our message data'
        }),
        TopicArn: 'our-sns-topic-message-broker'
    }

    return snsClient.publish(params)
        .then((response) => {
            return response.MessageId
        })
}

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

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

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

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


事件驱动的通信

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

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

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

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

function asyncProcessEvent(name: string): Promise<string> {
    /** do some ServiceA business logic
        ....
        ....
    */
    /**
     * call ServiceB to run some different business logic
    */
    let snsClient = new AWS.SNS()
    let params = {
        Message: JSON.stringify({
            'event': 'service-a-event'
        }),
        TopicArn: 'our-sns-topic-message-broker'
    }

    return snsClient.publish(params)
        .then((response) => {
            return response.MessageId
        })
}

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

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


结论

这些是基于微服务的架构中所有可能的通信模式吗?当然不是。基于同步和异步模式进行通信的方式还有很多种。但是这三个突出了支持同步与异步的优缺点。在选择时要考虑耦合因素,但也需要考虑开发和调试的具体情况与注意事项。

作者:Kyle Galbraith
翻译:疯狂的技术宅
原文:https://blog.logrocket.com/methods-for-microservice-communication/

链接: https://www.fly63.com/article/detial/5050

vue.js $emit/$on的用法和理解_vue组件之间数据传输通信

每个 Vue 实例都实现了事件接口vm.$emit( event, arg ) 触发当前实例上的事件;vm.$on( event, fn )监听event事件后运行。实例说明:Vuejs 用$emit与$on来进行兄弟组件之间的数据传输通信,Vuejs 用$emit与$on来进行跨页面之间的数据传输通信

两个浏览器窗口间通信总结

两个浏览器窗口间通信:一个窗口更新localStorage,另一个窗口监听window对象的storage事件来实现通信;所有的WebSocket都监听同一个服务器地址,利用send发送消息,利用onmessage获取消息的变化;借助iframe 或 window.open;HTML5 中的 Web Worker 可以分为两种不同线程类型

前端跨页面通信,你知道哪些方法?

在浏览器中,我们可以同时打开多个Tab页,每个Tab页可以粗略理解为一个“独立”的运行环境,即使是全局对象也不会在多个Tab间共享。然而有些时候,我们希望能在这些“独立”的Tab页面之间同步页面的数据、信息或状态。

Vue组件之间通信的七种方式

使用Vue也有很长一段时间,但是一直以来都没对其组件之间的通信做一个总结,这次就借此总结一下。父子组件之间的通信props和$emit 父组件通过props将数据下发给props

浏览器标签页之间通信的实现

前端开发过程中,总是避免不了要进行前端标签页之间的通信,最经典的例子莫过于音乐播放网站中,当第一次点击播放列表中的歌曲时,它会打开一个新的标签页进行播放,而当在列表中再次点击歌曲播放时

基于 ThinkJS 的 WebSocket 通信详解

我们的项目是基于 ThinkJS + Vue 开发的,最近实现了一个多端实时同步数据的功能,所以想写一篇文章来介绍下如何在 ThinkJS 的项目中利用 WebSocket 实现多端的实时通信。ThinkJS 是基于 Koa 2 开发的企业级 Node.js 服务端框架

Socket是如何通信的?

其实服务器的处理和客户端大同小异,分三个逻辑分支:检索成功,用检索到的Socket来处理接收报文;检索失败,服务器侦听(listen)目的端口,创建全新的Socket服务客户;检索失败,服务器没有侦听目的端口,丢弃处理

vue中使用v-model完成组件间的通信

如何实现两个组件之间的双向传递呢?即,在父组件中修改了值,子组件会立即更新。在子组件中修改了值,父组件中立即更新。vue中有一个很神奇的东西叫v-model,它可以完成我们的需求。

vue父子组件通信高级用法

vue项目的一大亮点就是组件化。使用组件可以极大地提高项目中代码的复用率,减少代码量。但是使用组件最大的难点就是父子组件之间的通信。父组件通过$refs调用子组件的方法。 以上就是父子组件通信的方式

vue 数据通信总结

数据单向流动prop react也是一样prop ; $emit / $on (任意组件间传递)创建个空的组件,来作eventbus 用来触发及监听事件 ;vuex 牛刀集中式存储管理应用的所有组件的状态

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!