1. 服务器性能优化的核心指标解析当服务器负载飙升时最直观的表现就是响应变慢甚至服务不可用。要解决这个问题我们首先需要理解三个关键性能指标CPU、内存和磁盘I/O。这就像医生看病要先量血压、测心跳一样服务器诊断也要从这些基础指标入手。CPU使用率是判断计算资源是否过载的首要指标。正常情况下CPU使用率应该在70%以下如果长期超过90%就说明计算资源吃紧。我遇到过最极端的情况是某个Java应用因为线程死锁导致CPU飙到100%整个系统直接卡死。这时候用top命令就能快速定位问题进程top -c内存方面主要看两个指标使用量和交换分区swap情况。物理内存不足时系统会开始使用swap但swap的性能比物理内存差很多一旦开始频繁交换性能就会断崖式下降。可以用free -h查看内存状态free -h total used free shared buff/cache available Mem: 62G 25G 3.2G 1.2G 33G 35G Swap: 8.0G 512M 7.5G磁盘I/O问题往往最难排查。我曾经处理过一个MySQL查询变慢的问题最后发现是因为磁盘队列长度await太高。使用iostat可以查看磁盘负载iostat -x 1 Device r/s w/s rkB/s wkB/s await svctm %util sda 5.00 20.00 320.00 1280.00 12.00 4.00 10.002. CPU性能优化实战2.1 压力测试工具的选择与使用要对CPU进行压力测试我推荐使用sysbench这个多线程基准测试工具。它不仅可以测试CPU性能还能测试内存、磁盘和数据库性能。安装很简单# Ubuntu/Debian sudo apt install sysbench # CentOS/RHEL sudo yum install sysbench测试CPU性能的命令如下这里用40个线程计算质数到20000sysbench cpu --threads40 --cpu-max-prime20000 run测试结果中要特别关注events per second这个指标数值越高说明CPU性能越好。在我的测试中AMD EPYC 7763处理器的成绩是Intel Xeon 8380的1.3倍左右。2.2 代码层面的CPU优化在实际项目中我见过太多因为代码不当导致CPU使用率飙升的案例。有几点经验特别值得分享第一避免不必要的计算。比如有个电商系统在计算商品价格时每次都要重新计算税费和折扣后来改为只在价格变动时计算CPU负载直接降了30%。第二合理使用缓存。我曾经优化过一个天气预报服务把计算结果缓存5分钟QPS从100提升到了2000。用Java实现很简单// 使用Guava Cache LoadingCacheString, WeatherData cache CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterWrite(5, TimeUnit.MINUTES) .build(new CacheLoaderString, WeatherData() { public WeatherData load(String city) { return calculateWeather(city); } });第三选择合适的数据结构。HashMap查找是O(1)而ArrayList的contains是O(n)在大数据量时差异巨大。我曾经把一个使用ArrayList.contains()的代码改为HashSet.contains()执行时间从3秒降到了0.01秒。3. 内存优化深度解析3.1 内存泄漏排查实战内存泄漏是Java应用的常见问题。有一次我们的服务运行几天后就会OOM用jmap和jvisualvm分析后发现是某个静态Map不断增长导致的。排查步骤很经典获取堆转储文件jmap -dump:formatb,fileheap.hprof pid用MAT或jvisualvm分析发现某个Map占了80%内存检查代码发现是缓存没有设置上限和过期时间最终解决方案是改用Caffeine缓存设置最大条目和过期时间CacheString, Data cache Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(1, TimeUnit.HOURS) .build();3.2 内存分配优化技巧JVM内存配置对性能影响巨大。经过多次调优我总结出一个经验公式对于8G物理内存的机器可以这样配置-Xms6g -Xmx6g -XX:MaxMetaspaceSize256m -XX:ReservedCodeCacheSize128m解释一下Xms和Xmx设为相同值避免动态调整开销留2G给操作系统和其他进程Metaspace和CodeCache根据应用类型调整对于Tomcat还需要注意线程数设置。太多线程会导致内存不足太少又无法充分利用CPU。经验值是# 在setenv.sh中设置 export CATALINA_OPTS-Xmx4g -Xms4g -XX:MaxMetaspaceSize256m # 在server.xml中设置 Connector port8080 maxThreads200 minSpareThreads20/4. 磁盘I/O性能调优4.1 文件系统选择与优化磁盘性能调优首先要选对文件系统。经过多次测试我发现对于SSDext4和xfs性能相当对于HDDxfs性能更好对于数据库建议用xfs并设置noatime挂载时可以这样优化# /etc/fstab /dev/sdb1 /data xfs defaults,noatime,nodiratime 0 0对于MySQL这类数据库还要调整I/O调度器。SSD建议用noop或deadlineecho noop /sys/block/sdb/queue/scheduler4.2 数据库I/O优化MySQL的I/O优化我总结为三板斧第一合理设置innodb_buffer_pool_size这个值应该占可用内存的70-80%[mysqld] innodb_buffer_pool_size12G第二调整刷盘策略。对于允许少量数据丢失的场景可以这样设置innodb_flush_log_at_trx_commit2 sync_binlog1000第三使用SSD并开启O_DIRECTinnodb_flush_methodO_DIRECT我曾经用这些优化方法把一个每秒只能处理200请求的MySQL提升到了2000。5. 全链路压力测试方案5.1 测试工具链搭建完整的压力测试需要一套工具链。我的常用组合是JMeter模拟用户请求Prometheus Grafana监控系统指标ELK收集和分析日志一个简单的JMeter测试计划可以这样配置ThreadGroup guiclassThreadGroupGui testclassThreadGroup testnameHTTP测试 enabledtrue intProp nameThreadGroup.num_threads100/intProp intProp nameThreadGroup.ramp_time60/intProp longProp nameThreadGroup.duration300/longProp /ThreadGroup5.2 测试场景设计设计测试场景要考虑真实业务场景。比如电商系统要模拟浏览商品80%请求加入购物车15%下单支付5%可以用JMeter的Throughput Controller来实现ThroughputController guiclassThroughputControllerGui testclassThroughputController testname浏览商品 enabledtrue intProp nameThroughputController.percent80/intProp /ThroughputController测试时要循序渐进先小规模测试再逐步增加压力。我一般按照这个步骤单接口基准测试100并发混合场景测试200并发峰值压力测试最大并发稳定性测试中等压力长时间运行6. 性能问题快速诊断指南遇到性能问题时我有一套快速诊断流程先用top看整体资源使用情况用vmstat 1看CPU、内存、I/O等待用iostat -x 1看磁盘负载用netstat -antp看网络连接用jstack或arthas看Java线程状态对于MySQL这几个命令特别有用-- 查看当前运行的所有SQL SHOW FULL PROCESSLIST; -- 查看锁等待 SELECT * FROM information_schema.INNODB_TRX; -- 查看慢查询 SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10;有一次我们用这套方法仅用10分钟就定位到一个死锁问题而之前团队已经排查了2小时无果。