分布式服务框架(拾遗)

前言

现在的大部分工程都已经是基于分布式架构来处理。所以这里对分布式框架做一个简单的总结

常用的RPC框架

RPC框架原理

RPC(Remote Procedure Call,远程过程调用)一般用来实现部署在不同机器上的系统之间的方法调用,使得程序能够像访问本地系统资源一样,通过网络传输去访问远端系统资源。RPC框架实现的架构原理是类似的。

分布式服务框架(拾遗)

  • Client Code :客户端调用方代码实现,负责发起RPC调用,为调用方用户提供使用API
  • Serialization/Deserialization:负责对RPC调用通过网络传输的内容进行序列化和反序列化,不同的RPC框架有不同的实现机制。(后面章节有介绍序列化/反序列化)不同的序列化方式在可读性、码流大小、支持的数据类型及性能方面存在较大差异。
  • Stub Proxy:可以看作是一种代理对象,屏蔽RPC调用过程中复杂的网络处理逻辑,使用RPC调用透明化,能够保持与本地调用代码一样的代码风格
  • Transport:作为RPC框架底层的通信传输模块,一般通过Socket在客户端和服务端之间传递消息
  • Server Code:服务端业务逻辑代码实现

RMI简介

Java RMI是一种基于Java的远程调用技术,是Java特有的一种RPC实现。其底层通信采用BIO实现的Socket完成、且使用了Java原生的序列化机制,所有序列化对象必须实现java.io.Serializable接口。

缺点

  • Java原生序列化机制与BIO通信机制本身存在性能问题,导致RMI的性能较差,对性能要求高的使用场景不推荐使用该方案

CXF/Axis2简介

WebService是一种跨平台的RPC技术协议,WebService技术栈由SOAP(Sample Object Access Protocol,简单对象访问协议)、UDDI、WSDL组成。CXF/Axis2就是基于WebService实现的

Thrift介绍

Apache Thrift是跨越不同的平台和语言,协助构建可伸缩的分布式系统的一种RPC实现。最初由FaceBook内部开发使用,现在已经开源。最大的特点是具备广泛的语言支持,以及高性能。 Apache Thrift作为在多语言并存的异构系统之间的RPC调用方案是一个非常不错的选择。尤其对XML-PRC/JSON-RPC/SOAP-RPC与WSDL协议栈实现的RPC方案,有着非常明显的性能优势。原因在于Thrift是采用二进制编码协议、使用TCP/IP传输协议的一种RPC实现,而XML-PRC/JSON-RPC/SOAP-RPC与WSDL协议栈实现的RPC采用的是HTTP作为传输协议。 对于网络数据传输,TCP/IP协议的性能要远远高于HTTP协议,不仅是因为HTTP协议是应用层协议,HTTP协议传输内容除应用本身数据外,还带有不少描述本次请求上下文的数据(响应状态码、Header等)。此外HTTP协议一般使用文本传输协议对传输内容进行编码,相对于一般采用TCP/IP协议码流要大。

gRPC介绍

gRPC是Google的一个高性能、开源和通用的RPC框架,面向移动和HTTP/2设计。目前提供C、Java和Go语言版本。

HTTPClient介绍

超文本传输协议(HTTP)是现在互联网使用的最重要的协议。HTTPClient就是基于HTTP协议进行调用。这里不再赘述。

分布式服务框架总体架构与功能

面向服务的架构(SOA)是一种设计范式,用于创建解决方案的逻辑单元,这些逻辑单元可组合、可复用,以支持实现面向服务计算的特定战略目标和收益

服务拆分原则

目前在互联网企业,业务不断扩展、快速演进,单一的系统已经不足以承载大量的业务,如果把所有的业务实现在一个单一的系统应用中会产生以下问题:

  • 业务模块边界不清,代码耦合严重,无法很好的实现代码模块级别或者功能级别的复用,从而服务快速的迭代
  • 所有的开发人员都在一个应用工程代码库进行迭代开发、测试、发版,会导致应用发布上线过于频繁,不利于线上系统的稳定性。且整个应用代码的稳定性、可维护性很难得到保障
  • 因为不同业务实现之间没有进行拆分隔离部署,某些高QPS耗时较长的复杂操作会影响整体应用的可用性。

解决以上问题的一个很好的做法就是系统拆分,以服务化的思想为指导,实现面向服务的架构,做服务化拆分。一般首先需要从整体上梳理公司的业务,将业务模块化,分解出各个业务模块之间的依赖及业务模块之间的边界。按照业务边界及业务之间的依赖顺序进行系统拆分,这是系统拆分的常见做饭。通过系统拆分实现SOA架构的价值,沉淀出一批稳定的后端服务,通过叠加复用快速响应用户的前端需求。

从单体到SOA架构的转变如下:

分布式服务框架(拾遗)

分布式服务总体架构

分布式服务框架主要包括服务消费端服务提供端服务数据网络传输协议的序列化/反序列化服务数据的通信机制服务注册中心服务治理这几分部分组成

  • 一般地,用Spring实现服务的引入与发布,分别实现服务消费端和服务提供端
  • 服务数据的序列化/反序列化实现选择有多种,比如JSON格式、Thrift、Avro、Java默认序列化、XML格式等,
  • 出于性能考虑,服务数据的通信机制目前的主流实现一般采用Netty、Mina或者类似的NIO网络通信框架
  • 服务注册中心目前的主流是采用Zookeeper来实现,用来实现服务注册、服务发现、服务自动上下线等功能。也可以采用Netflix的Eureka来实现这些功能。

分布式服务架构由服务提供端、消费端、服务注册中心、服务治理四部分组成。

分布式服务框架(拾遗)

  • 服务提供端启动服务,将服务提供者信息注册到服务注册中心,服务提供者信息一般包括服务主机地址、端口、服务接口信息等
  • 服务消费端将服务提供者信息从服务注册中心获取到本地缓存,同时将服务消费者信息上报到服务注册中心
  • 服务消费端根据某种软负载策略选择一个服务提供者发起服务调用,服务调用首先采用某种序列化方案,将数据序列化为可以在网络传输的字节数组,采用某种NIO框架完成调用
  • 为了管理大规模的服务依赖关系,需要提供服务治理功能

序列化/反序列化实现

序列化(Serialization)是将对象的状态信息转化为可存储或者传输的形式过程,简言之,就是把对象转化为字节序列化的过程。反序列化则是序列化的逆过程。

评价一个序列化算法优劣的两个重要指标:

  • 序列化后码流的大小
  • 序列化本身的速度及系统资源开销大小(CPU、内存等)

Java默认序列化

Java默认序列化的优缺点都比较明显:

优点:

  • Java语言自带,无须引用三方依赖
  • 与Java语言有天然的最好的易用性和亲和性

缺点:

  • 只支持Java语言,不支持跨语言
  • Java默认的序列化性能欠佳,序列化后产生的码流过大,对于引用过程的对象序列化易发生OOM

XML序列化

XML序列化的优势在于可读性好,利于调试。但是由于使用标签来表示数据,导致序列化后码流大,而且效率不高。

JSON序列化

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。相比XML,JSON序列化后码流小,可读性也好。目前主要的JSON序列化工具有:Jackson、fastJSON和GSON。相对而言Jackson和fastjson比GSON的性能好。Jackson和GSON比fastJSON稳定性高

Hessian序列化

Hessian是一个支持跨语言传输的二进制序列化协议

protobuf序列化

protobuf是Google的一种数据交换的格式,它独立于语言,独立于平台。是一个纯粹的展示层协议,可以和各种传输层协议一起使用。protobuf空间开销小及高解析性能,非常适合公司内部对性能要求高的RPC调用。 protobuf主要的问题是需要编写.proto IDL文件,使用起来工作量稍大,且需要额外学习proto IDL特有的语法。

Protostuff序列化

由于protobuf需要预先编写.proto IDL 文件,再通过protobuf提供的编译器生成对应于各种语言的代码。但是对于Java语言而言,Java具有反射和动态代码生成的能力,这个预编译过程不是必须的。仅对于Java语言,且无需跨语言的使用场景,Protostuff继承了Google的protobuf的高性能的同时免去了编写.proto 文件的麻烦。是一款值得推荐的序列化方式

Thrift序列化

thrift和protobuf类似,使用Thrift之前需要编写.thrift结尾的IDL文件,在使用Thrift提供的编译器编译成对应的代码。Thrift支持多种序列化协议。

Avro序列化

avro支持两种序列化编码方式,二进制编码和JSON编码,使用二进制编码的性能更高,序列化后产生的码流更小,而使用JSON编码的好处是编码后的可读性好。

JBoss Marshaling序列化

相对于原生Java序列化是一个很好的替代品

序列化框架的选型

由于每一种序列化协议都有自己的优缺点及适用场景。我们再选型的时候,一般从以下方面考虑: (技术层面)

  • 序列化空间开销,即序列化后码流大小,码流过大会对带宽、存储空间造成较大压力
  • 序列化时间开销,即序列化过程消耗的时长,序列化消耗时间过长会拖慢整个服务的响应时间
  • 序列化协议是否支持跨平台、跨语言,公司内部是否存在异构系统通信需要
  • 可扩展性/兼容性
  • 成熟度及支持的数据结构的丰富性 (选型建议)
  • 对于公司间的系统调用,性能要求在100ms以上的服务,基于XML的SOAP的协议是一个值得考虑的方案
  • 基于Web Browser的Ajax以及Mobile APP与服务端之间的通信,JSON协议是首选
  • 对于开发环境比较恶劣的考虑,采用JSON或者XML能够极大的提高调试效率
  • 对于性能和简洁性有极高要求的场景,Hessian、protobuf、Thrift、Avro之间具有一定的竞争关系。
  • 对于T级别的数据的持久化应用场景,protobuf和avro是首要选择
  • 对需要提供一个完整的RPC解决方案,Thrift是一个好的选择
  • 对序列化后需要支持不同的传输协议,或者需要跨防火墙访问的高性能场景,protobuf可以优先考虑

转载于:https://my.oschina.net/mrku/blog/1930260