今天我们来进行架构探险:从零开始写分布式服务框架,你能学会吗

常用的RPC框架

1.1 RPC框架原理

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

1.2 RMI介绍

Java RMI ( Remote Method Invocation)是一种基 于Java的远程方法调用技术,是Java特有的一种RPC实现。它能够使部署在不同主机上的Java对象之间进行透明的通信与方法调用,如图1-2 所示。

1.3 CXF/Axis2 介绍

WebService是一种跨平台的RPC技术协议。WebService技术栈由SOAP(SampleObjectAccess Protocol, 简易对象访问协议)、UDDI ( Universal Description, Discovery andIntegration,统一描述、 发现与集成)、WSDL ( Web Services Description Language, 网络服务描述语言)组成。其中,SOAP是一种使用XML进行数据编码的通信协议,独立于平台,独立于语言,简单可扩展,因为SOAP基于HTTP协议进行数据传输,故能绕过防火墙。

SOAP提供了一种标准方法,使得运行在不同的操作系统并使用不同技术和编程语言的应用程序可以互相通信。UDDI是一个独立于平台的框架,是一种通用描述、发现与集成服务。WSDL 是使用XML编写的网络服务描述语言,用来描述WebService,以及如何访问WebService。

CXF演示项目工程结构

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

2.1面向服务的体系架构( SOA )

面向服务的架构(SOA) 是伴随着互联网快速发展产生的一种系统架构方法。

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

面向服务设计范式主要由以下设计原则组成:

◎标准化服务契约:服务遵循相同的契约设计标准。

◎服务松散耦合: 服务契约对服务消费者松耦合,服务之间松耦合。

◎服务抽象: 服务契约仅包含必要信息,并且关于服务的信息局限为服务契约中发布的信息。

◎服务可重用性:服务可作为可重用资源。

◎服务自治:服务对其底层运行时执行环境有很大的控制权。

◎服务无状态性: 服务无状态保证了服务部署的横向扩展性。

◎服务可发现性:服务可以通过描述性元数据有效发现并解释服务。

◎服务可组合性: 可以通过组合叠加原子服务形成复杂上层业务服务。

SOA中的服务化收益°如图2-1所示。

SOA中的服务化收益

分布式服务框架序列化与反序列化实现

3.1序列化原理及常用的序列化介绍

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

而反序列化( Deserialization)是序列化的逆过程。将字节数组反序列化为对象,把字节序列恢复为对象的过程称为对象的反序列化。

序列化能帮助我们解决如下问题。

◎通过将对象序列化为字节数组,使得不共享内存通过网络连接的系统之间能够能够进行对象的传输。

◎通过将对象序列化为字 节数组,能够将对象永久存储到存储设备。

◎解决远程接口调用 JVM之间内存无法共享的问题。

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

◎序列化后 码流的大小。

◎序列化本身的速度及 系统资源开销大小(包括内存、CPU等)。

各种常用的序列化的性能对比“如图3-1所示。

实现分布式服务框架服务的发布与引入

4.1 Spring Framework框架概述

4.1.1 Spring Framework介绍

Spring Framework为Java 企业级开发提供了-站式的轻量级(相对EJB而言)解决方案,目前已经成为Java企业级开发领域事实上的标准。

Spring抽象了我们在开发过程中遇到的很多共性的问题,为我们解决这些问题提供了很好的脚手架。

◎提供了 编程式事务模板类TransactionTemplate.java与声明式事务注解@Transactional的解决方案,简化了开发过程中事务控制的繁杂工作。

◎以 DataAccessException.java为基类,抽象了统一的数据库异常表示。

◎提供了统一的数据库集成抽象层,同时通过提供模板类JdbcTemplate.java简化了JDBC操作代码。

◎提供了 Spring MVC这一优秀的MVC框架,极大简化了开发人员在展现层与后台服务调用之间的工作,同时也提供了扩展点,可以无缝集成现有的其他主流MVC框架(Struts1.x、 Struts2.x、 WebWork 等),实际,上,Spring MVC渐渐有取代其他MVC框架的趋势。

◎提供了SpringAOP及通过集成Aspectj为AOP开发提供了开箱即用的强大支持。

◎最核心的是提供了 I0C容器,提供了依赖反转模式的实现,为Java 企业级开发带来了革命性的创新体验。

Spring还有大量其他的有用的特性,限于篇幅,不在此一- -列举了。同时,Spring 本身也是基于模块化构建的,在实际使用的时候,可以按需引入所需的模块,如图4-1所示。

Spring Runtime架构图

分布式服务框架注册中心

5.1服务注册中心介绍

分布式服务框架部署在多台不同的机器上,例如服务提供者部署在集群A,服务调用者部署在集群B,在服务调用的过程中,集群A中的机器需要与集群B中的机器进行通信,如图5-1所示。

服务提供者集群与服务调用者集群

有如下问题需要解决。

◎集群A中的服务调用 者如何发现集群B中的服务提供者。

◎集群A中的服务调用者如何选择集群B中的某一台服务提供者机器发起调用。

◎集群 B中的服务某台提供者机器下线之后,集群A中的服务调用者如何感知到这台机器的下线,不再对已下线的机器发起调用。

◎集群B提供的某个服务 如何获知集群A中哪些机器正在消费该服务。

以上问题将通过服务注册中心来解决,我们采用服务注册中心来实时存储更新服务提供者信息及该服务的实时调用者信息,如图5-2所示。

服务调用者、服务注册中心、服务提供者关系示意图

分布式服务框架底层通信实现

6.1.1 Linux下实现的I/O模型

因为程序运行在操作系统上,编程语言实现的I/O操作API最终依赖于操作系统的I/O实现。Linux 操作系统目前占服务器市场大部分份额,下面一 -起了解一下Linux操作系统实现的几种1/O模型及其特点。

在这之前,先理清阻塞、非阻塞、同步、异步这4个概念。

◎阻塞: 调用方发起调用请求,在没有返回结果之前,调用方线程被挂起,处于一直等待状态。

◎非阻塞: 非阻塞和阻塞的概念相对应,调用方发起调用请求,当前线程不会等待挂起,而会立刻返回。后续可以通过轮询等手段来获取调用结果状态。

◎同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。

◎异步: 异步的概念和同步相对。当一个异步过程调用发出后,调用者不会立刻得到结果,通过回调等措施来处理这个调用。

Linux下实现了5种I/O模型。

(1)阻塞I/O模型:默认情况下,所有的文件操作都是阻塞的。在进程空间中调用reevfrom,其系统调用直到数据包到达且被复制到应用进程的缓冲区中或者发生错误才返回,在此期间会一直等待,进程在从调用rec/from开始到它返回的整段时间内都是被阻塞的,如图6-1所示。

阻塞I/O模型

(2)非阻塞I/O 模型:进程把一个套接口设置成非阻塞是在通知内核。当所请求的I/O操作不能满足要求的时候,不把本进程投入睡眠,而是返回一个错误。也就是说当数据没有到达时并不等待,而是以一个错误返回,如图6-2所示。

非阻塞I/O模型

(3) I/O复用模型: Linux提供select/poll, 进程通过将一个或多个fd传递给select或poll系统调用,阻塞在select;这样select/poll可以帮我们侦测许多fd 是否就绪。但是select/poll是顺序扫描fd是否就绪的,而且支持的fd数量有限。Linux还提供了-一个epoll系统调用,epoll 基于事件驱动方式,而不是顺序扫描,当有fd就绪时,立即回调函数rollback,如图6-3所示。

I/O复用模型

(4)信号驱动异步I/O 模型:首先开启套接口信号驱动I/O功能,并通过系统调用sigaction安装一-个信 号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的)。

当数据报准备好被读时,就为该进程生成一个SIGIO信号。随即可以在信号处理程序中调用recvfrom来读数据报,并通知主循环数据已准备好被处理。也可以通知主循环,让它来读数据报,如图6-4所示。

(5)异步I/O模型:告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核复制到用户自己的缓冲区)通知我们。这种模型与信号驱动模型的主要区别是信号驱动I/O由内核通知我们何时可以启动一个I/O操作;异步I/O模型由内核通知我们I/O操作何时完成,如图6-5所示。

分布式服务框架软负载实现

软负载的实现原理

负载均衡的目的是将请求按照某种策略分布到多台机器上,使得系统能够实现横向扩展,是应用实现可伸缩性的关键技术,也是系统能够应对大流量的核心技术之一。分布式服务框架中实现负载均衡是通过软件算法来实现的,有别于基于硬件设备(如F5)实现负载均衡,故称为软负载。

在分布式服务框架中,负载均衡是在服务消费端实现的,其实现原理如下。

◎服务消费端在应用启动之 初从服务注册中心获取服务提供者列表,缓存到服务调用端本地缓存。

◎服务消费端发起服务调用之前, 先通过某种策略或者算法从服务提供者列表本地缓存中选择本次调用的目标机器,再发起服务调用,从而完成负载均衡的功能。

分布式服务框架服务治理

服务治理介绍

在大规模服务化之前,系统应用之间的交互可能只是简单地通过WebService、RMI等RPC框架来实现,通过手工配置调用端服务地址进行调用,通过F5等硬件进行负载均衡。但是随着业务的不断演进,服务个数越来越多的时候,这种做法就遇到了瓶颈,因为服务数多本身就是问题,量变引发质变,服务数多了,会导致很多问题。

问题一:随着服务的增多,服务之间的依赖关系变得越来越复杂,靠人力很难梳理清楚整个链路服务之间的依赖关系。这样会导致很多风险,比如系统发布需要先发布下游服务,再发布上游服务,若无法梳理清楚服务之间的依赖,就无法正确安排系统发布顺序。

此时,需要依赖服务治理功能,自动画出应用之间的依赖关系图。

问题二:需要对每个服务本身的服务质量了如指掌才能保证整个链路服务的稳定性。服务质量包括服务QPS、每天调用总量、top50、 top90、 top99 响应时间等指标。

问题三:随着服务数量的增多,沟通成本随之增加,需要对每个服务标注负责人。

问题四:当发现某个非关键服务出错率很高,对业务关键链路造成了影响,要有一键降级的功能将该服务从调用链路中摘除。

问题五:对某个已有服务升级之后,需要在线上环境进行灰度发布或者AB测试。要求服务有自动分组能力,某个消费组的请求只打到对应的服务组上。

问题六:服务部署集群中,可能某些机器配置更好,有更高的服务吞吐能力,能支持更高的QPS,要求可以对该机器配置更高的服务权重,使得请求按权重比例打到该机器问题七:当调用链路横跨多个服务、多个应用,对每一次调用需要有一个唯一标识将服务之间的调用串联起来,有助于排查线上问题。

服务治理是一个很大的主题,它涵盖了非常多的内容。限于篇幅,无法做到面面俱到,这里只对相关的部分内容做一一个概要性质的介绍,可以将部分内容归纳为以下主题。

◎服务注册与发现。

◎软负载。

◎服务质量监控与服务指标数据采集。

◎记录负责人。

◎服务分组路由。

◎服务依赖关系分析。

◎服务降级。

◎服务权重调整。

◎服务调用链路跟踪。

因为模块比较多,小编就不一一为大家介绍了,下面呢,小编就把《架构探险:从零开始写分布式服务框架》给大家分享出来。

大家转发关注小编一下,+私信小编V X 17835068576 ,领取PDF。

学习呢,是一个循序渐进的一个过程,大家一定要用心来学习。

推荐阅读更多精彩内容