当前位置:首页 期刊杂志

分布式服务框架的设计与实现

时间:2024-05-04

张鹏飞

(四川大学计算机学院,成都 610065)

0 引言

随着互联网浪潮风起云涌,互联网行业发展非常迅速。在一个不断发展的大型应用中,新的业务功能和需求不断增加,技术也在不断演进,不同团队构建的功能和子系统采用的技术构成五花八门,子系统之间开发、部署和运维也存在较大差异。如果企业内部没有统一的服务框架进行技术层面的拉通,开发和运维都将会受到很大的约束。

传统垂直架构的核心就是要对应用进行服务化,服务化改造使用到的核心技术就是分布式服务框架。

1 框架设计

分布式服务框架包括服务提供者、服务消费者、服务注册发现、序列化、服务通信、负载均衡、日志管理等组件。

图1

其中,服务提供端是分布式服务框架最重要的组成部分,通过将本地服务注册到服务注册中心上来发布可用的服务。包含IoC组件、流量控制组件、服务发布组件等。IoC组件提供了依赖注入功能,将对象从对象提供者和使用者之间分离开来,由IoC容器管理对象依赖关系和生命周期。

序列化:序列化是将对象转化为字节序列的过程。反序列化是序列化的逆过程。序列化帮助我们解决了几个问题。第一、使不共享内存通过网络连接的系统之间可以进行对象的传输。第二、解决远程接口调用JVM之间内存无法共享的问题。

日志管理:记录重要的框架层日志、异常链数据,同时将日志的接口暴露出来,让业务层的程序员能根据日志来调试程序,解决潜在的问题。

服务配置:支持配置文件方式配置,能够集成主流框架,能够在框架运行时根据不同的业务场景来调整服务的参数和配置。

服务通信:提供NIO的同步请求响应模式和基于消息的一异步通信方式。

负载均衡:负载均衡的目的是将请求按照某种策略分布到多台机器上,使系统能够实现横向扩展。

框架运行具体流程为:

服务提供端启动服务器,框架将服务提供者信息(服务主机IP地址、端口号、提供的服务接口信息等)注册到服务注册中心。服务消费端将服务提供信息从服务注册中心读取到本地缓存中,同时将服务消费者的信息上传到服务注册中心去。服务消费端使用系统提供的几种软负载均衡算法的某一种来选择某一个服务提供者,发起服务调用命令。服务提供端收到来自服务消费端的请求,使用数据序列化方案将调用数据序列化为可以在网络中传输的字节数组,发送给服务消费端来完成服务的调用。

2 分布式服务框架的实现

2.1 服务提供端的实现

大多数使用Java来进行开发的系统都会用Spring来作为组件的容器,开发人员也很熟悉Spring的配置。本文为了提高分布式服务框架的易用性,实现了该框架和Spring的集成,使用Spring管理服务的发布和引入,进而使远程服务发布Bean与远程调用编程界面与本地Bean方法调用一致,屏蔽了远程调用服务与本地方法调用的差异性。

服务端利用Java注解的方式将服务接口用@Rpc-Service标注出来,在框架初始化的时候,框架扫描本地包,将被标注为@RpcService的类加入到容器MapserviceBeanMap中。利用Spring提供的Bean容器,在初始化Spring上下文的时候,把service-BeanMap中的服务方法发布到服务注册中心去。在Sping Bean生命周期的最后一步,设置完服务端Server类后,启动网络连接,接受客户端的请求。到此为止,服务器端的初始化完成。

服务端启动代码:

2.2 服务消费端的实现

服务请求消息的实体是Resquest类,该类封装了请求消息ID、请求版本号、请求接口名、请求方法名等信息。服务消费端使用动态代理的设计模式思想,客户端调用方法时就像该方法实现的类在本地一样,Java动态代理读取客户端请求的方法信息封装成Request类,启动网络连接,将Request发送到服务端去,当调用结果正常返回或者超时发生异常时候,返回该结果。服务消费端初始化和一次服务调用代码如下:

2.3 服务注册中心的实现

服务注册中心是分布式服务框架的目录服务器,相比于传统的目录服务器,它有如下几个特点。第一,支持数据持久化,支持集群。第二,集群中所有客户端应该看到同一份数据,不能出现读或者写数据不一致。第三,当注册中心的数据发生变更时(增加、删除、修改)需要能将及时变化的数据通知客户端。本文使用Zookeeper来设计服务注册中心。Zookeeper是Apache Hadoop的一个子项目,它主要用来解决分不少应用中经常遇到的一些数据管理问题,如统一命名服务、状态同步服务、集群管理等。

Zookeeper是采用树型目录结构的,本文定义的注册中心节点树如图2所示。

第一层节点Key用来唯一标识一个应用,可以看作是该应用的一个命名空间。第二层节点Service用来存粗实现服务的信息。第三层节点用来区分服务消费端和服务提供端。最后一层存储服务消费端或者服务提供端主机IP与服务端口号。其中Key和Service是持久节点,其他节点是临时节点。Zookeeper持久节点被创建后,就会一直存在于Zookeeper服务器上,直到有删除操作来主动删除这个节点。而临时节点的生命周期和客户端会话绑定在一起,客户端会话失效,则这个节点就会被自动清除。这样就实现了服务的自动上线和下线,当提供服务的服务提供端关闭时,该服务信息也会在注册中心自动下线。

图2

2.4 服务数据的通信的实现

无论是服务提供端接受调用方法,还是返回调用结果,都需要通过网络来进行传输。这是本地调用与远程调用最主要的区别。网络模块是影响分布式服务框架性能的关键模块。本文使用来Netty来构建网络模块。Netty是著名的NIO开源框架,提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty的线程模型是基于Reactor设计的,如图3所示。

本文设计了Netty服务端和Netty客户端。Netty服务端的作用是服务端业务逻辑处理器和编码解码处理器。Netty服务端接收客户端发起的请求字节数组,然后通过解码器NettyDecodeHandler将字节数组解码为对应的Java请求对象。然后根据解码得到的Java请求对象确定服务提供者接口以及方法,最后通过使用Java反射技术来发起调用。

图3

Netty客户端发起一次服务调用,并得到调用结果,整个过程如下。第一,获取服务提供者列表,通过某种软负载均衡算法选择一个服务提供者。第二,根据服务提供者信息在Netty连接池中获取对应的Channel连接。第三,将服务请求数据对象通过某种序列化协议编码成字节数组,通过Channel发送到服务端。第四,同步等待服务返回调用结果。

3 结语

本文设计实现了一个轻量级的分布式服务框架,涉及通信、服务调度等。该框架能提供简洁高效的RPC调用服务,对整个业务系统不会造成任何入侵;实现了序列化与反序列化引擎,软负载均衡算法引擎,能让用户根据业务场景选择最优的解决方案。功能上,该框架使用同步调用、异步调用,传输经过序列化的对象,当请求正常返回和异常返回时都做了相应的处理;性能上,该框架可用让用户根据业务场景选择合适的序列化方案、负载均衡方案,使用Netty提供了针对大量消费端连接的解决方案。但是该框架存在一些不足,例如可用在TCP协议之上自定义协议族,可提高系统的安全性。

参考文献:

[1]ZHOU Wan-lei.Supporting Fault-tolerant and Open Distributed Processing Using RPC[D].Australia:Deakin University,1996.

[2]李林锋.分布式服务框架:原理与实践[M].北京:电子工业出版社,2006.1

[3]查骏.基于NIO的远程调用框架的设计与实现[D].上海:复旦大学,2012.

[4]刘礼鸣.基于本体的服务治理平台研究[D].上海:上海交通大学,2011

[6]A.L.Ananda.B.H.Tay,E.K.Koh.A Survey of Asynchronous Remote Procedure Calls[D].ACM SIGOPS Operating Systems Review,1992.

[7]XIAO Xin-xiao,JIA Rui-xiang.Distributed Monitoring and Control System for Energy Saving Based on RPC[D].Qindao:Qilu University of Technology,2014.

免责声明

我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!