1 JVM

JVM (Java Virtual Machine) 是一种虚拟机,具有 2 个主要特性:

  • 支持跨平台程序:JVM 定义了 Java 字节码,JVM 字节码是一套虚拟的指令集,他不与任何具体平台(CPU, 操作系统)绑定。JVM 通过将 Java 字节码指令翻译成具体平台的指令,使得用 Java 字节码表示的程序能够运行在不同平台上。对于用任一语言编写的程序,只要其源代码能被编译成 Java 字节码,那么该程序就可以跨平台运行。目前支持 Java 字节码的语言有:Java, Kotlin, Scala, Groovy。
  • 自动管理内存:在 JVM 上运行的程序,其运行期间内存的分配和无用内存的回收,由 JVM 自动管理,而不是由程序管理。

Java进阶训练营毕业总结 - 图1

2 NIO

2.1 I/O模型

网络程序的读网络数据操作包含 2 个步骤:

  • 步骤1:等待对端进程发送的数据被写到本机的内核缓冲区
  • 步骤2:从内核缓冲区复制数据到用户空间。仅当内核缓冲区有数据时,才能执行后一步骤。

网络编程 API 按其对这 2 个步骤的处理方式,可以分成 5 个模型:

  • 阻塞I/O(BIO)模型:线程在 2 个步骤中都被阻塞(指线程失去参与线程调度的资格)。
  • 非阻塞I/O(NIO)模型:若步骤1未完成,则读操作直接返回,即步骤1不会阻塞线程。若步骤1已完成,则执行步骤2,步骤2是阻塞的。
  • I/O多路复用模型:该模型为应用提供 selector 接口,应用将多个网络连接注册到一个 selector 上,然后用该 selector 查询这些网络连接的步骤1是否完成,这个查询是阻塞的,直到至少有 1 个网络连接的步骤1完成,然后就可以对完成了步骤1的连接执行步骤2,步骤2是阻塞的。Linux 通过 epoll 系统调用实现该模型。该模型是高并发网络应用的常用模型。
  • 信号驱动的I/O模型:对于步骤1,应用线程向内核发信号,表示要读取数据,然后线程即可继续执行,即步骤1不阻塞线程。等步骤1完成后,内核向应用线程发信号,然后应用线程执行步骤2,步骤2是阻塞的。
  • 异步I/O模型:应用线程读fff操作后,即可继续执行,等步骤1完成后,内核完成步骤2,然后向应用线程发信号。Windows 实现了该模型,Linux 没有实现该模型。

阻塞式IO.PNG
阻塞I/O(BIO)模型

非阻塞式IO.PNG
非阻塞I/O(NIO)模型

IO复用.PNG
I/O多路复用模型

信号驱动的IO.PNG
信号驱动的I/O模型

异步IO.PNG
异步I/O模型

图片来源:极客时间,秦金卫,Java进阶训练营,Week2-02.pdf

2.2 Netty

Netty 是一个优秀的网络应用开发框架,他基于I/O多路复用模型。

3 并发编程

3.1 并发编程是什么

事务:事务有开始时间、结束时间,从开始时间到结束时间的时段称为事务的生存期。事务有执行中、暂停2种状态。

并发:若2个事务的生存期存在重叠,则说这2个事务在重叠时段内是并发的,或简单地说这2个事务是并发的。

并发程序:若一个程序的进程包含多个并发线程(通常这些线程协作完成同一任务),则称这个程序是并发程序。

并发编程:并发编程就是编写并发程序。

3.2 为什么要并发编程

简化编程:某些场景明显具有多个执行流,例如控制台贪吃蛇游戏有更新蛇的位置和监听玩家输入2个执行流,在这些场景下,并发编程比单线程编程更简单。

提高资源利用率和系统性能:充分利用CPU等资源,提高系统性能(并发量、吞吐量、延迟)。

3.3 并发编程的问题

要控制并发线程的执行时序,以免程序出差。

3.4 并发编程图谱

并发编程图谱: https://www.yuque.com/zixiu1991/ik6gvs/kz705l

4 Spring 和 ORM 等框架

Spring: Spring 框架的核心是 IoC(Inversion of Control) 和 AOP(Aspect Oriented Programming)。Bean 的生命周期是 Spring 框架的重要知识点,对于理解 Spring IoC/AOP 的运行机制很重要。

Spring MVC: 用于 Web 开发的 MVC(Model-View-Controller) 框架。

Spring Boot: 加速开发 Spring 应用的脚手架,核心思想:约定大于配置,注解大于 XML。

Spring Boot Starter: Spring Boot 集成第三方组件的机制。

ORM: ORM(Object-Relational Mapping)指将关系数据库的记录转换成面向对象编程语言的对象,或反之。Java 领域常用 ORM 库有: JPA, Hibernate, MyBatis 等。Spring 集成了常用 ORM 库,既能用于关系数据库,也能用于非关系数据库(Redis, MongoDB 等)。

Lombok: Lombok 是基于 jsr269 实现的一个 java 类库,用他的注解可以自动生成类的 get、set方法及构造函数,还能自动生成 logger、toString、hashCode、Builder 等 Java 特色的函数或是符合设计模式的方法,从而简化 Java 代码。 Lombok 基于字节码增强技术,在编译期处理。Lombok 可以配合开发工具(IntelliJ IDEA, Eclipse 等)使用。

Guava: Google 出品的 Java 常用功能库,被广泛使用,部分特性被引进 JDK。

Hutool: 国产 Java 常用功能库,很实用,有名气。

5 MySQL 数据库和 SQL

5.1 为什么要优化 MySQL 性能

对于数据密集型系统,数据库性能是系统性能的瓶颈,为提升系统性能,应重点考虑提升数据库性能。

5.2 MySQL 服务器配置优化

优化 MySQL 服务器配置,即 my.cnf/my.ini 文件中的参数,可以提升 MySQL 性能。

主要可优化参数如下:
1)连接请求的变量
1、max_connections
2、back_log
3、wait_timeout和interative_timeout
2)缓冲区变量
4、key_buffer_size
5、query_cache_size(查询缓存简称 QC)
6、max_connect_errors
7、sort_buffer_size
8、max_allowed_packet=32M
9、join_buffer_size=2M
10、thread_cache_size=300
3)配置 Innodb 的几个变量
11、innodb_buffer_pool_size=128M
12、innodb_flush_log_at_trx_commit
13、innodb_thread_concurrency=0
14、innodb_log_buffer_size
15、innodb_log_file_size=50M
16、innodb_log_files_in_group=3
17、read_buffer_size=1M
18、read_rnd_buffer_size=16M
19、bulk_insert_buffer_size=64M
20、binary log

5.3 数据库设计优化

  • 如何恰当选择引擎?
    - 库表如何命名?
    - 如何合理拆分宽表?
    - 如何选择恰当数据类型:明确、尽量小
    - char、varchar 的选择
    - (text/blob/clob)的使用问题?
    - 文件、图片是否要存入到数据库?
    - 时间日期的存储问题?
    - 数值的精度问题?
    - 是否使用外键、触发器?
    - 创建恰当索引:索引字段、字段顺序、索引类型(Hash, B+树)

  • 唯一约束和索引的关系?
    - 是否可以冗余字段?
    - 是否使用游标、变量、视图、自定义函数、存储过程?
    - 自增主键的使用问题?
    - 能够在线修改表结构(DDL 操作)?
    - 逻辑删除还是物理删除?
    - 要不要加 create_time,update_time 时间戳?
    - 数据库碎片问题?
    - 如何快速导入导出、备份数据?

    5.4 应用侧 SQL 使用优化

    大批量写入的优化:
    PreparedStatement 减少 SQL 解析
    Multiple Values/Add Batch 减少交互
    Load Data,直接导入

数据更新优化:
数据的范围更新
注意 GAP Lock 的问题
导致锁范围扩大

模糊查询优化:
Like 的问题
前缀匹配
否则不走索引
全文检索
solr/ES

连接查询优化:
驱动表的选择问题
避免笛卡尔积

索引失效的情况汇总:
隐式数据类型、字符编码转换
NULL,not,not in,函数等
减少使用 or,可以用 union(注意 union all 的区别),以及前面提到的 like
大数据量下,放弃所有条件组合都走索引的幻想,改用“全文检索”
必要时可以使用 force index 来强制查询走某个索引

SQL 使用指南:
查询数据量和查询次数的平衡
避免不必须的大量重复数据传输
避免使用临时文件排序或临时表
分析类需求,可以用汇总表

5.5 诊断 MySQL 性能问题的方法

-慢查询日志
-看应用和运维的监控

6 MySQL 复制、读写分离、分库分表

6.1 单机 MySQL 的问题和解决方案

单机 MySQL 的问题:

  • 容量不足:单机的存储空间不能满足系统的需求。
  • 并发能力不足:单机的CPU,内存,网络带宽等资源不足以支撑系统需要的并发读写量。
  • 可用性低:一旦部署 MySQL 的机器宕机,整个数据库系统就不可用了,进而导致系统不可用。

以下解决方案可解决以上问题:

解决方案名称 解决的问题 解决方案描述
复制 可用性低 思想:把一个数据库重复部署在多个 MySQL 实例上,只要至少 1 个 MySQL 实例正常运行,数据库系统就可用。

原理:MySQL binlog 记录了数据库修改操作,从节点获取主节点的 binlog,并在本节点上执行,使得从节点的数据与主节点一致。
读写分离 并发能力不足 读写分离基于复制,让主节点处理写请求,多个从节点分摊读请求。对于读请求远多于写请求(例如 10:1)的场景,可以大大降低每个节点的读请求压力。
数据库垂直拆分 容量不足,并发能力不足 1 将不同业务的数据拆分到不同的数据库,并部署在不同的 MySQL 实例上。
2 将有很多字段的表拆分到不同的表。
3 将大字段拆分到单独的表。
数据库水平拆分 容量不足,并发能力不足 对于记录很多的表,创建多个结构一样的表,这些表分别容纳部分记录,这些表可以放在同一个数据库,也可放在不同数据库(位于不同 MySQL 实例)

6.2 分布式事务

数据库拆分以后,存在事务跨多个 MySQL 实例的问题,这种事务称为分布式事务。

有 2 种分布式事务解决方案:

  • 强一致性事务:如 MySQL 自带的基于 XA 分布式事务协议的 XA 事务。
  • BASE 柔性事务:BASE 柔性事务具有基本可用(Basically Available),柔性状态(Soft state)和最终一致性(Eventually consistent)3 个特性。

BASE 柔性事务有以下模式:

  • TCC: TCC 模式即将每个服务业务操作分为两个阶段,第一个阶段检查并预留相关资源,第二阶段根据所有服务业务的 Try 状态来操作,如果都成功,则进行 Confirm 操作,如果任意一个 Try 发生错误,则全部 Cancel
  • SAGA: 与 TCC 相比,Saga 模式没有 try 阶段,直接提交事务。复杂情况下,对回滚操作的设计要求较高
  • AT: AT 模式就是两阶段提交,自动生成反向 SQL

分布式事务产品:

  • Seata: Seata 是阿里集团和蚂蚁金服联合打造的分布式事务框架,支持 TCC 和 AT 2 种 BASE 柔性事务模式。
  • Hmily: Hmily 是一个高性能分布式事务框架,支持 TCC 和 TAC 2 种 BASE 柔性事务模式。使用 Java 语言开发(JDK1.8+),天然支持 Dubbo、SpringCloud、Motan 等微服务框架的分布式事务。
  • ShardingSphere; ShardingSphere 自身并没有实现分布式事务,而是通过整合其他分布式事务产品来提供分布式事务能力。整合现有的成熟事务方案,为本地事务、两阶段事务和柔性事务提供统一的分布式事务接口,并弥补当前方案的不足,提供一站式的分布式事务解决方案是 Apache ShardingSphere 分布式事务模块的主要设计目标。ShardingSphere 支持 XA 事务的常见几个开源实现,支持 Seata 柔性事务。

ShardingSphere-XA.PNG
ShardingSphere 支持的 XA 事务产品(图片来源:极客时间,秦金卫,Java进阶训练营,Week8-02.pdf)

6.3 应用如何使用读写分离和分库分表

为了使用读写分离和分库分表技术,一方面要部署 MySQL 集群,另一方面应用侧也要接入这些技术。

ShardingSphere-JDBC 和 ShardingSphere-Proxy 以不同的方式为应用提供读写分离和分库分表技术:

  • ShardingSphere-JDBC: ShardingSphere-JDBC 作为程序库,与应用运行在同一个进程中。
  • ShardingSphere-Proxy: ShardingSphere-Proxy 作为 MySQL 服务器的代理,运行在单独的进程中,一般部署在与应用不同的机器上,应用连接 ShardingSphere-Proxy 而不是连接 MySQL 服务器。

    7 RPC 和微服务

    7.1 RPC

    7.1.1 RPC 是什么

    远程服务调用(一台机器上的程序调用另一台机器上的服务,这里服务泛指应用编程接口)是网络应用的常见情景。

HTTP + JSON 是远程服务调用的一种常见形式,服务端对客户端暴露 HTTP 接口,客户端向服务端发送 HTTP 请求(请求体是 JSON 文本),得到服务端的 HTTP 响应(响应体是 JSON 文本)后,将 响应体转换成领域对象,再用领域对象执行业务。客户端使用 HTTP + JSON 调用远程的根据用户ID获取用户信息服务演示:

  1. OkHttpClient client = new OkHttpClient();
  2. String url = "http://localhost:8080/user/123";
  3. Request request = new Request.Builder().url(url).build();
  4. Response response = client.newCall(request).execute()
  5. String responseBody = response.body().string();
  6. User user = JSON.parseObject(responseBody, User.class)
  7. // ... 使用 user 执行业务

而 RPC(Remote Procedure Call) 则是远程服务调用的另一种形式。客户端使用 RPC 框架得到实现了服务接口的代理对象,然后调用该代理对象的方法,即实现了远程服务调用。客户端使用 RPC 调用远程的根据用户ID获取用户信息服务演示:

  1. String remoteServerUrl = "http://localhost:8080/";
  2. // 使用 RPC 框架得到实现了服务接口的代理对象
  3. UserService userService = RpcFramework.create(UserService.class, remoteServerUrl);
  4. User user = userService.findById(123);
  5. // ... 使用 user 执行业务

7.1.2 为什么要使用 RPC

  • 简化编程
  • 提高性能
  • 其他???

    7.1.3 RPC 原理

    RPC原理.PNG
    RPC 原理(图片来源:极客时间,秦金卫,Java进阶训练营,Week9-01.pdf)

上图展示了 RPC 原理,RPC 原理涉及 5 个方面:设计,代理,序列化,网络传输 和 查找实现类。

  • 设计:RPC 是基于接口的远程服务调用,要设计客户端和服务端需要共享的信息,比如与接口相关的所有数据类型的定义。
  • 代理:RPC 是基于接口的远程服务调用。Java 下,代理可以选择动态代理,或者 AOP 实现。C# 直接有远程代理。
  • 序列化:远程服务调用的请求和响应消息在网络间传输需要序列化、反序列化。序列化方案有:
    • 语言原生的序列化,RMI,Remoting
    • 二进制平台无关,Hessian,avro,kyro,fst 等
    • 文本,JSON、XML 等
  • 网络传输:RPC 请求和响应消息的传输方式。最常见的传输方式:
    • TCP/SSL/TLS
    • HTTP/HTTPS
  • 查找实现类:服务端收到 RPC 请求后,需要找到服务的实现类的机制。一般是注册方式,例如 dubbo 默认将接口和实现类配置到 Spring。

    7.2 微服务

    7.2.1 微服务是什么

    微服务是一种软件架构,核心思想是为了实现复杂系统,将整体系统拆分成恰当粒度的子系统,进行独立的开发、部署、运维,每个子系统实现的服务比较微小,所以叫微服务。可以从以下几个视图看待微服务架构:

  • 用例视图:每个子系统负责部分业务。

  • 开发视图:每个子系统有独立的源代码工程。
  • 进程视图:子系统间通过 RPC 相互调用,整体系统的外界通过网关与子系统通讯。
  • 物理视图:每个子系统运行在独立的机器、进程上。

软件架构发展路径.PNG
软件架构发展路径(图片来源:极客时间,秦金卫,Java进阶训练营,Week10-02.pdf)

微服务架构示意图.PNG
微服务架构示意图(图片来源:极客时间,秦金卫,Java进阶训练营,Week10-02.pdf)

7.2.2 微服务相关技术问题

1、多个相同服务如何管理? ==> 集群/分组/版本 => 分布式与集群
2、服务的注册发现机制? ==> 注册中心/注册/发现
3、如何负载均衡,路由等集群功能? ==> 路由/负载均衡
4、熔断,限流等治理能力。 ==> 过滤/流控
5、心跳,重试等策略。
6、高可用、监控、性能等等。

7.2.3 微服务相关产品

7.2.3.1 Dubbo

Apache Dubbo 是一款高性能、轻量级的开源 Java 服务框架。具有六大核心能力:面向接口代理的高性能 RPC 调用,智能负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维。

Dubbo 整体架构.PNG
Dubbo 整体架构(图片来源:极客时间,秦金卫,Java进阶训练营,Week9-02.pdf)

  1. config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
    2. proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory
    3.registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
    4. cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为Cluster,Directory,Router,LoadBalance
    5. monitor 监控层:RPC 调用次数和和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
    6. protocol 远程调用层:封装 RPC 调用,以 Invocation,Result 为中心,扩展接口为 Protocol,Invoker,Exporter
    7. exchange 信息交换层:封装请求响应模式,同步转异步,以 Request,Response 为中心,扩展接口为Exchanger,ExchangeChannel,ExchangeClient,ExchangeServer
    8. transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel,Transporter,Client,Server,Codec
    9. serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization,ObjectInput, ObjectOutput,ThreadPool

    7.2.3.2 Spring Cloud

    Spring Cloud 技术体系.PNG
    Spring Cloud 技术体系(图片来源:极客时间,秦金卫,Java进阶训练营,Week10-02.pdf)

    7.2.3.3 其他产品

    APM(应用性能监控):
  • Apache Skywalking
  • Pinpoint
  • Zipkin
  • Jaeger

监控:

  • ELK
  • promethus+Grafana
  • MQ+时序数据库(InfluxDB/openTSDB 等)

权限控制:权限控制核心问题有 Authentication, Authorization 和 Audit 3 个,针对这 3 个问题有以下产品:

  • CAS+SSO(TGT、ST)
  • JWT/Token, OAuth2.0
  • SpringSecurity, Apache Shiro

    8 分布式缓存

    缓存:利用空间换时间,解决系统各级处理速度不匹配问题。

缓存有多级,如进程内内存缓存,本地磁盘缓存,远程缓存。

远程缓存产品:Redis/Memcached 缓存中间件,Hazelcast/Ignite 内存网格。

缓存淘汰策略:FIFO/LRU, 按国定时间过期,按业务时间加权。

缓存常见问题:缓存穿透、缓存击穿、缓存雪崩。

9 分布式消息队列

消息队列是一种系统间通信方式,具有以下优点:

  • 异步通信:异步通信,减少线程等待,特别是处理批量等大事务、耗时操作。
  • 系统解耦:系统不直接调用,降低依赖,特别是不在线也能保持通信最终完成。
  • 削峰平谷:压力大的时候,缓冲部分请求消息,类似于背压处理。
  • 可靠通信:提供多种消息模式、服务质量、顺序保障等

常见的 2 种消息处理模式:

  • 点对点:PTP,Point-To-Point对应于Queue
  • 发布订阅:PubSub,Publish-Subscribe,对应于 Topic

开源消息中间件/消息队列:
一代:ActiveMQ/RabbitMQ
二代:Kafka/RocketMQ(目前的主流产品)
三代:Apache Pulsar