性能 - 性能调优的常见手段 性能调优的五步法有哪些?
bigegpt 2024-10-12 06:08 7 浏览
常见的互联网架构中,一般都能看到 Spring + MyBatis + MySQL + Redis 搭配的身影。一般来说,应用内部的接口都是直接调用的,所谓的面向接口编程,应用间的调用直接调或者通过类似 Dubbo 之类的服务框架来执行,数据格式往往采用 JSON,即统一也方便各数据间做转换和取值,缓存一般使用 Redis 或 Memcached,存储一些对象或 JSON 格式的字符串。对外提供的接口,一般都需要进行压力测试,以便估算其性能,并为后续的调优提供指导方向,以下接口便是在压测过程中出现的各种“奇怪现象”,所谓奇怪,指的是从表象上看与我们正常的逻辑思路不符,但其本质还是我们对压力下程序的表现出来的特征不熟悉,用惯用的知识结构试图去解释,这根本是行不通的。下文是我在一次全面压测过程后对数据进行的分析汇总,其中的现象是很多压测常见的,里面的分析过程及改进措施我认为有很大的参考意义。具体内容如下:(部分接口为了安全我省略了其名称,但不影响我们的分析,另外形如 1N3T 之类的表示的是 1 台 Nginx,3 台 Tomcat,具体的 TPS 数值只是为了说明优化前后的比照,没有实际意义)
名词解释
TPS
每秒钟处理完的事务次数,一般 TPS 是对整个系统来讲的。一个应用系统 1s 能完成多少事务处理,一个事务在分布式处理中,可能会对应多个请求,对于衡量单个接口服务的处理能力,用 QPS 比较多。
QPS
每秒钟处理完请求的次数;注意这里是处理完。具体是指发出请求到服务器处理完成功返回结果。可以理解在 Server 中有个 Counter,每处理一个请求加 1,1 秒后 Counter = QPS。
RT
响应时间,处理一次请求所需要的平均处理时间
并发量
系统能同时处理的请求数
真实调优案例
接口:获取列表
压测现象:单台 TPS 700 多,应用 CPU 高负载
问题分析
旧框架,平均响应时间长,应用 CPU 高,程序内部有大量的 BEAN 到 MAP 到 JSON 之间的转换,修改数据库连接数后,TPS 没有提升。
改进措施
重构系统,用 MyBatis 替代之前的 DAO 操作,减少 BEAN - MAP - JSON 之间的内部数据转换,减少程序内部的无用操作。
改进效果
TPS 改进后能到 3000 左右,有较大提升,但压测时应用 CPU 几乎跑满,还有改善空间。
压测现象:数据库资源利用率高
问题分析
单台应用,数据库资源 CPU 都能到 50%,10 台 TOMCAT 在 1万 并发下数据库 CPU 跑满,LOAD 值 700 多,但 DB 的 QPS 也不过 11554,并不算多,因此怀疑是 SQL 执行耗费了 CPU,可能是某条 SQL 没有按索引查找或者索引失效。
改进措施
查看 SQL 文件发现如下 sql:select count(1) from orders where order_status_id !=40 ,将其改为 select order_id from orders 然后通过程序把 order_status_id != 40 的过滤掉。通过 list.size() 来获取。order_status_id 即使加了索引,由于是 != 比较,所以不会去按索引查找,导致 CPU 高
改进效果
相同环境下(1台 Nginx,10 台 Tomcat,1000 并发),TPS 由 3000 变成 3727,略有增长,但是 DB 的 CPU 明显下降,变为 30%,效果明显
压测现象:1N15T,TPS 4552;10N15T,TPS 9608
问题分析
后端都是 15 台 Tomcat,前端 1 台 Nginx 时 TPS 为 4552,通过 LVS 挂 10 台 Nginx 时为 9608,增长不明显,其 Nginx 和 Tomcat 都压力不大,集群结果不合理,怀疑是 Nginx 转发配置的问题;
改进措施
未进一步改进:可能是需要调整 Nginx 的参数,之前发现过 Nginx 不同的配置对后端集群环境的 TPS 影响很大
改进效果
无
接口:信息查询
压测现象:单台 TPS 2000 多,应用 CPU 高,DB 的 QPS 15000 左右
问题分析
旧框架,程序内部有很多 Bean - Map - Json 相互的转换
改进措施
删除冗余代码、更换连接池包,使用 MyBatis
改进效果
TPS 由 2000 多增长为 8000 多,DB 的 QPS 为 9000 左右,优化后压测应用的 CPU 占用高,几乎跑满。
压测现象:数据库无压力,应用增加多台后 TPS 不变
问题分析
1N1T 和 1N10T 的 TPS 一样,都为 5000,增大并发时错误数增多,应用 CPU 耗费 70%,DB 无压力,Nginx 单台通过 ss –s 发现端口占满,即 Nginx 到 Tomcat 之间转发的连接端口 time-wait 状态 6 万多。Nginx 存在瓶颈。
改进措施
调优 Nginx 参数,将短连接改为长连接
改进效果
1N3T 的 TPS 能到 17376,Tomat 的 CPU 压力 84%,DB 的 QPS 18000,CPU 69%,应用的资源基本使用到量。
接口:获取详情
压测现象:单台应用 TPS 2600,10 台 Tomcat 才 3700
问题分析
增加应用服务器,TPS 增长不明显,且 Nginx、Tomcat、DB 的负载都不高,说明服务器本身不是瓶颈,考虑是不是网络的问题,通过监控网卡包流量发现网络数据跑满,因为此接口会有大量数据的输出,因此瓶颈在网络上。另外,测试过程中发现 Redis 有报错,Redis 服务器是虚机,可能服务能力有限。
改进措施
开启 Tomcat 的 gzip 压缩。
改进效果
同等并发下(1 台 Nginx,10 台 Tomcat,1000 并发),TPS 由 3727 增长到 10022,增长了近 3 倍,效果显著。
压测现象:1N10T 集群下 Nginx 参数调优对 TPS 提升效果明显
问题分析
经过 Tomcat 的启用 gzip 后,1N10T 下 TPS 为 10022,需进一步提升。
改进措施
优化 Nginx:
- Nginx 日志关闭
- Nginx 进程数量 worker,由 24 改为 16
- nginx keepalive 数量由 256 改为 2048
改进效果
TPS 由 10022 提升为 13270。
压测现象:1N5T 和 1N10T 的 TPS 相差不大
问题分析
1N10T 的 TPS 为 1万3千多,1N5T 的 TPS 为 1万2千多,相差不大,应用的 Tomcat 资源利用没满,CPU 为 65%,DB 的 QPS 已经到 2万多了,单台服务器 DB 基本上到量了,因此再增加应用也没效果,只会导致响应的时间变长。
改进措施
单台 DB 已经无法改进了,要不提升服务器硬件,要不读写分离。
改进效果
无
接口:促销
压测现象:通过 Redis 存取数据,TPS 才 1000 多,CPU 有压力
问题分析
此接口通过 Redis 取数据,TPS 不高才 1000 多,但 CPU 占用了 80%,说明程序内部有大量序列化反序列化的操作,可能是 JSON 序列化的问题。
改进措施
将 net.sf.json 改成 alibaba 的 fastjson
改进效果
同等并发条件下 TPS 由 1000 多提升为 5000 多,提高了近5倍。
压测现象:参数多时 TPS 下降明显
问题分析
此接口根据参数从 Redis 中获取数据,每个参数与 Redis 交互一次,当一组参数时 TPS 5133,五组参数时 TPS 1169,多次交互影响了处理性能。
改进措施
将从 Redis 获取数据的 get 改为 mget,减少交互次数。
改进效果
五组参数时 1N3T 压测 TPS 9707,据此估算即使是单台 Tomcat,TPS 也能有三四千,性能比单次 get 的调用方式提升了 3,4 倍。
压测现象:1N3T TPS 1万多,在增大 Tomcat 可能 TPS 增长不会明显
问题分析
此处说的是可能,因为 Nginx 服务器的 CPU 虽然不高,但 QPS 已经 8000 多,此时应该是 Nginx 的服务器网络流量成为了瓶颈。(只是猜测)
改进措施
可以增加多台 Nginx 负载,前端加 LVS
接口:追踪接口
压测现象:1N10T 的 TPS 低于 1N3T 的 TPS
问题分析
1N3T 在 2000 并发下 TPS 为 9849,此时 DB 的 QPS 为 90000,CPU 80%,将 Tomcat 增到 10 台,5000 并发下,TPS 为 7813,DB 的 QPS 为 19000,CPU 75%,load 1,说明压力增大情况下 DB 的压力反而下来了,注意到 Nginx 服务器的网卡流量达到 885M,说明是压力过大情况下,网络满了,发生丢包,导致 DB 端压力反而下来了。
改进措施
注意压测情况下部分接口由于数据量传输较大,会出现网络瓶颈。
接口:回填接口
压测现象:TPS 不到 500,DB 的 QPS 3500
问题分析
虽然缺少应用的 CPU 及 DB 的 CPU 利用率数据,较低的 TPS 应该是应用的瓶颈,且需要关注是不是 DB 在处理查询的时候缓慢。
改进措施
- 连接池由 DBCP 改为 HIKAR
- 减少了日志打印输出
- SQL 优化,将部分条件过滤改为在 Java 代码中执行
改进效果
TPS 由不到 500 增长为 1300 多
接口:券查询
压测现象:集群结果与单台应用结果相比不合理
问题分析
查看是否存在瓶颈资源,可以看到 5 台 Tomcat 集群下,TPS 为 9952,但 DB 的 QPS 为 5-6 万,CPU 利用率为 37%,说明对数据库进行了大量的主键或索引查询,一般单台 DB 的 QPS 也就 4万左右,再增加应用的集群数量,对 TPS 也不会有太大影响。
改进措施
可以考虑分库
接口:推荐
压测现象:Nginx 长短连接差异
问题分析
18 台 Nginx,2 Tomcat 时 TPS 8100,此时应用服务器的端口数满,一般来说,Nginx 短连接在高并发下容易导致端口占满的问题。
改进措施
将 Nginx 改为长连接
改进效果
TPS 增长为 10733,TPS 稳定,起伏减少,但是 CPU 耗尽。说明 CPU 打满了,此时如果还要优化就的进行代码调优了。
接口:查询
压测现象:18N20T 的 TPS 才 6842
问题分析
18 台 Nginx,20 台 Tomcat,TPS 才 6842,此时应用 CPU 利用率 85%,说明 CPU 存在瓶颈,但检查此接口并未做大计算量的工作,有可能是日志的级别问题,CPU 在频繁的打日志。
改进措施
将日志级别由 DEBUG 级改为 INFO 级
改进效果
同等环境 TPS 由 6842 增长为 23592
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,
咱们下期见!学习更多JAVA知识与技巧,关注与私信博主(666)
相关推荐
- Go语言泛型-泛型约束与实践(go1.7泛型)
-
来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...
- golang总结(golang实战教程)
-
基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...
- Go 官宣:新版 Protobuf API(go pro版本)
-
原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...
- Golang开发的一些注意事项(一)(golang入门项目)
-
1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...
- golang 托盘菜单应用及打开系统默认浏览器
-
之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...
- golang标准库每日一库之 io/ioutil
-
一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...
- 文件类型更改器——GoLang 中的 CLI 工具
-
我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...
- Go (Golang) 中的 Channels 简介(golang channel长度和容量)
-
这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...
- Golang引入泛型:Go将Interface「」替换为“Any”
-
现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...
- 一文带你看懂Golang最新特性(golang2.0特性)
-
作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...
- Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移
-
以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...
- Golang使用grpc详解(golang gcc)
-
gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...
- Etcd服务注册与发现封装实现--golang
-
服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...
- Golang:将日志以Json格式输出到Kafka
-
在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...
- 如何从 PHP 过渡到 Golang?(php转golang)
-
我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- linux安装minio (74)
- ubuntuunzip (67)
- vscode使用技巧 (83)
- secure-file-priv (67)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)