分布式高级篇(二) - 压测与性能监控
性能压测与优化
压力测试
- 压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。压测都是为了系统在线上的处理能力和稳定性维持在一个标准范围内,做到心中有数
- 使用压力测试,我们有希望找到很多种其他测试方法更难发现的错误。有两种错误类型是:内存泄露、并发与同步
- 有效的压力测试系统将应用以下这些关键条件:重复、并发、量级、随机变化
性能指标
-
响应时间(Respone Time:RT)
响应时间指用户从客户端发起一个请求开始,到客户端接收到从服务器端返回的响应结束,整个过程所耗费的时间
-
HPS(Hits Per Second):每秒点击次数,单位是 次/秒
-
TPS(Transaction per Second):系统每秒处理交易数,单位是 笔/秒
-
QPS(Query Per Second):系统每秒处理查询次数,单位是 次/秒
对于互联网业务中,如果某些业务有且仅有一个请求连接,那么 TPS=QPS=HPS,一般情况下用TPS来衡量整个业务流程,用QPS来衡量接口查询次数,用HPS来表示对服务器单击请求
-
无论TPS、QPS、HPS,此指标是衡量系统处理能力非常重要的指标,越大越好,根据经验,一般情况下:
- 金融行业:1000TPS~50000TPS,不包括互联网化的活动
- 保险行业:100TPS~100000TPS,不包括互联网化的活动
- 制造行业:10TPS~5000TPS
- 互联网电子商务:10000TPS~1000000TPS
- 互联网中型网站:1000TPS~50000TPS
- 互联网小型网站:500TPS~10000TPS
-
最大响应时间(Max Response Time):指用户发出请求或者指令到系统做出的反应(响应)的最大时间
-
最小响应时间(Mininum Response Time): 指用户发出请求或者指令到系统做出反应(响应)的最小时间
-
90%响应时间(90% Response Time):是指所有用户的响应时间进行排序,第90%的响应时间
-
从外部看,性能测试主要关注如下三个指标
- 吞吐量:每秒钟系统能够处理的请求数、任务数
- 响应时间:服务处理一个请求或一个任务的耗时
- 错误率:一批请求中结果出错的请求所占比例
压测工具JMeter
下载安装JMeter
-
下载地址
JMeter 使用
-
解压
-
进入bin目录,运行
jmeter.bat
JMeter 压测示例
-
1:添加线程组(添加--线程(用户)--线程组)
右击TestPlan
-
线程属性
- 线程数:模拟多少个用户同时访问
- Ranp-Up时间(秒):多少秒内完成上面设置的线程数。例如:10秒 200线程数 :代表没秒20个请求
- 循环次数:代表每个线程循环的次数 例如循环次数=100,每个线程请求执行100次,200个线程就是20000次
-
2:HTTP请求(添加--取样器--HTTP请求)
指定请求接口,端口和请求所需的参数
-
3:查看百度的测试结果(添加--监听器--查看结果树/汇总报告/聚合报告)
JMeter Address Already in use 错误解决
-
windows本身提供的端口访问机制问题。
-
Windows提供给TCP/IP链接的端口为1024-5000,并且要四分钟来循环回收他们,就导致我们在短时间内跑大量的请求时将端口占满了
-
解决方式
-
1、cmd中,用regedit命令打开注册表
-
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParameters
-
影响性能考虑点
- 数据库、应用程序、中间件(tomcat、nginx)、网络和操作系统等
- 首先要考虑自己的应用属于CPU密集型还是IO密集型
性能监控
JVM内存模型
-
JVM内存模型
-
程序计数器(Program Counter Register)
- 记录的是正在执行的虚拟机字节码指令的地址
- 此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError的区域
-
‘虚拟机:VM Stack
- 描述的是JAVA方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法接口等信息
- 局部变量表存储了编译器可知的各种基本数据类型、对象引用
- 线程请求的栈深度不够会报StackOverFlowError异常
- 栈动态扩展的容量不够会报OutOfMemoryError异常
- 虚拟机栈是线程隔离的,即每个线程都有自己独立的虚拟机栈
-
本地方法:Native Stack
- 本地方法栈类似于虚拟机栈,只不过本地方法栈使用的是本地方法
-
堆:Heap
- 几乎所有的对象实例都在堆上分配内存
堆
-
所有的对象实例以及数组都要在堆上分配。堆是垃圾回收器管理的主要区域,也被称为“GC堆”;也是我们优化最多考虑的地方
堆可以细分为:
- 新生代
- Eden空间 (伊甸园区)
- FromSurvivor 空间 (幸存0区)
- ToSurvivor 空间 (幸存1区)
- 老年代
- 永久代/元空间
- java8以前永久代,受JVM 管理,java8以后元空间,直接使用物理内存。因此,默认情况下,元空间的大小仅受本地内存限制
- 新生代
-
垃圾回收
垃圾回收流程图
jconsole与jvisualvm
- jdk的两个小工具jconsole、jvisualvm(升级版的jconsole);通过命令行启动,可监控本地和远程应用。远程应用需要配置
jvisualvm
-
监控内存泄露,跟踪垃圾回收,执行时内存、CPU分析,线程分析...
-
cmd 启动 jvisualvm
运行:正在运行的线程
休眠:sleep
等待:wait
驻留:线程池里的空闲线程
监视:阻塞的线程,正在等待锁
安装插件方便查看gc
-
工具---插件安装---visual gc(安装完成,重启
jvisualvm
)
监控指标
中间件指标
-
监控nginx
-
docker stats 查看容器资源占用
-
jmeter 压测 nginx (192.168.83.133:80/) 50个线程 一直循环
观察发现nginx主要是占用cpu,内存变化不大
-
-
监控网关
-
jmeter 压测 GateWay(localhost:9527/) 50个线程 一直循环
也是主要占用CPU,但是Eden区
gc
特别频繁,可以修改这块来提高吞吐量
-
-
压测首页全量数据
-
包括html、js、css等静态资源
-
数据库指标
优化-nginx动静分离
-
由于动态资源和静态资源目前都处于服务端,所以为了减轻服务器压力,我们将js、css、img等静态资源放置在Nginx端,以减轻服务器压力
-
将项目static目录下的 index 复制到
nginx
的挂载文件/html/static
目录下-
修改
conf/conf.d/
目录下的mall.conf
#添加 location /static/ { root /usr/share/nginx/html/; }
-
压测报表(*)
-
对不同内容压测的数据统计
压测内容 压测线程数 吞吐量/s 90%响应时间/ms 99%响应时间/ms Nginx 50 6721 14 22 GateWay 50 16211 5 16 简单服务
localhost:12000/hello50 24715 3 8 GateWay+简单服务
localhost:9527/hello50 6300 15 76 Nginx+GateWay+简单服务(全链路)
mall.com/hello50 120 1644 2453 首页一级菜单渲染
localhost:12000/50 445(db,thymeleaf) 163 248 首页一级菜单渲染(thymeleaf开启缓存)
localhost:12000/50 528(db) 143 227 首页一级菜单渲染(开缓存&优化数据库(加索引)&关日志)
localhost:12000/50 1244 66 116 三级分类数据获取
localhost:12000/index/catalog.json50 3.8(db导致) 13205 13519 三级分类数据获取(多次查库变一次查库)
localhost:12000/index/catalog.json50 218 330 536 三级分类数据获取(加索引)
localhost:12000/index/catalog.json50 16.7 3314 3554 首页全量数据获取
localhost:12000/50 7(静态资源) 6603 6740 首页全量数据获取(动静分离)
localhost:12000/50 36.3 1565 2018 -
测试结论:
- 中间件越多,性能损失越大,大多数都损失在网络交互中
- 业务:
- DB(MySQL优化:服务器、索引...)
- 模板的渲染速度(缓存)
- 静态资源(动静分离)
- gc内存分配不合理
优化三级分类数据获取
-
之前版本,嵌套循环查询数据库
-
优化思路
-
1、将数据库的多次查询变为一次
com.touch.air.mall.product.service.impl.CategoryServiceImpl.getCatalogJson
-