写点什么

Java Chassis 3 技术解密:多种序列化方式支持

  • 2024-01-16
    广东
  • 本文字数:2989 字

    阅读完需:约 10 分钟

原文链接:https://bbs.huaweicloud.com/blogs/418806


打开一个简单的 REST 接口:

@RestSchema(schemaId = "ProviderController")@RequestMapping(path = "/")public class ProviderController {  @PostMapping("/benchmark")  public DataModel sayHello(@RequestHeader("wait") int wait, @RequestBody DataModel dataModel) {    if (wait > 0) {      Thread.sleep(wait);    }    return dataModel;  }}
复制代码

契约:

openapi: 3.0.1info:  title: swagger definition for org.apache.servicecomb.samples.ProviderController  version: 1.0.0servers:- url: /paths:  /benchmark:    post:      operationId: sayHello      parameters:      - name: wait        in: header        required: true        schema:          type: integer          format: int32      requestBody:        content:          application/json:            schema:              $ref: '#/components/schemas/DataModel'          application/protobuf:            schema:              $ref: '#/components/schemas/DataModel'          text/plain:            schema:              $ref: '#/components/schemas/DataModel'        required: true        x-name: dataModel      responses:        "200":          description: response of 200          content:            application/json:              schema:                $ref: '#/components/schemas/DataModel'            application/protobuf:              schema:                $ref: '#/components/schemas/DataModel'            text/plain:              schema:                $ref: '#/components/schemas/DataModel'components:  schemas:    ChildDataModel:      type: object      properties:        numInt:          type: integer          format: int32        numLong:          type: integer          format: int64        numDouble:          type: number          format: double        numFloat:          type: number          format: float        data:          type: string      x-java-class: org.apache.servicecomb.samples.ChildDataModel    DataModel:      type: object      properties:        data:          type: object          additionalProperties:            $ref: '#/components/schemas/ChildDataModel'      x-java-class: org.apache.servicecomb.samples.DataModel
复制代码

可以看到 Java Chassis 使用了 Open API 3.0.1 的协议规范,Request Body 和 responses 增加了 application/protobuf 、 text/plain 的支持。 这种使用形式,奠定了 Java Chassis 3 多序列化支持方式的基础,细心的读者应该很快能够发现这种方式与其他支持多序列化框架之间的差异。

  • Spring Boot

支持多序列化方式,需要实现 HttpMessageConverter 接口,并在 Controller 声明支持的 Content-Type。 如果使用 Spring Fox 或者 Spring Doc 等 Open API 工具生成契约,契约内容只会包含 Controller 声明的序列化类型。 Spring Boot 存在隐式的契约情况,这意味着契约并不能完全代表 Controller 服务的能力。 如果需要对接口增加或者减少序列化支持,都需要修改代码。

  • Dubbo

Dubbo 需要在 Provider 使用 dubbo:protocol 声明序列化方式, 在 Consumer 使用 dubbo:reference 声明序列化方式。 由于 Dubbo 是基于IDL的契约系统, 在使用 RPC 的场景下,可以通过配置动态调整序列化方式。 REST 支持在 Dubbo 是完全独立的单元, 序列化方式也独立于 RPC 接口, RPC 和 REST 不能互操作。

Open API 基于 REST 的语义,来支持 IDL 的语义。 Java Chassis 能够更加直观的支持通过第三方工具以 HTTP 协议族访问微服务, 只需要按照契约的描述构造 HTTP 的报文。 在编码侧, Java Chassis 的客户端可以使用 REST 语义的接口,如 RestOperations,也可以使用 RPC 语义的接口访问服务端。

定义服务端接口:

public interface ProviderService {  DataModel sayHello(int wait, DataModel dataModel);}
复制代码

通过 RPC 访问:

@RestSchema(schemaId = "ConsumerController")@RequestMapping(path = "/")public class ConsumerController {  @RpcReference(schemaId = "ProviderController", microserviceName = "provider")  private ProviderService providerService;
@PostMapping("/benchmark") public DataModel sayHello(@RequestHeader("wait") int wait, @RequestBody DataModel dataModel) { return providerService.sayHello(wait, dataModel); }}
复制代码

Java Chassis 以 OpenAPI 为基础的 Edge Service 部件,能够实现请求在通信协议、序列化方式上的自动转换。比如将 HTTP 协议转 Highway 协议、application/json 转 application/protobuf 等。

基于 Java Chassis Benchmark ,做一个简单性能测试。该测试对比了两种场景:


场景一的默认配置:

servicecomb:  rest:    parameter:      default-request-encoding: "application/json"      default-response-encoding: "application/json"
复制代码

场景二的默认配置:

servicecomb:  rest:    parameter:      default-request-encoding: "application/protobuf"      default-response-encoding: "application/protobuf"
复制代码

测试结果参考下表。该数据主要用于说明序列化差异,因此省去了测试环境的描述。下表的平均时延统计了测试客户端计算的请求-响应时间的平均值。

从这组数据可以看出:

  • 在数据量比较小的场景下,使用 json 和 proto-buffer 性能差异很小。 在数据量比较大的情况下,proto-buffer 的性能明显好于 json

  • 在业务时延比较大(>100ms)的时候, 序列化的时延可以忽略。

不同的序列化方式除了性能差异,在可维护方面也会存在很大的差异。比如 proto-buffer 在兼容性方面的表现会比 json 差,当修改接口定义的时候, 比如增加属性、删除属性、修改属性等,proto-buffer 更容易导致兼容性问题,做好兼容性防范对多数用户而言,都是比较困难的事情。

支持多协议、多序列化方式的另外一个考虑,是对接遗留系统。对接遗留系统会背负大量历史债务,使得新系统本身设计偏离预期的方向。在 Java Chassis 多序列化方式的选择上, 只提供了目前广泛使用的 json 和 proto-buffer 支持, 而没有选择支持其他序列化方案。 以架构的韧性去处理遗留系统问题,是 Java Chassis 坚持的一个重要设计理念,对接遗留系统或者保持与遗留系统的兼容,不是它的主要设计目标。


在序列化方式选择上,简单的总结如下:

  • 使用 REST 协议是绝大多数场景的最优选择,能够最好的兼顾性能、可靠性、韧性等方面的要求。

  • 对于数据量比较大,业务时延很低(<100ms),并且业务比较稳定,业务接口不需要频繁变动的场景,可以采用 proto-buffer来优化性能,按需调整。

客户故事:某个客户的关键核心系统对于时延要求很高,因此需要采用私有协议和序列化方式来提升性能。但是对于一些非核心系统,需要使用 REST 接口,方便日常开发、调试。Java Chassis 的解耦设计使得客户无需对代码进行任何改造,就可以满足两方面的要求。

用户头像

公众号:华为云PaaS服务,有见面礼等你哦! 2022-09-26 加入

还未添加个人简介

评论

发布
暂无评论
Java Chassis 3技术解密:多种序列化方式支持_Java_华为云PaaS服务小智_InfoQ写作社区