微服务间通信:API接口详解

服务间通信:API接口

目录

服务间通信:API接口

概述

同步通信

使用REST API

使用gRPC API

断路器模式(Circuit breaker pattern)

服务发现模式

异步通信

使用异步消息模式

消息


概述

  • 单块应用

    • 运行在同一个进程中,直接使用函数调用进行通信

    • 需要与其他应用集成时,采用 REST Api 进行通信

  • 微服务应用

    • 被分解出来的服务之间需要协作

    • 分布式环境下,协作会跨主机、跨进程

    • 当前最流行的进程间通信方式是 REST

    • 服务间的通信方式对于应用的可用性至关重要

  • 可选项

    • 同步通信:如基于HTTP的 REST 和 gRPC

    • 异步通信:如基于消息的的AMQP 和 STOMP

    • 通信内容类型:

      • 基于文本:JSON、XML

      • 基于字节:Avro,Protocol Buffers

  • 微服务的API 可发为两类

    • 操作:由客户端调用,包括名字,参数,返回类型

    • 事件:包括类型和字段集,发布到消息通道(Message Channel)

  • 跟单块应用不同,编译期无法发现微服务 API 的问题,只有在运行期才能发现

  • 最佳实践

    • 使用某种接口定义语言(IDL)对服务接口进行定义,如 Swagger

      Swagger:Rest API的描述语言

       

       

    • API-First:先定义 API,再进行开发

  • 微服务 API 的演进

    • 当加入新功能时,或功能变更时,API 需随着时间而演进

    • 不应该,也不可能强制所有调用者同步更新

    • 应采用滚动升级(Rolling Update),确保新旧版本同时在线

    • 当所有调用者都完成升级后,再撤回旧版本

同步通信

使用REST API

  • Roy Fielding. Architectural Styles and the Design of Network-based Software Architectures. 2000

     

  • 资源的定义、URI标识符(一对多)、表示(JSON),操作/Http动词(请求方式),状态码

  • REST成熟度模型

    • 0级:没有资源概念。使用一个 URI 处理所有请求,请求内容封装在请求体中

      • http://localhost:8080/services

        • {type: 'teacher', operation: 'getAll', parameter: 'name="张%"'}

        • {type: 'teacher', operation: 'getAll', parameter: 'name="张%"'}

      • 面向服务的架构:SOA,SOAP,BPEL

    • 1级:引入资源概念,一个资源的所有操作都通过一个URI完成

      • http://localhost:8080/services/teacher

      • {operation: 'getAll', parameter: 'name = ...'}

    • 2级:引入HTTP动词,资源的不同操作使用适当的HTTP动词和返回状态码

      • POST /services/teachers {name: 'zhangsan', } ------ 201

      • GET /services/teachers?name=张&age=37 ----- 200

      • PUT

    • 3级:实现HATEOAS()原则 ,不仅返回当前的资源表示,还返回后续操作的链接,使客户端无须再执行硬编码URI。(注:这才是真正的RESTful,但实际中很少能做到)

      • Axios.get("http://localhost/assignment/1")

      • Axios.get(json.href.key)

      • json: {[,,,,], href: {key: http://localhost/api/assignment/1}}

      • Spring-HATEOAS

       

  • 使用 Open API 规范 描述 API

  • 缺点:

    • 无法一次操作获取多个对象

    • 返回太多无用的信息 http://localhost/student/1 {name: zhangsan, id: 123, password: 1123, calssId: 123} http://localhost/class/123

    • 解决办法:GraphQL

使用gRPC API

  • 二进制的基于消息的协议

  • 使用 基于Protocol Buffer协议进行描述

  • 使用Protocol Buffer生成客户端桩(Stub)和服务器端骨架(skeleton)

  • 使用 HTTP/2

断路器模式(Circuit breaker pattern)

  • 问题:当请求的服务总是超时,怎么办?

  • 服务雪崩:一个服务拖跨一个应用

  • 目标:零延时

  • 当一个服务的请求连续出现超时,并且连续超时的次数超过某个阀值时,则再次请求该服务时会被断路器直接拒绝,而不会发出真正的请求。

  • 以下内容来自网络

    • 如果调用失败,将失败值的增加1

    • 如果调用失败的次数超过某个阈值,就打开电路

    • 如果电路处于打开状态,则立即返回错误信息或返回一个默认值

    • 如果电路处于打开状态且已经过了一段时间,则半开电路

    • 如果电路半开,下一次请求调次失败,请再次打开

    • 如果电路半开,下一次请求调用成功,请将其关闭

  • 断路器可部署在 API 网关上

    • 网关返回缓存数据,或直接错误数据

  • 开源实现:Hystrix for JVM 、Polly for .NET、Spring Cloud Hystrix, Dubbo, Nacos

  • 基础设施实现:Kubernetes + Istio Service Mesh

服务发现模式

  • 发送消息前,如何知道目标服务的网络位置,如IP和端口?

    • 我们现在的做法(最差):硬编码

    • 传统做法:从配置文件中获取

    • 微服务:因为要满足扩展性,目标服务可能会动态增减,因此目标IP地址是动态的

  • 必须提供一个动态的服务发现机制

    • 提供服务注册组件,管理所有服务实例的网络位置信息

    • 当服务实例启动或停止时,会更新服务网络数据

    • 注册中心会定期轮询服务实例其健康状态,因此服务实例也要提供类似API

    • 客户端向服务注册中心询问服务的网络信息,得到回复后发出请求

  • 两种实现:

    • 服务及其客户端直接与服务注册中心交互

      • 自我注册模式:服务实例启动或停止时,自动更新注册中心

      • 客户端发现模式:客户端从注册中心获取所有可用服务实例及其负载均衡配置

      • spring cloud netflix

    • 通过基础设施完成:Kubernetes

      • 第三方注册模式:服务实例由第三方自动注册

      • 服务器端发现模式:客户端向路由器发送请求,后者负责服务发现

      • 虽然与基础设施耦合,但还是推荐(因为不用写代码)

异步通信

使用异步消息模式

  • 一个基于消息的应用,通常被称为消息代理(message broker)

    • 作为服务通信的中介

    • 通信过程:

      • 客户端发送一条消息到代理

      • 服务从代理中读取消息

      • 服务进行处理并将结果封装成一条消息

      • 服务将消息发回给代理

      • 客户端从代理读取返回的消息

      • 客户端根据消息进行处理

    • 以上过程是异步的

      • 客户端发完消息后,并不会等着消息的返回

      • 客户端不需要知道服务的网络信息

      • 服务端不需要知道客户身份信息

  • 消息模式:客户端通过异常消息调用服务

消息

  • 案例:使用 Spring Integration 开发一个 hello world 例子

  • 消息模型

    • 出处: Enterprise Integration Patterns

    • 消息通过消息通道(message channel)进行交换

    • 发送者往通道上发送消息

    • 接收者从通道接收消息

  • 消息

    • 由消息头(header)和消息体(body) 构成

    • 消息头包括:

      • 一组键值对

      • 消息的元数据

      • 消息id

      • 消息返回地址:返回消息的通道

    • 消息体是消息要发送的数据,可以是文本或二进制类型

  • 三种消息类型

    • 文档:只包含纯数据

    • 命令:指定操作和参数

    • 事件:指出发送者发生的事件,如下订单

  • 消息通道

     

  • 消息通道类型:点对点,订阅-发布式

  • 可以实现同步的消息通信,但这种场景选用 REST

  • 异步请求/响应,或异步点对点

 

  • 单向通知:只请求,没响应

  • 订阅-发布:多个服务从通道中获取消息并处理

你可能感兴趣的:(java,网络)