最近给公司的华硕服务器做了一次性能调优,把接口平均响应时间从500ms降到了100ms,降幅80%。
这台服务器是华硕的RS700-E9系列,跑的是一个Java Web应用,用的是Spring Boot + MySQL。随着用户量增长,接口响应越来越慢,高峰期甚至能到2秒。老板下了死命令,必须在一周内把响应时间降下来。
我花了三天时间,从硬件到软件,从系统到应用,做了一次全面的性能调优。最终效果不错,平均响应时间从500ms降到了100ms,高峰期也能稳定在200ms以内。
本文分享这次调优的完整过程,包括问题定位、BIOS设置、系统优化、应用优化、数据库优化、监控验证等。不只是华硕服务器,这些调优思路对任何服务器都适用。
一、问题定位
调优的第一步,不是上来就改配置,而是先定位问题。
1. 建立性能基线
首先,我建立了性能基线,知道当前的性能是什么水平。
- 平均响应时间:500ms
- P95响应时间:1200ms
- P99响应时间:2000ms
- CPU使用率:高峰期85%
- 内存使用率:70%
- 磁盘IO:util 60%
- 数据库连接数:高峰期接近上限
有了基线,调优之后才能对比效果。
2. 找到瓶颈
然后,我用各种工具找瓶颈。
- 用top看CPU和内存
- 用iostat看磁盘IO
- 用netstat看网络连接
- 用jstack看Java线程状态
- 用慢查询日志看数据库
经过分析,发现了几个瓶颈:
- CPU:高峰期CPU使用率高,其中系统态占比大(sys% > 30%)
- 磁盘IO:数据库的随机写比较多,IO等待时间长
- 数据库:有几个慢查询,没有走索引
- JVM:GC频繁,尤其是Full GC
- 网络:连接数多,TIME_WAIT状态的连接多
找到了瓶颈,就可以针对性优化了。
二、BIOS设置优化
很多人做性能调优,只关注软件,忽略了BIOS。其实,BIOS设置对性能影响很大。
1. 关闭节能模式
华硕服务器的BIOS里,默认开启了节能模式(Power Saving Mode)。节能模式会降低CPU频率,减少功耗,但会影响性能。
我把节能模式改成了"性能模式"(Performance Mode),让CPU一直运行在最高频率。
操作路径: BIOS → Advanced → Power Management → Power Saving Mode → Disabled BIOS → Advanced → CPU Configuration → Intel SpeedStep → Disabled(如果不需要节能)
2. 开启超线程
确认超线程(Hyper-Threading)是开启的。超线程能让一个物理核心模拟两个逻辑核心,提高并发能力。
华硕服务器默认是开启的,但有时候会被关掉。检查一下: BIOS → Advanced → CPU Configuration → Hyper-Threading → Enabled
3. 内存设置
- 确认内存运行在最高频率(DDR4-2933或更高)
- 关闭内存节能模式(Memory Power Saving)
- 开启NUMA(如果是多CPU的服务器)
4. PCIe设置
- 确认PCIe插槽运行在最高速率(Gen3 x16或Gen4 x16)
- 如果用了NVMe SSD,确认PCIe通道分配正确
5. 风扇设置
把风扇策略改成"性能模式",让风扇转速更高,散热更好。温度高了,CPU会降频,影响性能。
BIOS → Advanced → Fan Configuration → Fan Policy → Performance
三、操作系统优化
BIOS设置好之后,优化操作系统。我们用的是CentOS 7。
1. 关闭不必要的服务
关闭不需要的服务,释放CPU和内存。
systemctl disable postfix
systemctl disable firewalld # 如果有其他防火墙
systemctl disable cups
systemctl disable avahi-daemon只保留必要的服务:sshd、network、crond等。
2. 文件描述符限制
默认的文件描述符限制是1024,高并发场景下不够用。
修改 /etc/security/limits.conf:
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535修改 /etc/sysctl.conf:
fs.file-max = 10000003. 网络优化
高并发场景下,网络优化很重要。
修改 /etc/sysctl.conf:
# 开启TCP连接复用
net.ipv4.tcp_tw_reuse = 1
# 开启TCP快速回收
net.ipv4.tcp_tw_recycle = 1
# 减少TIME_WAIT时间
net.ipv4.tcp_fin_timeout = 30
# 增加本地端口范围
net.ipv4.ip_local_port_range = 1024 65535
# 增加TCP最大连接数
net.core.somaxconn = 65535
# 增加TCP接收/发送缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216执行 sysctl -p 生效。
4. 磁盘调度算法
如果用的是机械硬盘,把磁盘调度算法改成deadline或noop,提高IO性能。
echo deadline > /sys/block/sda/queue/scheduler如果用的是SSD,用noop调度算法。
永久生效,在 /etc/rc.local 里加上上面的命令。
5. 文件系统优化
如果用的是ext4,挂载时加上noatime选项,减少磁盘写入。
修改 /etc/fstab:
/dev/sda1 / ext4 defaults,noatime 0 1noatime表示不更新文件的访问时间,能减少磁盘IO。
6. 关闭透明大页
数据库场景下,透明大页(Transparent Huge Pages)会导致性能问题。
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag永久生效,在 /etc/rc.local 里加上。
四、JVM优化
我们的应用是Java写的,JVM优化很重要。
1. 堆内存设置
根据服务器内存,合理设置堆内存。我们的服务器是64G内存,给JVM分配了16G堆。
-Xms16g -Xmx16gXms和Xmx设成一样大,避免动态扩容的开销。
2. GC算法选择
JDK 8用G1 GC,JDK 11+也推荐G1 GC。
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200G1 GC适合大堆内存,能控制GC停顿时间。
3. GC日志
开启GC日志,方便排查GC问题。
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-Xloggc:/var/log/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M4. 其他优化
# 禁用显式GC(System.gc())
-XX:+DisableExplicitGC
# 优化字符串
-XX:+UseStringDeduplication
# 类元数据空间
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m优化后,Full GC从每天几次降到了几乎没有,Young GC的停顿时间也从200ms降到了50ms。
五、应用优化
JVM优化之后,优化应用层。
1. 连接池优化
数据库连接池用的是HikariCP,调整了参数:
spring:
datasource:
hikari:
maximum-pool-size: 50
minimum-idle: 10
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000连接池大小不是越大越好,根据数据库的处理能力设置。一般来说,连接数 = (核心数 * 2) + 有效磁盘数。
2. 线程池优化
应用里的异步线程池,调整了核心线程数和最大线程数。
@Bean
public ExecutorService taskExecutor() {
return new ThreadPoolExecutor(
10, 50, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadFactoryBuilder().setNameFormat("task-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}线程池参数要根据任务类型设置:
- CPU密集型:核心线程数 = CPU核心数 + 1
- IO密集型:核心线程数 = CPU核心数 * 2
3. 缓存优化
增加了本地缓存(Caffeine)和分布式缓存(Redis)。
- 热点数据放本地缓存,减少Redis访问
- 数据库查询结果放Redis,减少数据库压力
- 设置合理的过期时间,避免缓存雪崩
加了缓存之后,很多接口直接从缓存返回,响应时间从几百ms降到了几ms。
4. 异步处理
把一些非核心流程改成异步处理:
- 发送邮件、短信
- 记录操作日志
- 统计数据更新
异步处理不阻塞主流程,接口响应更快。
六、数据库优化
数据库是性能瓶颈的重灾区,重点优化。
1. 慢查询优化
通过慢查询日志,找到了几个慢查询,逐个优化。
- 加索引:给where条件和join字段加索引
- 避免select *:只查需要的字段
- 避免在索引列上用函数:比如
WHERE DATE(create_time) = '2022-06-01'改成范围查询 - 分页优化:深分页用延迟关联
有一个查询,原来要2秒,加了索引之后,降到了50ms。
2. 索引优化
检查了所有表的索引,删除了没用的索引,增加了缺失的索引。
- 用
EXPLAIN看查询计划 - 确认索引是否被用到
- 避免索引失效(隐式类型转换、前导模糊查询等)
3. MySQL配置优化
修改了MySQL的配置文件 /etc/my.cnf:
[mysqld]
# 缓冲池大小,设为物理内存的50-70%
innodb_buffer_pool_size = 32G
# 日志文件大小
innodb_log_file_size = 1G
# 刷新日志策略,0=每秒刷新,1=每次提交刷新,2=每次提交写文件但不刷新
innodb_flush_log_at_trx_commit = 2
# 刷写方式,O_DIRECT绕过系统缓存
innodb_flush_method = O_DIRECT
# 连接数
max_connections = 500
# 临时表大小
tmp_table_size = 256M
max_heap_table_size = 256M
# 查询缓存(MySQL 8.0已移除)
# query_cache_type = 1
# query_cache_size = 128Minnodbflushlogattrx_commit = 2 是一个权衡,性能更好,但极端情况下可能丢1秒数据。如果对数据一致性要求高,设为1。
4. 读写分离
如果读多写少,可以考虑读写分离。
- 主库负责写
- 从库负责读
- 用MyCat或ShardingSphere做中间件
我们的应用读多写少,做了读写分离之后,数据库的压力小了很多。
七、监控和验证
优化之后,要验证效果。
1. 性能指标监控
用Prometheus + Grafana监控:
- 接口响应时间(平均、P95、P99)
- CPU、内存、磁盘IO、网络
- JVM:堆内存、GC次数、GC停顿时间
- 数据库:连接数、慢查询数、QPS
2. 压测验证
用JMeter做压测,模拟高峰期的流量:
- 100并发,持续10分钟
- 对比优化前后的响应时间和吞吐量
优化前:平均500ms,吞吐量200 TPS 优化后:平均100ms,吞吐量800 TPS
3. 持续观察
优化不是一劳永逸的,要持续观察。
- 每天看监控报表
- 每周做一次性能复盘
- 发现新的瓶颈,继续优化
八、调优的注意事项
说说调优中需要注意的事项。
1. 不要过早优化
先让系统跑起来,找到真正的瓶颈,再优化。不要凭感觉优化,很多时候你以为的瓶颈,并不是真正的瓶颈。
2. 每次只改一个地方
调优的时候,每次只改一个参数,然后测试效果。如果一次改多个,出了问题不知道是哪个改坏的。
3. 有回滚方案
每个优化,都要有回滚方案。万一改了之后性能更差,或者出了问题,能快速回滚。
4. 不要过度优化
优化到一定程度,收益会递减。不要为了追求极致性能,把系统搞得很复杂。够用就好。
5. 文档记录
把所有的优化都记录下来:改了什么、为什么改、效果如何。这样以后出了问题,能快速定位,新人也能快速上手。
九、写在最后
这次华硕服务器的性能调优,把响应时间降了80%,效果很明显。
但我想说的是,性能调优不是什么高深的技术,而是一个系统工程。从硬件到软件,从系统到应用,从数据库到网络,每个环节都可能是瓶颈。
调优的核心思路是:先定位瓶颈,再针对性优化,最后验证效果。不要凭感觉,要用数据说话。
这些调优思路,不只是适用于华硕服务器,任何服务器、任何应用都适用。
2022年了,应用的性能越来越重要。用户的耐心越来越少,响应慢一秒,可能就流失一个用户。做好性能调优,不仅是技术问题,也是业务问题。
最后,用一句话总结:"性能调优的本质,是找到瓶颈,然后用最小的代价,获得最大的提升。"
愿大家的系统,都能又快又稳。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录