Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客
Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客
Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客
Java核心知识点整理大全4-笔记-CSDN博客
Java核心知识点整理大全5-笔记-CSDN博客
Java核心知识点整理大全6-笔记-CSDN博客
Java核心知识点整理大全7-笔记-CSDN博客
Java核心知识点整理大全8-笔记-CSDN博客
Java核心知识点整理大全9-笔记-CSDN博客
Java核心知识点整理大全10-笔记-CSDN博客
Java核心知识点整理大全11-笔记-CSDN博客
Java核心知识点整理大全12-笔记-CSDN博客
Java核心知识点整理大全13-笔记-CSDN博客
往期快速传送门👆:
目录
6.1.11. JPA 原理
6.1.11.1. 事务
6.1.11.2. 本地事务
6.1.11.1. 分布式事务
6.1.11.1. 两阶段提交
1 准备阶段
2 提交阶段:
6.1.12. Mybatis 缓存
6.1.12.1. Mybatis 的一级缓存原理(sqlsession 级别)
value:用户信息
6.1.12.2. 二级缓存原理(mapper 基本)
1. Mybatis 全局配置中启用二级缓存配置
2. 在对应的 Mapper.xml 中配置 cache 节点
3. 在对应的 select 查询节点中添加 useCache=true
6.1.13. Tomcat 架构
7. 微服务
7.1.1. 服务注册发现
7.1.1.1. 客户端注册(zookeeper)
7.1.1.2. 第三方注册(独立的服务 Registrar)
7.1.1.3. 客户端发现
7.1.1.4. 服务端发现
7.1.1.5. Consul
7.1.1.6. Eureka
7.1.1.7. SmartStack
7.1.1.8. Etcd
7.1.2. API 网关
7.1.2.1. 请求转发
7.1.2.2. 响应合并
7.1.2.3. 协议转换
7.1.2.4. 数据转换
7.1.2.5. 安全认证
7.1.3. 配置中心
7.1.3.1. zookeeper 配置中心
7.1.4. 事件调度(kafka)
7.1.5. 服务跟踪(starter-sleuth)
6.1.11. JPA 原理
6.1.11.1. 事务
事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity )、一致性 ( Consistency )、隔离性 ( Isolation ) 和持久性 ( Durabilily )。
6.1.11.2. 本地事务
紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内。此种事务处理 方式不存在对应用服务器的依赖,因而部署灵活却无法支持多数据源的分布式事务。在数据库连 接中使用本地事务示例如下:
public void transferAccount() {
Connection conn = null;
Statement stmt = null;
try{
conn = getDataSource().getConnection();
// 将自动提交设置为 false,若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交
conn.setAutoCommit(false);
stmt = conn.createStatement();
// 将 A 账户中的金额减少 500
stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
// 提交事务
conn.commit();
// 事务提交:转账的两步操作同时成功
} catch(SQLException sqle){
// 发生异常,回滚在本事务中的操做
conn.rollback();
// 事务回滚:转账的两步操作完全撤销
stmt.close();
conn.close();
}
}
6.1.11.1. 分布式事务
Java 事务编程接口(JTA:Java Transaction API)和 Java 事务服务 (JTS;Java Transaction Service) 为 J2EE 平台提供了分布式事务服务。分布式事务(Distributed Transaction)包括事务 管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器 ( Resource Manager )。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务 参与单元的协调与控制。
public void transferAccount() {
UserTransaction userTx = null;
Connection connA = null; Statement stmtA = null;
Connection connB = null; Statement stmtB = null;
try{
// 获得 Transaction 管理对象
userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction");
connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
userTx.begin(); // 启动事务
stmtA = connA.createStatement();// 将 A 账户中的金额减少 500
stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmtB = connB.createStatement();
stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
userTx.commit();// 提交事务
// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
} catch(SQLException sqle){
// 发生异常,回滚在本事务中的操纵
userTx.rollback();// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销
} catch(Exception ne){ }
}
6.1.11.1. 两阶段提交
两阶段提交主要保证了分布式事务的原子性:即所有结点要么全做要么全不做,所谓的两个阶段 是指:第一阶段:准备阶段;第二阶段:提交阶段。
1 准备阶段
事务协调者(事务管理器)给每个参与者(资源管理器)发送 Prepare 消息,每个参与者要么直接返回 失败(如权限验证失败),要么在本地执行事务,写本地的 redo 和 undo 日志,但不提交,到达一 种“万事俱备,只欠东风”的状态。
2 提交阶段:
如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则, 发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过 程中使用的锁资源。(注意:必须在最后阶段释放锁资源)将提交分成两阶段进行的目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成 所有能完成的工作。
6.1.12. Mybatis 缓存
Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存 是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以 后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。二级缓存 是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的 sqlsession 是可以共享的。
6.1.12.1. Mybatis 的一级缓存原理(sqlsession 级别)
第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一 个 map。 key:MapperID+offset+limit+Sql+所有的入参
value:用户信息
同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作 (修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所 以要从数据库查询,从数据库查询到再写入缓存。
6.1.12.2. 二级缓存原理(mapper 基本)
二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓 存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存 在,不存在则查询数据库。 key:MapperID+offset+limit+Sql+所有的入参。
具体使用需要配置:
1. Mybatis 全局配置中启用二级缓存配置
2. 在对应的 Mapper.xml 中配置 cache 节点
3. 在对应的 select 查询节点中添加 useCache=true
6.1.13. Tomcat 架构
7. 微服务
7.1.1. 服务注册发现
服务注册就是维护一个登记簿,它管理系统内所有的服务地址。当新的服务启动后,它会向登记 簿交待自己的地址信息。服务的依赖方直接向登记簿要 Service Provider 地址就行了。当下用于服 务注册的工具非常多 ZooKeeper,Consul,Etcd, 还有 Netflix 家的 eureka 等。服务注册有两种 形式:客户端注册和第三方注册。
7.1.1.1. 客户端注册(zookeeper)
客户端注册是服务自身要负责注册与注销的工作。当服务启动后向注册中心注册自身,当服务下 线时注销自己。期间还需要和注册中心保持心跳。心跳不一定要客户端来做,也可以由注册中心 负责(这个过程叫探活)。这种方式的缺点是注册工作与服务耦合在一起,不同语言都要实现一 套注册逻辑。
7.1.1.2. 第三方注册(独立的服务 Registrar)
第三方注册由一个独立的服务Registrar负责注册与注销。当服务启动后以某种方式通知Registrar, 然后 Registrar 负责向注册中心发起注册工作。同时注册中心要维护与服务之间的心跳,当服务不 可用时,向注册中心注销服务。这种方式的缺点是 Registrar 必须是一个高可用的系统,否则注册 工作没法进展。
7.1.1.3. 客户端发现
客户端发现是指客户端负责查询可用服务地址,以及负载均衡的工作。这种方式最方便直接,而 且也方便做负载均衡。再者一旦发现某个服务不可用立即换另外一个,非常直接。缺点也在于多 语言时的重复工作,每个语言实现相同的逻辑。
7.1.1.4. 服务端发现
服务端发现需要额外的 Router 服务,请求先打到 Router,然后 Router 负责查询服务与负载均衡。 这种方式虽然没有客户端发现的缺点,但是它的缺点是保证 Router 的高可用。
7.1.1.5. Consul
7.1.1.6. Eureka
7.1.1.7. SmartStack
7.1.1.8. Etcd
7.1.2. API 网关
API Gateway 是一个服务器,也可以说是进入系统的唯一节点。这跟面向对象设计模式中的 Facade 模式很像。API Gateway 封装内部系统的架构,并且提供 API 给各个客户端。它还可能有 其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等。下图展示了一个适应当前架构的 API Gateway。
API Gateway 负责请求转发、合成和协议转换。所有来自客户端的请求都要先经过 API Gateway, 然后路由这些请求到对应的微服务。API Gateway 将经常通过调用多个微服务来处理一个请求以 及聚合多个服务的结果。它可以在 web 协议与内部使用的非 Web 友好型协议间进行转换,如 HTTP 协议、WebSocket 协议。
7.1.2.1. 请求转发
服务转发主要是对客户端的请求安装微服务的负载转发到不同的服务上
7.1.2.2. 响应合并
把业务上需要调用多个服务接口才能完成的工作合并成一次调用对外统一提供服务。
7.1.2.3. 协议转换
重点是支持 SOAP,JMS,Rest 间的协议转换。
7.1.2.4. 数据转换
重点是支持 XML 和 Json 之间的报文格式转换能力(可选)
7.1.2.5. 安全认证
1. 基于 Token 的客户端访问控制和安全策略
2. 传输数据和报文加密,到服务端解密,需要在客户端有独立的 SDK 代理包
3. 基于 Https 的传输加密,客户端和服务端数字证书支持
4. 基于 OAuth2.0 的服务安全认证(授权码,客户端,密码模式等)
7.1.3. 配置中心
配置中心一般用作系统的参数配置,它需要满足如下几个要求:高效获取、实时感知、分布式访 问。
7.1.3.1. zookeeper 配置中心
实现的架构图如下所示,采取数据加载到内存方式解决高效获取的问题,借助 zookeeper 的节点 监听机制来实现实时感知。
7.1.4. 事件调度(kafka)
消息服务和事件的统一调度,常用用 kafka ,activemq 等。
7.1.5. 服务跟踪(starter-sleuth)
随着微服务数量不断增长,需要跟踪一个请求从一个微服务到下一个微服务的传播过程, Spring Cloud Sleuth 正是解决这个问题,它在日志中引入唯一 ID,以保证微服务调用之间的一致性,这 样你就能跟踪某个请求是如何从一个微服务传递到下一个。
1. 为了实现请求跟踪,当请求发送到分布式系统的入口端点时,只需要服务跟踪框架为该请求 创建一个唯一的跟踪标识,同时在分布式系统内部流转的时候,框架始终保持传递该唯一标 识,直到返回给请求方为止,这个唯一标识就是前文中提到的 Trace ID。通过 Trace ID 的记 录,我们就能将所有请求过程日志关联起来。
2. 为了统计各处理单元的时间延迟,当请求达到各个服务组件时,或是处理逻辑到达某个状态 时,也通过一个唯一标识来标记它的开始、具体过程以及结束,该标识就是我们前文中提到 的 Span ID,对于每个 Span 来说,它必须有开始和结束两个节点,通过记录开始 Span 和结 束 Span 的时间戳,就能统计出该 Span 的时间延迟,除了时间戳记录之外,它还可以包含一 些其他元数据,比如:事件名称、请求信息等。
3. 在快速入门示例中,我们轻松实现了日志级别的跟踪信息接入,这完全归功于spring-cloudstarter-sleuth 组件的实现。在 Spring Boot 应用中,通过在工程中引入 spring-cloudstarter-sleuth 依赖之后, 它会自动的为当前应用构建起各通信通道的跟踪机制,比如:
通过诸如 RabbitMQ、Kafka(或者其他任何 Spring Cloud Stream 绑定器实现的消息 中间件)传递的请求。
通过 Zuul 代理传递的请求。
通过 RestTemplate 发起的请求。
7.1.6. 服务熔断(Hystrix)
在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个 系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不 可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。 熔断器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到 许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序 不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费 CPU 时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经 修正,应用程序会再次尝试调用操作。
7.1.6.1. Hystrix 断路器机制 断路器很好理解, 当 Hystrix Command 请求后端服务失败数量超过一定比例(默认 50%), 断路器会 切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态 一段时间后(默认 5 秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix 的断路器 就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效 请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。