当前位置: 首页 > article >正文

项目优化性能监控

目录

1. 性能平台搭建

1.1 影响性能的关键要素

1.2 压力测试

1.3 压力测试指标

1.4 Jmeter

1.5 Jmeter常用插件

1.6 性能关键指标

1.7 服务器硬件资源监控

1.8 系统负载:load average

1.9 搭建压测监控平台

1.10 梯度压测:分析接口性能瓶颈

2. 项目优化

2.1 Tomcat调优

2.2 容器优化Tomcat升级Undertow

2.3 数据库调优

2.4 OpenResty调优

2.5 缓存调优

2.6 JVM调优

3. 项目重构

3.1 重构原因

3.2 重构的要求

3.3 重构步骤


1. 性能平台搭建

1.1 影响性能的关键要素

  • 产品设计
  • 基础网络
  • 代码质量跟架构
  • 移动端环境
  • 硬件及云服务

1.2 压力测试

压力测试

1.3 压力测试指标

压力测试

压力测试

1.4 Jmeter

压力测试

压力测试

1.5 Jmeter常用插件

开启插件下载:

  • 下载地址:http://jmeter-plugins.org/downloads/all/,官网上下载plugins-manager.jar直接在线下载, 然后执行在线下载即可。

    压力测试

1、PerfMon:监控服务器硬件,如CPU,内存,硬盘读写速度等
Allows collecting target server resource metrics
2、Basic Graphs:主要显示平均响应时间,活动线程数,成功/失败交易数等
Average Response Time 平均响应时间
Active Threads 活动线程数
Successful/Failed Transactions 成功/失败 事务数
3、Additional Graphs:主要显示吞吐量,连接时间,每秒的点击数等
Response Codes
Bytes Throughput
Connect Times
Latency

压力测试

1.6 性能关键指标

  • 1.响应时间

  • 2.压力机活动线程数

    压力机活动线程数表明压测过程中施加的压力的情况

  • 3.TPS每秒事务数 数字愈大,代表性能越好

  • 4.QPS每秒查询数
    数字愈大,代表性能越好(1tps>=1QPS)

  • 5.吞吐量 吞吐量: 每秒的请求数量

1.7 服务器硬件资源监控

压测的时候,我们需要实时了解服务器【CPU、内存、网络、服务器Load】的状态如何,哪如何监控服 务器的资源占用情况呢?方法有很多种:

  • 使用操作系统命令:top、vmstat、iostat、iotop、dstat、sar...
  • 使用finalshell
  • 使用JMeter压测工具perfmon
  • 使用Grafana+Prometheus+node_exporter

1.8 系统负载:load average

Load Average含义

系统负载System Load是系统CPU繁忙程度的度量,即有多少进程在等待被CPU调度(进程等待队 列的长度)。
平均负载(Load Average)是一段时间内系统的平均负载,这个一段时间一般取1分钟、5分钟、 15分钟。
多核CPU和单核CPU的系统负载数据指标的理解还不一样。
top 指令可以查看系统负载

单核CPU三种Load情况

举例说明:把CPU比喻成一条(单核)马路,进程任务比喻成马路上跑着的汽车,Load则表示马 路的繁忙程度。 情况1-Load小于1:不堵车,汽车在马路上跑得游刃有余

情况2-Load等于1:马路已无额外的资源跑更多的汽车了

情况3-Load大于1:汽车都堵着等待进入马路

1.9 搭建压测监控平台

压力测试

node_exporter:类似一一种代理工具,将机器压力信息数据push到Prometheus
Prometheus:是一个开源的系统监控和报警系统
InfluxDB:是一个开源的、高性能的时序型数据库

安装Docker+JMeter+InfluxDB+Grafana+node_exporter+Prometheus

  • 配置Docker环境
    yum 包更新到最新
sudo yum update -y

安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖 的

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

设置yum源为阿里云
配置yum源的代理,类似于maven镜像仓库,加速下载软件。

sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安装docker

sudo yum install docker-ce -y
# 启动
systemctl start docker

安装后查看docker版本

ocker -v
  • 安装InfluxDB
    下载InfluxDB的镜像:
docker pull influxdb:1.8   

启动InfluxDB的容器,并将端口 8083 和 8086 映射出来:

docker run -d --name influxdb -p 8086:8086 -p 8083:8083 influxdb:1.8

进入容器内部,创建名为jmeter的数据库:

docker exec -it influxdb /bin/bash

输入 influx 命令,即可进入 influx 操作界面
输入 create database jmeter 命令,创建名为 jmeter 的数据库
输入 show databases 命令,查看数据库创建成功

root@517f57017d99:/# influx
Connected to http://localhost:8086 version 1.7.10
InfluxDB shell version: 1.7.10
> create database jmeter
> show databases

使用JMeter 库, select 查看数据,这个时候是没有数据的:
输入 use jmeter 命令,应用刚才创建的数据库
输入 select * from jmeter 命令,查询库中有哪些数据

> use jmeter
> select * from jmeter
  • 设置JMeter脚本后置监听器
    配置后置监听器
    想要将 JMeter的测试数据导入 InfluxDB ,就需要在 JMeter中使用 Backend Listener 配置

压力测试

主要配置说明

压力测试

运行验证
运行 Jmeter 脚本,然后再次在 influxdb 中查看数据,发现类似下面的数据说明输入导入成功:

压力测试

  • 安装Grafana
    下载Grafana镜像:
docker pull grafana/grafana

启动Grafana容器:

docker run -d --name grafana -p 3000:3000 grafana/grafana

验证部署成功
网页端访问http://101.200.146.199:3000验证部署成功 默认账号密码admin/admin

选择添加数据源

压力测试

找到并选择 influxdb

压力测试

配置数据源
 

压力测试


数据源创建成功时会有绿色的提示
导入模板

压力测试

模板导入分别有以下3种方式: 直接输入模板id号 直接上传模板json文件 直接输入模板json内容

压力测试

找展示模板
在Grafana的官网找到我们需要的展示模板
Apache JMeter Dashboard dashboad-ID:5496
JMeter Dashboard(3.2 and up) dashboad-ID:3351

导入找到的模板,使用模板id
导入模板,我这里选择输入模板id号,导入后如下,配置好模板名称和对应的数据源,然后 import 即可

压力测试

查看效果
展示设置,首先选择创建的application

压力测试

注意: 如果我们修改过表名,也就是在jmeter的Backend Listener的measurement配置(默认为 jmeter),这个时候就需要去设置中进行修改,我这里使用的就是默认的,所以无需修改

以上这些我们就可以查看压测的响应时间,活动线程数等

  • 安装node_exporter
# 下载
wget -c
https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_ex
porter-0.18.1.linux-amd64.tar.gz
# 解压
mkdir /usr/local/hero/
tar zxvf node_exporter-0.18.1.linux-amd64.tar.gz -C /usr/local/hero/
# 启动
cd /usr/local/hero/node_exporter-0.18.1.linux-amd64
nohup ./node_exporter > node.log 2>&1 &

注意:在被监控服务器中配置开启端口9100 http://101.200.87.86:9100/metrics

  • 安装Prometheus

下载解压运行

# 下载
wget -c
https://github.com/prometheus/prometheus/releases/download/v2.15.1/prometheus
-2.15.1.linux-amd64.tar.gz
# 解压
tar zxvf prometheus-2.15.1.linux-amd64.tar.gz -C /usr/local/hero/
cd /usr/local/hero/prometheus-2.15.1.linux-amd64
# 运行
nohup ./prometheus > prometheus.log 2>&1 &

配置prometheus
在prometheus.yml中加入如下配置

- job_name: 'hero-Linux'
static_configs:
- targets:
['172.17.187.78:9100','172.17.187.79:9100','172.17.187.81:9100']

测试Prometheus
测试Prometheus是否安装配置成功 http://101.200.146.199:9090/targets

压力测试

  • 在Grafana中配置Prometheus的数据源

压力测试

Grafana导入Linux展示模板
导入Linux系统dashboard
Node Exporter for Prometheus Dashboard EN 20201010
dashboard-ID: 11074
Node Exporter Dashboard
dashboard-ID: 16098

压力测试

压力测试

1.10 梯度压测:分析接口性能瓶颈

以上主要的四种性能指标【响应时间、并发用户数、吞吐量、资源使用率】它们之间存在一定的相关 性,共同反映出性能的不同方面。

压力测试

情况01-模拟低延时场景,用户访问接口并发逐渐增加的过程。
预计接口的响应时间为20ms
线程梯度:5、10、15、20、25、30、35、40个线程
循环请求次数5000次

  • 网络瓶颈
    随着压力的上升,TPS不再增加,接口响应时间逐渐在增加,偶尔出现异常,瓶颈凸显。系统的 负载不高。CPU、内存正常,说明系统这部分资源利用率不高。带宽带宽显然已经触顶了。

优化方案:
方案01-降低接口响应数据包大小
方案02-提升带宽【或者在内网压测】

结论:
在低延时场景下,服务瓶颈主要在服务器带宽。
TPS数量等于服务端线程数 乘以 (1000ms/ RT均值)
RT=21ms,TPS=800,服务端线程数:= 800/ (1000ms/ RT均值) = 17

情况02-模拟高延时场景,用户访问接口并发逐渐增加的过程。接口的响应时间为500ms
线程梯度:100、200、300、400、500、600、700、800个线程;
循环请求次数200次

结论:
在高延时场景下,服务瓶颈主要在容器最大并发线程数。
RT=500ms,TPS=800,服务端线程数:= 800/ (1000ms/ RT) = 400
Tomcat默认的最大的线程数?200
观察服务容器最大线程数,发现处理能力瓶颈卡在容器端

TPS在上升到一定的值之后,异常率较高 (原因容器使用的IO是是阻塞式IO模型)

2. 项目优化

2.1 Tomcat调优

Springboot开发的服务使用嵌入式的Tomcat服务器,那么Tomcat配置使用的是默认配置,我们需要对 Tomcat配置进行适当的优化,让Tomcat性能大幅提升。
我们可以改变yml文件改变内置tomcat配置

# Tomcat的maxConnections、maxThreads、acceptCount三大配置,分别表示最大连接数,最大
线程数、最大的等待数,可以通过application.yml配置文件来改变这个三个值,一个标准的示例如
下:
server.tomcat.uri-encoding: UTF-8
server.tomcat.accept-count: 1000 # 等待队列最多允许1000个请求在队列中等待
server.tomcat.max-connections: 20000 # 最大允许20000个链接被建立
## 最大工作线程数,默认200, 4核8g内存,线程数经验值800
server.tomcat.threads.max: 800 # 并发处理创建的最大的线程数量
server.tomcat.threads.min-spare: 100 # 最大空闲连接数,防止突发流量
# 暴露所有的监控点
management.endpoints.web.exposure.include: '*'
# 定义Actuator访问路径
management.endpoints.web.base-path: /actuator
# 开启endpoint 关闭服务功能
management.endpoint.shutdown.enabled: true
  • maxThreads:最大线程数
    每一次HTTP请求到达Web服务,Tomcat都会创建一个线程来处理该请求。
    最大线程数决定了Web服务容器可以同时处理多少个请求,默认值是200。

个人经验:
1C2G,线程数200
4C8G,线程数800

  • accept-count:最大等待连接数
    当调用HTTP请求数达到Tomcat的最大线程数时,还有新的请求进来,这时Tomcat会将该剩余请 求放到等待队列中
    默认值是100,如果等待队列超了,新的请求会被拒绝(connection refused)

  • Max Connections:最大连接数

最大连接数是指在同一时间内,Tomcat能够接受的最大连接数。如果设置为-1,则表示不限制

默认值: 对BIO模式,默认值是Max Threads;如果使用定制的Executor执行器,哪默认值将是执行器 中Max Threads的值。
对NIO模式,Max Connections 默认值是10000

  • IO模型

众所周知文件读写性能是影响应用程序性能的关键因素之一。NIO与原来的IO有同样的作用和目的,但 是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO以更加高效的方式进行文件 的读写操作。
Java的NIO【new io】是从Java 1.4版本开始引入的一套新的IO API用于替代标准的Java IO API。 JDK1.7之后,Java对NIO再次进行了极大的改进,增强了对文件处理和文件系统特性的支持。我们称之 为AIO,也可以叫NIO2。

优化:使用NIO2的Http协议实现,对请求连接器进行改写。

@Configuration
public class TomcatConfig {
//自定义SpringBoot嵌入式Tomcat
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new
TomcatServletWebServerFactory() {};
tomcat.addAdditionalTomcatConnectors(http11Nio2Connector());
return tomcat;
}
//配置连接器nio2
public Connector http11Nio2Connector() {
Connector connector=new
Connector("org.apache.coyote.http11.Http11Nio2Protocol");
Http11Nio2Protocol nio2Protocol = (Http11Nio2Protocol)
connector.getProtocolHandler();
//等待队列最多允许1000个线程在队列中等待
nio2Protocol.setAcceptCount(1000);
// 设置最大线程数
nio2Protocol.setMaxThreads(1000);
// 设置最大连接数
nio2Protocol.setMaxConnections(20000);
//定制化keepalivetimeout,设置30秒内没有请求则服务端自动断开keepalive链接
nio2Protocol.setKeepAliveTimeout(30000);
//当客户端发送超过10000个请求则自动断开keepalive链接
nio2Protocol.setMaxKeepAliveRequests(10000);
// 请求方式
connector.setScheme("http");
connector.setPort(9003); //自定义的端口,与源端口9001
可以共用,知识改了连接器而已
connector.setRedirectPort(8443);
return connector;
}
}

结论:可以发现服务响应时间大幅缩短,并且稳定

小结:将NIO升级为AIO之后,RT的毛刺大幅降低,异常数(超时3s)几乎为0。

2.2 容器优化Tomcat升级Undertow

Undertow是一个用Java编写的灵活的高性能Web服务器,提供基于NIO的阻塞和非阻塞API。

  • 支持Http协议
  • 支持Http2协议
  • 支持Web Socket
  • 最高支持到Servlet4.0
  • 支持嵌入式

SpringBoot的web环境中默认使用Tomcat作为内置服务器,其实SpringBoot提供了另外2种内置的服务 器供我们选择,我们可以很方便的进行切换。

  • Undertow红帽公司开发的一款基于 NIO 的高性能 Web 嵌入式服务器 。轻量级Servlet服务器, 比Tomcat更轻量级没有可视化操作界面,没有其他的类似jsp的功能,只专注于服务器部署,因此 undertow服务器性能略好于Tomcat服务器;
  • Jetty开源的Servlet容器,它是Java的web容器。为JSP和servlet提供运行环境。Jetty也是使用Java 语言编写的。

配置操作过程:

  1. 在spring-boot-starter-web排除tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
  1. 导入其他容器的starter
<!--导入undertow容器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
  1. 配置
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接
server.undertow.threads.io: 800
# 阻塞任务线程池, 当执行类似servlet请求阻塞IO操作, undertow会从这个线程池中取得线
程
# 默认值是IO线程数*8
server.undertow.threads.worker: 8000
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内
存管理
# 每块buffer的空间大小越小,空间就被利用的越充分,不要设置太大,以免影响其他应用,合
适即可
server.undertow.buffer-size: 1024
# 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region
# 是否分配的直接内存(NIO直接分配的堆外内存)
server.undertow.direct-buffers: true

小结:
更换了服务容器之后,RT更加平稳,TPS的增长趋势更平稳,异常数(超时3s)几乎为0。
在低延时情况下,接口通吐量不及Tomcat。
稳定压倒一切,如果只是写json接口,且对接口响应稳定性要求高,可以选用Undertow

2.3 数据库调优

影响数据库性能:

  • 服务器: OS、CPU、Memory、Network
  • MySQL :
    数据库表结构【对性能影响最大】
    低下效率的SQL语句
    超大的表
    大事务
    数据库配置
    数据库整体架构

数据库调优途径:

  • 优化SQL语句调:根据需求创建结构良好的SQL语句【实现同一个需求,SQL语句写法很多】
  • 数据库表结构调优:索引,主键,外键,多表关系等等
  • MySQL配置调优:最大连接数,连接超时,线程缓存,查询缓存,排序缓存,连接查询缓存等等
  • 服务器硬件优化:多核CPU、更大内存

2.4 OpenResty调优

OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方 模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服 务和动态网关。OpenResty的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻 塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

小结:使用了OpenResty反向代理了服务,TPS会在原有的基础上再翻倍!

2.5 缓存调优

压力测试​​

缓存预热

2.6 JVM调优

3. 项目重构

3.1 重构原因

  • 代码排版风格不一致,函数、变量命名随意,错别字,拼音命令都有出现。
  • 存在不少废弃代码(代码被注释,或者代码没有被使用)
  • 包结构混乱,导致开发经常重复实现已有的功能
  • 过滤器滥用并且没有设置优先级
  • 日志打印千奇百怪,不注意控制日志级别
  • 参数校验满天飞,一个函数中关于桉树校验的逻辑可能有许多行
  • 错误码泛滥,散落在各个文件,工具类也泛滥
  • 函数方法不封装,封装不合理
  • 接口文档和代码不一致,接口文档无法及时刷新

3.2 重构的要求

重构可达可小,小到一个变量名和函数名的改动这类微重构,大到重写整个接口业务逻辑的系统性重构
对于微重构,可以做在平时,穿插在问题修改,需求开发过程中
需要制定完整的详细计划
熟悉代码结构,业务场景
确定重构范围
确认参与人员

3.3 重构步骤

  • 第一阶段:利用工具批量修复问题
  • 第二阶段:删除冗余代码
  • 第三阶段:深入到代码进行重构
  • 第四阶段:测试验证
  • 第五阶段:代码检视

http://www.kler.cn/a/458858.html

相关文章:

  • Docker 安装与配置 Nginx
  • 嵌入式系统 第七讲 ARM-Linux内核
  • 【QGIS入门实战精品教程】7.3:QGIS制作千层饼(DEM+等高线+影像+TIN)
  • MySQL数据库——常见慢查询优化方式
  • LeetCode - 初级算法 数组(删除排序数组中的重复项)
  • STM32-笔记23-超声波传感器HC-SR04
  • 基于YOLOv10和BYTETracker的多目标追踪系统,实现地铁人流量计数功能(基于复杂场景和密集遮挡条件下)
  • 前端学习DAY29(1688侧边栏)
  • NPM组件包 vant部分版本内嵌挖矿代码
  • 《燕云十六声》d3dcompiler_47.dll缺失怎么解决?
  • 深度学习中的HTTP:从请求到响应的计算机网络交互
  • JVM实战—5.G1垃圾回收器的原理和调优
  • windows 下通过脚本方式实现 类似 Linux keepalived IP 动态绑定效果
  • 有限元分析学习——Anasys Workbanch第一阶段笔记(2)应力奇异及位移结果对比、初步了解单元的基本知识
  • JVM的详细介绍
  • 【机器学习】 卷积神经网络 (CNN)
  • 基于Docker基础与操作实战
  • 【WdatePicker】选择不能小于当天
  • 深度学习模型格式转换:pytorch2onnx(包含自定义操作符)
  • 当现代教育技术遇上仓颉---探秘华为仓颉编程语言与未来教育技术的接轨
  • 电子电器架构 ---什么是智能电动汽车上的BMS?
  • VScode怎么重启
  • C# init 关键字的使用
  • 【ArcGIS Pro/GeoScene Pro】可视化时态数据
  • javaweb线上问题排查(若依定时任务)
  • 分布式版本管理工具——git 中忽略文件的版本跟踪(初级方法及高级方法)