和老婆分床两晚上才整理出来的架构师架构设计理论 | 快速入手手册 | 个人总结

31 阅读13分钟

为什么要分层

每一层去解决每一层的问题,对应不同的职责。

在这里插入图片描述

基于领域模型的分层设计更难一些。

分层模型的演进

分层模型V1.0时代-Servlet JSP 时代

在这里插入图片描述

  • Servlet+Tomcat容器完成Web接入
  • 使用JavaBean+JDBC完成数据的接入
  • 使用JSP完成页面展示

劣势

V1.0这种分层模型有弊端,那就是做不到前后端分离,在web处理上只要doget\dopost。

分层模型V1.0时代-MVC分层设计

在这里插入图片描述

基于mvc的分层设计,出现了很多分层框架,比如ssh、mvc......

SSH框架

SSH就是由三个组件

我们至始到终是针对一个模型的业务对象去做的。把它从业务模型对象转换成数据模型。而这个业务模型对象的逻辑处理,封装都在业务逻辑层做相应的处理。

在这里插入图片描述

  • 表示层:web的接入
  • 业务逻辑层:web中的请求流转到业务逻辑层通过Spring去做一些处理
  • 数据持久层:做业务逻辑的时候一旦需要数据持久化的时候,就通过数据持久层的Hibernate数据源获取数据,把一个领域模型转换成数据模型。

劣势

  • Hibernate 自动生成 SQL 语句,这简化了开发,但开发者失去了对 SQL 的直接控制权。当需要进行复杂查询优化或使用数据库特定功能(如存储过程、高级索引)时,Hibernate 可能生成效率不高的 SQL,难以进行深度调优。
  • 对于大量的数据更新、插入或删除操作,Hibernate 的缓存机制和对象状态管理会消耗大量内存,并且缺乏高效的批处理支持,性能通常不如直接使用 JDBC 或 MyBatis
  • 表示层还在使用jsp,仍然做不到前后端分离

这些劣势在一定程度上催生了以 Spring、Spring MVC 和 MyBatis 为核心的 SSM 框架组合的流行.

SSM框架

在这里插入图片描述

  • SpringMvc取代Struts,更好的做前后端分离,前端的url请求可以更好的通过get\post协议解析到后端具体的Controller方法中去
  • Mybatis通过xml配置文件实现了半自动化sql,取代了Hibernate。
  • Spring强大到增加了配置注解、数据源、声明式事务处理

分层模型2.0时代-SpringBoot all in one

在这里插入图片描述

在这里插入图片描述

弊端

  • 解决了单一应用内的软件分层,却没有解决整体应用的分层
  • 单一应用性能瓶颈,无法支撑亿级流量
  • 团队协作问题

针对2.0时代的弊端,我们引入了分布式分层V3.0

分层模型V3.0时代-分布式分层

在这里插入图片描述

  • 水平扩展:一台服务器上跑了以一个应用,我现在扩展服务器节点,我整体系统性能会上去,应用不被影响。当某层成为瓶颈时,通过增加该层的机器数量(水平扩展)来提升其处理能力。
  • 负载均衡:其实就是nginx处理请求,平均分发到每台服务器上去。
  • 高可用:服务器挂几个应用仍然不受影响,仍然能运行。
  • 数据一致性:你架构从单体变到分布式的时候,数据也要不被影响。

亿级流量平台分层架构

在分布式架构下,利用好分层模型演进过程中的一些思想去构造一个亿级流量平台。

单一应用的分层架构我们讲到了MVC分层设计,我们可以用这个思想去解决分布式应用中的架构设计问题。

在这里插入图片描述

分布式分层--WEB概念层

在这里插入图片描述

分布式分层--业务概念层

业务架构师通常专注在业务服务模块的划分工作。

在这里插入图片描述

分布式分层--数据访问及存储层

在这里插入图片描述

分布式分层的这种理念与思想,归根结底是为了让:我们的应用能够跑在廉价的硬件设备上

在这里插入图片描述

访问层架构设计-lvs接入系统

在这里插入图片描述

LVS的三种不同模式

  • LVS/NAT

    • 这种模式有LVS性能瓶颈!
  • LVS-DR(企业级用的最多的一种模式)

    在这里插入图片描述

    ​ 后端服务集群在响应的时候没有LVS的概念,直接发给了客户端app。这样做就可以免去LVS系统接入的性能损耗。

  • LVS/TUN

    在这里插入图片描述

    ​ 这种模式就是把客户端的源ip也打包起来,到了后端服务器集群进行二次解析。

在这里插入图片描述

移动端的请求会先去DNS寻址,找到公网ip。通过公网ip找到LVS接入系统,从而将不同请求分发到机房的不同服务器上的不同Tomcat服务集群。请求到了Tomcat做了后端的逻辑处理,响应又会返回到LVS,返回到移动端。

访问层架构设计Nginx

职责分类:

  • 接入层Nginx
    • 职责(做的工作和业务无关)
      • 请求解析
      • 请求业务路由
      • 业务负载均衡
      • 响应压缩
  • 应用层Nginx
    • 职责(做的工作和业务有关)
      • 应用负载均衡
      • 缓存调度
      • 授权认证
      • 业务逻辑
      • 业务限流
      • 业务降级

Nginx 功能

在这里插入图片描述

在这里插入图片描述

反向代理

反向代理后端服务器集群

在这里插入图片描述

当我访问localhost:7777/static/index.html的时候,它会自动轮询访问localhost:8088/static/index.html和localhost:8099/static/index.html两个页面。

动静分离

在现代化软件开发中,大部分分都采用动静分离。动态资源通过代理到后端服务访问,静态资源放在CDN上,请求访问resource路径的时候就去CDN指定url访问。

在这里插入图片描述

缓存节点

我们可以通过nginx把经常访问的页面缓存起来,下次访问的时候就不用到后端来请求资源了。我们可以设置一个缓存期效给用户使用。

在这里插入图片描述

在这里插入图片描述

API网关层设计

分布式会话管理(网关层最重要的一个东西)

虽然我们在用同一个浏览器上网,上同一个网站,但连接的是不同的http请求,每一次都是独立的新的Http请求,这是因为Http请求具有无状态性。因此引入了session会话管理机制,记住用户每一次的登录状态,下次保留登录信息,保存会话状态。

分布式会话管理

区别于传统的依赖web server session的会话管理状态,需要引入集中的会话存储器,用于鉴别分布式状态下的BS端之间的会话标识。

会话管理的几种方式

在这里插入图片描述

  • cookie并非安全,被劫持概率高

  • token在现在前后端分离架构中用的比较多,凭证也会被劫持,伪造请求

  • Https请求防泄漏(这个最安全 )

  • 风控主动失效以及过期机制

  • Session会话管理一般都放在Redis里或者数据库里

接入层控制

QS:接入层为什么需要控制?控制的是什么呢?

通过API网关接入层控制程序入口处需要实现的逻辑,包括:

  • 身份验证
    • 通过会话管理获取登录用户凭证
    • 通过用户凭证获取到用户身份信息
    • 验证对应URL是否被对应身份的用户访问
  • 流量控制
    • 对应的URL的流量是否可以承载,若不能,限流
    • 对应服务分级的流量是否可以承载,若不能,限流。
    • 对应整个系统的总流量是否可以承载,若不能,限流。
  • 路由服务、
    • 根据对应的url的规则找到响应服务
    • 判定服务状态,做服务路由调用
  • 记录调试
    • 切面打印日志调试信息
    • 切面打印cat监控
  • 统计信息

服务调用及聚合

API网关通过了接入层控制并路由后进入核心的服务调用环节,通过对后端服务的调用并聚合服务输出的数据返回访问层。

分类:

  • 重接入:SpringMvc+dubbo
  • 轻接入:SpringCloud Zuul

在这里插入图片描述

之所以说这是重接入,是因为service层的逻辑代码都会聚合到Controller层返回,。一次请求,所有结果都聚合在Controller层返回。

在这里插入图片描述

在这里插入图片描述

轻接入其实就是用网关把请求路由出去,不管业务处理、不管聚合。

在这里插入图片描述

核心服务层设计

核心服务层设计之服务通信

服务&微服务

什么是服务?

传统的服务其实就是基于一个进程、我将我所有的业务逻辑放在一个jar包、一个war包去做一个单进程的部署。我们对这个进程进行简单的垂直拆分会在这个服务里做服务分层:

在这里插入图片描述

传统服务的缺点:

  • 所有服务部署耦合在一起
  • 隔离性弱,互相影响
  • 部署臃肿
  • 开发维护困难

微服务形态

我们把原本的单进程应用拆分成了多个服务应用:

在这里插入图片描述

把一个大的jar包根据业务领域的不同拆分成多个jar包,部署到多个服务器。【其实就是以业务为边界进行拆分

微服务优点

  • 服务高内聚低耦合
  • 隔离性强,不会互相影响
  • 单独部署
  • 独立开发

微服务要解决的问题

  • 服务治理
    • 服务调用通信
    • 健康管理
    • 限流熔断
  • 数据一致性
  • 调用性能
  • 研发流程,调试,部署

核心服务层设计之Dubbo服务治理(一)

Dubbo是用来解决微服务内服务治理问题轻量级开源Java RPC框架。

在这里插入图片描述

服务治理的功能

  • 服务提供者注册服务
  • 服务消费者获取服务,并通过负载均衡策略选择服务提供者
  • 动态增减服务提供者和服务消费者
  • 服务监控
  • 服务限流
  • 服务降级
  • 高容错
  • 定制化开发

在这里插入图片描述

核心服务层设计之异步化消息服务

消息中间件异步化的好处:

不会阻塞原来的业务
服务调用之间解耦,无需互相关注感知

在这里插入图片描述

商品交易服务无需感知交易服务的逻辑,只需要监听异步消息中间件即可。 商品销量的变化不需要添加在商品交易服务的逻辑里。

消息服务分类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

核心服务层设计之调度、池化

任务调度

应用场景:

  • 业务跑批轮训等待处理
  • 失败异常重试
  • 定时处理任务
实现方式
单机调度方式及实现
  • Timer定时器机制
    • 缺点:不能用于多线程,只能用于单线程
  • ScheduledExecutor
    • 内置了多线程,可以并发执行。
  • Quartz (常用)
    • 任务+调度

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

分布式调度及实现方式

Quartz分布式版本

有很多个机器都分布了这个形态:

在这里插入图片描述

比如有两个Quartz:

在这里插入图片描述

我们现在要做到:

  • 两台机器的时间是同步对称的
  • 代码部署也要对称
  • 需要中间层同步竞争锁(分布式环境下的竞争锁)

在这里插入图片描述

Elastic-Job分布式版本

在这里插入图片描述

池化技术(一)

池化技术是用来减少系统消耗,提升系统性能的。

池化技术分为:

  • 对象池
  • 连接池

在这里插入图片描述

简单的说,池化技术就是通过复用来提升性能。

常用的连接池

在这里插入图片描述

没有线程池的时候,你每次做一件事情的时候都要新创建一个线程,工作模式如下:

在这里插入图片描述

有了线程池的话,主程序就会去申请执行线程池里的线程。被执行的线程就会从idle状态转换为busy状态,被申请的线程就会去执行对应的任务。

在这里插入图片描述

池化技术(二)

Java线程池逻辑

概念

  • 核心线程数大小=最小线程数大小
    • 线程池里初始化状态为idle的线程数量
  • 最大线程数大小
    • 其实就是最多有多少个状态为idle的线程
  • 等待队列长度
    • 当主程序提交任务的时候发现线程池里已经没有状态为idle的线程可用的时候就会进入等待队列
  • 拒绝策略
    • 线程池里的线程数满了,这个时候主程序提交任务就会被拒绝,没有多余的idle线程执行提交过来的任务
  • idle等待时间
    • 如果线程的idle时间过长就会被释放。
总结

Java线程池的策略是:首先使用核心线程数,然后使用等待队列,当非busy的核心线程会去取等待队列里的任务,直到等待队列里的任务被塞满了,这个时候开线程最大线程数。最大线程数达到了就执行拒绝策略,当线程池里的idle线程超时超过了设置的时间的时候就会被释放。

在这里插入图片描述

在这里插入图片描述

核心服务层架构设计之缓存、隔离

缓存技术(一)

设计原则

  • 将数据写入、读取速度更快的存储(设备)
  • 将数据缓存到离应用最近的位置
  • 将数据缓存到离用户最近的位置

缓存分类

在这里插入图片描述

CDN缓存

就是把一些静态资源、页面进行CDN缓存,缓存到CDN服务器上。

反向代理缓存

一般做文件级别的缓存

分布式cache(Redis)

如何缓存

  • 实时写入
  • 异步写入
  • 读取时实时写入
  • 读取时异步写入

在这里插入图片描述

其实上面这种方案容易导致读写不一致的情况,我们可以升级一下:

在这里插入图片描述

但上面这种方案也不是完全可以保证读写一致,在升级:

在这里插入图片描述

缓存必须设置失效时间!

缓存服务器里的一些冷数据不经常访问,需要设置失效时间进行清除!

多级缓存

隔离术

隔离是指将系统或资源分隔开,系统隔离是为了在系统发生内部故障的时候限定传播范围、影响范围,即发生故障不会出现滚雪球效应。从而保证只有出现问题的服务不可用,其他服务可用。

常见隔离维度

在这里插入图片描述

微服务拆分属于进程拆分。

队列术

队列在数据结构中是一种线性表,从一端插入数据,然后从另一端删除数据。

在这里插入图片描述

流量削峰

  • 排队有时候比并发效率更高
  • 排队可以控制并发流量涌入

在这里插入图片描述

数据存储及接入层

什么是数据存储

在这里插入图片描述

数据的分类

在这里插入图片描述

数据存储的分类

在这里插入图片描述

数据存储如何选择

在这里插入图片描述

常用的数据存储中间件

在这里插入图片描述

关系型与非关系型数据库区别

在这里插入图片描述在这里插入图片描述

关系型数据库其实就是把数据模型投射到表上面去,一张张表的关系就是数据模型之间的关系。

代理访问

未来做数据库拆分,垂直拆分,水平拆分的时候要用到数据库代理访问。

常见的被代理对象
  • 后端服务器,如Nginx反向代理
  • 数据库服务器,如Mycat代理
  • 缓存服务器,如Twemproxy代理

监控、限流、降级

监控

为什么要监控?

在这里插入图片描述

通常监控的硬件指标
  • CPU空闲时间
  • 内存占用
  • 等待IO返回时间-越少越好
  • 网络带宽-不要被打满最好
通常监控的软件指标
  • CPU负载
  • 新生代清理次数
  • 新生代GC时间
  • 年老代清理次数
  • 年老代GC时间

限流

在这里插入图片描述

限流的维度

在这里插入图片描述

在这里插入图片描述

限流算法原理
  • 限制并发数

  • 令牌桶算法

  • 漏桶算法

降级

在这里插入图片描述

怎么降级
  • 关闭接口并设置默认返回
  • 降级逻辑