【高性能Java架构:核心原理与案例实战】
高性能Java架构:核心原理与案例实战
第1章 高性能Java核心知识概述
1.1 高性能
在做性能优化时,计算密集型和I/O密集型是有很大差别的,需要分开考虑
在做性能优化时,计算密集型和I/O密集型是有很大差别的,需要分开考虑
影响程序性能的原因
• 因为I/O阻塞会让CPU闲置,导致CPU浪费。
• 在多线程间增加锁来保证同步,导致并行系统串行化。
• 创建、销毁、维护太多进程和线程,导致操作系统把资源浪费在调度上。
• 没有异步返回数据进行处理。• 数据量过大,线程循环次数过多。
• 协议消耗资源过多。
• 未控制的慢请求、慢读取造成的并发不良。
1.2 高并发
1.3 高可用
1.4 算法、GC与诊断工具
1.5 分离术
1.6 基准测试
1.7 性能测试
1.8 业务测试
1.9 单元测试
1.10 数据库概述
(1)常用的性能基准测试工具有sysbench和mysqlslap。
(2)对应用程序进行性能测试的常用工具是JMeter。
(3)对MySQL和服务器CPU等信息进行性能监控架构可选择Grafana + InfluxDB +Telegraf架构或Prometheus + Grafana架构。
(4)集群可选择MyCAT。
(5)相关统计可选择percona-toolkit。
(6)慢SQL查询可选择mysqldumpslow。
(7)分布式事务可选择Fescar(Seata)。
(8)事务处理测试可选择HammerDB。
(9)快速备份与恢复可选择mysqlhotcopy。
(10)常规备份与恢复可选择mysqldump。
(11)二进制日志(binlog)解析工具可选择Maxwell。
常用的MySQL工具
1.11 缓存的核心知识
1.12 总结——业务、性能、编程、架构相辅相成
第2章 为MySQL填充亿级数据
2.1 问题描述
在编写代码之前,应先针对业务设计的数据格式创建表结构,然后填充亿级数据,此阶段出现的典型问题如下:(1)对于新上线的项目,我们希望能测试出它的最高承载用户量,在数据库为空的情况下,应如何增加亿级数据?(2)在学习和工作工程中,经常需要使用数据量庞大的表来模拟系统在真实环境中的响应情况。如果只写一段代码,之后循环使用INSERT语句插入数据则实在是太慢了,是否有更快速的方法?
2.2 问题分析与解决方案
我们分别通过INSERT INTO SELECT、存储过程和Loadfile三种方案为MySQL快速填充亿级数据
2.3 为MySQL填充亿级数据实战
2.3.1 INSERT INTO SELECT方案
2.3.2 存储过程方案
2.3.3 Loadfile方案
2.3.4 第三方解决方案
2.4 最终结果
第3章 MySQL基准测试:sysbench与mysqlslap
3.1 问题描述
(1)如何为刚搭建的MySQL数据库配置相关参数,例如8CPU、16MEM的服务器,应配置何种参数使该服务器最优?(2)当前设计的数据结构与表结构在没有其他因素影响性能时,基准响应情况如何?(3)当前负载均衡架构体系是否过多地影响了单台MySQL数据库的性能,例如,主从复制在当前架构中应当选择何种策略才不会过度损耗单台MySQL数据库的性能?(4)当前单台MySQL数据库的最大承载访问量是多少?(5)当MySQL数据库单表数据量过亿时,返回数据的速度极慢是正确的吗?
3.2 问题分析与解决方案
3.2.1 解决方案:sysbench
3.2.2 sysbench的命令与参数
3.2.3 解决方案:mysqlslap
3.2.4 mysqlslap的命令与参数
3.3 sysbench实战
3.3.1 使用sysbench压测CPU、内存和磁盘I/O
3.3.2 初次使用sysbench压测MySQL
3.3.3 深度使用sysbench压测MySQL
3.4 mysqlslap实战
3.5 其他基准压测工具
目前主流的第三方磁盘I/O压测工具有fio、Iometer和Orion
第4章 代码单元的性能测试与优化
4.1 问题描述
在编写代码过程中,程序中通常会有许多个函数和接口,此时需要对函数和接口进行单元测试,以便了解函数或接口的性能,此阶段出现的典型问题如下:(1)if和switch哪个性能更好?(2)FastJSON和GSON哪个性能更好?(3)程序使用Spring和不使用Spring哪个性能更好?(4)HashMap初始化是否需要指定初始大小?(5)HashMap获得容器占用大小时是否需要更多延时?(6)JDK的Lambda表达式是否会消耗更多的性能?(7)MyBatis和Spring-Data-JDBC哪个效率更高?(8)Redisson和Spring-Data-Reids哪个效率更高?
4.2 问题分析与解决方案
4.3 JMH实战
4.3.1 测试JMH基准性能
4.3.2 测试i++基准性能
4.3.3 用JMH执行多个函数的结果
第5章 Web性能测试解决方案:JMeter
5.1 问题描述
在代码写好之后,通常需要对场景进行性能测试,例如购买商品场景、登录场景、支付场景等,此阶段会出现的典型问题如下:(1)当前登录场景可能需要调用N个接口,每天高峰期的时候,应用程序可以承受多少人登录。(2)秒杀系统最多可以让多少人同时单击“购买”按钮而不出现异常。(3)连续100小时以上的疲劳测试是否会使系统内存出现无法下降、GC无法回收内存、疲劳测试之后CPU无法正常下降等问题。(4)在并发压力下,应用程序哪里消耗资源过多,需要进行优化?(5)在复杂场景下,整体接口包含调用逻辑,其中可能包括if-else判断、for/while循环、获取上一个接口的信息传输到下一个接口中等操作,如何简化这部分性能测试的需求?(6)针对协议如何进行测试?例如HTTP轮询与WebSocket哪个更消耗性能?大概相差多少?(7)当单台压力机无法生成更大的压力时,如何增加压力机?
5.2 问题分析与解决方案
5.3 JMeter的特点
5.4 深入理解JMeter
5.4.1 JMeter中的部分配置元件
5.4.2 JMeter参数化的实现方式
5.4.3 JMeter函数
5.4.4 通过JMeter读取外部文件
5.4.5 通过JMeter提取上一个接口返回值
5.5 JMeter实战
5.5.1 初次使用JMeter测试REST接口
5.5.2 录制性能测试脚本
第6章 SQL优化与索引优化
6.1 问题描述
在场景性能测试过程中,许多场景的响应速度可能并不如人意,此时可以通过优化SQL的方式,对场景性能测试函数与接口进行优化。此阶段会出现的典型问题如下:(1)在场景性能测试中,当前SQL是如何扫描MySQL的,导致返回速度特别慢?(2)当返回速度较慢时应如何增加索引?(3)应增加哪种类型的索引?(4)应用程序在生产环境中运行时,是如何知道哪条SQL语句执行的速度较慢的?
6.2 问题分析与解决方案
6.3 SQL执行计划
6.4 SQL优化与索引优化实战
6.4.1 SQL索引优化
6.4.2 分页查询优化
6.4.3 慢SQL日志分析工具mysqldumpslow
第7章 MySQL主从复制
7.1 问题描述
在程序上线运行一段时间之后,随着用户量的逐渐增多,单台MySQL开始无法承受所有的压力,为了承载更大的数据库并发,避免单台MySQL宕机,即无法正常提供服务,出现整体应用程序崩溃的情况,此时需要使用MySQL集群,此阶段会出现的典型问题如下:(1)在生产环境中,当MySQL处于运行状态时应如何备份当前数据?(2)在某场景下,某个接口需要锁表以便修改数据,而其他读取的线程都处于阻塞等待状态,此时应如何对其进行优化?(3)并发读取越来越多,单台无法满足业务需求,如何进行处理?
7.2 问题分析与解决方案
7.3 MySQL主从复制原理
部署过程中需要注意的事项
MySQL主从复制的架构拓扑
7.4 深入理解MySQL中的二进制日志
7.4.1 查看MySQL二进制日志状态
7.4.2 log_bin和sql_log_bin的区别
7.4.3 开启二进制日志
7.4.4 查看二进制日志文件的名称、大小和状态
7.4.5 删除某个日志之前的所有二进制日志文件
7.4.6 删除某个时间点以前的二进制日志文件
7.4.7 删除所有的二进制日志文件
7.4.8 查看二进制日志文件内容
7.4.9 通过二进制日志文件恢复MySQL
7.5 MySQL主从复制实战
7.5.1 构建MySQL主从复制架构
7.5.2 使用Spring Boot整合MySQL主从复制架构
第8章 MySQL分库分表:MyCAT
8.1 问题描述
8.2 问题分析与解决方案
8.3 MyCAT实战
8.3.1 构建MyCAT一主多从架构
8.3.2 构建MyCAT双主多从环境
8.3.3 MyCAT分库——垂直拆分
8.3.4 MyCAT分表——水平拆分
8.3.5 构建HAProxy + MyCAT + MySQL高可用架构
第9章 MySQL性能监控解决方案:Prometheus+Grafana
9.1 问题描述
在对MySQL进行主从复制、分库分表等架构之后,MySQL的节点数量变得越来越多,无法实时监控到每一台MySQL节点,此时应当如何处理?
9.2 问题分析与解决方案
9.3 Prometheus概述与适用场景
Prometheus是一个开源的服务监控系统和时间序列数据库,Kubernetes(k8s)内部使用的就是Prometheus数据库。Kubernetes的流行,带动了Prometheus社区的发展。Prometheus在大规模数据管理与读取上,比传统的NoSQL数据库要快很多。在数据压缩上,Prometheus具有高效压缩数据的算法,节省了存储空间,可有效减少服务器I/O的瓶颈。
Prometheus的适用场景如下:
(1)部署监控服务器,实现7×24实时监控。
(2)针对公司的业务及研发部门设计监控系统,对监控项和触发器给出合理意见。
(3)做好问题预警机制,对可能出现的问题及时告警并形成严格的处理机制。
(5)处理好公司服务器异地集中监控的问题。
Prometheus的主要特征:
(1)多维度数据模型。
(2)灵活的查询语言。
(3)不依赖分布式存储,单个服务器节点是自主的。
(4)以HTTP方式通过pull模型拉取时间序列数据。
(5)通过中间网关支持push模型。
(6)通过服务发现或者静态配置发现目
9.4 时序数据库概述与适用场景
在工作中,时序数据库(TimeSeries DataBase,TSDB)主要记录按照时间顺序进行管理的数据。这些以时间为变化的数据被统称为时序数据。时序数据库对该类数据有更好的读取性能,其应用场景如下所示
(1)Linux服务器每秒的CPU占用百分比、内存占用百分比、硬盘占用百分比等相关数据。
(2)无人汽车每秒的速度、油耗、方向、地理位置等相关数据。
(3)无人机每秒的经纬度、飞行高度、地理位置等相关数据。
(4)证券中心每秒开盘的行情数据、资金流数据。
(5)银行账号每天、每周的存款数据。
9.5 Grafana概述与适用场景
9.6 构建Prometheus + Grafana监控实战
第10章 堆内缓存解决方案:Java堆内缓存与Guava Cache
10.1 问题描述
当数据库臃肿性能不佳时,需要通过多层缓存的方式,在不同层级上设置缓存,减少数据库的连接次数与查询次数。假设有这样一个场景,首先查询一次堆内缓存,如果没有命中堆内缓存,则需要在MySQL中进行查询,然后将查询结果放置在堆内缓存中,以免下次查询不到,最后返回数据。这种方案比较常见,但是会出现许多细节上的问题,例如:(1)缓存穿透:DB中不存在数据,每次都穿过缓存查询DB,当给DB造成较大压力时应当如何处理?(2)缓存击穿:在缓存失效的瞬间涌入大量请求,造成DB的压力瞬间增大,此时应当如何处理?(3)缓存雪崩:大量缓存设置了相同的失效时间,使得性能瞬间急剧下降,此时应当如何处理?(4)JDK中主要包含几种缓存形式?
10.2 问题分析与解决方案
10.3 Java堆内缓存
10.3.1 Java堆内缓存原理
10.3.2 Java堆内缓存中的常见算法及实战
从0到1编写ArrayList
跳表算法
分段锁算法
无锁算法
安全失败
快速失败
10.4 Guava Cache实战
10.4.1 创建Google的容器工厂
10.4.2 屏蔽NULL值
10.4.3 管理字符串
10.4.4 操作Google的Multiset容器
10.4.5 操作Google的Multimap容器
10.4.6 操作Google的BiMap容器
10.4.7 操作Google的Table容器
10.4.8 操作Google的classToInstanceMap容器
10.4.9 操作Google的RangeSet容器
10.4.10 操作Google的RangeMap容器
10.4.11 操作Google的Guava Cache
第11章 堆外缓存与磁盘缓存解决方案:MapDB
11.1 问题描述
在互联网项目中,一般以堆内缓存的使用居多,无论Guava Cache还是JDK自带的HashMap、ConcurrentHashMap等,都是在堆内缓存中做数据计算操作。这是因为堆内缓存的响应速度最快,但是堆内缓存的价格也最高。有没有既能节约成本,又能提供较好的性能的工具呢?JVM一旦出现GC或者FULL GC的情况,就然删掉堆内存,此时应如何快速读取缓存数据?
11.2 问题分析与解决方案
实际上,堆内缓存、堆外缓存、磁盘缓存的响应速度是依次递减的。堆外缓存同样不需要考虑I/O、网卡、网络流量、连接数等一系列问题,数据并不存放在JVM内存上,而是直接存放在Linux系统内存上。因此针对在11.1节中提出的问题,均可使用堆外缓存处理。
11.2.1 堆外缓存
11.2.2 MapDB
11.2.3 实战:初次使用MapDB
11.3 MapDB的构造原理
11.4 MapDB的使用方法
11.5 MapDB实战
11.5.1 MapDB的序列化
11.5.2 MapDB的事务
11.5.3 MapDB的监听器与多级缓存
第12章 基于Redis的分布式锁解决方案:Redisson
12.1 分布式锁与Redisson原理
通常来说,秒杀系统在活动期间都需要极高的性能,为了防止超买或超卖,此时需要使用分布式锁解决数据的一致性问题。本章介绍基于Redis的分布式锁解决方案:Redisson。
分布式锁
Redisson原理
Redisson相关机制
12.2 单机版超买或超卖问题描述及解决方案
12.3 分布式版超买或超卖问题描述及解决方案
12.4 多线程死锁问题描述及解决方案
12.5 Redisson实战
12.5.1 Redisson的可重入锁
12.5.2 Redisson的公平锁
12.5.3 Redisson的联锁
12.5.5 Redisson的读写锁
12.5.6 Redisson的信号量
12.5.7 Redisson的分布式闭锁