一、前言
在实际生产环境中,TiDB作为一款分布式 NewSQL 数据库,对底层硬件资源的稳定性、性能一致性以及IO与网络能力具有较高要求。在部分场景下,如果将TiDB部署在虚拟机环境中,容易受到虚拟化层带来的资源争用与性能抖动影响,例如CPU调度不稳定、NUMA拓扑被屏蔽、磁盘IO虚拟化带来的额外开销以及网络时延和带宽的不确定性。这些问题在高并发、低延迟或大规模数据写入场景下,可能放大为整体集群性能瓶颈,影响TiDB的线性扩展能力和稳定运行。
相比之下,在物理机环境中直接部署TiDB,可以最大程度发挥分布式架构对计算、存储和网络资源的利用能力。物理机部署能够避免虚拟化带来的额外损耗,使TiDB、TiKV、PD等核心组件直接感知真实的CPU核数、NUMA结构、本地磁盘性能以及网络拓扑,从而在事务处理、数据调度和副本复制等关键路径上获得更低的延迟和更稳定的吞吐表现。尤其是在大规模集群或对性能敏感的业务场景中,物理机部署更有利于实现资源的精细化管控和性能的可预测性。
当然,物理机部署TiDB并不只是“去掉虚拟化层”这么简单,还需要在资源规划和系统调优层面进行更精细的设计。例如,需要合理进行NUMA绑定,确保TiDB组件的CPU亲和性和内存访问的本地性,避免跨NUMA节点访问带来的性能下降;同时,应根据不同组件的职责和负载特征,合理规划TiDB Server、TiKV和PD的内存分配与隔离,防止内存争用或OOM风险。此外,在磁盘布局、网络带宽、CPU核心分配等方面,也需要结合物理机的硬件特性进行针对性配置,才能真正发挥物理机部署TiDB的整体优势。
二、物理机部署及拓扑
1. 物理机配置:
3个物理机的配置都是96C,256GB,挂载2块nvme磁盘。查看numa信息如下:
# lscpu
架构: aarch64
CPU 运行模式: 64-bit
字节序: Little Endian
CPU: 96
在线 CPU 列表: 0-95
每个核的线程数: 1
每个座的核数: 48
座: 2
NUMA 节点: 4
厂商 ID: HiSilicon
型号: 0
型号名称: Kunpeng-920
步进: 0x1
CPU 最大 MHz: 2600.0000
CPU 最小 MHz: 200.0000
BogoMIPS: 200.00
L1d 缓存: 6 MiB
L1i 缓存: 6 MiB
L2 缓存: 48 MiB
L3 缓存: 96 MiB
NUMA 节点0 CPU: 0-23
NUMA 节点1 CPU: 24-47
NUMA 节点2 CPU: 48-71
NUMA 节点3 CPU: 72-95
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Spec store bypass: Vulnerable
Vulnerability Spectre v1: Mitigation; __user pointer sanitization
Vulnerability Spectre v2: Not affected
Vulnerability Srbds: Not affected
Vulnerability Tsx async abort: Not affected
标记: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma dcpop asimddp asimdfhm
2. 部署拓扑
- 物理机1(1个TiDB server, 1个PD和2个TIKV)
- 物理机2(1个TiDB server, 1个PD和2个TIKV,1个tiproxy)
- 物理机3(1个TiDB server, 1个PD和2个TIKV)
三、发现问题
在普通的部署过程中,首选对各个组件的配置都绑定了numa,一个物理机节点4个numa, 物理机1和物理机3一个物理机上部署4个组件,每个节点上绑定一个numa;物理机二中pd、tidb server和tikv都绑定numa,tiproxy没有绑定numa,部署好后对该集群进行性能压测,其中一个是大文本insert性能的测试,另外一个对查询进行并发压测。
1. 大文本的insert压测
该压测是使用java编写的程序,设计的文本长度为5000字符,启动300线程进行压测,程序拼接sql,每个sql拼接1000value值,执行300秒进行压测,
如下为部分配置和代码截图:
Jdbcurl后缀参数:keepAlive=true&autoReconnect=true&autoReconnectForPools=true&connectTimeout=60000&socketTimeout=90000
代码截图:



出现的问题
java程序报如下错误:
The last packet successfully received from the server was 16,050 milliseconds ago. The last packet sent successfully to the server was 16,268 milliseconds ago. java.lang.RuntimeException: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
看到的监控
Tidb server 内存监控,可以看到18.6宕机。


操作系统的日志如下:
可以看到tidb server 已经OOM:

2. 多线程并发查询压测
该方式使用jmter的方式进行压测,对某个表进行主键查询,开启500线程,执行300s进行压测,压测过程中的截图如下:
tiproxy的cpu占用很高:

四、解决方式
1. 针对OOM的解决方式如下
- 增加tikv的内存限制:

这里我设置了28GB
增加后重启,先执行:
1. tiup cluster reload tidb-uni -R tikv --skip-restart
2. tiup cluster restart tidb-uni -R tikv
- 增加tidb server的内存限制:

我这里设置为了50GB
2. 针对tiproxy的cpu使用率高解决方式
当时找了好长时间,最后确定tiproxy没有绑定numa,最后修改配置对tiproxy绑定numa后问题得以解决。
五、总结分析
针对OOM的情况,默认情况下 TiKV 的 block-cache 设置为机器总内存的 45%;tidb_server_memory_limit默认为机器总内存的80%,在物理机中是256GB的总内存,所以根据上述的默认值,会很大,当过多的业务并发时,就会造成整个机器的内存使用过高,从而操作系统会杀掉该组件。
针对tikv的storage.block-cache.capacity,官网有如下的配置建议说明,地址:https://pingkai.cn/docs/tidb/dev/benchmark-tidb-using-sysbench/#tikv-%E9%85%8D%E7%BD%AE
针对TIDB的内存设置,建议参考官网进行设置:https://pingkai.cn/docs/tidb/stable/configure-memory-usage/#%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AE-tidb-server-%E5%AE%9E%E4%BE%8B%E4%BD%BF%E7%94%A8%E5%86%85%E5%AD%98%E7%9A%84%E9%98%88%E5%80%BC。