分布式服务框架原理与实践笔记

一、应用架构演进

2006年前比较流行的三种经典架构:

LAMP架构(Linux + Apache + Mysql(读写分离) + Php(前后台界面和业务逻辑))

MVC架构 ( springmvc/struts + spring + mybatis/hibernate + tomcat )

EJB企业架构

以上三种的共性:都是垂直应用架构。

RPC架构:Remote Procedure Call,它是一种进程间通信方式,允许像调用本地服务一样地调用远程服务,它的具体实现方式可以不同。

SOA服务化架构:SOA是一种粗粒度、松耦合的以服务为中心的架构,接口之间通过定义明确的协议和接口进行通信。

微服务架构:微服务架构(MSA)是一种服务化架构风格,通过将功能分散到各个离散的服务中以实现对解决方案的解耦。

总结:服务化架构演进:MVC架构->RPC架构->SOA架构->微服务架构

 

二、分布式服务框架基础

阿里Dubbo:dubbo是阿里内部SOA服务化治理方案的核心框架,每天为2K+个服务提供30+亿次访问量支持,并被广泛应用于阿里内部各成员站点。自2011年开源后被许多非阿里公司使用。

Dubbo工作原理:

1.轻量级JAVA容器通过main函数初始化spring上下文,根据服务提供者配置的XML文件将服务按照指定协议发布,完成服务的初始化工作。

2.服务提供者根据配置的服务注册中心地址连接服务注册中心,将服务提供者信息发布到服务注册中心。

3.消费者根据服务消费者XML配置文件的服务引用信息,连接注册中心,获取指定服务的地址等路由信息。

4.服务注册中心根据服务订阅关系,动态地向指定消费者推送服务地址信息。

5.消费者调用远程服务时,根据路由策略,从本地缓存的服务提供者地址列表中选择一个服务提供者,然后根据协议类型建立链路,跨进程调用服务提供者(非本地路由优先策略时  )。

Dubbo架构的主要质量属性:

1.连通性:

注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。

监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表显示。

服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心。

注册中心、服务提供者、服务消费者三者之间均为长连接,监控中心除外。

注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者。

注册中心和监控中心全部宕机,不影响已支行的提供者和消费者,消费者在本地缓存了提供者列表。

注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。

2.健壮性:

监控中心宕机不影响使用,只影响部分采样数据。

数据库宕机后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务。

注册中心对等集群,任意一台宕机将自动切换到另一台。

注册中心全部宕机后,服务提供者和服务消费者仍能通过本地缓存通信。

服务提供者无状态,任意一台宕机后不影响使用。

服务提供者全部宕机后,服务消费者将无法使用,并无限次重连等待服务提供者恢复。

3.伸缩性:

注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心。

服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者。

4.扩展性:

微内核+插件式设计,平等对待第三方:由插件管理容器构成微内核,其他外围功能都可以通过插件实现,平等对待第三方,使用者可以替换平台的默认实现,也可通过插件扩展新功能。

管道设计,服务调用前后提供拦截面(类AOP切面):通过服务调用前拦截,事后通知的方式,开放服务调用拦截面给框架使用者,用于功能扩展,Dubbo自身的大多数据功能也基于Filter拦截实现。

原子化扩展点,最大化复用和扩展:扩展点是单个功能的抽象,只负责完成一件事,例如序列化框架扩展点,用于Dubbo默认提供的序列化方式。

5.除了RPC框架功能,Dubbo还提供了服务治理功能。

其他分布式服务框架:淘宝HSF、亚马逊Coral Service 。

分布式服务框架设计:

架构原理:通常分布式服务框架的架构可以抽象为三层:

1.RPC层:包括底层通信框架(例如NIO框架的封装、公有协议的封装等)、序列化和反序列化框架、用于屏蔽底通信协议细节和序列化方式差异的Remoting框架。

2.Filter Chain 层:服务调用职责链,提供多种服务调用切面框架自身和使用者扩展,如负载均衡、服务调用性能统计、服务调用完成通知机制、失败重发等。

3.Service层:主要包括java动态代理,消费者使用,主要用于将服务提供者的接口封装成远程服务调用;JAVA反射,服务提供者使用,根据消费者请求消息中的接口名、方法名、参数列表反射调用服务提供者的接口本地实现类。再向上就是业务的服务接口定义和实现类,对于使用Spring配置化开发的就是Spring bean, 服务由业务来实现,平台负责将业务接口发布成远程服务。

功能特性:服务订阅与发布,服务路由,集群容错,服务调用,多协议,序列化方式,统一配置等。

性能特性:高性能、低延时、性能线性增长。

可靠性:服务注册中心,消除单点故障,链路健壮性。

服务治理:服务运行状态管控,服务监控,服务生命周期管理,故障快速定界定位,服务安全。

不同行业,业务规模不同会导致架构存在一定的差异,但是差异是相对的,共性是绝对的。阿里dubbo、淘宝HSF、亚马逊Coral Service存在很多共性,如:配置化发布服务、基于服务注册中心的发布订阅机制、内部私有二进制协议通信、灵活的路由策略、服务治理等。

 

三、通信框架开发

一个高性能的通用通信框架是分布式服务框架必不可少的有机组成部分。通信框架涉及到Socket通信、多线程编程、协议栈等相关知识。

关键技术点分析:

绝大多数分布式服务框架(RPC框架)都推荐使用长连接进行内部通信,而不是短连接  。(原因:a.相比于短连接,长连接更节省资源。如果每发一条消息就要创建链路、发起握手认证、关闭链路释放资源,会损耗大量系统资源。长连接只在首次创建时或者链路断开重连才创建链路,链路创建成功后服务提供者和消费者会通过业务消息和心跳维系链路,实现多消息复用同一个链路节省资源。b.远程通信是常态,调用时延是关键指标:服务化之后,本地API调用变成了远程服务调用,大量本地方法演化成了跨进程通信,网络时延成为关键指标之一。相比于一次简单的服务调用,链路的重建通常耗时更多,这就会导致链路层的时延消耗远大于服务调用本身的消耗,这对于大型企业业务系统而言无法接受。)

在JDK1.4推出JAVA NIO之前,基于JAVA的所有Socket通信都采用了同步阻塞模式(BIO),这种一请求一应答的通信模式简化了上层应用于的开发,但是在性能和可靠性方面存在巨大瓶颈。因此在很长一段时间内,大型企业应用服务器都采用C++或C语言开发,因为它们可以直接使用操作系统提供的异步IO或者AIO的能力。

采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端的连接请求后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端,线程销毁,这就是典型的一请求一应答通信模型。

JDK1.4提供了对非阻塞IO(NIO)的支持。

NIO采用多路复用技术,一个多路复用器Selector可以同时轮询多个channel,由于JDK使用了epoll()代替传统的select实现,所以它并没有最大连接句柄1024/2048的限制。即意味着只要一个线程负责Selector的轮询,就可以接入成千上万的客户端。

越来越多的商用系统采用直接集成开源的NIO框架的方式替代自研方案。以最成熟的NIO框架Netty为例,Hadoop的RPC框架avro使用netty作为底层通信框架,实时流计算框架storm使用底层通信框架也是用netty,还有twitter内部使用的RPC框架Finagle的底层通信框架也是基于netty构建的。

netty的优势:API简单,使用门槛低,预置多种编码解码功能,支持多种主流协议,定制能力强,可通过ChannelHandler进行灵活扩展,性能高,功能强大,成熟,稳定,社区活跃,经历大规模的商业应用考验,质量得到验证。

框架功能设计

服务端功能设计:

1.提供上层API(屏蔽底层NIO框架),用于初始化服务端实例,设置服务端通信相关参数,包括服务端的IO线程池(线程组参数)、监听地址、TCP相关参数、接收和发送缓冲区大小等。

2.提供可扩展的编码解码插件,用户可以通过扩展插件的方式实现自定义协议的编码解码。

3.提供拦截面,用于私有协议栈开发。例如通过新增鉴权插件实现服务端对客户端的安全认证。

客户端功能设计:相比于服务端,客户端的创建更复杂些,需要考虑连接超时、连接失败等异常场景。

客户端创建流程:

1.创建Bootstrap实例,Bootstrap是Socket客户端创建工具类,用户通过Bootstrap可以方便的地创建Netty的客户端并发起异步TCP连接操作。

2.初始化TCP连接参数,设置编码解码Handler和其他业务Handler。

3.调用Bootstrap的connect方法异步发起连接。

4.采用设置连接监听器的方式,用于连接结果异步通知。

5.服务端返回TCP握手应答,系统回调监听器操作完成接口。

6.在操作完成接口中实现相关业务逻辑,通知客户端连接操作完成。

 

可靠性设计:链路有效性检测、断连重连机制、消息缓存重发、资源优雅释放。

通信性能三原则:传输、协议、线程。

Netty支持高性能通信架构的特性:异步非阻塞通信、高效的IO线程模型、高性能的序列化框架。

 

四、序列化与反序列化

服务提供者和消费者通过网络进行通信,对象需要进行序列化和反序列化。

序列化(Serialization)称为编码(encode),它将对象序列化为字节数组,用于网络传输,数据持久化或其他途径。

反序列化(Deserialization) 称为解码(decode),把从网络、磁盘等读取的字节数组还原成原始对象(通常是对象副本),以方便后续业务逻辑操作。

进行远程跨进程服务调用时(如RPC),需要使用特定的序列化技术,对需要进行网络传输的对象做编码或解码,以便完成远程调用。

序列化/反序列化的性能主要有三个指标:

1.序列化之后的码流大小。

2.序列化/反序列化的速度。

3.资源占用,主要是CPU和堆内存。

扩展性设计:netty提供的编码解码框架可以快速地实现序列化和反序列化框架的扩展,Netty内置了丰富的序列化/反序列化功能类库,用户可以直接使用,避免二次开发。

序列化和反序列化是RPC框架的基础组成部分,设计的好坏对服务化框架的性能、可扩展性和可靠性影响都很大。

 

五、协议栈

不同服务在性能上适用不同协议进行传输。比如对接异构第三方服务时,通常会选择HTTP/Restful等公有协议;对于内部不同模块之间的调用,会选择性能较高的二进制私有协议。

关键技术点(是否必须支持多协议、公有协议还是私有协议、集成开源还是自研)

功能设计(功能描述、通信模型、协议消息定义、协议栈消息序列化支持的字段类型、协议消息的序列化和反序列化、链路的创建、链路的关闭)

可靠性设计(客户端连接超时、客户端重连机制、客户端重复握手保护、消息缓存重发、心跳机制)

安全性设计:为了保证整个集群环境的安全,内部长连接采用基于IP地址的安全认证机制,服务端对握手请求消息的IP地址进行合法性校验,如果在白名单内,则校验通过,否则拒绝对方连接。

如果需要将服务开放给第三方非信任的消费者,需要采用更严格的安全认证机制,如基于密钥和AES的用户名+密码认证机制,也可以采用SSL/TSL安全传输。 

通信框架、序列化/反序列化、协议栈的关系:协议描述了分布式服务框架的通信契约,序列化和反序列化框架用于协议消息对象和二进制数组之间的相互转换,通信框架在技术上承载协议,协议要落地,需要依赖通信框架提供的基础通信能力。

 

六、服务路由        

1.透明化路由(基于服务注册中心的订阅发布、消费者缓存服务提供者地址)

2.负载均衡(随机、轮循、服务调用延时、一致性哈希、粘滞连接)

3.本地路由优先策略(injvm模式、innative模式)

4.路由规则(由消费者规则和服务提供者规则)

    a.条件路由规则(通过IP进行黑白名单控制;流量引导,只暴露部分服务提供者,防止整个集群服务都被冲垮,导致其它服务也不可用;读写分离;前后台分离;灰度升级。)

    b.脚本路由规则(通过都支持动态编译,修改后可以实时生效,不需要重启系统,这在线上动态调整路由规则时非常有效。)

路由策略的定制(自定义路由的主要场景:灰度升级、服务故障、与业务领域强相关的非通用路由定制需求。)

配置化路由:(本地配置,统一注册,动态下发)

服务路由功能是分布式服务框架的重要特性,作为基础平台,既要内置丰富的路由策略,同时还要具备灵活的扩展功能,方便用户做二次定制。

 

七、集群容错  

集群服务调用失败后,服务框架要能在底层自动容错。

集群容错场景(通信链路故障、服务端超时、服务端调用失败等。)

容错策略(失败自动转换、失败通知、失败缓存、快速失败、容错策略扩展等。)

相比于传统RPC框架,服务框架需要提供更丰富、更细粒度的功能和扩展点。

 

八、服务调用

除了常用的同步服务调用外,分布式服务框架还需要支持其他几种形式的服务调用。

服务调用的两种模式:

1.OneWay模式:只有请求,没有应答,例如通知消息(容易设计成异步)。

2.请求-应答模式:一请求,一应答的模式,最常用(可以用java的Future-Listener机制来实现异步服务调用)。

服务调用方式:(同步服务调用、异步服务调用、并行服务调用、泛化服务调用)

 

九、服务注册中心

专门用来管理服务订阅发布的配置管理节点

关键功能特性设计(支持对等集群、提供CURD接口、安全加固、订阅发布机制、可靠性)

基于ZooKeeper的服务注册中心设计:

1.服务订阅发布流程设计

2.服务健康状态检测

3.对等集群防止单点故障

4.变更通知机制

分布式服务框架需要一个服务注册中心实现服务的订阅和发布、服务动态发现以及透明化路由。

 

十、服务发布和引用

服务提供者需要支持通过配置、注解、API调用等方式,把本地接口发布成远程服务;对于消费者,可以通过对等的方式引用远程服务提供者,实现服务的发布和引用。

常用的三种服务发布方式:

1.XML配置化方式(推荐)

2.注解方式

3.API调用方式

服务引用设计:

1.本地接口调用转换成远程服务调用

2.服务地址本地缓存

3.远程服务调用

一个好的分布式服务框架对业务代码的侵入要足够低,如通过XML配置化的方式将普通JAVA接口发布成远程服务;消费者通过配置化方式引用服务提供者的接口。基于接口编程,服务框架底层的变更都不会影响上层应用,真正实现了业务和平台解耦。

 

十一、服务灰度发布

灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式:让一部分用户继续用A,一部分用户开始用B;如果用户对B没什么反对意见,那么慢慢扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。----------

服务灰度发布的主要作用:

1.解决服务升级不兼容问题。

2.及早获得用户的意见反馈,完善产品功能,提升服务质量。

3.缩小服务升级所影响的用户范围,降低升级风险。

4.让用户及早参与产品测试,加强用户互动。

服务灰度发布流程设计:

1.灰度环境准备:在正式进行服务灰度发布前,需要对灰度环境进行划分、隔离和准备。

a.系统运维人员通过管理员账号登录灰度发布Portal或者进入服务治理的灰度发布界面。

b.在生产环境中圈定本轮灰度发布的范围,通常它是一个应用集群,包括前后台服务,当然也可能是单个服务。

c.将选择的灰度服务发布范围信息保存到服务注册中心,用于后续的规则下发和灰度升级历史查询等。

d.通知灰度升级范围内的服务实例下线,通常会采用优雅停机的方式让待升级的服务下线,保证升级不中断业务。

e.应用进程收到优雅停机指令后,将本进程内缓存的消息处理完,然后优雅退出。

f.从软件仓库中选择需要升级的服务安装镜像包,用于灰度环境的版本升级.

g.将升级包批量上传到灰度环境中,把原来的业务软件包做本地备份后,升级服务版本。

h.灰度环境升级部署成功后,返回灰度环境部署成功消息给灰度发布管理控制台,然后进行后续的灰度发布操作。

2.灰度规则设置:灰度环境准备完成后,运维人员需要对灰度规则进行设置,

3.灰度规则下发:灰度规则设置完成后,需要将规则下发给参与消息路由的软负载均衡器SLB、Web和后台服务。

4.灰度路由:通过SLB定制的灰度发布插件,可以将HTTP消息按照规则分发到不同的web前台,web前台根据内置的服务框架SDK,通过客户端灰度路由插件,解析灰度规则,将服务路由到灰度或者非灰度环境,实现服务的灰度路由。

5.失败回滚:如果灰度升级失败,需要支持失败回滚。

灰度发布策略的主要思想是把影响集中到一个点,然后再发散到一个面,出现意外情况后很容易就能回退。分布式服务框架支持服务的灰度发布,可以实现业务的快速试错和敏捷交付,缩短新业务和产品的上线周期,非常重要。
 

转载于:https://my.oschina.net/xiejunbo/blog/830186

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值