Java Chassis 3 技术解密:多种序列化方式支持
原文链接:https://bbs.huaweicloud.com/blogs/418806
打开一个简单的 REST
接口:
的契约
:
可以看到 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 语义的接口访问服务端。
定义服务端接口:
通过 RPC 访问:
Java Chassis 以 OpenAPI 为基础的 Edge Service 部件,能够实现请求在通信协议、序列化方式上的自动转换。比如将 HTTP 协议转 Highway 协议、application/json 转 application/protobuf 等。
基于 Java Chassis Benchmark ,做一个简单性能测试。该测试对比了两种场景:
场景一的默认配置:
场景二的默认配置:
测试结果参考下表。该数据主要用于说明序列化差异,因此省去了测试环境的描述。下表的平均时延统计了测试客户端计算的请求-响应时间的平均值。
从这组数据可以看出:
在数据量比较小的场景下,使用
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 的解耦设计使得客户无需对代码进行任何改造,就可以满足两方面的要求。
评论