找回密码
 加入怎通
查看: 464|回复: 0

从发现到优化,解决性能问题通用思路(发现就是硬道理)

[复制链接]
我来看看 发表于 2023-04-09 00:47:04 | 显示全部楼层 |阅读模式
9 L1 X) o# V, Y3 }

原标题:从发现到优化,解决性能问题通用思路一、文章概述技术系统有一个发展过程,在业务初期主要是实现业务功能和目标,由于数据和访问量都不大,所以性能问题并不作为首要考虑但是随着业务发展,随着数据和访问量增大甚至激增,造成例如首页五秒钟才能展示等问题,这种不佳体验会造成用户流失,此时性能就是必须面对之问题。

# f$ _3 D R9 d3 n$ o

我们把技术系统分为早期、中期、后期三个阶段:早期:主要实现业务需求,性能非重点考虑中期:性能问题注解显现,影响业务发展后期:技术迭代性能与业务必须同时考虑如何发现性能问题,并且最终如何解决性能问题就是本文讨论之要点。

' Y0 w" I7 q# s+ A% v+ A# [0 Z* D

二、什么是性能我们可以从四个维度介绍什么是性能:两个维度定义性能:速度慢压力大两个维度描述性能:定性:直观感受定量:指标分析三、发现性能问题1、定性 + 速度一个页面需要长时间打开,一个列表很慢才能加载完成,一个接口访问导致超时异常,这些显而易见之问题可以归为此类。

$ x. G5 c! d. V. E4 a- l. M

2、定量 + 速度1)速度指标一个公司有7200名员工,每天上班打卡时间是早上8点到8点30分,每次打卡时间系统执行时长5秒,那么RT、QPS、并发量分别是多少?RT表示响应时间,问题已经包含答案:RT = 5秒

( k2 M; k3 z, Y* g. i

QPS表示每秒访问量,假设行为平均分布:QPS = 7200 / (30 * 60) = 4并发量表示系统同时处理请求数:并发量 = QPS x RT = 4 x 5 = 20根据上述实例引出公式:并发量 = QPS x RT

s# T8 _6 F% ^$ X7 B

2)QPS VS TPSQPS(Queries Per Second):每秒查询量TPS(Transactions Per Second):每秒事务数需要注意此事务并不是指数据库事务,而是包括以下三个阶段:

4 ^. j" c$ x: n

接收请求处理业务返回结果QPS = N * TPS (N>=1)N=1表示接口有一个事务:public class OrderService {public Order queryOrderById(String orderId) {

2 ]5 M9 B1 ?6 N, ~4 L/ b) E

return orderMapper.selectById(orderId);}}N>1表示接口有多个事务:public class OrderService {public void updateOrder(Order order) {

: d; C4 ^- y R6 C* H! q

// transaction1orderMapper.update(order);// transaction2sendOrderUpdateMessage(order);}}3)发现问题①打印日志public class FastTestService {

6 Q' Z, a4 [5 f' P* k

public void test01() {long start = System.currentTimeMillis();biz1();biz2();long costTime = System.currentTimeMillis() - start;

_8 ~+ P! y9 J

System.out.println("costTime=" + costTime);}private void biz1() {try {System.out.println("biz1");Thread.sleep(500L);

4 ?1 E- Q- j [

} catch (Exception ex) {log.error("error", ex);}}private void biz2() {try {System.out.println("biz2");

7 V6 z$ n0 T: h6 [, T* Z4 D* @% |

Thread.sleep(1000L);} catch (Exception ex) {log.error("error", ex);}}}②StopWatchimport org.springframework.util.StopWatch;

7 L+ J5 q A1 ~& B

import org.springframework.util.StopWatch.TaskInfo;public class FastTestService {public void test02() {

& K6 D. A8 Y& k

StopWatch sw = new StopWatch("testWatch");sw.start("biz1");biz1();sw.stop();sw.start("biz2");biz2();sw.stop();

$ C- b8 ?) T- A% s1 K5 X0 [

// 简单输出耗时System.out.println("costTime=" + sw.getTotalTimeMillis());System.out.println();// 输出任务信息TaskInfo[] taskInfos = sw.getTaskInfo();

6 }4 w! }# D5 V& R$ h

for (TaskInfo task : taskInfos) {System.out.println("taskInfo=" + JSON.toJSONString(task));}System.out.println();

! i6 _" x0 A1 p" W# A

// 格式化任务信息System.out.println(sw.prettyPrint());}}输出结果:costTime=1526taskInfo={"taskName":"biz1","timeMillis":510,"timeNanos":510811200,"timeSeconds":0.5108112}

J {" c1 E- v- U2 l

taskInfo={"taskName":"biz2","timeMillis":1015,"timeNanos":1015439700,"timeSeconds":1.0154397}StopWatch testWatch: running time = 1526250900 ns

0 o9 x# ^0 s- _0 {6 K; K9 U

---------------------------------------------ns % Task name---------------------------------------------

0 _( x0 l1 m( L* `' A# c

510811200 033% biz11015439700 067% biz2③traceArthas是阿里开源Java诊断工具:Arthas是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率

5 K9 n- H3 o1 N! [

Arthas trace命令监控链路每个节点耗时:https://arthas.aliyun.com/doc/trace.html我们通过实例说明,首先编写并运行代码:package java.front.optimize;

" a) D5 q( q; Q+ z; Q8 b4 ^

public class FastTestService {public static void main(String[] args) {FastTestService service = new FastTestService();

5 O* `% @7 K1 |7 z/ C

while (true) {service.test03();}}public void test03() {biz1();biz2();}private void biz1() {try {System.out.println("biz1");

) e( E! a8 Z( C

Thread.sleep(500L);} catch (Exception ex) {log.error("error", ex);}}private void biz2() {try {System.out.println("biz2");

7 W/ b% b3 U3 l

Thread.sleep(1000L);} catch (Exception ex) {log.error("error", ex);}}}第一步进入arthas控制台:$ java -jar arthas-boot.jar

$ ]9 Y) `. ~' S2 W* F* ?5 s

[INFO] arthas-boot version: 3.6.2[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER

4 @" ^, W% {4 H& x/ f. ~

* [1]: 14121[2]: 20196 java.front.optimize.FastTestService第二步输入监控进程号并回车第三步trace命令监控相应方法:trace java.front.optimize.FastTestService test03

$ J* m# k: o: A% J: w

第四步查看链路耗时:`---[1518.7362ms] java.front.optimize.FastTestService:test03()+---[33.66% 511.2817ms ] java.front.optimize.FastTestService:biz1() #54

0 |& E+ B( h1 T3 z/ M- e

`---[66.32% 1007.2962ms ] java.front.optimize.FastTestService:biz2() #553、定性 + 压力系统压力大也会表现出速度慢之特征,但是这种慢不仅仅是需要几秒后才能打开网页,而是网页一直处于加载状态最终白屏。

# S# }; N/ A! R8 x; r, j

4、定量 + 压力服务器常见压力指标如下:内存CPU磁盘网络服务端开发比较容易引发内存和CPU问题,所以我们重点关注1)发现CPU问题首先编写一段造成CPU飙高之代码并运行:public class FastTestService {。

9 y: S. p" L& E* I* |* x

public static void main(String[] args) {FastTestService service = new FastTestService();while (true) {

& q# o7 T6 K7 _" d/ z

service.test();}}public void test() {biz();}private void biz() {System.out.println("biz");}}①dashboard + thread

( g/ L% V5 P6 @8 @

dashboard查看当前系统实时面板,发现线程ID=1 CPU占用非常高(这个ID不可以与jstack nativeID相对应):$ dashboardID NAME GROUP PRIORI STATE %CPU DELTA TIME TIME INTERRU DAEMON

$ y! C0 u. V S% T% w2 B

1 main main 5 RUNNA 96.06 4.812 2:41.2 false falsethread查看最忙前N个线程:$ thread -n 1"main" Id=1 deltaTime=203ms time=1714000ms RUNNABLE

- ]: M0 V |! J. z4 D% L* v" ] F

at app//java.front.optimize.FastTestService.biz(FastTestService.java:83)at app//java.front.optimize.FastTestService.test(FastTestService.java:61)

: E8 b5 k& J% X b. v. S

at app//java.front.optimize.FastTestService.main(FastTestService.java:17)2)发现内存问题①free$ free -htotal used free shared buff/cache available

' {. N4 E* s) Y: j: r3 ^

Mem: 10G 5.5G 3.1G 28M 1.4G 4.4GSwap: 2.0G 435M 1.6Gtotal服务器总内存used已使用内存free未被任何应用使用空闲内存shared被共享物理内存

% C: I: r% L2 j$ j8 q& Q1 |

cacheIO设备读缓存(Page Cache)buffIO设备写缓存(Buffer Cache)available可以被程序应用之内存②memoryArthas memory命令查看JVM内存信息:https://arthas.aliyun.com/doc/heapdump.html

; ?* V! J( B! N# ?

查看JVM内存信息(官方实例)$ memoryMemory used total max usageheap 32M 256M 4096M 0.79%g1_eden_space 11M 68M -1 16.18%

" O# W- ~/ e1 Z7 b x

g1_old_gen 17M 184M 4096M 0.43%g1_survivor_space 4M 4M -1 100.00%nonheap 35M 39M -1 89.55%codeheap_non-nmethods 1M 2M 5M 20.53%

0 F2 g3 f/ s) X9 ~* Y& N" Z9 |* v4 z: Q

metaspace 26M 27M -1 96.88%codeheap_profiled_nmethods 4M 4M 117M 3.57%compressed_class_space 2M 3M 1024M 0.29%

$ b, w% k+ H, _0 x! x0 W

codeheap_non-profiled_nmethods 685K 2496K 120032K 0.57%mapped 0K 0K - 0.00%direct 48M 48M - 100.00%③jmap

. W6 D! Q, ^6 @0 E" ]. n& `

查看JAVA程序进程号jps -l查看实时内存占用jhsdb jmap --heap --pid 20196导出快照文件jmap -dump:format=b,file=/home/tmp/my-dump.hprof 20196

4 W- U' D6 D% P, n

内存溢出自动导出堆快照-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath==/home/tmp/my-dump.hprof④heapdumpArthas heapdump命令支持导出堆快照:

: _& C' @# I' T" D

https://arthas.aliyun.com/doc/heapdump.htmldump至指定文件heapdump /home/tmp/my-dump.hprofdump live对象至指定文件heapdump --live /home/tmp/my-dump.hprof

A b' ?9 o1 W8 D7 n; i0 s

dump至临时文件heapdump⑤垃圾回收jstat可以查看垃圾回收情况,观察程序是否频繁GC或者GC用时是否过长:jstat -gcutil 每秒查看垃圾回收情况

3 p# m# w. R* U" b5 [

$ jstat -gcutil 20196 1000S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT0.00 0.00 57.69 0.00 - - 0 0.000 0 0.000 0 0.000 0.000

9 s5 C1 g4 F/ J+ g6 ^- x+ ^# W

0.00 0.00 57.69 0.00 - - 0 0.000 0 0.000 0 0.000 0.0000.00 0.00 57.69 0.00 - - 0 0.000 0 0.000 0 0.000 0.000

i% y3 J. `. k+ J) ]) \+ V( _

各参数说明如下:S0:新生代中Survivor 0区占已使用空间比例S1:新生代中Survivor 1区占已使用空间比例E:新生代占已使用空间比例O:老年代占已使用空间比例P:永久带占已使用空间比例YGC:应用程序启动至今,发生Young GC次数

( E- ^- M! ~. c4 E) ~1 w

YGCT:应用程序启动至今,Young GC所用时间(秒)FGC:应用程序启动至今,发生Full GC次数FGCT:应用程序启动至今,Full GC所用时间(秒)GCT:应用程序启动至今,所用垃圾回收总时间(秒)

8 u2 ]/ m' J; N0 ]4 s4 k

3)综合发现问题①压力测试进行系统压测可以主动暴露系统问题,评估系统容量,简单常用参数如下:常用工具:JMeter阶梯发压:线程数10、20、30递增至瓶颈持续时间:持续1分钟,Ramp-Up=0TPS:Throughput

7 b" ` Y( T8 i( |( L

响应时间:重点关注95Line②监控系统监控系统可以更加友好展示相关指标,如果公司具有一定技术实力可以自研,否则可以选择使用业界通用方案四、优化性能问题1、四个方法减少请求空间换时间任务并行化任务异步化。

9 f" j9 f2 S( V

2、五个层面代理层前端层服务层缓存层数据层3、优化说明一说到性能优化不难想到例如加索引、加缓存等方案,这也许是正确的,但是这样思考可能会造成遗漏,因为这只是缓存层和数据层的方案如果可以将无效流量在最外层拒绝,那么这是对系统更好地好保护。

) F0 w3 v( Q. ] ~; \& `6 U' l2 Q. t

四个方法可以应用在每一个层面,我们不妨举一些例子:1)减少请求 + 前端层在秒杀场景中设置前置验证码2)减少请求 + 服务层多次RPC是否可以转换为一次批量RPC3)空间换时间 + 服务层引入缓存4)空间换时间 + 缓存层

9 r5 _. u B6 N" N# k

引入多级缓存5)空间换时间 + 数据层新增索引6)任务并行化 + 服务层如果多个调用互不依赖,使用Future并行化7)任务异步化 + 服务层如果无需等待返回结果,可以异步执行五、文章总结第一本文讨论了系统早期、中期、后期如何看待性能问题,第二讨论了什么是性能,第三讨论了如果发现性能问题,第四讨论了如何优化性能问题,希望本文对大家有所帮助。

% U1 x8 s9 {6 ~- [

作者丨IT徐胖子来源丨公众号:JAVA前线(ID:www_xpz)dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn活动推荐第八届DAMS-中国数据智能管理峰会将于2023年3月31日在上海举办

0 ?+ Q: i3 Y- v6 G& _

,与大家一起探索大数据与云原生强强联合的方式、挖掘由此激发的软件发展和技术进步报名链接:https://www.bagevent.com/event/8100960?bag_track=SH演讲嘉宾所在单位:。

2 e! K. b: H7 {) V& A7 z* }( q. k" K* M

阿里、腾讯、京东、美团、华为云、字节、蚂蚁、网易、新浪、携程、哔哩哔哩、小红书、vivo、快狗打车、货拉拉、工商银行、建设银行、中国银行、平安银行、光大银行、汇丰银行、微众银行、复旦大学等产学研界技术领跑单位。

) ~( M; H4 V3 Q- Y4 X

演讲议题聚焦:大数据&数据资产管理:数据治理丨存算分离丨云原生OLAP丨湖仓一体丨智能分析数据库:云原生分布式丨时间序列丨服务自治丨中间件丨跨云多活运维:AIOps丨故障分析丨性能优化丨离在线混部丨高可用建设

9 H9 }( ]% y0 \8 ^& A, c

金融科技:规模化监控丨实时数仓丨分布式改造丨国产化替代丨数字化转型丨混沌工程返回搜狐,查看更多责任编辑:

! J8 N# q) a) \% h $ r3 z- u2 c# O ' n: \; }( h6 Z2 D4 o7 h b ! e* Z4 ?5 ?( I" Z( p3 y7 D# P, i7 ^
回复

使用道具 举报

    您需要登录后才可以回帖 登录 | 加入怎通

    本版积分规则

    QQ|手机版|小黑屋|网站地图|真牛社区 ( 苏ICP备2023040716号-2 )

    GMT+8, 2026-4-3 10:03 , Processed in 0.162053 second(s), 22 queries , Gzip On.

    免责声明:本站信息来自互联网,本站不对其内容真实性负责,如有侵权等情况请联系420897364#qq.com(把#换成@)删除。

    Powered by Discuz! X3.5

    快速回复 返回顶部 返回列表