Java平台企业版简称
JEE架构:
web容器 —综合业务逻辑 --> EJB容器 — 数据存取ORM --> 数据库
将不同的模块化组件聚合后运行在通用的应用服务器上。
典型的二八原则应用场景:将80%通用的与业务无关的逻辑和流程封装在应用服务器的模块化组件里,通过配置的模式提供给应用程序访问,应用程序实现20%的专用逻辑,并通过配置的形式来访问应用服务器提供的模块化组件。
JEE架构下的典型的职能团队划分:UI交互研发团队,后端服务研发团队,DBA团队
web MVC框架Struts在用户交互UI层进一步划分了前端的职责,将用户交互层划分为视图,模型和控制器。
后来,Spring发布,作为逻辑层实现的核心容器,使用简单方便灵活核心思想:IOC 和 AOP
SSH架构:
最终打包到一个JEE规范的War包里,并部署在tomcat容器中,整个结构还是趋于传统的单体架构,业务逻辑仍然耦合在一个项目中。
职能团队:前端团队,后端业务逻辑研发团队,DBA团队
互联网异军突起的环境下,传统的JEE和SSH无法满足海量用户发起的高并发请求进行处理的需求,无法突破耦合在一起的模块化组件的性能瓶颈,单一进程已经无法满足需求,并且水平扩展的能力也是很有限的。
SOA面向服务的架构(服务化),将应用程序的模块化组件通过定义明确的接口和契约联系起来,接口是采用重力的方式进行定义的。独立于某种语言、硬件和操作系统,通常通过网络通信来完成,但不局限于某种网络协议,可以是底层的TCP/IP, 也可以是应用层的HTTP,也可以是消息队列协议,甚至可以是某种数据库存储形式。
架构特点
SOA两个主流实现方式
(1)Web Service
使得运行在不同的机器及操作系统上的服务的互相发现和调用成为可能,并且可以通过某种协议交换数据。
工作原理
(2)ESB企业服务总线
用于设计和实现网络化服务交互和通信的软件模型。
适用于事件处理, 数据转换和映射,消息和事件异步队列顺序处理,完全和异常处理,协议转换和保证通信服务的质量等场景。
特点:ESB服务没有中心化的服务节点,每个服务提供者都是通过总线的模式插入系统,总线根据流程的编排负责将服务的输出进行转换并发送给流程要求的下一个服务进行处理。
ESB核心在于企业服务总线的功能和职责:
web service问题
ESB问题
微服务(松耦合,高内聚,不再强调服务总线和通信机制的多样性)倡导将软件应用设计成多个独立开发、可配置、可运行和可维护的子服务,子服务之间通过良好的接口定义通信机制,通常使用restful 风格的api形式来通信(通常在http或https通道上传输JSON格式的数据来实现)
微服务真正的目的是通过对微服务进行水平扩展解决传统的单体应用在在业务急剧增长时遇到的问题。
微服务架构
传统单体架构
特点
微服务在SOA服务化的基础上进行了演进和叠加,形成了适合现代化应用场景的一个方法论。
不同点 | SOA | 微服务 |
---|---|---|
目的不同 | 强调不同异构服务之间的协作和契约,强调有效集成、业务流程编排、历史应用集成等 | 一系列微小的服务来实现整体的业务流程,目的是有效拆分应用,实现敏捷开发和部署 |
部署方式不同 | 将多个业务服务通过组件化模块打包在一个war包里,然后统一部署在一个应用服务器上 | 将完整的应用拆分成多个细小的服务,通常使用敏捷扩容、缩容的Docker技术实现自动化容器管理 |
服务粒度不同 | 没有要求 | 倡导将服务拆分成更细的粒度,通过多个服务组合来实现业务流程的处理,拆分到职责单一,甚至小到不能再进行拆分 |
康威定律:团队的交流机制应该与架构设计机制相对应。
微服务架构按照业务的功能进行划分,每个单一的业务功能叫做一个服务,每个服务对应一个独立的职能团队,团队包含用户交互UI设计师,后台服务开发人员,DBA,运营和运维人员
传统整体架构需要跨服务沟通,微服务内部沟通,提供沟通效率。
案例:所有外部服务和内部服务都由统一的API网关进行管理,初期,中心化的API网关统一了所有API的入口,看起来很规范,从技术角度来看限制了API的多样化,随着业务发展,每个用户请求经过机房时只要有服务之间的交互,则都会从API网关进行路由,服务上量以后,由于内部服务之间的交互都会叠加在API网关的调用上,所以在很大程度上放大了API网关的调用TPS(每秒处理的事务数目。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程),API网关很快就遇到了性能瓶颈. ---------典型的微服务的反模式,微服务倡导去中心化治理
eg:第一层SOA服务化采用Dubbo框架进行定制化,如果Dubbo服务化出现了大面积的崩溃,则服务化体系会切换到点对点的hessian远程调用–服务化降级,降级后点对点的 hessian远程调用时没有中心化节点,整体符合微服务的原理。
微服务化中服务提供者和消费者之间如何对接口的改变进行容错。 消费者需要对提供的功能进行兼容性设计,尤其对服务提供者返回的内容进行兼备,或者解决在服务提供者改变接口或者数据的格式情况下,如何让服务消费者正常运行。
用来定义服务化中服务之间交互接口改变的最佳规则。
服务契约:三种契约同时存在
例:支付平台中,交易系统在完成一笔支付后,需要到财务系统为商户入账。
服务提供者契约是服务提供者单方面定下的规则
消费者契约会成为提供者契约的一部分
消费者驱动的契约多个服务消费者可以对服务提供者提出约束,服务提供者需要在将来遵守服务消费者提出的契约
微服务之间的交互通过定义良好的接口来实现,不允许使用共享数据来实现
eg:有些方案设计使用缓存或者数据库作为两个微服务之间的纽带,在业务处理过程中为了处理简单,前一个服务将中间结果存入数据库或者缓存,下一个服务从缓存或者数据库中拿出数据继续处理。
缺点:
根据业务的需求选择调用后端的某个服务,返回给使用端前,代理可以对后端服务的输出进行加工,也可以直接把后端服务的返回结果返回给使用端。
典型案例:平滑的系统迁移
在新老系统上双写 —> 迁移双写之前的历史遗留数据 —> 将读写请求切换到新系统 —> 下调双写逻辑,只写新系统
逻辑图:
根据业务流程处理的需要,以一定的顺序调用依赖的多个服务,对依赖的微服务返回的数据进行组合、加工和转换,最后以一定的形式返回给使用方。
每个依赖的微服务都有自己的缓存和数据库,聚合服务本身可以有自己的数据存储,也可以是简单的耦合
架构:
DRY原则: 将三个独立的逻辑块封装成三个独立运行的微服务,然后使用服务聚合模式开发聚合服务,将三个独立的逻辑块聚合在一起提供给上层组合服务
好处
eg:电商平台应前端应用就是后端各个微服务的一个最大的聚合服务
例如电商前台------显示商品-----> 商品服务
-------选择商品------> 购物车服务
----------结算----------> 交易服务
也可以是个纯后端服务
例如交易服务----------锁定库存或扣减库存-----> 库存服务
------------------去支付---------------> 支付服务
------------------开发票---------------> 发票服务
类似一个工作流,调用使用同步的RESTful风格的远程调用实现,同步调用,串联服务没有完成并返回前,所有服务阻塞等待。
优势:串联链路上在增加一个节点时,只要不是在串联服务的正后面增加,那么串联服务是无感知的。
eg:UI应用 -----购买-----> 交易服务 -----扣减库存----> 库存服务
是服务代理模式、服务聚合模式和服务串联模式相结合的产物。
分支服务可以拥有自己的数据库存储
eg: 支付服务 ------> 支付渠道1 -----> 渠道网关
-------> 支付渠道2 -----> 渠道网关
--------> 账户支付 ------> 账户服务
支付服务对接两个外部支付网关,都要经过各自的支付渠道网关,同时支持账户余额支付,这个支付服务就是一个分支模式,
梳理核心系统的最小化服务集合,这些核心系统服务使用同步调用,其他核心链路以外的服务可以使用异步消息队列进行异步化
eg:电商前端 ------> 购物车服务
------> 交易服务 —> 消息队列 ------> 物流服务
由于去掉了数据共享,所以仅仅通过服务之间良好定义的接口进行交互和通信,使得每个服务都是自治的。
下面两种情况下仍需要数据共享模式
单元化架构
遗留的整体服务
一个服务依赖的服务可能出错,超时或者宕机,如果没有及时发现和隔离问题,或者在设计中没有考虑如何应对这样的问题,很可能在短时间内服务的线程池中的线程被用满,资源耗尽,导致出现雪崩效应。
若一所航船遇到意外,其中一个船舱进了水,希望这个船舱和其他船舱隔离,其他的船舱可以不进水,不受影响。
案例1:微服务的每个节点的服务池分为三组:
案例2:
一些社交平台将名人的自媒体流量全部路由到服务的核心池子中
将普通用户的流量路由到另外一个服务池子中,有效隔离了普通用户和重要用户的负载
多个功能混合部署在一个微服务实例中,这些微服务的不同功能通常使用同一个线程池,导致一个功能流量增加时耗尽线程池的线程,而阻塞其他功能的服务。
当输入负载迅速增加时,如果没有有效的措施对负载进行熔断,会导致服务迅速被压垮,服务被压垮会导致依赖的服务都被压垮,出现雪崩效应,模拟家庭电路保险开关,微服务实现熔断模式。
针对服务突然上量,需要限流机制,限流机制一般会控制访问的并发量,例如每秒允许处理的并发用户数及查询量、请求量。
通过原子变量单位时间内的访问次数,如果超出某个阈值,则拒绝后续的请求,等到下一个单位时间再重新计数。
实现方法:循环数组。
例如:定义五个元素的环形数组,计数周期为1s,可以记录4s内的访问量,其中1个元素为当前时间点的标志,通常来说每秒程序都会将前面3秒的访问量打印到日志,供统计分析。
将时间除以数组元素的个数5,然后取模,映射到环形数组里的数据元素。
通过一个线程在单位时间内生产固定数量的令牌,然后把令牌放入队列,每次请求调用需要从桶中拿取一个令牌,拿到令牌后才有资格执行请求调用,否则只能等待拿到令牌再执行,或者直接丢弃。
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();
}
}
微服务发生熔断和限流,解决方法:失效转移模式
拆分到可以让使用方自由地编排底层子服务来获得相应的组合服务即可,同时考虑团队的建设及人员的数量和分配等。
微服务领域,Jar包被分为一方库,二方库,三分库
一般分为:服务导出层,接口层和逻辑实现层
本地服务层通过数据库DAO层与数据库进行交互,这里使用了数据库事务,保证了数据存取的一致性
业务流程层通过组合本地服务和外部服务来完成业务逻辑的实现。
微服务项目需要实现自动化的持续部署和持续集成的功能:代码管理,自动编译,发布QA,自动化测试,性能测试,准生产部署和测试、生产环境发布等。
5.3微服务