分布式服务架构-第一章 分布式微服务架构设计原理

第一章 分布式微服务架构设计原理

  • 传统企业级技术无法满足互联网产品服务于海量用户的需求;
  • 互联网技术以拆分为原则来满足服务于海量用户的需求
  • 满足用户对高可用性,高性能,可伸缩,可扩展和安全性的非功能质量的要求

1.从传统单体架构到服务化架构

1.1 JEE架构

Java平台企业版简称

JEE架构:

web容器 —综合业务逻辑 --> EJB容器 — 数据存取ORM --> 数据库

  • Web层:负责与用户交互或者对外提供接口
  • 业务逻辑层:为了实现业务逻辑而设计的流程处理和计算处理模块
  • 数据存取层:将业务逻辑层处理的结果持久化以待后续查询,并维护领域模型中对象的生命周期

将不同的模块化组件聚合后运行在通用的应用服务器上。

典型的二八原则应用场景:将80%通用的与业务无关的逻辑和流程封装在应用服务器的模块化组件里,通过配置的模式提供给应用程序访问,应用程序实现20%的专用逻辑,并通过配置的形式来访问应用服务器提供的模块化组件。

JEE架构下的典型的职能团队划分:UI交互研发团队,后端服务研发团队,DBA团队

1.2 SSH架构

web MVC框架Struts在用户交互UI层进一步划分了前端的职责,将用户交互层划分为视图,模型和控制器。

后来,Spring发布,作为逻辑层实现的核心容器,使用简单方便灵活核心思想:IOC 和 AOP

  • IOC: 控制反转
  • AOP:面向切面编程 – AspectJ 是实现AOP的专业框架和平台
    • AOP 实现方式1 :对字节码进行重新编译,将切面插入字节码的某些点和面上,可以使用cglib库实现
    • AOP实现方式2:定制类加载器,在类加载时对字节码进行补充
    • AOP实现方式3:JVM本身提供了动态代理组件,通过它实现任意对象的代理模式

SSH架构:

  • 实现交互ui接口的web mvc层
  • 实现业务逻辑的spring层
  • 实现对象关系映射的hibernate层

最终打包到一个JEE规范的War包里,并部署在tomcat容器中,整个结构还是趋于传统的单体架构,业务逻辑仍然耦合在一个项目中。

职能团队:前端团队,后端业务逻辑研发团队,DBA团队

1.3 服务化架构

互联网异军突起的环境下,传统的JEE和SSH无法满足海量用户发起的高并发请求进行处理的需求,无法突破耦合在一起的模块化组件的性能瓶颈,单一进程已经无法满足需求,并且水平扩展的能力也是很有限的。

SOA面向服务的架构(服务化),将应用程序的模块化组件通过定义明确的接口和契约联系起来,接口是采用重力的方式进行定义的。独立于某种语言、硬件和操作系统,通常通过网络通信来完成,但不局限于某种网络协议,可以是底层的TCP/IP, 也可以是应用层的HTTP,也可以是消息队列协议,甚至可以是某种数据库存储形式。

架构特点

  • SOA定义了良好的对外接口,通过网络协议对外提供服务,松耦合性
  • 每个服务的内部结构和实现在发生改变时,不影响整个流程对外提供服务,只要对外提供的接口保持不变
  • SOA在这一时代的数据通信格式通常为XML,后来被JSON取代
  • SOA通过定义标准的对外接口,让底层通用服务进行下沉,供多个上层的使用方同时使用,增加服务的可重用性。
  • SOA可以让企业最大化地使用内部和外部的公共服务,避免重复造轮子。

SOA两个主流实现方式

(1)Web Service

使得运行在不同的机器及操作系统上的服务的互相发现和调用成为可能,并且可以通过某种协议交换数据。

每个服务对等的,互相解耦。
在这里插入图片描述

工作原理

  • 服务提供者web service2 和web service 3 通过UDDI协议将服务注册到web service 目录中
  • 服务消费者web service1通过UDDI 协议从web service 目录中查询服务,并获得服务的WSDL服务描述文件
  • 服务消费者web service 1 通过WSDL语言远程调用和消费 web service 2 和3提供的服务

(2)ESB企业服务总线

用于设计和实现网络化服务交互和通信的软件模型。

适用于事件处理, 数据转换和映射,消息和事件异步队列顺序处理,完全和异常处理,协议转换和保证通信服务的质量等场景。

特点:ESB服务没有中心化的服务节点,每个服务提供者都是通过总线的模式插入系统,总线根据流程的编排负责将服务的输出进行转换并发送给流程要求的下一个服务进行处理。

在这里插入图片描述

ESB核心在于企业服务总线的功能和职责:

  • 监控和控制服务之间的消息路由
  • 控制可插拔的服务化的功能和版本
  • 解析服务之间交互和通信的内容和格式
  • 通过组合服务、资源和消息处理器来统一编排业务需要的信息处理流程
  • 使用冗余来提供服务的备份能力

2.从服务化到微服务

2.1微服务架构的产生

web service问题

  • 依赖中心化的服务发现机制
  • 使用SOAP通信协议,通常使用XML格式来序列化通信数据,XML格式的数据冗余太大,协议太重
  • 服务化管理和治理设施并不完善

ESB问题

  • 系统内部复杂
  • 过重的整体服务
  • 系统变更影响范围经常会随之扩大

微服务(松耦合,高内聚,不再强调服务总线和通信机制的多样性)倡导将软件应用设计成多个独立开发、可配置、可运行和可维护的子服务,子服务之间通过良好的接口定义通信机制,通常使用restful 风格的api形式来通信(通常在http或https通道上传输JSON格式的数据来实现)

微服务真正的目的是通过对微服务进行水平扩展解决传统的单体应用在在业务急剧增长时遇到的问题。

2.2 微服务架构与传统单体架构的对比

微服务架构

在这里插入图片描述

  • 每个的职责单一的功能放在一个独立的服务中
  • 每个服务运行在一个单独的进程中
  • 每个服务有多个实例在运行,每个实例可以运行在容器化平台内,达到平滑伸缩的效果
  • 每个服务有自己的数据存储
  • 每个服务有自己的运营平台,以及独享的运营人员,每个服务高度自治,内部变化对外透明
  • 每个服务都可根据性能需求独立低进行水平伸缩

传统单体架构

在这里插入图片描述

特点

  • 所有模块化组件混合后运行在同一个服务JVM进程中
  • 无法对某个模块化组件进行水平扩展
  • 某个模块化组件发生变化时,需要所有的模块化组件进行编译打包和上线
  • 模块间依赖不清晰,互相耦合,互相依赖
2.3 微服务架构与SOA服务化的对比

微服务在SOA服务化的基础上进行了演进和叠加,形成了适合现代化应用场景的一个方法论。

不同点SOA微服务
目的不同强调不同异构服务之间的协作和契约,强调有效集成、业务流程编排、历史应用集成等一系列微小的服务来实现整体的业务流程,目的是有效拆分应用,实现敏捷开发和部署
部署方式不同将多个业务服务通过组件化模块打包在一个war包里,然后统一部署在一个应用服务器上将完整的应用拆分成多个细小的服务,通常使用敏捷扩容、缩容的Docker技术实现自动化容器管理
服务粒度不同没有要求倡导将服务拆分成更细的粒度,通过多个服务组合来实现业务流程的处理,拆分到职责单一,甚至小到不能再进行拆分

3.微服务架构的核心要点和实现原理

3.1微服务架构中职能团队的划分

康威定律:团队的交流机制应该与架构设计机制相对应。

微服务架构按照业务的功能进行划分,每个单一的业务功能叫做一个服务,每个服务对应一个独立的职能团队,团队包含用户交互UI设计师,后台服务开发人员,DBA,运营和运维人员

传统整体架构需要跨服务沟通,微服务内部沟通,提供沟通效率。

3.2微服务的去中心化治理

案例:所有外部服务和内部服务都由统一的API网关进行管理,初期,中心化的API网关统一了所有API的入口,看起来很规范,从技术角度来看限制了API的多样化,随着业务发展,每个用户请求经过机房时只要有服务之间的交互,则都会从API网关进行路由,服务上量以后,由于内部服务之间的交互都会叠加在API网关的调用上,所以在很大程度上放大了API网关的调用TPS(每秒处理的事务数目。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程),API网关很快就遇到了性能瓶颈. ---------典型的微服务的反模式,微服务倡导去中心化治理

eg:第一层SOA服务化采用Dubbo框架进行定制化,如果Dubbo服务化出现了大面积的崩溃,则服务化体系会切换到点对点的hessian远程调用–服务化降级,降级后点对点的 hessian远程调用时没有中心化节点,整体符合微服务的原理。

3.3微服务的交互模式
(1)读者容错模式(Tolerant Reader)

微服务化中服务提供者和消费者之间如何对接口的改变进行容错。 消费者需要对提供的功能进行兼容性设计,尤其对服务提供者返回的内容进行兼备,或者解决在服务提供者改变接口或者数据的格式情况下,如何让服务消费者正常运行。

(2)消费者驱动契约模式

用来定义服务化中服务之间交互接口改变的最佳规则。

服务契约:三种契约同时存在

  • 提供者契约:以提供者为中心
  • 消费者契约:是对某个消费者的需求进行更为精确的描述
  • 消费者驱动的契约:代表服务提供者向其所有当前消费者承诺遵守的约束

:支付平台中,交易系统在完成一笔支付后,需要到财务系统为商户入账。

  • 生产者契约:财务系统提供dubbo服务化接口,参数为:商户账号ID,入账订单号和入账金额
  • 消费者契约:财务系统返回DTO,包含商户账号ID,入账订单号,入账金额,入账时间,财务流水号,入账状态等,而交易系统只需要使用其中的入账订单号和入账状态。
  • 消费者驱动的契约:为保证资金安全,交易系统作为入账的发起者向账户提出要求,需要账务做幂等和滤重处理,对重复的入账请求进行拦截。财务系统在接受这个契约后,即使将来有任何改变,也不能打破这个限制,否则会造成资金的损失,这在金融系统中是最严重的。

服务提供者契约是服务提供者单方面定下的规则

消费者契约会成为提供者契约的一部分

消费者驱动的契约多个服务消费者可以对服务提供者提出约束,服务提供者需要在将来遵守服务消费者提出的契约

(3)去数据共享模式

微服务之间的交互通过定义良好的接口来实现,不允许使用共享数据来实现

eg:有些方案设计使用缓存或者数据库作为两个微服务之间的纽带,在业务处理过程中为了处理简单,前一个服务将中间结果存入数据库或者缓存,下一个服务从缓存或者数据库中拿出数据继续处理。

缺点:

  • 使得微服务之间的交互除了接口契约,还存在数据存储契约
  • 上游的数据格式发生变化,可能导致下游的处理逻辑出现问题
  • 多个服务共享一个资源服务,对资源服务的运维难以划清职责和界限
  • 双机房独立部署时,需考虑服务和资源的路由情况,跨机房的服务调用不能使用独立的资源部署模式,难以实现服务自治
3.4微服务的分解和组合模式
(1)服务代理模式

根据业务的需求选择调用后端的某个服务,返回给使用端前,代理可以对后端服务的输出进行加工,也可以直接把后端服务的返回结果返回给使用端。

在这里插入图片描述

典型案例:平滑的系统迁移

在新老系统上双写 —> 迁移双写之前的历史遗留数据 —> 将读写请求切换到新系统 —> 下调双写逻辑,只写新系统

逻辑图:

(2)服务聚合模式

根据业务流程处理的需要,以一定的顺序调用依赖的多个服务,对依赖的微服务返回的数据进行组合、加工和转换,最后以一定的形式返回给使用方。

每个依赖的微服务都有自己的缓存和数据库,聚合服务本身可以有自己的数据存储,也可以是简单的耦合

架构:

在这里插入图片描述

DRY原则: 将三个独立的逻辑块封装成三个独立运行的微服务,然后使用服务聚合模式开发聚合服务,将三个独立的逻辑块聚合在一起提供给上层组合服务

好处

  • 三个独立的子服务可以各自独立开发、敏捷变更和部署
  • 聚合服务封装下层的业务处理服务,由三个独立的子服务完成数据持久化等工作
  • 三个独立的子服务对于其他使用方仍然可以重用

eg:电商平台应前端应用就是后端各个微服务的一个最大的聚合服务

​ 例如电商前台------显示商品-----> 商品服务

​ -------选择商品------> 购物车服务

​ ----------结算----------> 交易服务

​ 也可以是个纯后端服务

​ 例如交易服务----------锁定库存或扣减库存-----> 库存服务

​ ------------------去支付---------------> 支付服务

​ ------------------开发票---------------> 发票服务

(3)服务串联模式

类似一个工作流,调用使用同步的RESTful风格的远程调用实现,同步调用,串联服务没有完成并返回前,所有服务阻塞等待。

优势:串联链路上在增加一个节点时,只要不是在串联服务的正后面增加,那么串联服务是无感知的。

eg:UI应用 -----购买-----> 交易服务 -----扣减库存----> 库存服务

(4)服务分支模式

是服务代理模式、服务聚合模式和服务串联模式相结合的产物。

分支服务可以拥有自己的数据库存储

在这里插入图片描述

eg: 支付服务 ------> 支付渠道1 -----> 渠道网关

​ -------> 支付渠道2 -----> 渠道网关

​ --------> 账户支付 ------> 账户服务

支付服务对接两个外部支付网关,都要经过各自的支付渠道网关,同时支持账户余额支付,这个支付服务就是一个分支模式,

(5)服务异步消息模式

梳理核心系统的最小化服务集合,这些核心系统服务使用同步调用,其他核心链路以外的服务可以使用异步消息队列进行异步化

在这里插入图片描述

eg:电商前端 ------> 购物车服务

​ ------> 交易服务 —> 消息队列 ------> 物流服务

(6)服务共享数据模式

由于去掉了数据共享,所以仅仅通过服务之间良好定义的接口进行交互和通信,使得每个服务都是自治的。

在这里插入图片描述

下面两种情况下仍需要数据共享模式

  • 单元化架构

  • 遗留的整体服务

3.5微服务的容错模式

一个服务依赖的服务可能出错,超时或者宕机,如果没有及时发现和隔离问题,或者在设计中没有考虑如何应对这样的问题,很可能在短时间内服务的线程池中的线程被用满,资源耗尽,导致出现雪崩效应。

1.舱壁隔离模式

若一所航船遇到意外,其中一个船舱进了水,希望这个船舱和其他船舱隔离,其他的船舱可以不进水,不受影响。

(1)微服务容器分组

案例1:微服务的每个节点的服务池分为三组:

  • 准生产环境:内侧使用
  • 灰度环境:普通商户的流量
  • 生产环境:大流量和vip商户

案例2:

一些社交平台将名人的自媒体流量全部路由到服务的核心池子中

将普通用户的流量路由到另外一个服务池子中,有效隔离了普通用户和重要用户的负载

(2)线程池隔离

多个功能混合部署在一个微服务实例中,这些微服务的不同功能通常使用同一个线程池,导致一个功能流量增加时耗尽线程池的线程,而阻塞其他功能的服务。

2.熔断模式

当输入负载迅速增加时,如果没有有效的措施对负载进行熔断,会导致服务迅速被压垮,服务被压垮会导致依赖的服务都被压垮,出现雪崩效应,模拟家庭电路保险开关,微服务实现熔断模式。

在这里插入图片描述

3.限流模式

针对服务突然上量,需要限流机制,限流机制一般会控制访问的并发量,例如每秒允许处理的并发用户数及查询量、请求量。

(1)计数器

通过原子变量单位时间内的访问次数,如果超出某个阈值,则拒绝后续的请求,等到下一个单位时间再重新计数。

实现方法:循环数组。

例如:定义五个元素的环形数组,计数周期为1s,可以记录4s内的访问量,其中1个元素为当前时间点的标志,通常来说每秒程序都会将前面3秒的访问量打印到日志,供统计分析。

将时间除以数组元素的个数5,然后取模,映射到环形数组里的数据元素。

(2)令牌筒

通过一个线程在单位时间内生产固定数量的令牌,然后把令牌放入队列,每次请求调用需要从桶中拿取一个令牌,拿到令牌后才有资格执行请求调用,否则只能等待拿到令牌再执行,或者直接丢弃。

(3)信号量
package com.example.demo.web;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample {

    private static ExecutorService exec = Executors.newCachedThreadPool();

    public static void main(String[] args) {

        final Semaphore sem = new Semaphore(5);
        for (int i = 0; i < 20; i++) {

            Runnable run = new Runnable() {
                @Override
                public void run() {
                    try{

                        //获得许可
                        sem.acquire();
                        //同时只有5个请求可以到达这里
                        Thread.sleep((long) (Math.random()));
                        //释放许可
                        sem.release();
                        System.out.println("剩余许可:" + sem.availablePermits());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            exec.execute(run);
        }
        exec.shutdown();
    }
}

4.失效转移模式

微服务发生熔断和限流,解决方法:失效转移模式

  • 快速失败,直接返回使用方错误
  • 是否有备份服务,有,迅速切换到备份服务
  • 可能是某台服务的问题,eg,OOM,这种情况适合使用failover策略,采用重试的方法解决,但这种方法要求服务提供者的服务实现幂等性。
3.6微服务的粒度

拆分到可以让使用方自由地编排底层子服务来获得相应的组合服务即可,同时考虑团队的建设及人员的数量和分配等。

4.Java平台微服务架构的项目组织形式

4.1微服务项目的依赖关系

微服务领域,Jar包被分为一方库,二方库,三分库

  • 一方库:本服务在JVM进程内依赖的Jar包
  • 二方库:在服务外通过网络通信或者RPC调用的服务的Jar包
  • 三方库:所依赖的其他公司或者组织提供的服务或者模块
4.2微服务项目的层级结构

一般分为:服务导出层,接口层和逻辑实现层

  • 服务导出层(War):web.xml , spring环境
  • 服务接口层(Jar):业务接口、DTO、枚举类
  • 服务实现层(Jar):业务实现类,外部服务包装类,DAO

本地服务层通过数据库DAO层与数据库进行交互,这里使用了数据库事务,保证了数据存取的一致性

业务流程层通过组合本地服务和外部服务来完成业务逻辑的实现。

4.3微服务项目的持续发布

微服务项目需要实现自动化的持续部署和持续集成的功能:代码管理,自动编译,发布QA,自动化测试,性能测试,准生产部署和测试、生产环境发布等。

5.服务化管理和治理框架的技术选型

5.1RPC
  • JDK RMI:使用jdk内置的序列化和反序列化协议。 没有得到广泛的应用,不能跨语言;底层网络协议;开源框架的飞速发展。
  • Hessian 及 Buriap:基于http传输,与语言无关,适合传输较小的对象,
  • Spring HTTP Invoker:调用了jdk内置对象序列化技术传输对象,与RMI原理一致,通过http通道传输,效率低于RMI,不能跨语言。
5.2服务化
  • Dubbo:hessian序列化的数据,使用zookeeper作为注册中心注册和发现服务,通过客户端负载均衡来路由请求。
  • HSF:高性能网络通信,淘宝内部大规模使用,性能比dubbo高,但与业务系统耦合重。
  • Thrift:facebook实现的高性能支持多语言远程服务调用框架。传输数据采用二进制序列化格式
  • AXIS:
  • Mule ESB:可以把多个复杂的异构系统通过总线模式集成在一起,并让他们之间可以互相通信

5.3微服务

  • Spring Boot:应用可随时随地启动和运行,将容器嵌入自启动的Jar包中,内部启动嵌入的容器,通过内嵌的服务器将应用中提供的服务暴露。
  • Netflix:主要提供服务发现,断路器和监控,智能路由、客户端和负载均衡、易用的REST客户端等服务化必需的功能。
  • Spring Cloud Netflix:集成了spring boot对微服务敏捷启动和发布的功能,以及netflix提供的微服务化管理和治理的能力。包括服务发现组件eureka,容错性组件hystrix,智能路由组件zuul和客户端负载均衡组件ribbon。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值