plantegg

java tcp mysql performance network docker Linux

关于本博

find me on twitter: @plantegg

知识星球:https://t.zsxq.com/0cSFEUh2J

Github: 欢迎star

关注基础知识,一次把问题搞清楚,从案例出发深挖相关知识。

以前觉得自己一看就懂,实际是一问就打鼓,一用就糊涂。所以现在开始记录并总结再联系案例,一般是先把零散知识记录下来(看到过),慢慢地相关知识积累更多,直到碰到实践案例或是有点领悟到于是发现这块知识可以整理成一篇系统些的文章(基本快懂了)。

“技术变化太快,容易过时”,我的看法是网络知识、操作系统、计算机原理等核心概念知识的寿命会比你的职业生涯还长。这些都是40岁之后还会还会很有用

如何在工作中学习 所有方法我都记录在这篇文章中了,希望对你能有所帮助。

所有新文章从这里可以看到,即使再简单的一篇总结我可以持续总结三五年,有新的发现、感悟都是直接在原文上增减,不会发表新的文章。

image-20220421102225491

为什么写博客而不是公众号,我见过20年前的互联网,深度依赖搜索引擎,所以还是喜欢博客。另外技术类文章更适合电脑阅读(随时摘录、实验)

精华文章推荐

在2010年前后MySQL、PG、Oracle数据库在使用NUMA的时候碰到了性能问题,流传最广的这篇 MySQL – The MySQL “swap insanity” problem and the effects of the NUMA architecture http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/ 文章描述了性能问题的原因(文章中把原因找错了)以及解决方案:关闭NUMA。 实际这个原因是kernel实现的一个低级bug,这个Bug在2014年修复了https://github.com/torvalds/linux/commit/4f9b16a64753d0bb607454347036dc997fd03b82,但是修复这么多年后仍然以讹传讹,这篇文章希望正本清源、扭转错误的认识。

image-20210517082233798

CPU的制造和概念 从最底层的沙子开始用8篇文章来回答关于CPU的各种疑问以及大量的实验对比案例和测试数据来展示了CPU的各种原理,比如多核、超线程、NUMA、睿频、功耗、GPU、大小核再到分支预测、cache_line失效、加锁代价、IPC等各种指标(都有对应的代码和测试数据)。

image-20210802161410524

《Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的》 从一个参数引起的rt抖动定位到OS锁等待再到CPU Pause指令,以及不同CPU型号对Pause使用cycles不同的影响,最终反馈到应用层面的rt全过程。在MySQL内核开发的时候考虑了Pause,但是没有考虑不同的CPU型号,所以换了CPU型号后性能差异比较大

image.png

10倍性能提升全过程 在双11的紧张流程下,将系统tps从500优化到5500,从网络到snat、再到Spring和StackTrace,一次全栈性能优化过程的详细记录和分析。

image.png

就是要你懂TCP–半连接队列和全连接队列:偶发性的连接reset异常、重启服务后短时间的连接异常,通过一篇文章阐明TCP连接的半连接队列和全连接队大小是怎么影响连接创建的,以及用什么工具来观察队列有没有溢出、连接为什么会RESET

image.png

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的

就是要你懂网络–一个网络包的旅程:教科书式地阐述书本中的路由、网关、子网、Mac地址、IP地址是如何一起协作让网络包最终传输到目标机器上。 同时可以跟讲这块的RFC1180比较一下,RFC1180 写的确实很好,清晰简洁,图文并茂,结构逻辑合理,但是对于90%的程序员没有什么卵用,看完几周后就忘得差不多,因为他不是从实践的角度来阐述问题,中间没有很多为什么,所以一般资质的程序员看完当时感觉很好,实际还是不会灵活运用

国产CPU和Intel、AMD性能PK 从Intel、AMD、海光、鲲鹏920、飞腾2500 等CPU在TPCC、sysbench下的性能对比来分析他们的性能差距,同时分析内存延迟对性能的影响

image-20220319115644219

从网络路由连通性的原理上来看负载均衡lvs的DR、NAT、FullNAT到底搞了些什么鬼,以及为什么要这么搞,和带来的优缺点:《就是要你懂负载均衡–lvs和转发模式》

LVS 20倍的负载不均衡,原来是内核的这个Bug,这个内核bug现在还在,可以稳定重现,有兴趣的话去重现一下,然后对照源代码以及抓包分析一下就清楚了。

就是要你懂TCP–握手和挥手,不是你想象中三次握手、四次挥手就理解了TCP,本文从握手的本质–握手都做了什么事情、连接的本质是什么等来阐述握手、挥手的原理

nslookup OK but ping fail–看看老司机是如何解决问题的,解决问题的方法肯定比知识点重要多了,同时透过一个问题怎么样通篇来理解一大块知识,让这块原理真正在你的只是提示中扎根下来

如何在工作中学习 一篇很土但是很务实可以复制的方法论文章。不要讲举一反三、触类旁通,谁都知道要举一反三、触类旁通,但是为什么我总是不能够举一反三、触类旁通?

举三反一–从理论知识到实际问题的推导 坚决不让思路跑偏,如何从一个理论知识点推断可能的问题

性能相关(2015-2018年)

就是要你懂TCP–半连接队列和全连接队列 偶发性的连接reset异常、重启服务后短时间的连接异常

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的 发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响

就是要你懂TCP–性能优化大全

就是要你懂TCP–TCP性能问题 Nagle算法和delay ack

10倍性能提升全过程 在双11的紧张流程下,将系统tps从500优化到5500,从网络到snat、再到Spring和StackTrace,看看一个性能全栈工程师如何在各种工具加持下发现各种问题的。

CPU系列文章(2021年完成)

CPU的制造和概念

十年后数据库还是不敢拥抱NUMA?

[Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的](/2019/12/16/Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的/)

[Perf IPC以及CPU性能](/2021/05/16/Perf IPC以及CPU利用率/)

CPU性能和CACHE

[CPU 性能和Cache Line](/2021/05/16/CPU Cache Line 和性能/)

AMD Zen CPU 架构 以及 AMD、海光、Intel、鲲鹏的性能对比

Intel、海光、鲲鹏920、飞腾2500 CPU性能对比

网络相关基础知识(2017年完成)

就是要你懂网络–一个网络包的旅程

通过案例来理解MSS、MTU等相关TCP概念

就是要你懂TCP–握手和挥手

wireshark-dup-ack-issue and keepalive

一个没有遵守tcp规则导致的问题

[kubernetes service 和 kube-proxy详解](/2020/09/22/kubernetes service 和 kube-proxy详解/)

DNS相关

就是要你懂DNS–一文搞懂域名解析相关问题

nslookup OK but ping fail

Docker中的DNS解析过程

windows7的wifi总是报DNS域名异常无法上网

LVS 负载均衡

就是要你懂负载均衡–lvs和转发模式

就是要你懂负载均衡–负载均衡调度算法和为什么不均衡

网络工具

就是要你懂Unix Socket 进行抓包解析

就是要你懂网络监控–ss用法大全

就是要你懂抓包–WireShark之命令行版tshark

netstat timer keepalive explain

Git HTTP Proxy and SSH Proxy

MySQL Sysbench 性能测试综合报告

测试源码:https://github.com/plantegg/sysbench_report

MySQL Sysbench 性能测试综合报告 (详细版)

📊 执行摘要

本报告汇总了 10 个不同环境下的MySQL性能测试结果,涵盖IDC自建机房、华为云和阿里云等多种部署场景。

测试环境概览

环境 CPU型号 核数 内存 Buffer Pool Flush Log
idc INTEL(R) XEON(R) SILVER 4510 48 376G 16GB 2
idc.trx1 INTEL(R) XEON(R) SILVER 4510 48 376G 16GB 1
huawei Intel(R) Xeon(R) Gold 6348 CPU @ 2.60GHz 64 251G 16GB 2
aliyun Intel(R) Xeon(R) 6982P-C 8 30Gi 16GB 2
aliyun.trx1 Intel(R) Xeon(R) 6982P-C 8 30Gi 16GB 1
aliyun.trx1.repl Intel(R) Xeon(R) 6982P-C 8 30Gi 16GB 1
aws.io2.trx1 Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz 8 30Gi 16GB 1
aws.io2 Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz 8 30Gi 16GB 2
aws.io1 Intel(R) Xeon(R) Platinum 8488C 8 30Gi 16GB 2
aws.gp3 Intel(R) Xeon(R) Platinum 8488C 8 30Gi 16GB 2

测试配置

  • 测试工具: sysbench + tsar
  • 测试数据集: 16表 × 1000万行
  • 测试时长: 每场景30秒
  • 测试场景: 点查询、只读、读写混合、只写
  • 并发级别: 1, 8, 16, 32, 64, 128 线程

🏆 性能排名

点查询性能对比 (oltp_point_select)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 24,725 159,877 252,082 304,631 299,555 287,407
idc.trx1 15,153 129,671 231,142 296,421 297,696 285,109
huawei 6,019 45,989 86,219 155,542 196,915 190,484
aliyun 15,750 109,914 196,497 301,160 328,098 309,373
aliyun.trx1 15,625 113,189 195,783 302,140 326,549 310,429
aliyun.trx1.repl 17,027 109,505 190,769 287,309 329,548 301,471
aws.io2.trx1 11,888 75,291 127,179 161,447 162,516 155,947
aws.io2 12,004 75,171 126,712 160,866 157,480 153,448
aws.io1 1,835 56,871 170,296 251,905 249,718 236,283
aws.gp3 2,316 60,437 162,670 232,535 228,321 217,381

只写性能对比 (oltp_write_only)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 19,282 77,540 94,457 88,015 103,249 115,778
idc.trx1 15,367 61,477 78,108 82,004 97,106 108,842
huawei 4,930 30,173 49,163 70,800 85,898 64,958
aliyun 12,484 61,401 90,134 101,548 110,923 121,385
aliyun.trx1 6,909 38,470 57,604 88,163 112,561 105,554
aliyun.trx1.repl 5,832 27,926 36,521 52,252 86,217 95,690
aws.io2.trx1 3,575 21,479 37,696 59,664 76,279 79,531
aws.io2 8,881 44,059 64,137 79,024 79,754 70,019
aws.io1 1,786 19,047 39,006 68,442 94,216 66,370
aws.gp3 1,689 17,630 34,757 36,656 43,519 52,980

读写混合性能对比 (oltp_read_write)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 9,208 49,874 64,265 68,103 69,255 69,969
idc.trx1 7,297 45,183 58,254 63,486 65,714 67,345
huawei 3,728 25,512 40,124 49,743 51,940 52,357
aliyun 7,952 51,194 71,761 81,858 83,569 82,403
aliyun.trx1 6,868 44,801 66,062 78,590 83,049 84,131
aliyun.trx1.repl 8,125 51,348 76,515 98,436 109,191 111,512
aws.io2.trx1 5,074 29,077 41,737 47,906 49,160 50,050
aws.io2 6,743 35,997 45,274 50,664 51,002 50,315
aws.io1 1,924 24,967 54,742 68,211 71,816 70,575
aws.gp3 1,741 19,019 42,144 60,885 64,869 63,936

只读性能对比 (oltp_read_only)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 11,527 58,919 73,087 74,820 74,631 73,444
idc.trx1 10,803 60,145 71,110 73,527 73,290 72,280
huawei 4,433 27,454 41,995 49,173 51,212 51,027
aliyun 9,389 60,278 76,662 84,123 85,224 85,054
aliyun.trx1 9,311 59,695 76,820 84,023 85,283 85,127
aliyun.trx1.repl 11,207 73,855 103,284 120,653 125,685 122,608
aws.io2.trx1 7,068 39,993 47,383 50,146 49,763 49,209
aws.io2 7,039 39,720 47,558 49,995 49,821 49,165
aws.io1 1,845 28,879 64,551 73,173 74,400 74,024
aws.gp3 1,692 31,915 59,828 66,972 67,678 67,480

📈 延迟分析

点查询延迟对比 (95%分位, ms)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 0.04 0.06 0.10 0.16 0.32 0.61
idc.trx1 0.26 0.23 0.13 0.18 0.31 0.62
huawei 0.17 0.19 0.21 0.31 0.48 0.94
aliyun 0.07 0.08 0.10 0.16 0.29 0.59
aliyun.trx1 0.07 0.08 0.10 0.16 0.29 0.58
aliyun.trx1.repl 0.06 0.09 0.11 0.18 0.30 0.60
aws.io2.trx1 0.09 0.12 0.18 0.32 0.56 1.06
aws.io2 0.09 0.12 0.18 0.32 0.55 1.08
aws.io1 0.72 0.49 0.13 0.20 0.36 0.72
aws.gp3 0.67 0.46 0.14 0.23 0.39 0.78

读写混合延迟对比 (95%分位, ms)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 2.81 4.82 8.74 15.27 36.24 80.03
idc.trx1 3.49 5.28 8.58 15.83 36.24 75.82
huawei 6.79 8.43 11.45 20.00 49.21 106.75
aliyun 3.30 4.10 6.32 11.65 29.72 86.00
aliyun.trx1 3.68 4.65 6.55 11.45 25.28 94.10
aliyun.trx1.repl 2.86 3.89 5.18 8.58 17.95 38.25
aws.io2.trx1 4.82 6.79 10.09 19.29 50.11 125.52
aws.io2 3.89 5.88 10.65 19.65 47.47 139.85
aws.io1 13.95 9.73 9.06 13.70 29.72 106.75
aws.gp3 15.00 17.32 15.00 15.83 33.72 116.80

只写延迟对比 (95%分位, ms)

环境 1线程 8线程 16线程 32线程 64线程 128线程
idc 0.52 0.94 1.76 4.18 8.74 16.12
idc.trx1 0.63 1.18 2.00 4.10 8.13 14.46
huawei 2.35 2.86 3.49 5.00 8.90 17.95
aliyun 0.99 1.37 1.70 2.86 7.17 23.95
aliyun.trx1 1.37 1.93 2.43 3.13 4.74 9.22
aliyun.trx1.repl 1.44 2.43 3.43 4.82 6.55 12.08
aws.io2.trx1 2.57 3.07 3.49 4.41 7.30 14.46
aws.io2 1.61 2.00 2.52 4.25 13.70 38.94
aws.io1 5.09 4.82 4.65 5.37 7.70 24.38
aws.gp3 5.99 5.67 5.67 15.00 29.72 44.98

💡 关键发现

性能特点

  1. CPU架构影响

    • 不同CPU架构在各场景下表现差异明显
    • 单核性能对点查询场景影响显著
  2. 事务持久化设置

    • innodb_flush_log_at_trx_commit=1 vs 2 对写入性能影响明显
    • 建议根据业务对数据安全性要求选择合适配置
  3. 并发扩展性

    • 各环境在不同并发级别下的扩展性表现不同
    • 需要根据实际业务并发选择合适的硬件配置
  4. 延迟控制

    • 高并发下延迟控制能力体现系统稳定性
    • 95%分位延迟是衡量用户体验的重要指标

环境推荐

  • 查询密集型业务: 推荐 aliyun.trx1 环境
  • 写入密集型业务: 推荐 aliyun 环境
  • 混合负载: 需要综合考虑QPS、延迟和成本

📊 64线程性能对比

测试场景 idc idc.trx1 huawei aliyun aliyun.trx1 aliyun.trx1.repl aws.io2.trx1 aws.io2 aws.io1 aws.gp3
点查询 299,555 297,696 196,915 328,098 326,549 329,548 162,516 157,480 249,718 228,321
只读 74,631 73,290 51,212 85,224 85,283 125,685 49,763 49,821 74,400 67,678
读写混合 69,255 65,714 51,940 83,569 83,049 109,191 49,160 51,002 71,816 64,869
只写 103,249 97,106 85,898 110,923 112,561 86,217 76,279 79,754 94,216 43,519

第一章:idc 环境详细报告

测试时间: 2025-11-27 10:28:39
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 51706 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.9.10.145
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 2

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
=== CPU 信息 ===
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 2
Core(s) per socket: 12
座: 2
NUMA 节点: 2
厂商 ID: GenuineIntel
CPU 系列: 6
型号: 143
型号名称: INTEL(R) XEON(R) SILVER 4510
步进: 8
CPU MHz: 2400.000
BogoMIPS: 4800.00
虚拟化: VT-x
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 2048K
L3 缓存: 30720K
NUMA 节点0 CPU: 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46
NUMA 节点1 CPU: 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_pt cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq cldemote movdiri movdir64b md_clear pconfig spec_ctrl intel_stibp flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 376G 47G 257G 1.7G 71G 326G
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 24,725 24,725 0.04 0.04 0.0 0.6 0.6 0.2 11.6 2025-11-24 08:56:53 ~ 2025-11-24 08:57:23
oltp_point_select 8 159,877 159,877 0.05 0.06 0.4 4.8 2.9 1.0 51.9 2025-11-24 08:57:25 ~ 2025-11-24 08:57:55
oltp_point_select 16 252,082 252,082 0.06 0.10 0.6 8.1 4.8 0.6 56.9 2025-11-24 08:57:57 ~ 2025-11-24 08:58:27
oltp_point_select 32 304,631 304,631 0.10 0.16 0.9 10.3 5.8 0.0 42.3 2025-11-24 08:58:29 ~ 2025-11-24 08:58:59
oltp_point_select 64 299,555 299,555 0.21 0.32 1.1 10.4 5.7 0.0 30.0 2025-11-24 08:59:01 ~ 2025-11-24 08:59:31
oltp_point_select 128 287,407 287,407 0.45 0.61 1.0 10.5 5.7 0.0 22.0 2025-11-24 08:59:33 ~ 2025-11-24 09:00:03
oltp_read_only 1 11,527 720 1.39 1.61 0.0 1.3 0.4 0.0 1.0 2025-11-24 09:00:05 ~ 2025-11-24 09:00:35
oltp_read_only 8 58,919 3,682 2.17 3.30 0.3 9.5 1.2 0.1 4.8 2025-11-24 09:00:37 ~ 2025-11-24 09:01:07
oltp_read_only 16 73,087 4,568 3.50 5.28 0.2 13.8 1.6 0.0 5.7 2025-11-24 09:01:09 ~ 2025-11-24 09:01:39
oltp_read_only 32 74,820 4,676 6.84 9.73 0.3 14.7 1.6 0.0 5.5 2025-11-24 09:01:41 ~ 2025-11-24 09:02:11
oltp_read_only 64 74,631 4,664 13.72 17.01 0.3 14.7 1.6 0.0 4.9 2025-11-24 09:02:13 ~ 2025-11-24 09:02:43
oltp_read_only 128 73,444 4,590 27.88 33.12 0.3 14.6 1.7 0.0 4.8 2025-11-24 09:02:45 ~ 2025-11-24 09:03:15
oltp_read_write 1 9,208 460 2.17 2.81 0.0 1.7 0.8 0.2 29.3 2025-11-24 09:03:17 ~ 2025-11-24 09:03:47
oltp_read_write 8 49,874 2,494 3.21 4.82 0.2 10.0 2.0 0.4 52.4 2025-11-24 09:03:49 ~ 2025-11-24 09:04:19
oltp_read_write 16 64,265 3,213 4.98 8.74 0.3 12.8 2.1 0.2 38.9 2025-11-24 09:04:21 ~ 2025-11-24 09:04:51
oltp_read_write 32 68,103 3,405 9.39 15.27 0.2 13.8 2.1 0.0 36.2 2025-11-24 09:04:53 ~ 2025-11-24 09:05:23
oltp_read_write 64 69,255 3,463 18.48 36.24 0.3 13.9 2.0 0.0 33.9 2025-11-24 09:05:25 ~ 2025-11-24 09:05:55
oltp_read_write 128 69,969 3,498 36.57 80.03 0.3 13.8 2.0 0.0 31.4 2025-11-24 09:05:57 ~ 2025-11-24 09:06:28
oltp_write_only 1 19,282 3,214 0.31 0.52 0.0 2.0 1.0 0.1 8.9 2025-11-24 09:06:30 ~ 2025-11-24 09:07:00
oltp_write_only 8 77,540 12,923 0.62 0.94 0.3 8.6 2.8 0.2 25.3 2025-11-24 09:07:02 ~ 2025-11-24 09:07:32
oltp_write_only 16 94,457 15,743 1.02 1.76 0.4 11.1 3.3 0.1 31.3 2025-11-24 09:07:34 ~ 2025-11-24 09:08:04
oltp_write_only 32 88,015 14,669 2.18 4.18 0.4 10.4 3.2 0.1 41.4 2025-11-24 09:08:06 ~ 2025-11-24 09:08:36
oltp_write_only 64 103,249 17,208 3.72 8.74 0.4 11.7 3.2 0.1 37.7 2025-11-24 09:08:38 ~ 2025-11-24 09:09:08
oltp_write_only 128 115,778 19,296 6.63 16.12 0.5 12.4 3.4 0.1 39.6 2025-11-24 09:09:10 ~ 2025-11-24 09:09:40


第二章:idc.trx1 环境详细报告

测试时间: 2025-11-27 10:29:01
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 50627 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.9.10.145
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 1

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
=== CPU 信息 ===
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 2
Core(s) per socket: 12
座: 2
NUMA 节点: 2
厂商 ID: GenuineIntel
CPU 系列: 6
型号: 143
型号名称: INTEL(R) XEON(R) SILVER 4510
步进: 8
CPU MHz: 2400.000
BogoMIPS: 4800.00
虚拟化: VT-x
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 2048K
L3 缓存: 30720K
NUMA 节点0 CPU: 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46
NUMA 节点1 CPU: 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_pt cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq cldemote movdiri movdir64b md_clear pconfig spec_ctrl intel_stibp flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 376G 47G 257G 1.7G 71G 326G
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 15,153 15,153 0.07 0.26 0.0 0.6 0.6 0.8 42.6 2025-11-24 08:38:54 ~ 2025-11-24 08:39:24
oltp_point_select 8 129,671 129,671 0.06 0.23 0.2 4.1 2.7 2.3 81.3 2025-11-24 08:39:26 ~ 2025-11-24 08:39:56
oltp_point_select 16 231,142 231,142 0.07 0.13 0.9 7.8 4.2 0.8 68.0 2025-11-24 08:39:58 ~ 2025-11-24 08:40:28
oltp_point_select 32 296,421 296,421 0.11 0.18 0.9 10.3 5.7 0.0 47.1 2025-11-24 08:40:30 ~ 2025-11-24 08:41:00
oltp_point_select 64 297,696 297,696 0.21 0.31 0.9 10.4 5.7 0.0 31.4 2025-11-24 08:41:02 ~ 2025-11-24 08:41:32
oltp_point_select 128 285,109 285,109 0.45 0.62 0.8 10.5 5.6 0.0 21.7 2025-11-24 08:41:34 ~ 2025-11-24 08:42:04
oltp_read_only 1 10,803 675 1.48 1.86 0.0 1.3 0.4 0.0 1.0 2025-11-24 08:42:06 ~ 2025-11-24 08:42:36
oltp_read_only 8 60,145 3,759 2.13 3.25 0.1 10.2 1.3 0.1 5.3 2025-11-24 08:42:38 ~ 2025-11-24 08:43:08
oltp_read_only 16 71,110 4,444 3.60 5.88 0.2 13.5 1.6 0.0 5.6 2025-11-24 08:43:10 ~ 2025-11-24 08:43:40
oltp_read_only 32 73,527 4,595 6.96 10.09 0.2 14.6 1.6 0.0 5.6 2025-11-24 08:43:42 ~ 2025-11-24 08:44:12
oltp_read_only 64 73,290 4,581 13.97 18.28 0.3 14.6 1.6 0.0 5.1 2025-11-24 08:44:14 ~ 2025-11-24 08:44:44
oltp_read_only 128 72,280 4,518 28.32 34.95 0.2 14.5 1.6 0.0 4.9 2025-11-24 08:44:46 ~ 2025-11-24 08:45:16
oltp_read_write 1 7,297 365 2.74 3.49 0.0 1.5 0.7 0.2 28.6 2025-11-24 08:45:18 ~ 2025-11-24 08:45:48
oltp_read_write 8 45,183 2,259 3.54 5.28 0.1 9.5 2.0 0.4 44.6 2025-11-24 08:45:50 ~ 2025-11-24 08:46:20
oltp_read_write 16 58,254 2,913 5.49 8.58 0.2 12.2 2.2 0.2 32.3 2025-11-24 08:46:22 ~ 2025-11-24 08:46:53
oltp_read_write 32 63,486 3,174 10.08 15.83 0.2 13.5 2.2 0.1 33.5 2025-11-24 08:46:55 ~ 2025-11-24 08:47:25
oltp_read_write 64 65,714 3,286 19.47 36.24 0.3 13.7 2.0 0.0 33.2 2025-11-24 08:47:27 ~ 2025-11-24 08:47:57
oltp_read_write 128 67,345 3,367 37.99 75.82 0.3 14.0 2.0 0.0 32.0 2025-11-24 08:47:59 ~ 2025-11-24 08:48:29
oltp_write_only 1 15,367 2,561 0.39 0.63 0.0 2.1 1.1 0.2 14.5 2025-11-24 08:48:31 ~ 2025-11-24 08:49:01
oltp_write_only 8 61,477 10,246 0.78 1.18 0.2 8.1 3.1 0.2 33.5 2025-11-24 08:49:03 ~ 2025-11-24 08:49:33
oltp_write_only 16 78,108 13,018 1.23 2.00 0.4 10.2 3.3 0.2 34.6 2025-11-24 08:49:35 ~ 2025-11-24 08:50:05
oltp_write_only 32 82,004 13,667 2.34 4.10 0.4 10.4 3.2 0.2 40.3 2025-11-24 08:50:07 ~ 2025-11-24 08:50:37
oltp_write_only 64 97,106 16,184 3.95 8.13 0.4 11.6 3.1 0.1 36.8 2025-11-24 08:50:39 ~ 2025-11-24 08:51:09
oltp_write_only 128 108,842 18,140 7.05 14.46 0.4 12.2 3.3 0.1 40.1 2025-11-24 08:51:11 ~ 2025-11-24 08:51:41


第三章:huawei 环境详细报告

测试时间: 2025-11-27 10:29:08
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 60059 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.16.104.124
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 2

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
=== CPU 信息 ===
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 64
On-line CPU(s) list: 0-63
Thread(s) per core: 2
Core(s) per socket: 16
座: 2
NUMA 节点: 2
厂商 ID: GenuineIntel
CPU 系列: 6
型号: 106
型号名称: Intel(R) Xeon(R) Gold 6348 CPU @ 2.60GHz
步进: 6
CPU MHz: 2600.000
BogoMIPS: 5200.00
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 1280K
L3 缓存: 43008K
NUMA 节点0 CPU: 0-31
NUMA 节点1 CPU: 32-63
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd rsb_ctxsw ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 arat avx512vbmi umip avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq md_clear spec_ctrl intel_stibp arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 251G 21G 127G 944K 102G 229G
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 6,019 6,019 0.17 0.17 0.0 0.2 0.1 0.1 22.1 2025-11-24 10:03:09 ~ 2025-11-24 10:03:39
oltp_point_select 8 45,989 45,989 0.17 0.19 0.0 1.3 0.6 0.4 77.2 2025-11-24 10:03:41 ~ 2025-11-24 10:04:12
oltp_point_select 16 86,219 86,219 0.19 0.21 0.2 3.5 1.5 0.6 92.5 2025-11-24 10:04:14 ~ 2025-11-24 10:04:44
oltp_point_select 32 155,542 155,542 0.21 0.31 0.5 7.0 2.7 0.4 96.2 2025-11-24 10:04:46 ~ 2025-11-24 10:05:16
oltp_point_select 64 196,915 196,915 0.32 0.48 0.4 8.7 3.2 0.0 95.2 2025-11-24 10:05:18 ~ 2025-11-24 10:05:48
oltp_point_select 128 190,484 190,484 0.67 0.94 0.5 8.6 3.2 0.0 90.4 2025-11-24 10:05:50 ~ 2025-11-24 10:06:20
oltp_read_only 1 4,433 277 3.61 4.10 0.0 0.5 0.1 0.0 5.7 2025-11-24 10:06:22 ~ 2025-11-24 10:06:52
oltp_read_only 8 27,454 1,716 4.66 6.79 0.0 4.1 0.5 0.1 29.2 2025-11-24 10:06:54 ~ 2025-11-24 10:07:24
oltp_read_only 16 41,995 2,625 6.09 9.06 0.1 7.6 0.7 0.1 38.9 2025-11-24 10:07:26 ~ 2025-11-24 10:07:56
oltp_read_only 32 49,173 3,073 10.41 16.71 0.1 10.2 0.8 0.1 41.8 2025-11-24 10:07:58 ~ 2025-11-24 10:08:28
oltp_read_only 64 51,212 3,201 19.99 31.94 0.2 11.1 0.9 0.0 41.0 2025-11-24 10:08:30 ~ 2025-11-24 10:09:00
oltp_read_only 128 51,027 3,189 40.12 53.85 0.2 11.2 0.9 0.0 39.5 2025-11-24 10:09:02 ~ 2025-11-24 10:09:32
oltp_read_write 1 3,728 186 5.36 6.79 0.0 0.6 0.2 0.2 50.4 2025-11-24 10:09:34 ~ 2025-11-24 10:10:04
oltp_read_write 8 25,512 1,276 6.27 8.43 0.1 4.6 0.8 0.8 92.8 2025-11-24 10:10:06 ~ 2025-11-24 10:10:36
oltp_read_write 16 40,124 2,006 7.97 11.45 0.1 7.6 1.0 0.6 91.4 2025-11-24 10:10:38 ~ 2025-11-24 10:11:08
oltp_read_write 32 49,743 2,487 12.86 20.00 0.1 10.1 1.1 0.4 90.3 2025-11-24 10:11:10 ~ 2025-11-24 10:11:40
oltp_read_write 64 51,940 2,597 24.63 49.21 0.2 10.8 1.0 0.2 90.0 2025-11-24 10:11:42 ~ 2025-11-24 10:12:12
oltp_read_write 128 52,357 2,618 48.87 106.75 0.2 10.6 1.0 0.2 86.6 2025-11-24 10:12:14 ~ 2025-11-24 10:12:45
oltp_write_only 1 4,930 822 1.22 2.35 0.0 0.5 0.2 0.2 37.4 2025-11-24 10:12:47 ~ 2025-11-24 10:13:17
oltp_write_only 8 30,173 5,029 1.59 2.86 0.1 2.7 0.7 0.5 78.5 2025-11-24 10:13:19 ~ 2025-11-24 10:13:49
oltp_write_only 16 49,163 8,194 1.95 3.49 0.1 4.8 1.2 0.6 87.7 2025-11-24 10:13:51 ~ 2025-11-24 10:14:21
oltp_write_only 32 70,800 11,800 2.71 5.00 0.2 7.1 1.6 0.5 91.8 2025-11-24 10:14:23 ~ 2025-11-24 10:14:53
oltp_write_only 64 85,898 14,316 4.47 8.90 0.3 8.8 1.9 0.4 93.3 2025-11-24 10:14:55 ~ 2025-11-24 10:15:25
oltp_write_only 128 64,958 10,826 11.82 17.95 0.2 6.3 1.5 0.5 97.7 2025-11-24 10:15:27 ~ 2025-11-24 10:15:57


第四章:aliyun 环境详细报告

测试时间: 2025-11-27 10:28:27
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 811 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.127.33.154
MYSQL_PORT: 3316
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 2

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Alibaba Cloud
CPU 系列: 6
型号: 173
型号名称: Intel(R) Xeon(R) 6982P-C
BIOS Model name: pc-i440fx-2.1
步进: 1
CPU MHz: 3600.000
CPU 最大 MHz: 3900.0000
CPU 最小 MHz: 800.0000
BogoMIPS: 5600.00
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 64K
L2 缓存: 2048K
L3 缓存: 516096K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm uintr md_clear serialize tsxldtrk arch_lbr amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 20Gi 1.2Gi 2.0Mi 9.1Gi 9.6Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 15,750 15,750 0.06 0.07 0.5 1.7 1.0 0.8 22.6 2025-11-23 07:59:31 ~ 2025-11-23 08:00:01
oltp_point_select 8 109,914 109,914 0.07 0.08 4.6 14.8 7.5 4.6 77.7 2025-11-23 08:00:03 ~ 2025-11-23 08:00:33
oltp_point_select 16 196,497 196,497 0.08 0.10 9.2 32.1 17.0 3.7 90.2 2025-11-23 08:00:35 ~ 2025-11-23 08:01:05
oltp_point_select 32 301,160 301,160 0.11 0.16 13.4 46.4 30.8 0.8 94.7 2025-11-23 08:01:07 ~ 2025-11-23 08:01:37
oltp_point_select 64 328,098 328,098 0.19 0.29 13.6 48.1 33.6 0.0 90.5 2025-11-23 08:01:39 ~ 2025-11-23 08:02:09
oltp_point_select 128 309,373 309,373 0.41 0.59 13.3 48.2 33.8 0.0 81.9 2025-11-23 08:02:11 ~ 2025-11-23 08:02:41
oltp_read_only 1 9,389 587 1.70 2.03 0.3 6.0 0.7 0.2 5.2 2025-11-23 08:02:43 ~ 2025-11-23 08:03:13
oltp_read_only 8 60,278 3,767 2.12 2.43 2.7 50.3 5.4 1.1 27.4 2025-11-23 08:03:15 ~ 2025-11-23 08:03:45
oltp_read_only 16 76,662 4,791 3.34 4.57 4.0 71.2 8.8 0.4 31.7 2025-11-23 08:03:47 ~ 2025-11-23 08:04:17
oltp_read_only 32 84,123 5,258 6.08 8.58 4.0 80.6 9.8 0.1 33.2 2025-11-23 08:04:19 ~ 2025-11-23 08:04:49
oltp_read_only 64 85,224 5,326 12.01 15.55 3.9 81.8 10.5 0.0 30.8 2025-11-23 08:04:51 ~ 2025-11-23 08:05:21
oltp_read_only 128 85,054 5,316 24.07 26.68 3.8 81.6 10.4 0.0 29.0 2025-11-23 08:05:23 ~ 2025-11-23 08:05:53
oltp_read_write 1 7,952 398 2.51 3.30 0.4 6.9 2.6 2.6 73.0 2025-11-23 08:05:55 ~ 2025-11-23 08:06:25
oltp_read_write 8 51,194 2,560 3.12 4.10 3.0 48.6 10.3 5.2 94.7 2025-11-23 08:06:27 ~ 2025-11-23 08:06:57
oltp_read_write 16 71,761 3,588 4.46 6.32 4.1 67.2 11.6 1.6 85.0 2025-11-23 08:06:59 ~ 2025-11-23 08:07:30
oltp_read_write 32 81,858 4,093 7.82 11.65 4.2 77.9 11.9 0.4 83.9 2025-11-23 08:07:32 ~ 2025-11-23 08:08:02
oltp_read_write 64 83,569 4,178 15.31 29.72 4.2 78.7 12.1 0.2 83.7 2025-11-23 08:08:04 ~ 2025-11-23 08:08:34
oltp_read_write 128 82,403 4,120 31.04 86.00 4.3 77.6 12.8 0.2 81.8 2025-11-23 08:08:36 ~ 2025-11-23 08:09:06
oltp_write_only 1 12,484 2,081 0.48 0.99 0.5 5.7 2.2 1.8 33.3 2025-11-23 08:09:08 ~ 2025-11-23 08:09:38
oltp_write_only 8 61,401 10,233 0.78 1.37 3.3 33.1 11.4 4.6 78.9 2025-11-23 08:09:40 ~ 2025-11-23 08:10:10
oltp_write_only 16 90,134 15,022 1.06 1.70 5.0 47.3 15.9 3.8 83.7 2025-11-23 08:10:12 ~ 2025-11-23 08:10:42
oltp_write_only 32 101,548 16,925 1.89 2.86 5.6 50.4 17.0 3.2 88.5 2025-11-23 08:10:44 ~ 2025-11-23 08:11:14
oltp_write_only 64 110,923 18,487 3.46 7.17 5.8 52.8 17.6 2.4 86.8 2025-11-23 08:11:16 ~ 2025-11-23 08:11:47
oltp_write_only 128 121,385 20,231 6.32 23.95 6.5 58.8 18.9 2.0 85.4 2025-11-23 08:11:49 ~ 2025-11-23 08:12:19


第五章:aliyun.trx1 环境详细报告

测试时间: 2025-11-27 10:27:05
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 791 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.127.33.154
MYSQL_PORT: 3316
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 1

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Alibaba Cloud
CPU 系列: 6
型号: 173
型号名称: Intel(R) Xeon(R) 6982P-C
BIOS Model name: pc-i440fx-2.1
步进: 1
CPU MHz: 3600.000
CPU 最大 MHz: 3900.0000
CPU 最小 MHz: 800.0000
BogoMIPS: 5600.00
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 64K
L2 缓存: 2048K
L3 缓存: 516096K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm uintr md_clear serialize tsxldtrk arch_lbr amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 20Gi 1.2Gi 2.0Mi 9.1Gi 9.6Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 15,625 15,625 0.06 0.07 0.5 1.8 0.9 0.8 22.3 2025-11-23 19:27:06 ~ 2025-11-23 19:27:36
oltp_point_select 8 113,189 113,189 0.07 0.08 4.7 15.6 7.6 4.7 78.1 2025-11-23 19:27:38 ~ 2025-11-23 19:28:08
oltp_point_select 16 195,783 195,783 0.08 0.10 9.1 31.9 16.4 3.9 90.4 2025-11-23 19:28:10 ~ 2025-11-23 19:28:40
oltp_point_select 32 302,140 302,140 0.11 0.16 13.1 46.5 30.2 0.8 93.8 2025-11-23 19:28:42 ~ 2025-11-23 19:29:12
oltp_point_select 64 326,549 326,549 0.20 0.29 13.6 47.2 33.4 0.0 90.1 2025-11-23 19:29:14 ~ 2025-11-23 19:29:44
oltp_point_select 128 310,429 310,429 0.41 0.58 13.2 47.4 33.5 0.0 81.1 2025-11-23 19:29:46 ~ 2025-11-23 19:30:16
oltp_read_only 1 9,311 582 1.72 2.03 0.3 5.6 0.6 0.2 5.0 2025-11-23 19:30:18 ~ 2025-11-23 19:30:48
oltp_read_only 8 59,695 3,731 2.14 2.43 2.7 48.4 5.5 1.1 27.2 2025-11-23 19:30:50 ~ 2025-11-23 19:31:20
oltp_read_only 16 76,820 4,801 3.33 4.57 3.9 70.1 8.5 0.4 31.7 2025-11-23 19:31:22 ~ 2025-11-23 19:31:52
oltp_read_only 32 84,023 5,251 6.09 8.58 3.9 79.1 9.6 0.1 31.6 2025-11-23 19:31:54 ~ 2025-11-23 19:32:24
oltp_read_only 64 85,283 5,330 12.00 15.55 3.9 80.2 10.3 0.0 31.0 2025-11-23 19:32:26 ~ 2025-11-23 19:32:56
oltp_read_only 128 85,127 5,320 24.05 27.17 3.7 79.4 10.1 0.0 28.7 2025-11-23 19:32:58 ~ 2025-11-23 19:33:29
oltp_read_write 1 6,868 343 2.91 3.68 0.4 5.8 2.2 3.9 78.4 2025-11-23 19:33:31 ~ 2025-11-23 19:34:01
oltp_read_write 8 44,801 2,240 3.57 4.65 2.7 43.5 9.2 8.5 96.9 2025-11-23 19:34:03 ~ 2025-11-23 19:34:33
oltp_read_write 16 66,062 3,303 4.84 6.55 4.1 62.1 11.4 3.7 96.5 2025-11-23 19:34:35 ~ 2025-11-23 19:35:05
oltp_read_write 32 78,590 3,930 8.14 11.45 4.4 73.3 12.1 1.3 94.8 2025-11-23 19:35:07 ~ 2025-11-23 19:35:37
oltp_read_write 64 83,049 4,152 15.41 25.28 4.3 76.3 12.0 0.5 89.1 2025-11-23 19:35:39 ~ 2025-11-23 19:36:09
oltp_read_write 128 84,131 4,207 30.41 94.10 4.2 75.7 11.9 0.4 83.4 2025-11-23 19:36:11 ~ 2025-11-23 19:36:41
oltp_write_only 1 6,909 1,152 0.87 1.37 0.4 4.0 1.7 5.7 94.9 2025-11-23 19:36:43 ~ 2025-11-23 19:37:14
oltp_write_only 8 38,470 6,412 1.25 1.93 2.0 22.2 7.5 7.8 97.7 2025-11-23 19:37:16 ~ 2025-11-23 19:37:46
oltp_write_only 16 57,604 9,601 1.67 2.43 3.2 28.4 10.1 7.1 97.6 2025-11-23 19:37:48 ~ 2025-11-23 19:38:18
oltp_write_only 32 88,163 14,694 2.18 3.13 5.1 41.1 14.4 4.7 97.6 2025-11-23 19:38:20 ~ 2025-11-23 19:38:50
oltp_write_only 64 112,561 18,760 3.41 4.74 6.1 52.3 17.9 2.5 97.3 2025-11-23 19:38:52 ~ 2025-11-23 19:39:22
oltp_write_only 128 105,554 17,592 7.27 9.22 5.6 49.4 16.8 2.3 94.8 2025-11-23 19:39:24 ~ 2025-11-23 19:39:54


第六章:aliyun.trx1.repl 环境详细报告

测试时间: 2025-12-01 18:26:22
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 517 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.127.33.154
MYSQL_PORT: 3316
TABLES: 16
TABLE_SIZE: 100000
TEST_TIME: 10

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 1

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Alibaba Cloud
CPU 系列: 6
型号: 173
型号名称: Intel(R) Xeon(R) 6982P-C
BIOS Model name: pc-i440fx-2.1
步进: 1
CPU MHz: 3600.000
CPU 最大 MHz: 3900.0000
CPU 最小 MHz: 800.0000
BogoMIPS: 5600.00
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 64K
L2 缓存: 2048K
L3 缓存: 516096K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm uintr md_clear serialize tsxldtrk arch_lbr amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 21Gi 6.7Gi 2.0Mi 2.8Gi 8.8Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 17,027 17,027 0.06 0.06 0.5 1.5 0.9 0.2 4.6 2025-12-01 18:21:28 ~ 2025-12-01 18:21:38
oltp_point_select 8 109,505 109,505 0.07 0.09 4.2 14.3 6.8 0.4 12.2 2025-12-01 18:21:40 ~ 2025-12-01 18:21:50
oltp_point_select 16 190,769 190,769 0.08 0.11 8.9 28.6 15.7 0.2 8.5 2025-12-01 18:21:52 ~ 2025-12-01 18:22:02
oltp_point_select 32 287,309 287,309 0.11 0.18 12.7 41.0 28.7 0.0 6.5 2025-12-01 18:22:04 ~ 2025-12-01 18:22:14
oltp_point_select 64 329,548 329,548 0.19 0.30 13.0 43.3 30.9 0.0 3.8 2025-12-01 18:22:16 ~ 2025-12-01 18:22:26
oltp_point_select 128 301,471 301,471 0.42 0.60 12.7 42.3 31.6 0.0 2.5 2025-12-01 18:22:28 ~ 2025-12-01 18:22:38
oltp_read_only 1 11,207 700 1.43 1.50 0.4 4.1 0.6 0.0 0.1 2025-12-01 18:22:40 ~ 2025-12-01 18:22:50
oltp_read_only 8 73,855 4,616 1.73 1.93 3.4 35.6 6.2 0.0 0.6 2025-12-01 18:22:52 ~ 2025-12-01 18:23:02
oltp_read_only 16 103,284 6,455 2.48 3.19 5.3 55.6 11.5 0.0 0.7 2025-12-01 18:23:04 ~ 2025-12-01 18:23:14
oltp_read_only 32 120,653 7,541 4.24 5.88 5.5 65.8 13.0 0.0 0.8 2025-12-01 18:23:16 ~ 2025-12-01 18:23:26
oltp_read_only 64 125,685 7,855 8.14 10.84 5.2 67.2 13.8 0.0 0.8 2025-12-01 18:23:28 ~ 2025-12-01 18:23:38
oltp_read_only 128 122,608 7,663 16.68 19.29 5.3 65.4 13.8 0.0 0.6 2025-12-01 18:23:40 ~ 2025-12-01 18:23:50
oltp_read_write 1 8,125 406 2.46 2.86 0.3 3.6 0.9 2.1 52.2 2025-12-01 18:23:52 ~ 2025-12-01 18:24:02
oltp_read_write 8 51,348 2,567 3.11 3.89 2.7 26.9 6.1 4.4 81.0 2025-12-01 18:24:04 ~ 2025-12-01 18:24:14
oltp_read_write 16 76,515 3,826 4.18 5.18 4.1 42.0 10.0 3.2 83.1 2025-12-01 18:24:16 ~ 2025-12-01 18:24:26
oltp_read_write 32 98,436 4,922 6.50 8.58 5.0 53.8 13.1 1.5 82.1 2025-12-01 18:24:28 ~ 2025-12-01 18:24:38
oltp_read_write 64 109,191 5,460 11.71 17.95 5.3 58.7 14.0 0.7 71.0 2025-12-01 18:24:40 ~ 2025-12-01 18:24:51
oltp_read_write 128 111,512 5,576 22.89 38.25 5.5 62.8 14.7 0.5 51.9 2025-12-01 18:24:53 ~ 2025-12-01 18:25:03
oltp_write_only 1 5,832 972 1.03 1.44 0.4 2.5 1.1 4.8 90.0 2025-12-01 18:25:05 ~ 2025-12-01 18:25:15
oltp_write_only 8 27,926 4,654 1.72 2.43 1.5 10.3 3.8 6.1 89.2 2025-12-01 18:25:17 ~ 2025-12-01 18:25:27
oltp_write_only 16 36,521 6,087 2.63 3.43 2.1 13.7 5.1 4.8 78.9 2025-12-01 18:25:29 ~ 2025-12-01 18:25:39
oltp_write_only 32 52,252 8,709 3.67 4.82 2.8 18.9 7.3 3.8 70.4 2025-12-01 18:25:41 ~ 2025-12-01 18:25:51
oltp_write_only 64 86,217 14,370 4.45 6.55 4.4 31.3 12.3 3.2 80.9 2025-12-01 18:25:53 ~ 2025-12-01 18:26:03
oltp_write_only 128 95,690 15,948 8.00 12.08 4.7 32.8 12.8 2.2 74.1 2025-12-01 18:26:05 ~ 2025-12-01 18:26:16


第七章:aws.io2.trx1 环境详细报告

测试时间: 2025-11-30 09:15:26
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 5679 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.1.2.89
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 1

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Intel(R) Corporation
CPU 系列: 6
型号: 106
型号名称: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
BIOS Model name: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
步进: 6
CPU MHz: 2899.956
BogoMIPS: 5799.91
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 1280K
L3 缓存: 55296K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves wbnoinvd ida arat avx512vbmi pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid md_clear flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 18Gi 243Mi 24Mi 11Gi 11Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 11,888 11,888 0.08 0.09 0.6 2.7 1.1 4.0 50.3 2025-11-30 09:02:35 ~ 2025-11-30 09:03:05
oltp_point_select 8 75,291 75,291 0.11 0.12 5.1 25.9 10.7 6.1 82.0 2025-11-30 09:03:07 ~ 2025-11-30 09:03:37
oltp_point_select 16 127,179 127,179 0.13 0.18 7.8 42.7 22.0 2.6 86.1 2025-11-30 09:03:39 ~ 2025-11-30 09:04:09
oltp_point_select 32 161,447 161,447 0.20 0.32 7.4 54.4 26.7 0.8 86.5 2025-11-30 09:04:11 ~ 2025-11-30 09:04:41
oltp_point_select 64 162,516 162,516 0.39 0.56 7.6 55.8 27.9 0.0 85.5 2025-11-30 09:04:43 ~ 2025-11-30 09:05:13
oltp_point_select 128 155,947 155,947 0.82 1.06 7.7 57.8 28.6 0.0 81.8 2025-11-30 09:05:15 ~ 2025-11-30 09:05:46
oltp_read_only 1 7,068 442 2.26 2.86 0.4 6.0 0.5 0.4 7.9 2025-11-30 09:05:48 ~ 2025-11-30 09:06:18
oltp_read_only 8 39,993 2,500 3.20 3.82 3.1 55.9 6.2 1.9 35.5 2025-11-30 09:06:20 ~ 2025-11-30 09:06:50
oltp_read_only 16 47,383 2,961 5.40 8.74 3.0 73.2 8.3 0.8 39.2 2025-11-30 09:06:52 ~ 2025-11-30 09:07:22
oltp_read_only 32 50,146 3,134 10.21 14.46 2.7 81.9 9.9 0.1 38.8 2025-11-30 09:07:24 ~ 2025-11-30 09:07:54
oltp_read_only 64 49,763 3,110 20.57 23.95 2.8 81.8 9.9 0.0 36.6 2025-11-30 09:07:56 ~ 2025-11-30 09:08:26
oltp_read_only 128 49,209 3,076 41.59 45.79 2.8 80.9 10.1 0.0 35.3 2025-11-30 09:08:28 ~ 2025-11-30 09:08:58
oltp_read_write 1 5,074 254 3.94 4.82 0.3 5.6 1.9 4.6 68.4 2025-11-30 09:09:00 ~ 2025-11-30 09:09:30
oltp_read_write 8 29,077 1,454 5.50 6.79 2.3 40.2 8.5 10.0 96.1 2025-11-30 09:09:32 ~ 2025-11-30 09:10:02
oltp_read_write 16 41,737 2,087 7.66 10.09 3.1 61.4 10.3 4.4 96.0 2025-11-30 09:10:04 ~ 2025-11-30 09:10:34
oltp_read_write 32 47,906 2,395 13.35 19.29 2.8 70.4 10.0 2.0 90.2 2025-11-30 09:10:36 ~ 2025-11-30 09:11:06
oltp_read_write 64 49,160 2,458 26.02 50.11 2.8 72.8 10.7 1.2 81.6 2025-11-30 09:11:08 ~ 2025-11-30 09:11:39
oltp_read_write 128 50,050 2,503 51.10 125.52 3.0 76.5 11.0 0.7 76.1 2025-11-30 09:11:41 ~ 2025-11-30 09:12:11
oltp_write_only 1 3,575 596 1.68 2.57 0.2 2.7 1.2 7.5 96.1 2025-11-30 09:12:13 ~ 2025-11-30 09:12:43
oltp_write_only 8 21,479 3,580 2.23 3.07 1.6 16.4 5.0 9.7 96.2 2025-11-30 09:12:45 ~ 2025-11-30 09:13:15
oltp_write_only 16 37,696 6,283 2.55 3.49 2.8 28.8 8.5 7.4 96.0 2025-11-30 09:13:17 ~ 2025-11-30 09:13:47
oltp_write_only 32 59,664 9,944 3.22 4.41 4.0 44.1 13.1 4.4 95.9 2025-11-30 09:13:49 ~ 2025-11-30 09:14:19
oltp_write_only 64 76,279 12,713 5.03 7.30 4.3 55.4 15.5 2.4 95.0 2025-11-30 09:14:21 ~ 2025-11-30 09:14:51
oltp_write_only 128 79,531 13,255 9.65 14.46 4.4 57.5 16.0 1.9 87.8 2025-11-30 09:14:53 ~ 2025-11-30 09:15:24


第八章:aws.io2 环境详细报告

测试时间: 2025-11-30 08:10:38
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 1879 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.1.2.89
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 2

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Intel(R) Corporation
CPU 系列: 6
型号: 106
型号名称: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
BIOS Model name: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
步进: 6
CPU MHz: 2899.956
BogoMIPS: 5799.91
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 1280K
L3 缓存: 55296K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves wbnoinvd ida arat avx512vbmi pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid md_clear flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 18Gi 251Mi 24Mi 12Gi 11Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 12,004 12,004 0.08 0.09 0.6 2.8 0.8 0.9 20.1 2025-11-30 07:57:47 ~ 2025-11-30 07:58:17
oltp_point_select 8 75,171 75,171 0.11 0.12 5.2 27.1 8.4 4.6 70.1 2025-11-30 07:58:19 ~ 2025-11-30 07:58:49
oltp_point_select 16 126,712 126,712 0.13 0.18 8.3 44.3 20.8 2.3 83.8 2025-11-30 07:58:51 ~ 2025-11-30 07:59:21
oltp_point_select 32 160,866 160,866 0.20 0.32 7.6 55.6 27.6 0.7 88.5 2025-11-30 07:59:23 ~ 2025-11-30 07:59:53
oltp_point_select 64 157,480 157,480 0.41 0.55 7.6 57.3 28.3 0.0 86.7 2025-11-30 07:59:55 ~ 2025-11-30 08:00:25
oltp_point_select 128 153,448 153,448 0.83 1.08 7.5 55.8 27.9 0.0 78.9 2025-11-30 08:00:27 ~ 2025-11-30 08:00:58
oltp_read_only 1 7,039 440 2.27 2.86 0.4 6.0 0.6 0.4 8.2 2025-11-30 08:01:00 ~ 2025-11-30 08:01:30
oltp_read_only 8 39,720 2,482 3.22 3.82 3.1 56.1 6.5 2.0 36.4 2025-11-30 08:01:32 ~ 2025-11-30 08:02:02
oltp_read_only 16 47,558 2,972 5.38 7.70 2.7 75.0 7.7 0.9 39.3 2025-11-30 08:02:04 ~ 2025-11-30 08:02:34
oltp_read_only 32 49,995 3,125 10.24 14.73 2.8 82.1 10.0 0.1 39.2 2025-11-30 08:02:36 ~ 2025-11-30 08:03:06
oltp_read_only 64 49,821 3,114 20.55 23.95 2.8 82.1 10.3 0.0 38.9 2025-11-30 08:03:08 ~ 2025-11-30 08:03:38
oltp_read_only 128 49,165 3,073 41.63 45.79 2.8 82.0 10.5 0.0 36.4 2025-11-30 08:03:40 ~ 2025-11-30 08:04:10
oltp_read_write 1 6,743 337 2.96 3.89 0.4 7.3 2.5 2.5 50.3 2025-11-30 08:04:12 ~ 2025-11-30 08:04:42
oltp_read_write 8 35,997 1,800 4.44 5.88 2.8 53.1 10.6 4.7 94.0 2025-11-30 08:04:44 ~ 2025-11-30 08:05:14
oltp_read_write 16 45,274 2,264 7.07 10.65 2.9 69.0 11.1 2.4 85.7 2025-11-30 08:05:16 ~ 2025-11-30 08:05:46
oltp_read_write 32 50,664 2,533 12.63 19.65 2.9 78.5 11.3 0.5 76.2 2025-11-30 08:05:48 ~ 2025-11-30 08:06:18
oltp_read_write 64 51,002 2,550 25.08 47.47 2.8 77.0 11.0 0.3 71.6 2025-11-30 08:06:20 ~ 2025-11-30 08:06:51
oltp_read_write 128 50,315 2,516 50.83 139.85 3.0 78.0 11.5 0.4 71.6 2025-11-30 08:06:53 ~ 2025-11-30 08:07:23
oltp_write_only 1 8,881 1,480 0.68 1.61 0.5 5.9 2.3 2.3 31.3 2025-11-30 08:07:25 ~ 2025-11-30 08:07:55
oltp_write_only 8 44,059 7,343 1.09 2.00 3.2 34.6 12.0 4.8 71.6 2025-11-30 08:07:57 ~ 2025-11-30 08:08:27
oltp_write_only 16 64,137 10,690 1.50 2.52 4.4 49.6 16.0 3.7 78.3 2025-11-30 08:08:29 ~ 2025-11-30 08:08:59
oltp_write_only 32 79,024 13,171 2.43 4.25 4.5 58.9 17.1 2.0 81.3 2025-11-30 08:09:01 ~ 2025-11-30 08:09:31
oltp_write_only 64 79,754 13,292 4.81 13.70 4.5 59.5 17.6 1.6 81.6 2025-11-30 08:09:33 ~ 2025-11-30 08:10:03
oltp_write_only 128 70,019 11,670 10.96 38.94 4.1 53.5 16.8 2.3 84.7 2025-11-30 08:10:05 ~ 2025-11-30 08:10:35


第九章:aws.io1 环境详细报告

测试时间: 2025-11-28 11:09:53
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 7925 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.1.0.47
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 2

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Intel(R) Corporation
CPU 系列: 6
型号: 143
型号名称: Intel(R) Xeon(R) Platinum 8488C
BIOS Model name: Intel(R) Xeon(R) Platinum 8488C
步进: 8
CPU MHz: 2400.000
BogoMIPS: 4800.00
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 2048K
L3 缓存: 107520K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid cldemote movdiri movdir64b md_clear serialize amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 21Gi 253Mi 16Mi 8.9Gi 8.7Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 1,835 1,835 0.54 0.72 0.3 2.4 1.0 8.6 89.6 2025-11-28 10:57:00 ~ 2025-11-28 10:57:30
oltp_point_select 8 56,871 56,871 0.14 0.49 3.1 14.2 5.2 5.4 64.7 2025-11-28 10:57:32 ~ 2025-11-28 10:58:02
oltp_point_select 16 170,296 170,296 0.09 0.13 7.4 43.1 19.7 3.1 90.8 2025-11-28 10:58:04 ~ 2025-11-28 10:58:34
oltp_point_select 32 251,905 251,905 0.13 0.20 6.2 58.5 25.3 1.3 94.2 2025-11-28 10:58:36 ~ 2025-11-28 10:59:06
oltp_point_select 64 249,718 249,718 0.26 0.36 7.1 59.0 28.1 0.0 90.9 2025-11-28 10:59:08 ~ 2025-11-28 10:59:38
oltp_point_select 128 236,283 236,283 0.54 0.72 6.5 59.9 27.8 0.0 83.4 2025-11-28 10:59:40 ~ 2025-11-28 11:00:10
oltp_read_only 1 1,845 115 8.67 10.46 0.3 2.2 0.3 0.1 1.5 2025-11-28 11:00:12 ~ 2025-11-28 11:00:42
oltp_read_only 8 28,879 1,805 4.43 7.43 2.0 26.8 3.6 1.0 20.0 2025-11-28 11:00:44 ~ 2025-11-28 11:01:14
oltp_read_only 16 64,551 4,034 3.96 5.88 2.7 66.8 7.7 0.7 37.5 2025-11-28 11:01:16 ~ 2025-11-28 11:01:46
oltp_read_only 32 73,173 4,573 6.99 11.24 2.5 79.5 9.2 0.3 39.7 2025-11-28 11:01:48 ~ 2025-11-28 11:02:18
oltp_read_only 64 74,400 4,650 13.76 19.65 2.6 81.9 10.0 0.0 37.2 2025-11-28 11:02:20 ~ 2025-11-28 11:02:50
oltp_read_only 128 74,024 4,626 27.65 31.37 2.5 81.6 10.0 0.0 36.0 2025-11-28 11:02:52 ~ 2025-11-28 11:03:22
oltp_read_write 1 1,924 96 10.39 13.95 0.3 3.0 1.2 2.6 37.3 2025-11-28 11:03:24 ~ 2025-11-28 11:03:54
oltp_read_write 8 24,967 1,248 6.41 9.73 1.6 26.0 6.0 8.2 92.0 2025-11-28 11:03:56 ~ 2025-11-28 11:04:27
oltp_read_write 16 54,742 2,737 5.84 9.06 2.7 59.0 10.1 4.5 95.7 2025-11-28 11:04:29 ~ 2025-11-28 11:04:59
oltp_read_write 32 68,211 3,411 9.38 13.70 2.6 73.2 10.3 2.2 89.3 2025-11-28 11:05:01 ~ 2025-11-28 11:05:31
oltp_read_write 64 71,816 3,591 17.81 29.72 2.7 78.2 11.2 0.7 88.3 2025-11-28 11:05:33 ~ 2025-11-28 11:06:03
oltp_read_write 128 70,575 3,529 36.24 106.75 2.7 76.1 11.0 1.2 88.7 2025-11-28 11:06:05 ~ 2025-11-28 11:06:35
oltp_write_only 1 1,786 298 3.36 5.09 0.3 2.6 1.1 3.4 35.3 2025-11-28 11:06:37 ~ 2025-11-28 11:07:07
oltp_write_only 8 19,047 3,174 2.52 4.82 1.4 13.9 4.7 6.8 65.8 2025-11-28 11:07:09 ~ 2025-11-28 11:07:39
oltp_write_only 16 39,006 6,501 2.46 4.65 2.2 25.9 8.5 7.0 80.9 2025-11-28 11:07:41 ~ 2025-11-28 11:08:11
oltp_write_only 32 68,442 11,407 2.80 5.37 3.0 41.0 12.3 5.7 87.6 2025-11-28 11:08:13 ~ 2025-11-28 11:08:43
oltp_write_only 64 94,216 15,703 4.07 7.70 3.6 53.5 15.8 3.8 91.0 2025-11-28 11:08:45 ~ 2025-11-28 11:09:16
oltp_write_only 128 66,370 11,062 11.37 24.38 2.5 39.9 12.5 5.2 96.3 2025-11-28 11:09:18 ~ 2025-11-28 11:09:51


第十章:aws.gp3 环境详细报告

测试时间: 2025-11-28 11:28:11
测试工具: sysbench + tsar (按时间段精确匹配)
tsar数据样本: 8979 条记录

测试配置信息

1
2
3
4
5
6
7
=== 测试配置信息 ===
MYSQL_HOST: 10.1.0.52
MYSQL_PORT: 3306
TABLES: 16
TABLE_SIZE: 10000000
TEST_TIME: 30

MySQL配置参数

1
2
3
4
5
mysql: [Warning] Using a password on the command line interface can be insecure.
Variable_name Value
innodb_buffer_pool_size 17179869184
innodb_flush_log_at_trx_commit 2

压测服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
=== CPU 信息 ===
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 2
每个座的核数: 4
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: (invalid)
CPU 系列: 6
型号: 143
型号名称: Intel(R) Xeon(R) Platinum 8488C
BIOS Model name: (invalid)
步进: 8
CPU MHz: 3437.734
BogoMIPS: 4800.00
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 48K
L1i 缓存: 32K
L2 缓存: 2048K
L3 缓存: 107520K
NUMA 节点0 CPU: 0-7
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid cldemote movdiri movdir64b md_clear serialize amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities

=== 内存信息 ===
total used free shared buff/cache available
Mem: 30Gi 21Gi 514Mi 16Mi 8.8Gi 8.8Gi
Swap: 0B 0B 0B

性能测试结果汇总 (含CPU/IO监控数据)

测试场景 并发数 QPS TPS 平均延迟(ms) 95%延迟(ms) CPU软中断(%) CPU用户(%) CPU系统(%) CPU等待(%) IO利用率(%) 测试时间段
oltp_point_select 1 2,316 2,316 0.43 0.67 0.3 1.8 0.5 0.3 4.6 2025-11-28 11:15:20 ~ 2025-11-28 11:15:50
oltp_point_select 8 60,437 60,437 0.13 0.46 3.0 16.4 6.1 4.7 59.8 2025-11-28 11:15:52 ~ 2025-11-28 11:16:23
oltp_point_select 16 162,670 162,670 0.10 0.14 7.2 43.6 20.4 3.6 91.5 2025-11-28 11:16:25 ~ 2025-11-28 11:16:55
oltp_point_select 32 232,535 232,535 0.14 0.23 6.6 58.1 26.7 1.4 94.6 2025-11-28 11:16:57 ~ 2025-11-28 11:17:27
oltp_point_select 64 228,321 228,321 0.28 0.39 6.9 59.1 28.1 0.0 92.8 2025-11-28 11:17:29 ~ 2025-11-28 11:17:59
oltp_point_select 128 217,381 217,381 0.59 0.78 6.4 59.6 28.1 0.0 86.7 2025-11-28 11:18:01 ~ 2025-11-28 11:18:31
oltp_read_only 1 1,692 106 9.45 10.65 0.3 2.2 0.4 0.1 2.0 2025-11-28 11:18:33 ~ 2025-11-28 11:19:03
oltp_read_only 8 31,915 1,995 4.01 6.67 1.8 34.3 4.6 1.5 26.1 2025-11-28 11:19:05 ~ 2025-11-28 11:19:35
oltp_read_only 16 59,828 3,739 4.28 6.21 2.7 67.8 8.3 0.9 40.5 2025-11-28 11:19:37 ~ 2025-11-28 11:20:07
oltp_read_only 32 66,972 4,186 7.64 11.24 2.4 79.6 9.5 0.3 42.0 2025-11-28 11:20:09 ~ 2025-11-28 11:20:39
oltp_read_only 64 67,678 4,230 15.13 22.28 2.6 81.4 10.1 0.0 41.4 2025-11-28 11:20:41 ~ 2025-11-28 11:21:11
oltp_read_only 128 67,480 4,217 30.33 34.33 2.4 81.4 10.0 0.0 38.4 2025-11-28 11:21:13 ~ 2025-11-28 11:21:43
oltp_read_write 1 1,741 87 11.48 15.00 0.3 3.2 1.2 3.1 38.8 2025-11-28 11:21:45 ~ 2025-11-28 11:22:15
oltp_read_write 8 19,019 951 8.41 17.32 1.3 25.3 5.9 15.7 94.5 2025-11-28 11:22:17 ~ 2025-11-28 11:22:47
oltp_read_write 16 42,144 2,107 7.59 15.00 2.2 50.3 8.9 10.8 94.7 2025-11-28 11:22:49 ~ 2025-11-28 11:23:19
oltp_read_write 32 60,885 3,044 10.51 15.83 2.4 71.0 10.2 2.7 90.0 2025-11-28 11:23:21 ~ 2025-11-28 11:23:51
oltp_read_write 64 64,869 3,243 19.72 33.72 2.5 75.7 10.7 1.0 87.9 2025-11-28 11:23:53 ~ 2025-11-28 11:24:24
oltp_read_write 128 63,936 3,197 40.01 116.80 2.6 76.2 10.7 1.4 89.4 2025-11-28 11:24:26 ~ 2025-11-28 11:24:56
oltp_write_only 1 1,689 282 3.55 5.99 0.3 2.9 1.1 4.4 42.9 2025-11-28 11:24:58 ~ 2025-11-28 11:25:28
oltp_write_only 8 17,630 2,938 2.72 5.67 1.2 18.0 5.5 7.8 72.3 2025-11-28 11:25:30 ~ 2025-11-28 11:26:00
oltp_write_only 16 34,757 5,793 2.76 5.67 1.9 26.9 8.3 8.0 84.9 2025-11-28 11:26:02 ~ 2025-11-28 11:26:32
oltp_write_only 32 36,656 6,109 5.24 15.00 1.7 25.6 7.7 17.7 95.5 2025-11-28 11:26:34 ~ 2025-11-28 11:27:04
oltp_write_only 64 43,519 7,253 8.82 29.72 2.0 29.3 9.1 20.9 97.5 2025-11-28 11:27:06 ~ 2025-11-28 11:27:36
oltp_write_only 128 52,980 8,830 14.49 44.98 2.3 34.6 11.0 22.3 98.1 2025-11-28 11:27:38 ~ 2025-11-28 11:28:09


附录:监控指标说明

监控数据说明

报告列名 tsar对应列 说明
CPU软中断(%) sirq 软中断CPU使用率
CPU用户(%) user 用户态CPU使用率
CPU系统(%) sys 内核态CPU使用率
CPU等待(%) wait IO等待时间占用的CPU
IO利用率(%) util (IO部分) 磁盘IO使用率

性能指标说明

  • QPS (Queries Per Second): 每秒查询数,衡量数据库处理查询的能力
  • TPS (Transactions Per Second): 每秒事务数,与QPS在点查询场景下相等
  • 平均延迟: 所有请求的平均响应时间
  • 95%延迟: 95%的请求响应时间不超过此值,更能反映用户体验

测试场景说明

场景 描述 主要指标
oltp_point_select 主键点查询 QPS, 延迟
oltp_read_only 只读事务(包含多表JOIN) TPS, QPS
oltp_read_write 读写混合事务 TPS, 延迟
oltp_write_only 只写事务 TPS, IO利用率

数据来源说明

  • CPU/IO数据来源于tsar监控日志,按测试时间段精确匹配并计算平均值
  • 系统监控数据与性能数据时间精确对应,确保数据准确性
  • 测试使用sysbench工具,针对MySQL数据库进行标准化性能测试

报告生成时间: 2025-12-01 19:21:45

MySQL PreparedStatement 性能问题重现

问题描述

在生产环境中发现,当使用 useServerPrepStmts=true 参数时,包含大量参数的 PreparedStatement 查询性能极差。通过系统测试发现,SQL 格式和长度对性能有巨大影响

只需要一个空表就能稳定重现这个问题,可以给官方提交 bug 了

环境信息

  • MySQL版本: 5.7.29
  • JDBC驱动: mysql-connector-j-8.0.33
  • 测试场景: 5万个大整数参数的 IN 查询
  • 参数格式: 15位大整数(如 176302640511975)
  • 重现代码: https://github.com/plantegg/MySQLPrepared

核心发现

🔥 SQL 格式对性能的巨大影响

我们发现 SQL 字符串的格式和长度 是影响服务器端预编译性能的关键因素:

SQL格式 SQL长度 false平均时间 true平均时间 性能差异
紧凑格式 (?,?,?) 100KB 35ms 645ms 慢18倍 ⭐ 最优
带换行格式 2.1MB 47ms 9,128ms 慢194倍
带换行+空格 (128) 6.5MB 52ms 27,839ms 慢535倍
带换行+大量空格 (128) 8.5MB 62ms 44,521ms 慢712倍 🔥 最差

关键结论:

  • 最优化的紧凑格式 可以将服务器端性能提升 14倍(9,128ms → 645ms)
  • ⚠️ 即使优化后,客户端预编译(35ms)仍比服务器端(645ms)快 18倍

重现步骤

1. 环境准备

创建测试表:

1
mysql -h your-host -P your-port -u your-user -p your-database < create_table.sql

create_table.sql 内容:

1
2
3
4
5
6
7
8
9
10
DROP TABLE IF EXISTS `large_table`;

CREATE TABLE `large_table` (
`id` int(11) NOT NULL,
`col1` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`col2` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
-- ... col3-col19 ...
`col20` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

2. 运行测试

使用脚本(推荐)

1
2
3
4
5
6
7
8
9
10
# 最优配置(紧凑格式)
./run_test.sh --host localhost --port 3306 --database test \
--user root --password mypass --spaces 0

# 测试不同空格配置的影响
./run_test.sh --host localhost --port 3306 --database test \
--user root --password mypass --spaces 128

# 查看帮助
./run_test.sh --help

使用 Maven

1
2
3
4
5
6
7
8
mvn compile exec:java \
-Dexec.mainClass="com.test.PreparedStatementPerformanceTest" \
-Ddb.host=localhost \
-Ddb.port=3306 \
-Ddb.name=test \
-Ddb.user=root \
-Ddb.password=mypassword \
-Dparam.spaces=0

3. 参数说明

参数 默认值 说明
--spaces 128 参数之间的空格数量,0=最紧凑格式
--rounds 2 测试轮次

详细测试结果

测试 1: 紧凑格式 (spaces=0) ⭐ 推荐

SQL 示例: WHERE id IN (?,?,?,?,...)

1
2
3
4
5
6
7
8
9
10
11
配置: useServerPrepStmts=false
SQL长度: 100,151 字符 (~100KB)
平均执行时间: 35.0ms
Com_stmt_prepare: 0

配置: useServerPrepStmts=true
SQL长度: 100,151 字符 (~100KB)
平均执行时间: 645.5ms
Com_stmt_prepare: 1

性能差异: 慢 18 倍

测试 2: 带换行格式 (旧版本)

SQL 示例:

1
2
3
4
5
WHERE id IN (?
,
?
,
?
1
2
3
4
5
6
7
8
9
10
11
配置: useServerPrepStmts=false
SQL长度: 2,100,111 字符 (~2.1MB)
平均执行时间: 47.0ms
Com_stmt_prepare: 0

配置: useServerPrepStmts=true
SQL长度: 2,100,111 字符 (~2.1MB)
平均执行时间: 9,128.5ms
Com_stmt_prepare: 1

性能差异: 慢 194 倍

测试 3: 带空格格式 (spaces=128)

SQL 示例: WHERE id IN (?,<128 spaces>?,<128 spaces>?,...)

1
2
3
4
5
6
7
8
9
10
11
配置: useServerPrepStmts=false
SQL长度: 6,500,023 字符 (~6.5MB)
平均执行时间: 52.0ms
Com_stmt_prepare: 0

配置: useServerPrepStmts=true
SQL长度: 6,500,023 字符 (~6.5MB)
平均执行时间: 27,839.5ms
Com_stmt_prepare: 1

性能差异: 慢 535 倍

测试 4: 带换行+大量空格 (极端情况)

1
2
3
4
5
6
7
8
9
10
11
配置: useServerPrepStmts=false
SQL长度: 8,499,983 字符 (~8.5MB)
平均执行时间: 62.5ms
Com_stmt_prepare: 0

配置: useServerPrepStmts=true
SQL长度: 8,499,983 字符 (~8.5MB)
平均执行时间: 44,521.5ms
Com_stmt_prepare: 1

性能差异: 慢 712 倍

性能分析

1. SQL 长度与性能的线性关系

服务器端预编译性能随 SQL 长度线性恶化:

1
2
3
4
100KB  SQL → 645ms    (基准)
2.1MB SQL → 9,128ms (14倍恶化)
6.5MB SQL → 27,839ms (43倍恶化)
8.5MB SQL → 44,521ms (69倍恶化)

2. 客户端预编译的稳定性

客户端预编译几乎不受 SQL 长度影响:

1
2
3
100KB  SQL → 35-47ms
8.5MB SQL → 62ms
变化幅度: 仅 77%

3. 问题根因

根据 pstack 分析,服务器端预编译在处理大 SQL 时:

  1. 大量内存重分配:

    • 50,000 次参数替换操作
    • 每次替换需要在大 SQL 字符串中定位和替换
    • my_reallocmemmove 频繁调用
  2. 字符串操作复杂度:

    • O(SQL长度) × 参数数量 = 极高时间复杂度
    • 单线程 100% CPU 占用
  3. 内存碎片化:

    • 频繁的大块内存分配和释放
    • 进一步降低性能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Thread 1 (Thread 0x7feeb8043640 (LWP 2508284)):
#0 0x00007ff302bb5515 in __memmove_avx512_unaligned_erms () from /lib64/libc.so.6
#1 0x0000000000efffe6 in my_realloc (key=<optimized out>, ptr=0x7fee5e907380, size=7192160, flags=<optimized out>) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/mysys/my_malloc.c:112
#2 0x0000000000d9a921 in String::mem_realloc (this=0x7feeb80424b0, alloc_length=7192155, force_on_heap=force_on_heap@entry=false) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql-common/sql_string.cc:128
#3 0x0000000000d9b9d4 in String::replace (this=this@entry=0x7feeb80424b0, offset=7119079, arg_length=arg_length@entry=1, to=0x7fee5c3f5810 "286381588518215", to_length=15) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql-common/sql_string.cc:804
#4 0x0000000000d9ba81 in String::replace (this=this@entry=0x7feeb80424b0, offset=<optimized out>, arg_length=arg_length@entry=1, to=...) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql-common/sql_string.cc:783
#5 0x0000000000d026e2 in Prepared_statement::insert_params (this=this@entry=0x7fee5c171fe0, null_array=null_array@entry=0x7fee5c45240a "", read_pos=0x7fee5c4ccc05 "\336\274y\206", <incomplete sequence \303>, read_pos@entry=0x7fee5c46c315 "\016r\342\320\355\242\002", data_end=0x7fee5c4cdd95 "", query=query@entry=0x7feeb80424b0) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/sql_prepare.cc:924
#6 0x0000000000d03db6 in Prepared_statement::set_parameters (this=this@entry=0x7fee5c171fe0, expanded_query=expanded_query@entry=0x7feeb80424b0, packet=0x7fee5c46c315 "\016r\342\320\355\242\002", packet_end=<optimized out>) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/sql_prepare.cc:3496
#7 0x0000000000d0772f in Prepared_statement::execute_loop (this=0x7fee5c171fe0, expanded_query=0x7feeb80424b0, open_cursor=<optimized out>, packet=<optimized out>, packet_end=<optimized out>) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/sql_prepare.cc:3559
#8 0x0000000000d07aa4 in mysqld_stmt_execute (thd=thd@entry=0x7fee5c000b60, stmt_id=<optimized out>, flags=0, params=0x7fee5c45240a "", params_length=506251) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/sql_prepare.cc:2582
#9 0x0000000000cdf6f5 in dispatch_command (thd=thd@entry=0x7fee5c000b60, com_data=com_data@entry=0x7feeb8042d40, command=COM_STMT_EXECUTE) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/sql_parse.cc:1428
#10 0x0000000000ce00c7 in do_command (thd=thd@entry=0x7fee5c000b60) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/sql_parse.cc:1032
#11 0x0000000000d9cc08 in handle_connection (arg=arg@entry=0x1eb0a010) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313
#12 0x00000000013fc4a4 in pfs_spawn_thread (arg=0x1ea71270) at /export/home/pb2/build/sb_0-37309218-1576676711.18/mysql-5.7.29/storage/perfschema/pfs.cc:2197
#13 0x00007ff30305b3fb in start_thread () from /lib64/libpthread.so.0
#14 0x00007ff302b0de83 in clone () from /lib64/libc.so.6

监控数据

1
2
3
4
5
6
7
# top 监控
PID USER %CPU TIME+ COMMAND
2554029 mysql 99.3 4:40.64 mysqld // 单线程 100%

# show processlist 观察
Id User Command Time State Info
382 test Execute 8 starting NULL // SQL 还在组装中

解决方案

✅ 方案 1: 使用客户端预编译 + 紧凑格式(强烈推荐)

1
2
3
4
5
6
// JDBC 连接串
String url = "jdbc:mysql://host:port/database?useServerPrepStmts=false";

// 运行测试
./run_test.sh --host localhost --port 3306 --database test \
--user root --password mypass --spaces 0

优点:

  • ✅ 性能最优:仅需 35ms
  • ✅ 不受 SQL 长度影响
  • ✅ 不受参数数量影响
  • ✅ 稳定可靠

缺点:

  • ⚠️ 无法享受服务器端查询计划缓存(但对 IN 查询意义不大)

🔄 方案 2: 优化 SQL 格式(如果必须使用服务器端预编译)

如果由于某些原因必须使用 useServerPrepStmts=true,则务必优化 SQL 格式:

1
2
3
4
5
// 使用最紧凑格式: ?,?,?,?
// 避免: ?\n ,\n ?

String url = "jdbc:mysql://host:port/database?useServerPrepStmts=true";
// 运行时使用 --spaces 0

性能: 645ms(相比未优化的 9,128ms 提升 14 倍)

🔧 方案 3: 分批查询

1
2
3
4
5
6
// 将 50,000 个参数拆分为 50 批,每批 1,000 个
int batchSize = 1000;
for (int i = 0; i < ids.size(); i += batchSize) {
List<Long> batch = ids.subList(i, Math.min(i + batchSize, ids.size()));
// 执行查询
}

🗃️ 方案 4: 临时表方案

1
2
3
4
CREATE TEMPORARY TABLE temp_ids (id BIGINT);
INSERT INTO temp_ids VALUES (?), (?), ...;
SELECT * FROM large_table WHERE id IN (SELECT id FROM temp_ids);
DROP TEMPORARY TABLE temp_ids;

最佳实践

✅ 推荐配置

场景 useServerPrepStmts spaces 预期性能
生产环境 false 0 35ms ⭐ 最优
标准测试 false 0 35-50ms
必须服务器端预编译 true 0 645ms

❌ 避免配置

场景 useServerPrepStmts SQL格式 性能
❌ 带格式化 true 带换行/缩进 9,128ms 慢194倍
❌ 大量空格 true spaces > 0 27,839ms 慢535倍
❌ 极端情况 true 大量换行+空格 44,521ms 慢712倍

🎯 实施建议

  1. 开发阶段:

    • 设置 useServerPrepStmts=false
    • 使用 --spaces 0 测试
  2. 测试阶段:

    • 对比不同配置的性能
    • 使用 SHOW PROCESSLIST 监控
  3. 生产环境:

    • 强制使用客户端预编译
    • 避免大参数量 IN 查询
    • 如必须使用,考虑分批或临时表方案

完整对比表

配置 SQL格式 SQL长度 false平均 true平均 性能差异
最优 ?,?,? 100KB 35ms 645ms 慢18倍 ⭐
带换行 ?\n,\n? 2.1MB 47ms 9,128ms 慢194倍
+空格128 ?,<128>? 6.5MB 52ms 27,839ms 慢535倍
带换行+空格128 ?\n,\n<128>? 8.5MB 62ms 44,521ms 慢712倍 🔥

性能改善总结

通过 SQL 格式优化:

指标 优化前 优化后 改善幅度
SQL 长度 2.1MB 100KB 缩小 95%
服务器端性能 9,128ms 645ms 提升 14 倍
性能差异倍数 194倍 18倍 改善 10 倍

但最终建议: 使用客户端预编译(35ms)才是最佳方案!

结论

  1. SQL 长度是服务器端预编译的致命弱点

    • 长度增加 → 性能线性恶化
    • 从 100KB(645ms)到 8.5MB(44,521ms),性能下降 69 倍
  2. SQL 格式优化很重要

    • 移除换行和多余空格可提升性能 14 倍
    • 使用 --spaces 0 获得最紧凑格式
  3. 客户端预编译几乎不受影响

    • 100KB SQL: 35ms
    • 8.5MB SQL: 62ms
    • 性能稳定可靠
  4. 生产环境强烈建议

    • ✅ 使用 useServerPrepStmts=false
    • ✅ 使用最紧凑的 SQL 格式(--spaces 0
    • ✅ 避免大参数量 IN 查询,或使用分批/临时表方案
  5. 性能差异

    • 最优配置(35ms)vs 最差配置(44,521ms)= 1,272 倍差异
    • 这不是优化问题,而是架构选择问题

测试代码仓库

跨 Die 热迁移迁移导致的性能问题

场景

在 ARM 上,本来业务跑在 Die0 上,如果通过taskset 将 CPU 绑到 Die1,经过一段时间运行,内存也会慢慢随着释放/新分配慢慢都迁移到 Die1, 但是这之后仍然发现性能比在 Die0 上要差很多。而在 Intel X86 上没碰到过这个问题

分析

下图是内存带宽使用率监控数据,可以看到跨 Die 绑定后原来的 Die0 带宽急剧增加(7.5% -> 13%)这是因为内存都需要跨 Die 访问了,随着跨 Die 访问并慢慢将内存迁移到 Die1 后内存带宽使用率回落到 5%:

img

同时可以看到 CPU 使用率也从 35% 飙升到 76%,随着内存的迁移完毕,CPU 使用率回落到 48%,但仍然比最开始的 35% 高不少:

img

Intel X86 下跨 Die 迁移

Intel 基本都是一路就是一个 Die,所以你可以理解这里的跨 Die 就是跨路/Socket 迁移:

img

img

结论

ARM 比 X86 差这么多的原因是内存页表跨 Die 访问导致的,业务同学测试了开启 THP 负载的影响,从结果看,THP on 可有效降低cpu水位,但是依然存在跨die迁移cpu水位上升的问题。

alios 对应的 patch:https://gitee.com/anolis/cloud-kernel/pulls/2254/commits 不区分 x86 和 arm

页表是进程创建时在内核空间分配好的,所以迁移内存时并不会迁移页表。通过测试页表跨die迁移的poc,验证了跨die页表访问是导致本文所述问题的根本原因

课后作业:

去了解下内存页表/THP(透明大页)

学习 CPU 访问内存延时是怎么回事,然后学习 CPU 和内存速度的差异,最后再去看看大学的计算机组成原理

学习下 taskset/perf 等命令

CPU 使用率高就一定有效率吗?

背景

最近碰到一个客户业务跑在8C ECS 上,随着业务压力增加 CPU使用率也即将跑满,于是考虑将 8C 升级到16C,事实是升级后业务 RT 反而略有增加,这个事情也超出了所有程序员们的预料,所以我们接下来分析下这个场景

分析

通过采集升配前后、以前和正常时段的火焰图对比发现CPU 增加主要是消耗在 自旋锁上了:

image-20240202085410669

用一个案例来解释下自旋锁和锁,如果我们要用多线程对一个整数进行计数,要保证线程安全的话,可以加锁(synchronized), 这个加锁操作也有人叫悲观锁,抢不到锁就让出这个线程的CPU 调度(代价上下文切换一次,几千个时钟周期)

另外一种是用自旋锁(CAS、spin_lock) 来实现,抢不到锁就耍赖占住CPU 死磕不停滴抢(CPU 使用率一直100%),自旋锁的设计主要是针对抢锁概率小、并发低的场景。这两种方案针对场景不一样各有优缺点

假如你的机器是8C,你有100个线程来对这个整数进行计数的话,你用synchronized 方式来实现会发现CPU 使用率永远达不到50%

image-20240202090428778

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#taskset -a -c 56-63 java LockAccumulator 100 1000000000
累加结果: 1000000000 and time:84267

Performance counter stats for 'taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 100 100000000':

17785.271791 task-clock (msec) # 2.662 CPUs utilized
110,351 context-switches # 0.006 M/sec
10,094 cpu-migrations # 0.568 K/sec
11,724 page-faults # 0.659 K/sec
44,187,609,686 cycles # 2.485 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
22,588,807,670 instructions # 0.51 insns per cycle
6,919,355,610 branches # 389.050 M/sec
28,707,025 branch-misses # 0.41% of all branches

如果我们改成自旋锁版本的实现,8个核CPU 都是100%

image-20240202090714845

以下代码累加次数只有加锁版本的10%,时间还长了很多,也就是效率产出实在是低

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 100000000
累加结果: 100000000
操作耗时: 106593 毫秒

Performance counter stats for 'taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 100000000':

85363.429249 task-clock (msec) # 7.909 CPUs utilized
23,010 context-switches # 0.270 K/sec
1,262 cpu-migrations # 0.015 K/sec
13,403 page-faults # 0.157 K/sec
213,191,037,155 cycles # 2.497 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
43,523,454,723 instructions # 0.20 insns per cycle
10,306,663,291 branches # 120.739 M/sec
14,704,466 branch-misses # 0.14% of all branches

代码

放在了github 上,有个带调X86 平台 pause 指令的汇编,Java 中要用JNI 来调用,ChatGPT4帮我写的,并给了编译、运行方案:

1
2
3
4
5
6
7
8
9
10
javac SpinLockAccumulator.java
javah -jni SpinLockAccumulator

# Assuming GCC is installed and the above C code is in SpinLockAccumulator.c
gcc -shared -o libpause.so -fPIC SpinLockAccumulator.c

java -Djava.library.path=. SpinLockAccumulator

实际gcc编译要带上jdk的头文件:
gcc -I/opt/openjdk/include/ -I/opt/openjdk/include/linux/ -shared -o libpause.so -fPIC SpinLockAccumulator.c

在MySQL INNODB 里怎么优化这个自旋锁

MySQL 在自旋锁抢锁的时候每次会调 ut_delay(底层会掉CPU指令,让CPU暂停一下但是不让出——避免上下文切换),发现性能好了几倍。这是MySQL 的官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-performance-spin_lock_polling.html

所以我们继续在以上代码的基础上在自旋的时候故意让CPU pause(50个), 这个优化详细案例:https://plantegg.github.io/2019/12/16/Intel%20PAUSE%E6%8C%87%E4%BB%A4%E5%8F%98%E5%8C%96%E6%98%AF%E5%A6%82%E4%BD%95%E5%BD%B1%E5%93%8D%E8%87%AA%E6%97%8B%E9%94%81%E4%BB%A5%E5%8F%8AMySQL%E7%9A%84%E6%80%A7%E8%83%BD%E7%9A%84/

该你动手了

随便找一台x86 机器,笔记本也可以,macOS 也行,核数多一些效果更明显。只要有Java环境,就用我编译好的class、libpause.so 理论上也行,不兼容的话按代码那一节再重新编译一下

可以做的实验:

  • 重复我前面两个运行,看CPU 使用率以及最终耗时
  • 尝试优化待pause版本的自旋锁实现,是不是要比没有pause性能反而要好
  • 尝试让线程sleep 一下,效果是不是要好?
  • 尝试减少线程数量,慢慢是不是发现自旋锁版本的性能越来越好了

改变线程数量运行对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//自旋锁版本线程数对总时间影响很明显,且线程少的话性能要比加锁版本好,这符合自旋锁的设定:大概率不需要抢就用自旋锁
#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 1 100000000
累加结果: 100000000
操作耗时: 2542 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 2 100000000
累加结果: 100000000
操作耗时: 2773 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 4 100000000
累加结果: 100000000
操作耗时: 4109 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 8 100000000
累加结果: 100000000
操作耗时: 11931 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 16 100000000
累加结果: 100000000
操作耗时: 13476 毫秒


//加锁版本线程数变化对总时间影响不那么大
#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 16 100000000
累加结果: 100000000 and time:9074

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 8 100000000
累加结果: 100000000 and time:8832

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 4 100000000
累加结果: 100000000 and time:7330

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 2 100000000
累加结果: 100000000 and time:6298

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 1 100000000
累加结果: 100000000 and time:3143

设定100并发下,改变机器核数对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//16核机器跑3次 耗时稳定在12秒以上,CPU使用率 1600%
#taskset -a -c 48-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 12860 毫秒

#taskset -a -c 48-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 12949 毫秒

#taskset -a -c 48-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 13692 毫秒

//8核机器跑3次,耗时稳定5秒左右,CPU使用率 800%
#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 6773 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 5557 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 2724 毫秒

总结

以后应该不会再对升配后CPU 使用率也上去了,但是最终效率反而没变展现得很惊诧了

从CPU 使用率、上下文切换上理解自旋锁(乐观锁)和锁(悲观锁)

MySQL 里对自旋锁的优化,增加配置 innodb_spin_wait_delay 来增加不同场景下DBA 的干预手段

这篇文章主要功劳要给 ChatGPT4 ,里面所有演示代码都是它完成的

相关阅读

流量一样但为什么CPU使用率差别很大 同样也是跟CPU 要效率,不过这个案例不是因为自旋锁导致CPU 率高,而是内存延时导致的

今日短平快,ECS从16核升配到48核后性能没有任何提升(Netflix) 也是CPU 使用率高没有产出,cacheline伪共享导致的

听风扇声音来定位性能瓶颈

你要是把这个案例以及上面三个案例综合看明白了,相当于把计算机组成原理就学明白了。这里最核心的就是“内存墙”,也就是内存速度没有跟上CPU的发展速度,导致整个计算机内绝大多场景下读写内存缓慢成为主要的瓶颈

如果你觉得看完对你很有帮助可以通过如下方式找到我

find me on twitter: @plantegg

知识星球:https://t.zsxq.com/0cSFEUh2J

开了一个星球,在里面讲解一些案例、知识、学习方法,肯定没法让大家称为顶尖程序员(我自己都不是),只是希望用我的方法、知识、经验、案例作为你的垫脚石,帮助你快速、早日成为一个基本合格的程序员。

争取在星球内:

  • 养成基本动手能力
  • 拥有起码的分析推理能力–按我接触的程序员,大多都是没有逻辑的
  • 知识上教会你几个关键的知识点
image-20240324161113874

tcp会偶尔3秒timeout的分析以及如何用php规避这个问题

这是一篇好文章,随着蘑菇街的完蛋,蘑菇街技术博客也没了,所以特意备份一下这篇

  • 作者:蚩尤

  • 时间:May 27, 2014

2年前做一个cache中间件调用的时候,发现很多通过php的curl调用一个的服务会出现偶尔的connect_time超时, 表现为get_curlinfo的connect_time在3秒左右, 本来没怎么注意, 因为客户端的curl_timeout设置的就是3秒, 某天, 我把这个timeout改到了5秒后, 发现了一个奇怪的现象, 很多慢请求依旧表现为connect_time在3秒左右..看来这个3秒并不是因为客户端设置的timeout引起的.于是开始查找这个原因.


首先, 凭借经验调整了linux内核关于tcp的几个参数

1
2
net.core.netdev_max_backlog = 862144
net.core.somaxconn = 262144

经过观察发现依旧会有3秒超时, 而且数量并没有减少.

第二步, 排除是大并发导致的问题, 在一台空闲机器上也部署同样的服务, 仅让线上一台机器跑空闲机器的服务, 结果发现依旧会有报错.排除并发导致的问题.

最后, 通过查了大量的资料才发现并不是我们才遇到过这个问题, 而且这个问题并不是curl的问题, 它影响到所有tcp的调用, 网上各种说法, 但结论都指向linux内核对于tcp的实现.(某些版本会出现这些问题), 有兴趣的可以看下下面这两个资料.
资料1
资料2

一看深入到linux内核..不管怎样修改的成本一定很大..于是乎, 发挥我们手中的php来规避这个问题的时间到了.

原本的代码, 简单实现,常规curl调用:

1
2
3
4
5
6
7
8
9
10
function curl_call($p1, $p2 ...) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_URL, 'http://demon.at');
$res = curl_exec($ch);
if (false === $res) {
//失败..抛异常..
}
return $res;
}

可以看出, 如果用上面的代码, 无法避免3秒connect_time的问题..这种实现对curl版本会有要求(CURLOPT_CONNECTTIMEOUT_MS),主要的思路是,通过对链接时间进行毫秒级的控制(因为超时往往发生在connect的时候),加上失败重试机制,来最大限度保证调用的正确性。所以,下面的代码就诞生了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function curl_call($p1, $p2, $times = 1) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_URL, 'http://demon.at');
$curl_version = curl_version();
if ($curl_version['version_number'] >= 462850) {
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 20);
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
} else {
throw new Exception('this curl version is too low, version_num : '
. $curl_version['version']);
}
$res = curl_exec($ch);
curl_close($ch);
if (false === $res) {
if (curl_errno($ch) == CURLE_OPERATION_TIMEOUTED
and $times != 最大重试阀值 ) {
$times += 1;
return curl_call($p1, $p2, $times);
}
}

return $res;
}

上面这段代码只是一个规避的简单实例, 一些小细节并没有可以完善..比如抛出异常常以后curl资源的手动释放等等..这里不做讨论..当然还漏了一点要说的是,对重试次数最好加上限制 :)

说明一下上面几个数字值的含义:

1
2
462850 //因为php的CURLOPT_CONNECTTIMEOUT_MS需要 curl_version 7.16.2,这个值就是这个版本的数字版本号,还需要注意的是, php版本要大于5.2.3
20 //连接超时的时间, 单位:ms

这样这个问题就这样通过php的代码来规避开了.
如果有对这个问题有更好的解决方法,欢迎指教.


总结

tcp connect 的流程是这样的
1、tcp发出SYN建链报文后,报文到ip层需要进行路由查询
2、路由查询完成后,报文到arp层查询下一跳mac地址
3、如果本地没有对应网关的arp缓存,就需要缓存住这个报文,发起arp请求
4、arp层收到arp回应报文之后,从缓存中取出SYN报文,完成mac头填写并发送给驱动。

问题在于,arp层缓存队列长度默认为3。如果你运气不好,刚好赶上缓存已满,这个报文就会被丢弃。

TCP层发现SYN报文发出去3s(默认值)还没有回应,就会重发一个SYN。这就是为什么少数连接会3s后才能建链。

幸运的是,arp层缓存队列长度是可配置的,用 sysctl -a | grep unres_qlen 就能看到,默认值为3。

一次抓包分析过程——Wireshark 新手上车

问题

网友尝试做星球第一个必做实验的时候,什么内核参数都没改,发现请求经常会停滞 100ms,这种要怎么判断是局域网的网络问题还是应用问题呢? 服务是 python3 -m http.server 启动的,看上去没有出现什么重传、窗口也没看到什么问题

因为不能提供环境给我,我尝试对这个抓包进行了分析,因为只有客户端抓包,所以分析结果是没有结论的,但分析过程比较适合入门 Wireshark,适合刚加入星球的、没分析过网络包的同学可以参考,熟手请忽略

分析

整个抓包 28MB,跨度 600 毫秒,看得出带宽很大、RTT 极小(到Wireshark 里看看前几个包的交互 RT 就知道了)

image-20240715093847359

详细分析

看第一次卡 100ms 之前的抓包,在100ms 以前客户端ack 了所有Server 发出来的的tcp包(红框),也就是说每一个发给客户端的包客户端都ack 完毕,证明客户端处理足够快,但是 8089端口不继续发包而是等了100ms再继续发,如下图:

image-20240715094218182

到这里的结论:

不是因为发送buffer、接收buffer太小导致的卡;也不是因为拥塞窗口导致的,就是Server 端没有发包。大概率是Server 进程卡了,或者Server 进程读取物理文件往OS buffer 写这些环节卡了(可以在服务端通过 strace -tt 看看进程在这 100 毫秒有没有往内核怼数据)

所以要继续在 Server 端来分析这个问题

怎么快速定位到红框、红线这里的包?

到 Time Sequence 图上点平台两边的点都可以自动跳转到这里,每个点代表一个网络包,横坐标代表时间

其它分析

将如下 Time Sequence 图使劲放大,从第一个包开始看,可以观察到教科书所说的慢启动

image-20240715095134352

整体看的话,慢启动几乎可以忽略,毕竟这个抓包是下载一个巨大的文件,如果是一个小文件这个慢启动还是影响很大的,如下图,红框部分看起来微不足道

image-20240715095506381

把时间范围放大,继续看,在卡之前红色箭头很长的,代表带宽、buffer有能力一次发送很多网络包,但是后面每次只发一点点网络包(绿色箭头长度)就卡了

image-20240715095647702

重现

我用 python3 当服务端未能重现这个卡100ms 的现象,拉取都很丝滑

image-20240715101505977

非常细节地去分析的话,也是能看到一些小问题的,比如1.9ms的卡顿、比如zero_window

image-20240715103928266

重现的时候,有1.9ms 这样的卡顿,但是不算有规律,因为这么小在整个传输过程中影响不大

image-20240715103708750

我重现的时候正好抓到了 seq 回绕,seq 是个 32位的无符号整数,到了最大值就从0又开始:

image-20240715115500312

此时的 Time Sequence:

image-20240715115655516

建议

可以用实验1里面的一些手段debug 一下Server 为什么卡了,除了 strace -tt 还可以用 ebpf 试试看看 Server 的调度上哪里顿了 100ms

新手如何通过Wireshark 来看抓包?

首先不要纯粹为了学习去看,而是要问你的问题是什么?如果网络传输速度慢,我们就看 Time Sequence(斜率越陡速度越快),去看为什么发送端不发包了

  • 如正文里的卡顿平台,在250ms内差不多要卡240ms 不发包,速度自然不行
  • 我重现抓包中的zero Windows
  • 达到网络BDP 瓶颈了,去看拥塞窗口在最大值的时候会丢包,触发降速

里面可以看、要看的东西太多,所以我也说不上要看什么,而是要问你的问题是什么

历时5年的net_write_timeout 报错分析

全网关于 JDBC 报错:net_write_timeout 的最好/最全总结

前言

上一次为了讲如何分析几百万个抓包,所以把这个问题中的一部分简化写了这篇抓包篇:https://articles.zsxq.com/id_lznw3w4zieuc.html 建议你先去看看把场景简化下,然后本篇中的分析涉及抓包部分就不再啰嗦讲解,请看抓包篇

问题描述

用户为了做数据分析需要把160个DB中的数据迁移到另外一个只读库中,有专门的迁移工具,但是这个迁移工具跑一阵后总是报错,报错堆栈显示是Tomcat 到DB之间的连接出了异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of 'net_write_timeout' on the server.
at sun.reflect.GeneratedConstructorAccessor150.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3749)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3649)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4090)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:972)
at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:2123)
at com.mysql.jdbc.RowDataDynamic.nextRecord(RowDataDynamic.java:374)
at com.mysql.jdbc.RowDataDynamic.next(RowDataDynamic.java:354)
at com.mysql.jdbc.RowDataDynamic.close(RowDataDynamic.java:155)
at com.mysql.jdbc.ResultSetImpl.realClose(ResultSetImpl.java:6726)
at com.mysql.jdbc.ResultSetImpl.close(ResultSetImpl.java:865)
at com.alibaba.druid.pool.DruidPooledResultSet.close(DruidPooledResultSet.java:86)

这个异常堆栈告诉我们Tomcat 到Database之间的连接异常了,似乎是 net_write_timeout 超时导致的

对应业务结构:

image-20230706210452742

net_write_timeout 原理简介

先看下 net_write_timeout的解释:

The number of seconds to wait for a block to be written to a connection before aborting the write. 只针对执行查询中的等待超时,网络不好,tcp buffer满了(应用迟迟不读走数据)等容易导致mysql server端报net_write_timeout错误,指的是mysql server hang在那里长时间无法发送查询结果。

报这个错就是DB 等了net_write_timeout这么久没写数据,可能是Tomcat 端卡死没有读走数据。

但是根据我多年来和这个报错打交道的经验告诉我:这个报错不只是因为net_write_timeout 超时导致的,任何Tomcat 到 DB间的连接断开了,都报这个错误,原因是JDBC 驱动搞不清楚断开的具体原因,统统当 net_write_timeout 了

一定要记住这个原理。如果这里不理解可以进一步阅读:https://wx.zsxq.com/dweb2/index/topic_detail/412251415855228

分析

首先把Tomcat 集群从负载均衡上摘一个下来,这样没有业务流量干扰更利于测试和分析日志

然后让迁移数据工具直接连这个没有流量的节点,问题仍然稳定重现。

进一步提取迁移工具的SQL,然后走API手工提交给Tomcat 执行,问题仍然稳定重现,现在重现越来越简单了,效率高多了。

Tomcat 上抓包

因为没有业务流量干扰,抓包很干净,但是因为DB 节点太多,所以量还是很大的,分析如抓包篇:https://articles.zsxq.com/id_lznw3w4zieuc.html

如下图红框所示的地方可以看到MySQL Server 传着传着居然带了个 fin 包在里面,表示MySQL Server要断开连接了,无奈Client只能也发送quit 断开连接。红框告诉我们一个无比有力的证据MySQL Server 在不应该断开的地方断开了连接,问题在 MySQL Server 端

image-20230620141017987

看起来是Database 主动端开了连接,因为这个过程Tomcat 不需要发任何东西给 Database。这个现象5年前在其它用户场景下就抓到过了,最后问题也不了了之,这次希望搞清楚

Database 分析

打开 DB 日志,捞取全量日志可以看到 DB 断开的原因是收到了kill Query!

有这个结果记住上面抓包图,以后类似这样莫名起来 DB 主动断开大概率就是 kill Query 导致的(经验攒得不容易!)

Database 抓包

确实能抓到kill,而且从用户账号来看就是从 Tomcat 发过去的!

继续分析Tomcat 抓包

从 DB 分析来看还是有人主动 kill 导致的,所以继续分析Tomcat的抓包看是不是因为代码bug导致Tomcat 发了kill 给DB

大海捞针,搜 kill,找Tomcat 发给DB的tcp length 长度是16-20的(刚好容纳kill id) 总的来说就是找不到,很神奇

由于 DB上记录的 Tomcat IP、port 都被中间链路转换过几次了,根本没办法一一对应搞清楚是哪个Tomcat 节点发出来的

继续尝试重现

分析完Tomcat 业务代码后感觉业务不会去kill,于是灵机一动在没有流量的Tomcat上跑了一个Sleep 600秒,不用任何数据,神奇的问题也稳定重现了,这下大概知道什么原因了,肯定是客户自己加了慢查询监控逻辑,一旦发现慢查询就 kill

于是问客户是不是有这种监控,果然有,停掉后反复重试不再有问题!

测试环境手工触发kill,然后能抓到下发的kill Query 给Database

image-20230707150658392

未解谜题

为什么没在Tomcat 抓到发给Database的 kill ?

我反复去重现了,如果是我手工触发Tomcat kill是可以清晰地抓到Tomcat 会发160个kill 给Database,但是我任其自然等待用户监控来杀就一定抓不到kill 下发给DB

我猜和 Tomcat 集群有关,首先用户监控是走的LVS,通过其中一个Tomcat 可以查询到所有 Tomcat 上的请求,然后发起 kill

但因为节点太多无法证实!当然业务监控也可以监控DB 然后直接发kill,但是和抓包看到的发起kill的用户不对,发起 kill 的用户是Tomcat独一无二的。

JDBC驱动报错 net_write_timeout 结论

Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server. - com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server.

这个报错不一定是 net_write_timeout 设置过小导致的,JDBC 在 streaming 流模式下只要连接异常就会报如上错误,比如:

  • 连接被 TCP reset
  • RDS 前端自带的Proxy 主动断开连接
  • 连接因为某种原因(比如 QueryTimeOut) 触发 kill Query导致连接中断
  • RDS 端因为kill 主动断开连接 //比如用户监控RDS、DRDS脚本杀掉慢查询

net_write_timeout:表示这么长时间RDS/DN 无法写数据到网络层发给DRDS/CN,原因是DRDS/CN 长时间没将数据读走

总结

首先一个错误现象对应多个完全不一样的错误原因是非常头疼的,这个问题反反复复在多个场景下出现,当然原因各异,但是这个传数据途中 DB 主动 fin连接还是第一次碰到并搞清楚,同样主动 fin 不一定是kill,但是我们要依照证据推进问题,既然是DB fin就有必要先从DB 来看原因。

从这个问题你可以先从什么是JDBC 流模式出发(mysql –quick 就是流模式,你可以快速查一个大数据试试;然后去掉–quick 对比一下),结合网络buffer 来了解流模式:https://plantegg.github.io/2020/07/03/MySQL%20JDBC%20StreamResult%20%E5%92%8C%20net_write_timeout/

然后从流模式来学习MySQL 的 net_write_timeout,假如你的代码报了 net_write_timeout 你会分析吗?

最后从连接断开去总结,比如网络不好、比如内核bug、比如DB crash、比如 kill、比如……都会导致连接断开,但这一切对业务来说只有 net_write_timeout 一个现象

这个问题分享出来是因为非常综合,我惊抱怨 socketTimeout、Communication failure等异常,这些异常也挺常见导致的原因多种,但是和 net_write_timeout 比起来还是不如 net_write_timeout 更综合,所以分享给大家,建议这几篇一起阅读效果最好!

实验模拟 Consider raising value of ‘net_write_timeout’

使用 Java MySQL JDBC Driver 的同学经常碰到如下错误堆栈,到底这个错误是 net_write_timeout 设置太小还是别的原因也会导致这个问题?需要我们用实验验证一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of 'net_write_timeout' on the server.
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3559)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3459)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3900)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:873)
at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1996)
at com.mysql.jdbc.RowDataDynamic.nextRecord(RowDataDynamic.java:374)
at com.mysql.jdbc.RowDataDynamic.next(RowDataDynamic.java:354)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:6312)
at Test.main(Test.java:38)
Caused by: java.io.EOFException: Can not read response from server. Expected to read 8 bytes, read 3 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3011)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3519)
... 8 more

JDBC 驱动对这个错误有如下提示(坑人):

Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server. - com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server.

实验中的一些说明:

  1. netTimeoutForStreamingResults=1 表示设置 net_write_timeout 为 1 秒,客户端会发送 set net_write_timeout=1 给数据库
  2. conn.setAutoCommit(false); //流式读取必须要 关闭自动提交
  3. stmt.setFetchSize(Integer.MIN_VALUE);

以上 2/3是触发流式读取的必要条件,第一条不设置默认是 600 秒,比较难等 :)

如果确实是 net_write_timeout 太小超时了, RDS 直接发 fin(但是 fin 前面还有一堆 response 包也在排队),然后 RDS 日志先报错:

1
2024-11-28T14:33:03.447397Z 12 [Note] Aborted connection 12 to db: 'test' user: 'root' host: '172.26.137.130' (Got timeout writing communication packets)

此时客户端还慢悠悠地读,RDS 没有回任何错误信息给客户端,客户端读完所有 Response 然后直接读到连接断开就报 Consider raising value of ‘net_write_timeout’ on the server 了,如果客户端读的慢,比如要 10 分钟实际连接在 RDS 上 10 分钟前就进入 fin 了,但是 10 分钟后客户端才报错

1
2
3
4
5
6
7
8
9
10
#netstat -anto | grep "3307"
tcp6 0 0 :::3307 :::* LISTEN off (0.00/0/0)
tcp6 0 140192 172.26.137.120:3307 172.26.137.130:51216 ESTABLISHED probe (0.04/0/0)
2024年 11月 28日 星期四 15:01:43 CST

//1秒中后此时 数据库感知到超时于是调用 close 断开连接,触发发送 fin给客户端,但是 fin 也需要排队,所以 140192增加了 1 变成140193
tcp6 0 0 :::3307 :::* LISTEN off (0.00/0/0)
tcp6 0 140193 172.26.137.120:3307 172.26.137.130:51216 FIN_WAIT1 probe (0.58/0/1)
2024年 11月 28日 星期四 15:01:44 CST

重现代码,数据库上构造一个大表,比如 10万行就行,能堆满默认的 tcp buffer size:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;

/*
* 编译:
* javac -cp /root/java/*:. Test.java
* 运行:
* java -cp .:./mysql-connector-java-5.1.45.jar Test "jdbc:mysql://gf1:3307/test?useSSL=false&useServerPrepStmts=true&cachePrepStmts=true&connectTimeout=500&socketTimeout=1700&netTimeoutForStreamingResults=1" root 123 "select *, id from streaming " 3000
* netTimeoutForStreamingResults=1 表示RDS 等超过 1 秒都因为 tcp buffer 满无法继续发送数据就断开连接
* */
public class Test {
private static String url;
private Str name;

public static void main(String args[]) throws NumberFormatException, InterruptedException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
url = args[0];
String user = args[1];
String pass = args[2];
String sql = args[3];
String interval = args[4];
try {
Connection conn = DriverManager.getConnection(url, user, pass);
while (true) {

conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.setFetchSize(Integer.MIN_VALUE);

long start = System.currentTimeMillis();
ResultSet rs = stmt.executeQuery(sql);
int count=0;
while (rs.next()) {
System.out.println("id:"+rs.getInt("id")+" count:"+count);
count++;
if(count<3) //1 秒后数据库端连接就已经关闭了,但是因为客户端读得慢,需要不 sleep 后才能读到 fin 然后报错,所以报错可以比实际晚很久
Thread.sleep(1500);
}
rs.close();
stmt.close();
Thread.sleep(Long.valueOf(interval));
break;
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

Consider raising value of ‘net_write_timeout’ 这个报错数据库端不会返回任何错误码给客户端,只是发 fin 断开连接,对客户端来说这条连接是 net_write_timeout 超时了 还是 被kill(或者其他原因) 是没法区分的,所以不管什么原因,只要连接异常 MySQL JDBC Driver 就抛 net_write_timeout 错误

如图,3 秒钟后 fin 包混在数据库 response 就被发到了客户端,实际2 秒前数据库已经报错了,也就是客户端和数据库端报错时间会差 2 秒(具体差几秒取决于重现代码里 sleep 多久然后-1)

image-20241128151324385

实验总结

这个报错不一定是 net_write_timeout 设置过小导致的,JDBC 在 streaming 流模式下只要连接异常就会报如上错误,比如:

  • 连接被 TCP reset
  • RDS 前端自带的Proxy 主动断开连接
  • 连接因为某种原因(比如 QueryTimeOut) 触发 kill Query导致连接中断
  • RDS 端因为kill 主动断开连接 //比如用户监控RDS 脚本杀掉慢查询
  • 开启流式读取后,只要客户端在读取查询结果没有结束就读到了 fin 包就会报这个错误

可以将 netTimeoutForStreamingResults 设为 0 或者 100,然后在中途 kill 掉 MySQL 上的 SQL,你也会在客户端看到同样的错误, kill SQL 是在 MySQL 的报错日志中都是同样的:

1
2024-11-28T07:33:12.967012Z 23 [Note] Aborted connection 23 to db: 'test' user: 'root' host: '172.26.137.130' (Got an error writing communication packets)

所以你看一旦客户端出现这个异常堆栈,除了抓包似乎没什么好办法,其实抓包也只能抓到数据库主动发了 fin 什么原因还是不知道,我恨这个没有错误码一统江湖的报错

net_write_timeout 后 RDS 直接发 fin(有时 fin 前面还有一堆 response 包也在排队),然后 rds 日志先报错:2024-11-28T06:33:03.447397Z 12 [Note] Aborted connection 12 to db: ‘test’ user: ‘root’ host: ‘172.26.137.130’ (Got timeout writing communication packets)

客户端慢悠悠地读,RDS 没有传任何错误信息给客户端,客户端读完所有 response 然后直接读到连接断开就报 Consider raising value of ‘net_write_timeout’ on the server 了,如果客户端读的慢,比如要 10 分钟实际连接在 RDS 上 10 分钟前就进入 fin 了,但是 10 分钟后客户端才报错

进阶阅读:https://plantegg.github.io/2024/09/25/%E4%B8%80%E4%B8%AA%E5%8E%86%E6%97%B65%E5%B9%B4%E7%9A%84%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/https://x.com/plantegg/status/1867535551337050153

长连接黑洞重现和分析

这是一个存在多年,遍及各个不同的业务又反反复复地在集团内部出现的一个问题,本文先通过重现展示这个问题,然后从业务、数据库、OS等不同的角度来分析如何解决它,这个问题值得每一位研发同学重视起来,避免再次踩到

背景

为了高效率应对故障,本文尝试回答如下一些问题:

  • 为什么数据库crash 重启恢复后,业务还长时间不能恢复?
  • 我依赖的业务做了高可用切换,但是我的业务长时间报错
  • 我依赖的服务下掉了一个节点,为什么我的业务长时间报错
  • 客户做变配,升级云服务节点规格,为什么会导致客户业务长时间报错

目的:希望通过这篇文章尽可能地减少故障时长、让业务快速从故障中恢复

重现

空说无凭,先也通过一次真实的重现来展示这个问题

LVS+MySQL 高可用切换

OS 默认配置参数

1
2
3
4
5
6
#sysctl -a |grep -E "tcp_retries|keepalive"
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 10
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15 //主要是这个参数,默认以及alios 几乎都是15

LVS 对外服务端口是3001, 后面挂的是 3307,假设3307是当前的Master,Slave是 3306,当检测到3307异常后会从LVS 上摘掉 3307挂上 3306做高可用切换

undefined

切换前的 LVS 状态

1
2
3
4
5
6
7
8
#ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 300
#ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 127.0.0.1:3001 rr
-> 127.0.0.1:3307 Masq 1 0 0

Sysbench启动压力模拟用户访问,在 31秒的时候模拟管控检测到 3307的Master无法访问,所以管控执行切主把 3306的Slave 提升为新的 Master,同时到 LVS 摘掉 3307,挂上3306,此时管控端着冰可乐、翘着二郎腿,得意地说,你就看吧我们管控牛逼不、我们的高可用牛逼不,这一套行云流水3秒钟不到全搞定

切换命令如下:

1
2
#cat del3307.sh
ipvsadm -d -t 127.0.0.1:3001 -r 127.0.0.1:3307 ; ipvsadm -a -t 127.0.0.1:3001 -r 127.0.0.1:3306 -m

此时Sysbench运行状态,在第 32秒如期跌0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#/usr/local/bin/sysbench --debug=on --mysql-user='root' --mysql-password='123' --mysql-db='test' --mysql-host='127.0.0.1' --mysql-port='3001' --tables='16'  --table-size='10000' --range-size='5' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --time='11080' --report-interval='1' --histogram='on' --threads=1 oltp_read_write run
sysbench 1.1.0 (using bundled LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 1
Report intermediate results every 1 second(s)
Debug mode enabled.

Initializing random number generator from current time


Initializing worker threads...

DEBUG: Worker thread (#0) started
DEBUG: Reporting thread started
DEBUG: Worker thread (#0) initialized
Threads started!

[ 1s ] thds: 1 tps: 51.89 qps: 947.00 (r/w/o: 739.44/207.56/0.00) lat (ms,95%): 35.59 err/s 0.00 reconn/s: 0.00
[ 2s ] thds: 1 tps: 60.03 qps: 1084.54 (r/w/o: 841.42/243.12/0.00) lat (ms,95%): 22.28 err/s 0.00 reconn/s: 0.00
…………
[ 29s ] thds: 1 tps: 68.00 qps: 1223.01 (r/w/o: 952.00/271.00/0.00) lat (ms,95%): 16.12 err/s 0.00 reconn/s: 0.00
[ 30s ] thds: 1 tps: 66.00 qps: 1188.00 (r/w/o: 924.00/264.00/0.00) lat (ms,95%): 16.71 err/s 0.00 reconn/s: 0.00
[ 31s ] thds: 1 tps: 67.00 qps: 1203.96 (r/w/o: 937.97/265.99/0.00) lat (ms,95%): 17.95 err/s 0.00 reconn/s: 0.00
[ 32s ] thds: 1 tps: 22.99 qps: 416.85 (r/w/o: 321.88/94.96/0.00) lat (ms,95%): 15.55 err/s 0.00 reconn/s: 0.00
[ 33s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 34s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 35s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00

5分钟后故障报告大批量涌进来,客户:怎么回事,我们的业务挂掉10分钟了,报错都是访问MySQL 超时,赶紧给我看看,从监控确实看到10分钟后客户业务还没恢复:

1
2
3
4
[ 601s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 602s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 603s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 604s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00

这时 oncall 都被从被窝里拎了起来,不知谁说了一句赶紧恢复吧,先试试把应用重启,5秒钟后应用重启完毕,业务恢复,大家开心地笑了,又成功防御住一次故障升级,还是重启大法好!

在业务/Sysbench QPS跌0 期间可以看到 3307被摘掉,3306 成功挂上去了,但是没有新连接建向 3306,业务/Sysbench 使劲薅着 3307

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ipvsadm -L -n --stats -t 127.0.0.1:3001
Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
-> RemoteAddress:Port
TCP 127.0.0.1:3001 2 660294 661999 78202968 184940K
-> 127.0.0.1:3306 0 0 0 0 0

#ipvsadm -Lcn | head -10
IPVS connection entries
pro expire state source virtual destination
TCP 13:11 ESTABLISHED 127.0.0.1:33864 127.0.0.1:3001 127.0.0.1:3307

#netstat -anto |grep -E "Recv|33864|3001|33077"
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 248 127.0.0.1:33864 127.0.0.1:3001 ESTABLISHED probe (33.48/0/8)
tcp6 0 11 127.0.0.1:3307 127.0.0.1:33864 ESTABLISHED on (49.03/13/0)

直到 900多秒后 OS 重试了15次发现都失败,于是向业务/Sysbench 返回连接异常,触发业务/Sysbench 释放异常连接重建新连接,新连接指向了新的 Master 3306,业务恢复正常

1
2
3
4
5
6
7
[ 957s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
DEBUG: Ignoring error 2013 Lost connection to MySQL server during query,
DEBUG: Reconnecting
DEBUG: Reconnected
[ 958s ] thds: 1 tps: 53.00 qps: 950.97 (r/w/o: 741.98/208.99/0.00) lat (ms,95%): 30.26 err/s 0.00 reconn/s: 1.00
[ 959s ] thds: 1 tps: 64.00 qps: 1154.03 (r/w/o: 896.02/258.01/0.00) lat (ms,95%): 22.69 err/s 0.00 reconn/s: 0.00
[ 960s ] thds: 1 tps: 66.00 qps: 1184.93 (r/w/o: 923.94/260.98/0.00) lat (ms,95%): 25.28 err/s 0.00 reconn/s: 0.00

到这里重现了故障中经常碰到的业务需要900多秒才能慢慢恢复,这个问题也就是 TCP 长连接流量黑洞

如果我们把 net.ipv4.tcp_retries2 改成5 再来做这个实验,就会发现业务/Sysbench 只需要20秒就能恢复了,也就是这个流量黑洞从900多秒变成了20秒,这回 oncall 不用再被从被窝里拎出来了吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[ 62s ] thds: 1 tps: 66.00 qps: 1191.00 (r/w/o: 924.00/267.00/0.00) lat (ms,95%): 17.63 err/s 0.00 reconn/s: 0.00
[ 63s ] thds: 1 tps: 63.00 qps: 1123.01 (r/w/o: 874.00/249.00/0.00) lat (ms,95%): 17.63 err/s 0.00 reconn/s: 0.00
[ 64s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 65s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 66s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 67s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 68s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 69s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 70s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 71s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 72s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 73s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 74s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 75s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 76s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 77s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 78s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 79s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 80s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 81s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 82s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
DEBUG: Ignoring error 2013 Lost connection to MySQL server during query,
DEBUG: Reconnecting
DEBUG: Reconnected
[ 83s ] thds: 1 tps: 26.00 qps: 457.01 (r/w/o: 357.01/100.00/0.00) lat (ms,95%): 16.41 err/s 0.00 reconn/s: 1.00
[ 84s ] thds: 1 tps: 60.00 qps: 1086.94 (r/w/o: 846.96/239.99/0.00) lat (ms,95%): 26.68 err/s 0.00 reconn/s: 0.00
[ 85s ] thds: 1 tps: 63.00 qps: 1134.02 (r/w/o: 882.01/252.00/0.00) lat (ms,95%): 23.10 err/s 0.00 reconn/s: 0.00

LVS + Nginx 上重现

NGINX上重现这个问题:https://asciinema.org/a/649890 3分钟的录屏,这个视频构造了一个LVS 的HA切换过程,LVS后有两个Nginx,模拟一个Nginx(Master) 断网后,将第二个Nginx(Slave) 加入到LVS 并将第一个Nginx(Master) 从LVS 摘除,期望业务能立即恢复,但实际上可以看到之前的所有长连接都没有办法恢复,进入一个流量黑洞

TCP 长连接流量黑洞原理总结

TCP 长连接在发送包的时候,如果没收到ack 默认会进行15次重传(net.ipv4.tcp_retries2=15, 这个不要较真,会根据RTO 时间大致是15次),累加起来大概是924秒,所以我们经常看到业务需要15分钟左右才恢复。这个问题存在所有TCP长连接中(几乎没有业务还在用短连接吧?),问题的本质和 LVS/k8s Service 都没关系

我这里重现带上 LVS 只是为了场景演示方便

这个问题的本质就是如果Server突然消失(宕机、断网,来不及发 RST )客户端如果正在发东西给Server就会遵循TCP 重传逻辑不断地TCP retran , 如果一直收不到Server 的ack,大约重传15次,900秒左右。所以不是因为有 LVS 导致了这个问题,而是在某些场景下 LVS 有能力处理得更优雅,比如删除 RealServer的时候 LVS 完全可以感知这个动作并 reset 掉其上所有长连接

为什么在K8S 上这个问题更明显呢,K8S 讲究的就是服务不可靠,随时干掉POD(切断网络),如果干POD 之前能kill -9(触发reset)、或者close 业务触发断开连接那还好,但是大多时候啥都没干,有强摘POD、有直接隔离等等,这些操作都会导致对端只能TCP retran

怎么解决

业务方

业务方要对自己的请求超时时间有控制和兜底,不能任由一个请求长时间 Hang 在那里

比如JDBC URL 支持设置 SocketTimeout、ConnectTimeout,我相信其他产品也有类似的参数,业务方要设置这些值,不设置就是如上重现里演示的900多秒后才恢复

SocketTimeout

只要是连接有机会设置 SocketTimeout 就一定要设置,具体值可以根据你们能接受的慢查询来设置;分析、AP类的请求可以设置大一点

最重要的:任何业务只要你用到了TCP 长连接一定要配置一个恰当的SocketTimeout,比如 Jedis 是连接池模式,底层超时之后,会销毁当前连接,下一次重新建连,就会连接到新的切换节点上去并恢复

RFC 5482 TCP_USER_TIMEOUT

RFC 5482 中增加了TCP_USER_TIMEOUT这个配置,通常用于定制当 TCP 网络连接中出现数据传输问题时,可以等待多长时间前释放网络资源,对应Linux 这个 commit

TCP_USER_TIMEOUT 是一个整数值,它指定了当 TCP 连接的数据包在发送后多长时间内未被确认(即没有收到 ACK),TCP 连接会考虑释放这个连接。

打个比方,设置 TCP_USER_TIMEOUT 后,应用程序就可以指定说:“如果在 30 秒内我发送的数据没有得到确认,那我就认定网络连接出了问题,不再尝试继续发送,而是直接断开连接。”这对于确保连接质量和维护用户体验是非常有帮助的。

在 Linux 中,可以使用 setsockopt 函数来设置某个特定 socket 的 TCP_USER_TIMEOUT 值:

1
2
int timeout = 30000; // 30 seconds
setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, (char *)&timeout, sizeof(timeout));

在这行代码中,sock 是已经 established 的 TCP socket,我们将该 socket 的 TCP_USER_TIMEOUT 设置为 30000 毫秒,也就是 30 秒。如果设置成功,这个 TCP 连接在发送数据包后 30 秒内如果没有收到 ACK 确认,将开始进行 TCP 连接的释放流程。

TCP_USER_TIMEOUT 相较 SocketTimeout 可以做到更精确(不影响慢查询),SocketTimeout 超时是不区分ACK 还是请求响应时间的,但是 TCP_USER_TIMEOUT 要求下层的API、OS 都支持。比如 JDK 不支持 TCP_USER_TIMEOUT,但是 Netty 框架自己搞了Native 来实现对 TCP_USER_TIMEOUT 以及其它OS 参数的设置,在这些基础上Redis 的Java 客户端 lettuce 依赖了 Netty ,所以也可以设置 TCP_USER_TIMEOUT

原本我是想在Druid 上提个feature 来支持 TCP_USER_TIMEOUT,这样集团绝大部分业务都可以无感知解决掉这个问题,但查下来发现 JDK 不支持设置这个值,想要在Druid 里面实现设置 TCP_USER_TIMEOUT 的话,得像 Netty 一样走Native 绕过JDK 来设置,这对 Druid 而言有点重了

ConnectTimeout

这个值是针对新连接创建超时时间设置,一般设置3-5秒就够长了

连接池

建议参考这篇 《数据库连接池配置推荐》 这篇里的很多建议也适合业务、应用等,你把数据库看成一个普通服务就好理解了

补充下如果用的是Druid 数据库连接池不要用它来设置你的 SocketTimeout 参数,因为他有bug 导致你觉得设置了但实际没设置上,2024-03-16号的1.2.22这个Release 才fix,所以强烈建议你讲 SocketTimeout 写死在JDBC URL 中简单明了

OS 兜底

假如业务是一个AP查询/一次慢请求,一次查询/请求就是需要半个小时,将 SocketTimeout 设置太小影响正常的查询,那么可以将如下 OS参数改小,从 OS 层面进行兜底

1
2
net.ipv4.tcp_retries2 = 8
net.ipv4.tcp_syn_retries = 4

keepalive

keepalive 默认 7200秒太长了,建议改成20秒,可以在OS 镜像层面固化,然后各个业务可以 patch 自己的值;

如果一条连接限制超过 900 秒 LVS就会Reset 这条连接,但是我们将keepalive 设置小于900秒的话,即使业务上一直闲置,因为有 keepalive 触发心跳包,让 LVS 不至于 Reset,这也就避免了当业务取连接使用的时候才发现连接已经不可用被断开了,往往这个时候业务抛错误的时间很和真正 Reset 时间还差了很多,不好排查

在触发 TCP retransmission 后会停止 keepalive 探测

LVS

如果你们试用了aliyun的SLB,当摘除节点的时候支持你设置一个时间,过了这个时间 aliyun的SLB 就会向这些连接的客户端发 Reset 干掉这些流量,让客户端触发新建连接,从故障中快速恢复,这是一个实例维度的参数,建议云上所有产品都支持起来,管控可以在购买 aliyun的SLB 的时候设置一个默认值:

connection_drain_timeout

其它

神奇的900秒

上面阐述的长连接流量黑洞一般是900+秒就恢复了,有时候我们经常在日志中看到 CommunicationsException: Communications link failure 900秒之类的错误,恰好 LVS 也是设置的 900秒闲置 Reset

1
2
#ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 300

为什么这个问题这几年才明显暴露

  • 工程师们混沌了几十年
  • 之前因为出现频率低重启业务就糊弄过去了
  • 对新连接不存在这个问题
  • 有些连接池配置了Check 机制(Check机制一般几秒钟超时 fail)
  • 微服务多了
  • 云上 LVS 普及了
  • k8s service 大行其道

我用的 7层是不是就没有这个问题了?

幼稚,你4层都挂了7层还能蹦跶,再说一遍只要是 TCP 长连接就有这个问题

极端情况

A 长连接 访问B 服务,B服务到A网络不通,假如B发生HA,一般会先Reset/断开B上所有连接(比如 MySQL 会去kill 所有processlist;比如重启MySQL——假如这里的B是MySQL),但是因为网络不通这里的reset、fin网络包都无法到达A,所以B是无法兜底这个异常场景, A无法感知B不可用了,会使用旧连接大约15分钟

最可怕的是 B 服务不响应,B所在的OS 还在响应,那么在A的视角 网络是正常的,这时只能A自己来通过超时兜底

总结

这种问题在 LVS 场景下暴露更明显了,但是又和LVS 没啥关系,任何业务长连接都会导致这个 900秒左右的流量黑洞,首先要在业务层面重视这个问题,要不以后数据库一挂掉还得重启业务才能从故障中将恢复,所以业务层面处理好了可以避免900秒黑洞和重启业务,达到快速从故障中恢复

再强调下这个问题如果去掉LVS/k8s Service/软负载等让两个服务直连,然后拔网线也会同样出现

最佳实践总结:

  • 如果你的业务支持设置 SocketTimeout 那么请一定要设置,但不一定适合分析类就是需要长时间返回的请求
  • 最好的方式是设置 OS 层面的 TCP_USER_TIMEOUT 参数,只要长时间没有 ack 就报错返回,但 JDK 不支持直接设置
  • 如果用了 ALB/SLB 就一定要配置 connection_drain_timeout 这个参数
  • OS 镜像层面也可以将 tcp_retries2 设置为5-10次做一个兜底
  • 对你的超时时间做到可控、可预期

假如你的业务不是 Java,而是 Python 的话,请参考Java/Python超时参数对照表:

功能 JDBC (Java) mysql-connector-python PyMySQL
连接建立超时 connectTimeout connect_timeout connect_timeout
读写操作超时 socketTimeout connection_timeout read_timeout/write_timeout
连接池等待超时 poolTimeout pool_timeout 需手动实现

相关故障和资料

ALB 黑洞问题详述:https://mp.weixin.qq.com/s/BJWD2V_RM2rnU1y7LPB9aw

数据库故障引发的“血案” :https://www.cnblogs.com/nullllun/p/15073022.html 这篇描述较细致,推荐看看

tcp_retries2 的解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tcp_retries1 - INTEGER
This value influences the time, after which TCP decides, that
something is wrong due to unacknowledged RTO retransmissions,
and reports this suspicion to the network layer.
See tcp_retries2 for more details.

RFC 1122 recommends at least 3 retransmissions, which is the
default.

tcp_retries2 - INTEGER
This value influences the timeout of an alive TCP connection,
when RTO retransmissions remain unacknowledged.
Given a value of N, a hypothetical TCP connection following
exponential backoff with an initial RTO of TCP_RTO_MIN would
retransmit N times before killing the connection at the (N+1)th RTO.

The default value of 15 yields a hypothetical timeout of 924.6
seconds and is a lower bound for the effective timeout.
TCP will effectively time out at the first RTO which exceeds the
hypothetical timeout.

RFC 1122 recommends at least 100 seconds for the timeout,
which corresponds to a value of at least 8.

tcp_retries2 默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒),但是这是很多年前的拍下来古董参数值,现在网络条件好多了,尤其是内网,个人认为改成 5-10 是比较恰当 azure 建议:https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection ,Oracle RAC的建议值是3:https://access.redhat.com/solutions/726753

十年后数据库还是不敢拥抱NUMA-续篇

背景

十年后数据库还是不敢拥抱NUMA, 这篇经典的纠正大家对NUMA 认知的文章一晃发布快3年了,这篇文章的核心结论是:

  • 之所以有不同的NUMA Node 是不同的CPU Core 到不同的内存距离远近不一样所决定的,这是个物理距离
  • 程序跑在不同的核上要去读写内存可以让性能差异巨大,所以我们要尽量让一个程序稳定跑在一个Node 内
  • 默认打开NUMA Node 其实挺好的

写这个续篇是我收到很多解释,因为跨Node 导致性能抖动,所以集团在物理机OS 的启动参数里设置了 numa=off ,也就是不管BIOS 中如何设置,我们只要在OS 层面设置一下 numa=off 就能让程序稳定下来不再抖了!

我这几年也认为这是对的,只是让我有点不理解,既然不区分远近了,那物理上存在的远近距离(既抖动)如何能被消除掉的呢?

所以这个续篇打算通过测试来验证下这个问题

设置

BIOS 中有 numa node 设置的开关(注意这里是内存交错/交织),不同的主板这个BIOS设置可能不一样,但是大同小异,基本都有这个参数

img

Linux 启动引导参数里也可以设置numa=on(默认值)/off ,linux 引导参数设置案例:

1
2
#cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.10.0-327.x86_64 ro crashkernel=auto vconsole.font=latarcyrheb-sun16 vconsole.keymap=us BIOSdevname=0 console=tty0 console=ttyS0,115200 scsi_mod.scan=sync intel_idle.max_cstate=0 pci=pcie_bus_perf ipv6.disable=1 rd.driver.pre=ahci numa=on nosmt=force

注意如上的 numa=on 也可以改为 numa=off

看完全置篇要记住一条铁律:CPU到内存的距离是物理远近决定的,你软件层面做些设置是没法优化这个距离,也就是没法优化这个时延 (这是个核心知识点,你要死死记住和理解,后面的一切实验数据都回过头来看这个核心知识点并揣摩)

实验

测试机器CPU,如下是BIOS numa=on、cmdline numa=off所看到的,一个node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 96
On-line CPU(s) list: 0-95
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz
Stepping: 4
CPU MHz: 2500.000
CPU max MHz: 3100.0000
CPU min MHz: 1000.0000
BogoMIPS: 4998.89
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 33792K
NUMA node0 CPU(s): 0-95

测试工具是lmbench,测试命令:

1
for i in $(seq 0 6 95); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

上述测试命令始终将内存绑定在 node0 上,然后用不同的物理core来读写这块内存,按照前一篇 这个时延肯定有快慢之分

BIOS和引导参数各有两种设置方式,组合起来就是四种,我们分别设置并跑一下内存时延,测试结果:

BIOS ON BIOS OFF
cmdline numa=on(默认值) NUMA 开启,内存在Node内做交织,就近有快慢之分 bios 关闭后numa后,OS层面完全不知道下层的结构,默认全局内存做交织,时延是个平均值
cmdline numa=off 交织关闭,效果同上 同上

测试原始数据如下(测试结果文件名 lat.log.BIOSON.cmdlineOff 表示BIOS ON,cmdline OFF ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//从下面两组测试来看,BIOS层面 on后,不管OS 层面是否on,都不会跨node 做交织,抖动存在
//BIOS on 即使在OS层面关闭numa也不跨node做内存交织,抖动存在
//默认从内存高地址开始分配空间,所以0核要慢
#grep -E "core|64.00000" lat.log.BIOSON.cmdlineOff
core:0 //第0号核
64.00000 100.717 //64.0000为64MB, 100.717 是平均时延100.717ns 即0号核访问node0 下的内存64MB的平均延时是100纳秒
core:24
64.00000 68.484
core:48
64.00000 101.070
core:72
64.00000 68.483
#grep -E "core|64.00000" lat.log.BIOSON.cmdlineON
core:0
64.00000 67.094
core:24
64.00000 100.237
core:48
64.00000 67.614
core:72
64.00000 101.096

//从下面两组测试来看只要BIOS off了内存就会跨 node 交织,大规模测试下内存 latency 是个平均值
#grep -E "core|64.00000" lat.log.BIOSOff.cmdlineOff //BIOS off 做内存交织,latency就是平均值
core:0
64.00000 85.657 //85 恰好是最大100,最小68的平均值
core:24
64.00000 85.741
core:48
64.00000 85.977
core:72
64.00000 86.671

//BIOS 关闭后numa后,OS层面完全不知道下层的结构,默认一定是做交织
#grep -E "core|64.00000" lat.log.BIOSOff.cmdlineON
core:0
64.00000 89.123
core:24
64.00000 87.137
core:48
64.00000 87.239
core:72
64.00000 87.323

从数据可以看到在BIOS 设置ON后,无论 OS cmdline 启动参数里是否设置了 ON 还是 OFF,内存延时都是抖动且一致的(这个有点诧异,说好的消除抖动的呢?)。如果BIOS 设置OFF后内存延时是个稳定的平均值(这个比较好理解)

疑问

  • 内存交错时为什么 lmbench 测试得到的时延是平均值,而不是短板效应的最慢值?

测试软件只能通过大规模数据的读写来测试获取一个平均值,所以当一大块内存读取时,虽然通过交织大块内存被切分到了快慢物理内存上,但是因为规模大慢的被平均掉了。(欢迎内核大佬指正)

  • 什么是内存交织?

我的理解假如你有8块物理内存条,如果你有一个int 那么只能在其中一块上,如果你有1MB的数据那么会按cacheline 拆成多个块然后分别放到8块物理内存条上(有快有慢)这样带宽更大,最后测试得到一个平均值

如果你开启numa那么只会就近交织,比如0-3号内存条在0号core所在的node,OS 做内存交织的时候只会拆分到这0-3号内存条上,那么时延总是最小的那个,如上测试中的60多纳秒。

这个问题一直困扰了我几年,所以我最近再次测试验证了一下,主要是对 BIOS=on 且 cmdline=off 时有点困扰

Intel 的 mlc 验证

测试参数: BIOS=on 同时 cmdline off

Intel 的 mlc 验证下,这个结果有点意思,latency稳定在 145 而不是81 和 145两个值随机出现,应该是mlc默认选到了0核,对应lmbench的这组测试数据(为什么不是100.717, 因为测试方法不一样):

1
2
3
4
5
6
7
8
9
10
11
12
//如下是
//从下面两种测试来看,BIOS层面 on后,不管OS 层面是否on,都不会跨node 做交织,抖动存在
//BIOS on 即使在OS层面关闭numa也不跨node做内存交织,抖动存在
#grep -E "core|64.00000" lat.log.BIOSON.cmdlineOff
core:0
64.00000 100.717
core:24
64.00000 68.484
core:48
64.00000 101.070
core:72
64.00000 68.483

此时对应的mlc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#./mlc
Intel(R) Memory Latency Checker - v3.9
Measuring idle latencies (in ns)...
Numa node
Numa node 0
0 145.8 //多次测试稳定都是145纳秒

Measuring Peak Injection Memory Bandwidths for the system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using traffic with the following read-write ratios
ALL Reads : 110598.7
3:1 Reads-Writes : 93408.5
2:1 Reads-Writes : 89249.5
1:1 Reads-Writes : 64137.3
Stream-triad like: 77310.4

Measuring Memory Bandwidths between nodes within system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using Read-only traffic type
Numa node
Numa node 0
0 110598.4

Measuring Loaded Latencies for the system
Using all the threads from each core if Hyper-threading is enabled
Using Read-only traffic type
Inject Latency Bandwidth
Delay (ns) MB/sec
==========================
00000 506.00 111483.5
00002 505.74 112576.9
00008 505.87 112644.3
00015 508.96 112643.6
00050 574.36 112701.5

当两个参数都为 on 时的mlc 测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#./mlc
Intel(R) Memory Latency Checker - v3.9
Measuring idle latencies (in ns)...
Numa node
Numa node 0 1
0 81.6 145.9
1 144.9 81.2

Measuring Peak Injection Memory Bandwidths for the system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using traffic with the following read-write ratios
ALL Reads : 227204.2
3:1 Reads-Writes : 212432.5
2:1 Reads-Writes : 210423.3
1:1 Reads-Writes : 196677.2
Stream-triad like: 189691.4

说明:mlc和 lmbench 测试结果不一样,mlc 时81和145,lmbench测试是68和100,这是两种测试方法的差异而已,但是快慢差距基本是一致的

结论

在OS 启动引导参数里设置 numa=off 完全没有必要、也不能解决抖动的问题,反而设置了 numa=off 只能是掩耳盗铃,让用户看不到 NUMA 结构

0%