达梦DM8数据库TPCC压测全流程:从BenchmarkSQL配置到性能优化实战
达梦DM8数据库TPCC压测全流程:从BenchmarkSQL配置到性能优化实战
最近在帮一个客户做数据库选型评估,他们核心业务系统对事务处理能力要求极高,最终把目光投向了国产数据库。达梦DM8作为其中的佼佼者,自然成了重点考察对象。而衡量一个OLTP数据库性能的“金标准”,绕不开TPC-C测试。虽然我们不会去搞官方认证那种动辄上千万的复杂流程,但用BenchmarkSQL这个开源工具跑一套标准的TPC-C压测,对于评估数据库在模拟真实订单、支付场景下的吞吐量和稳定性,绝对是极具说服力的。这不仅仅是看一个tpmC数字那么简单,整个过程更像是一次对数据库内核、配置、硬件协同工作的深度体检。今天,我就把自己从零搭建环境、配置工具、执行压测,再到一步步分析瓶颈、实施优化的完整实战经验分享出来,希望能给正在做性能测试或选型的DBA和开发朋友们一些实实在在的参考。
1. 测试环境与BenchmarkSQL的精准部署
工欲善其事,必先利其器。一个干净、可控的测试环境是获得可靠数据的前提。我选择在VMware Workstation上构建一个独立的测试环境,这样既能隔离生产干扰,也方便随时快照回滚,反复尝试不同的优化策略。
操作系统与数据库基础:我选用了银河麒麟V10 SP2作为操作系统,这是一个稳定且对国产软硬件生态支持良好的平台。达梦DM8数据库则采用了2023年11月的x86架构Kylin版本。虚拟机的资源配置需要仔细考量:虽然TPC-C测试对CPU和内存敏感,但为了模拟更普遍的部署场景,我初始仅分配了1个vCPU和3GB内存,后续会根据测试情况动态调整。这其实是一个很好的起点,能让我们看清数据库在“紧巴巴”的资源下的基线表现。
注意:BenchmarkSQL 4.1.1需要JDK 1.7或更高版本支持。建议直接安装OpenJDK 8或Oracle JDK 8,并确保
JAVA_HOME环境变量正确配置,这是后续所有脚本能正常运行的基础。
BenchmarkSQL的部署本身并不复杂,但有几个细节决定了成败:
- 获取与解压:从官方仓库下载benchmarksql-4.1.1.zip,直接解压即可。它的目录结构非常清晰,
run/目录下存放了所有核心脚本和配置文件。 - 驱动配置——关键一步:这是连接达梦数据库的桥梁。你需要将DM8的JDBC驱动JAR包(通常是
DmJdbcDriver18.jar)复制到BenchmarkSQL的lib/目录下。确保驱动版本与你的DM8数据库版本匹配,否则可能会遇到诡异的连接或语法兼容性问题。 - 配置文件props.dm的剖析:
run/props.dm是测试的“大脑”。我们需要创建一个针对达梦的配置文件。以下是一个最精简但必须正确配置的核心部分:
# 数据库连接配置 db=dm driver=dm.jdbc.driver.DmDriver conn=jdbc:dm://192.168.1.100:5238/TESTDB?compatibleMode=mysql&useUnicode=true&characterEncoding=utf-8 user=BENCHMARKSQL password=YourStrongPassword123 # 压测核心参数 warehouses=10 terminals=10 runMins=5这里对几个核心参数做个解读:
warehouses:仓库数量。它直接决定了测试数据集的大小。每个仓库大约对应100MB的初始数据。warehouses=10意味着准备约1GB的测试数据。terminals:并发终端数,模拟同时操作的虚拟用户。通常建议设置为warehouses的1到10倍。初始可以从1:1开始。runMins:压测稳定运行的时长(分钟)。太短可能无法越过数据库的预热阶段,太长则耗时。对于初步测试,5-10分钟是个合理的起点。
2. 数据库初始化与测试数据构建
压测需要一个专属的“战场”,我们不应该在生产库或已有业务的库上直接操作。为BenchmarkSQL创建一个独立的数据库和用户是规范操作。
首先,使用达梦的dminit工具初始化一个新库。我习惯指定明确的路径和端口,避免冲突。
./dminit path=/dm8/data DB_NAME=TPCCDB INSTANCE_NAME=TPCC INSTANCE_PORT=5238库创建好后,进入达梦的管理工具(或使用命令行工具disql)连接,并执行以下SQL来创建专属的表空间、用户并授权:
-- 创建专属表空间,初始大小可根据warehouses数量调整 CREATE TABLESPACE TS_BENCH DATAFILE 'TS_BENCH01.dbf' SIZE 1024 AUTOEXTEND ON NEXT 100; -- 创建测试用户并指定默认表空间 CREATE USER BENCHMARKSQL IDENTIFIED BY "Bench123456" DEFAULT TABLESPACE TS_BENCH; -- 授予足够的权限,DBA权限在测试环境更方便 GRANT DBA TO BENCHMARKSQL;用户创建完毕,接下来就是利用BenchmarkSQL脚本,在BENCHMARKSQL用户下构建TPC-C的标准表结构、灌入数据、建立索引。这一系列操作是自动化的,但顺序不能错。
cd benchmarksql-4.1.1/run # 第一步:创建表结构 ./runSQL.sh props.dm sqlTableCreates # 第二步:装载数据。此处的numWarehouses必须与props.dm中的warehouses值严格一致! ./runLoader.sh props.dm numWarehouses 10 # 第三步:创建索引 ./runSQL.sh props.dm sqlIndexCreates # 第四步(建议):收集统计信息,帮助优化器生成更优的执行计划 ./runSQL.sh props.dm sqlIndexCreates # 运行一个收集统计信息的脚本,或者直接使用达梦命令提示:数据装载是最耗时的步骤,尤其是warehouses设置较大时。请耐心等待,并观察磁盘I/O活动。确保数据文件所在磁盘有足够的空间和I/O性能。
3. 执行压测与报告深度解读
前期准备就绪,激动人心的压测执行阶段到来。命令非常简单:
./runBenchmark.sh props.dm脚本会启动指定数量(terminals)的终端线程,按照TPC-C标准的事务混合比例(新订单、支付、订单状态查询、发货、库存查询),疯狂地对数据库进行读写操作,持续指定的分钟数(runMins)。屏幕上会滚动输出实时的事务计数器。
压测结束后,BenchmarkSQL会在log/目录下生成详细的日志文件。但更直观的结果通常在控制台末尾直接输出。你会看到类似下面的结果:
Measured tpmC (NewOrders) = 1234.56 Measured tpmTOTAL = 9876.54这两个数字就是核心性能指标:
- tpmC:每分钟处理的新订单事务数。这是TPC-C测试中最核心的指标,直接反映了系统处理核心交易的能力。我们常说的“TPC-C性能多少万”,指的就是这个值。
- tpmTOTAL:每分钟处理的所有类型事务总数(TPS)。它反映了系统的整体事务吞吐量。
为了更清晰地理解这些指标与测试参数的关系,我整理了下面这个对照表:
| 指标/参数 | 含义 | 计算公式/关系 | 说明 |
|---|---|---|---|
| warehouses | 仓库数 | - | 决定数据规模,影响缓冲池命中率和锁竞争。 |
| terminals | 并发终端数 | - | 模拟用户并发压力,并非越高越好,需找到拐点。 |
| runMins | 测试时长 | - | 确保测试进入稳定状态,避免预热阶段干扰。 |
| tpmC | 新订单事务/分钟 | tpmTOTAL * 新订单权重(约45%) | 核心性能指标,代表业务处理能力。 |
| tpmTOTAL | 总事务数/分钟 (TPS) | 总事务数 / runMins | 系统整体吞吐量。 |
| Transaction Count | 总事务数 | tpmTOTAL * runMins | 测试期间完成的全部事务量。 |
第一次跑出来的tpmC值,只是一个起点。它可能因为默认配置、硬件限制或未优化的表结构而远未达到系统潜能。我的第一次测试,在1核3G的虚拟机上,10个仓库,tpmC只有可怜的几百。但这正是性能优化之旅的开始。
4. 系统级性能分析与瓶颈定位
拿到初步的压测结果后,不要急于修改数据库参数,而是应该进行系统的性能分析,找到真正的瓶颈所在。盲目调参往往事倍功半。
第一步:检查内存与缓冲池达梦数据库的性能严重依赖缓冲池。首先查看缓冲池的命中率:
SELECT * FROM V$BUFFERPOOL; -- 或使用更详细的命中率查询 SELECT name, block_size, sum(pages)/1024 as size_mb, (1 - (physical_reads / (gets + physical_reads))) * 100 as hit_ratio FROM V$BUFFER_STAT GROUP BY name, block_size;如果命中率低于95%,尤其是在压测稳定后仍很低,说明内存配置可能不足,需要考虑扩大BUFFER相关的内存参数(如BUFFER_POOLS、BUFFER),或者审视warehouses设置是否过大,导致活跃数据集远超内存容量。
第二步:分析磁盘I/O布局这是很多部署中容易被忽视的瓶颈。通过以下查询查看数据文件和重做日志文件的路径:
SELECT tablespace_name, file_name FROM dba_data_files; SELECT group_id, path FROM v$rlogfile;如果发现数据文件(.dbf)和重做日志文件(.log)都存放在同一块物理磁盘上,那么在TPC-C这种写密集型负载下,磁盘磁头会频繁在数据区和日志区之间来回移动,造成严重的I/O等待。最优实践是将它们分离到不同的、高性能的磁盘上(例如,数据文件放在SSD阵列,重做日志放在另一块独立的NVMe SSD上)。
第三步:捕捉与分析高负载SQLTPC-C模型中的事务是固定的,但执行效率取决于数据库如何执行它们。我们需要找出在压测期间累计耗时最长的SQL。
-- 查询历史SQL执行统计,按累计执行时间排序 SELECT TOP 10 sql_id, sql_text, SUM(exec_time) AS total_exec_time_ms, COUNT(*) AS executions, AVG(exec_time) AS avg_exec_time_ms FROM V$SQL_STAT_HISTORY WHERE sql_text IS NOT NULL GROUP BY sql_id, sql_text ORDER BY total_exec_time_ms DESC;在我的测试中,排名靠前的总是几条高频更新的语句,例如更新仓库余额(UPDATE warehouse SET w_ytd = w_ytd + ? WHERE w_id = ?)和查询地区信息(SELECT ... FROM district WHERE d_id = ? AND d_w_id = ? FOR UPDATE)。通过查看它们的执行计划(SELECT * FROM V$PLN_HISTORY WHERE SQL_ID = ?),我发现了一个共性问题:这些语句的主键查询,走的都是二级索引扫描(SSEK2),然后通过ROWID回表(BLKUP2)。对于TPC-C这种以主键访问为主的极端场景,这带来了不必要的开销。
5. 针对性优化策略与效果验证
基于以上分析,我们可以制定并实施具体的优化方案。
优化方案一:磁盘I/O分离假设我们新增了一块磁盘,挂载到了/dmlog。迁移重做日志的步骤如下:
- 确保数据库处于归档模式或正常关闭后进行(生产环境需谨慎,测试环境可停机操作)。
- 使用管理工具或SQL命令,修改重做日志文件路径。达梦提供了在线重命名日志文件的功能,但通常需要重启实例或切换日志组。一个相对安全的方法是先增加新的日志文件到新路径,再删除旧的。
优化方案二:SQL执行计划优化——聚集索引的力量针对高频主键查询走二级索引的问题,根源在于BenchmarkSQL默认创建的索引是非聚集的。在达梦中,表数据本身是按聚集索引组织的。如果我们将主键定义为聚集索引,那么根据主键查询就可以直接定位到数据行,消除回表开销。
具体操作是修改BenchmarkSQL的索引创建脚本。不要直接修改原文件,先做备份:
cp sqlIndexCreates sqlIndexCreates_clustered然后编辑sqlIndexCreates_clustered文件,找到创建主键约束的语句(通常是ALTER TABLE ... ADD PRIMARY KEY ...),在PRIMARY KEY前加上CLUSTER关键字。例如,对于warehouse表:
-- 原始可能类似: -- ALTER TABLE warehouse ADD PRIMARY KEY (w_id); -- 修改为: ALTER TABLE warehouse ADD CLUSTER PRIMARY KEY (w_id);对district,customer,orders,order_line,stock,item等表的主键也进行同样的修改。history表通常没有主键,保持不变。
优化方案三:关键数据库参数调整根据压测中观察到的现象,可以微调一些内存和并发相关参数。务必在测试环境反复调整并记录效果。以下是一些可能相关的参数(具体值需根据实际硬件和负载调整):
BUFFER:数据缓冲区大小,通常设置为可用物理内存的50%-70%。MAX_SESSIONS:最大会话数,应大于terminals数量。MVCC_RETRY_TIMES:在遇到“多版本操作冲突”报错时,可以适当调大此参数(例如从默认的5调到10或20),给并发更新更多的重试机会。
优化效果验证实施优化后,需要清理环境重新测试,进行苹果对苹果的比较:
- 删除旧表:
./runSQL.sh props.dm sqlTableDrops - 用优化后的脚本重建表、装载数据:
./runSQL.sh props.dm sqlTableCreates,./runLoader.sh ... - 使用修改后的聚集索引脚本创建索引:
./runSQL.sh props.dm sqlIndexCreates_clustered - 重新收集统计信息。
- 执行压测:
./runBenchmark.sh props.dm
在我的测试环境中,经过磁盘I/O分离和将核心表主键修改为聚集索引这两项主要优化后,tpmC值从最初的约7500提升到了9350以上,性能提升超过了25%。这个提升是显著的,它证明了优化方向是正确的,并且每项优化都切中了性能瓶颈。
6. 常见问题排查与实战经验分享
在压测过程中,你几乎一定会遇到一些报错和异常。这里分享两个我踩过的坑及其解决方法。
问题一:遭遇“多版本操作冲突”错误在高压并发下,控制台或日志中可能会出现“多版本操作冲突”的报错。这本质上是达梦数据库MVCC(多版本并发控制)机制在应对高并发更新时,事务间版本链冲突达到重试上限导致的。
解决方法:不要一上来就盲目调大
MVCC_RETRY_TIMES。首先应检查warehouses和terminals的比例。如果terminals数量远大于warehouses,会导致大量线程集中在少数几个仓库数据上更新,加剧冲突。可以尝试增加warehouses数量来分散热点。如果确实需要调整参数,可以适度增加dm.ini中的MVCC_RETRY_TIMES(比如从5调整到10或15),并重启数据库服务观察效果。
问题二:“当前光标不在结果集上”这个错误通常发生在执行runLoader.sh装载数据或者runBenchmark.sh压测时。错误信息很明确,根本原因在于配置文件props.dm中的warehouses参数与执行数据装载命令./runLoader.sh props.dm numWarehouses X中的X数值不一致。BenchmarkSQL要求这两个值必须完全相同,因为它需要确保压测程序访问的数据范围与预先装载的数据范围匹配。
解决方法:养成好习惯,用一个变量来定义仓库数。例如,在脚本中定义
WAREHOUSE_COUNT=100,然后在props.dm中设置warehouses=$WAREHOUSE_COUNT,在执行runLoader.sh时也使用numWarehouses $WAREHOUSE_COUNT。这样可以彻底避免因手动输入不一致导致的错误。
整个TPC-C压测从环境准备到优化闭环,是一个不断假设、验证、调整的迭代过程。它考验的不仅仅是对达梦数据库参数的理解,更是对TPC-C负载模型、操作系统、硬件资源的综合把控能力。对我而言,最大的收获不是那个最终提升了多少的tpmC分数,而是通过这个过程,真正摸清了这套数据库在高压事务场景下的行为模式和调优脉络。下次再遇到生产环境类似的性能问题,脑子里这套分析优化框架,就能立刻用上了。
