本文介绍PolarDB-X的全密态数据库在不同加密条件下的性能表现,有助于您评估和选择加密方案。
测试结论概览
测试维度 | 核心结论 |
在不同规格和并发压力下,开启100%列加密(对表所有列进行加密)的性能损耗稳定在10%左右。 | |
即使不开启加密,仅将标准JDBC替换为EncJDBC驱动,客户端CPU消耗会增加30%~50%。 | |
开启100%列加密(对表所有列进行加密)后,为达到最佳性能,客户端CPU消耗相较于明文场景增幅约55%~150%。 | |
性能损耗与加密列的数量呈正相关。加密列越多,性能损耗越大,客户端CPU消耗也越高。建议按需对敏感列进行加密。 |
测试设计
测试模型与指标
测试模型:采用业界标准的OLTP(在线事务处理)基准测试工具Oltpbench,并使用其中的TPC-C模型。
测试数据量:基于TPC-C模型的1000个仓库(Warehouse)构建,其中核心表
bmsql_order_line
数据量为3亿行,bmsql_stock
为1亿行。性能指标:TPS(Transactions Per Second),即数据库每秒成功提交的事务数。
本文中TPC-C的实现基于TPC-C的基准测试,并不能与已发布的TPC-C基准测试结果相比较,本文中的测试并不符合TPC-C基准测试的所有要求。
测试环境
测试客户端(ECS实例)与PolarDB-X实例部署于同一地域的同一VPC网络下,以降低网络延迟对测试结果的影响。
配置项 | ECS实例(客户端) | PolarDB-X实例(数据库) |
地域 | 北京 可用区I/H | 北京 可用区I/H |
实例规格 | 2 * ecs.c7.4xlarge(16核32 GB) | 2 * 4核32 GB |
4 * ecs.c7.4xlarge(16核32 GB) | 4 * 8核64 GB | |
镜像/版本 | Alibaba Cloud Linux 3.2104 LTS 64位 | polardb-2.4.0_5.4.19-20240927_xcluster5.4.19-20241010 |
测试场景
为模拟真实业务的数据敏感度差异,测试覆盖了不同比例的加密列:
20%列加密:优先加密ID、订单号等关键标识符字段。
50%列加密:在20%的基础上,增加对价格、日期、数量等业务信息字段的加密。
100%列加密:对所有表的全部字段进行加密。
详细测试结果
整体性能(100%列加密 vs 明文)
在100%列加密的场景下,全密态数据库的TPS相较于明文场景,性能损耗基本稳定在10%左右。
测试结果
2 * 4核32 GB
并发数
明文TPS
100%加密TPS
性能损耗
64
80,223
72,248
10%
128
99,019
88,469
11%
256
105,309
94,756
10%
512
104,313
95,962
8%
1024
98,990
95,182
4%
4 * 8核64 GB
并发数
明文TPS
100%加密TPS
性能损耗
64
108,581
96,828
11%
128
184,293
167,380
9%
256
263,538
239,913
9%
512
292,481
252,741
13%
1024
284,561
252,432
11%
EncJDBC驱动自身开销(明文测试)
为评估EncJDBC驱动自身的性能影响,在不开启任何加密的情况下,对比了标准JDBC和EncJDBC的客户端资源消耗。结果显示,主要的额外开销在于CPU。
测试条件
客户端规格(ECS实例)为ecs.c7.4xlarge
(16核32 GB),并发数为1024。
测试结果
规格 | CPU使用率 | 内存使用率(MB) | ||||
标准JDBC | EncJDBC | 标准JDBC | EncJDBC | |||
2 * 4核32 GB | 21.37% | 28.00% | +31% | 1077 | 1001 | -7.06% |
4 * 8核64 GB | 47.09% | 69.90% | +48% | 1048 | 1024 | -2.29% |
开启加密后客户端资源消耗
开启100%列加密后,客户端(ECS实例)的CPU消耗显著增加,这是全密态功能性能开销的主要部分。为达到最佳性能,应用侧需要预留充足的CPU资源。
测试条件
并发数为1024。
测试结果
规格 | CPU使用率 (加密前) | CPU使用率 (100%加密) | CPU增幅 |
2 * 4核32 GB | 13.01% | 33.45% | +157% |
4 * 4核32 GB | 20.60% | 32.07% | +56% |
2 * 8核64 GB | 19.93% | 36.77% | +85% |
4 * 8核64 GB | 17.73% | 43.59% | +146% |
结论
综合不同实例规格,开启全密态加密后,客户端的CPU资源消耗增幅在56%至157%之间,最大增幅超过1.5倍。
不同加密比例对性能和资源的影响
加密列的数量直接影响性能和客户端CPU消耗。下表数据展示了随着加密列比例的增加,性能损耗和客户端CPU使用率的变化。
测试条件
并发数为1024。
测试结果
2 * 4核32 GB
加密比例
客户端CPU使用率
TPS
性能损耗
20%
20.01%
96,792
2%
50%
22.23%
96,639
2%
100%
33.45%
95,182
4%
4 * 8核64 GB
加密比例
客户端CPU使用率
TPS
性能损耗
20%
22.50%
276,640
3%
50%
28.80%
276,640
8%
100%
43.59%
276,640
11%
结论
加密列的增加对性能有显著影响。在实际应用中,建议您仅对必要的敏感数据列进行加密,以在安全性与性能之间取得最佳平衡。
附录:测试步骤
步骤1:准备ECS压力机
需准备一个ECS实例,后续操作步骤中涉及的数据导入、运行压测等使用的都是这台ECS机器。
ECS实例推荐架构与操作系统:
X86:
CentOS 7.9及以上。
Alibaba Cloud Linux 3。
Ubuntu 18.0及以上。
ARM:CentOS 8.0及以上。
需将测试所用的ECS实例部署在专有网络VPC内,并记住该VPC的名称和ID,后续的所有实例都将部署在该VPC内。
需开放ECS实例的公网IP,用于后续操作压测工具。
步骤2:准备压测所用PolarDB-X实例
- 说明
创建PolarDB-X实例时,请将实例和压力机ECS实例放至同一个专有网络VPC内。
将压力机ECS实例的内网地址添加至PolarDB-X实例的白名单中。
在实例中创建一个待压测的数据库,此处以
tpcc_1000
为例。CREATE DATABASE tpcc_1000 MODE = 'auto';
步骤3:准备压测数据
准备压测工具
在压力机ECS上,下载并解压压测工具包benchmarksql.tar.gz。
tar xzvf benchmarksql.tar.gz
下载全密态驱动包aliyun-encdb-mysql-jdbc-1.0.9-2-20240910.094626-1.jar,并将其放置在
benchmarksql/lib
目录下。
配置压测参数
进入
benchmarksql/run
目录,编辑props.mysql
配置文件。cd benchmarksql/run vi props.mysql
根据您的环境修改配置。以下为配置示例及关键参数说明:
db=mysql driver=com.aliyun.encdb.mysql.jdbc.EncDriver conn=jdbc:mysql:encdb://{HOST}:{PORT}/tpcc_1000_enc?/MEK={MEK}&ENC_ALGO={ENC_ALGO}&useSSL=false&useServerPrepStmts=false&useConfigs=maxPerformance&rewriteBatchedStatements= true user={USER} password={PASSWORD} warehouses=1000 loadWorkers=100 terminals=128 //To run specified transactions per terminal- runMins must equal zero runTxnsPerTerminal=0 //To run for specified minutes- runTxnsPerTerminal must equal zero runMins=5 //Number of total transactions per minute limitTxnsPerMin=0 //Set to true to run in 4.x compatible mode. Set to false to use the //entire configured database evenly. terminalWarehouseFixed=true //The following five values must add up to 100 //The default percentages of 45, 43, 4, 4 & 4 match the TPC-C spec newOrderWeight=45 paymentWeight=43 orderStatusWeight=4 deliveryWeight=4 stockLevelWeight=4 // Directory name to create for collecting detailed result data. // Comment this out to suppress. resultDirectory=my_result_%tY-%tm-%td_%tH%tM%tS // osCollectorScript=./misc/os_collector_linux.py // osCollectorInterval=1 // osCollectorSSHAddr=user@dbhost // osCollectorDevices=net_eth0 blk_sda
参数说明
conn
: 数据库连接串。请替换{HOST}
和{PORT}
。{MEK}
: 主加密密钥(Master Encryption Key),一个32位的十六进制字符串。{ENC_ALGO}
: 对称加密算法,例如SM4_128_GCM
。user
: 数据库用户名。password
: 数据库密码。warehouses
: TPC-C仓库数量,决定数据总量。loadWorkers
: 数据导入时的并发线程数。terminals
: 压测时的并发线程数。runMins
: 压测持续时间(分钟)。
导入数据 在
benchmarksql/run
目录下,执行以下命令开始导入数据。cd benchmarksql/run/sql.common cp tableCreates.sql.auto tableCreates.sql cd .. nohup ./runDatabaseBuild.sh props.mysql &
验证数据完整性 数据导入完成后,通过命令行连接到PolarDB-X实例,执行以下SQL语句进行校验。若所有查询均返回空结果集,则表明数据导入成功且完整。
SELECT a.* FROM (SELECT w_id, w_ytd FROM bmsql_warehouse) a LEFT JOIN (SELECT d_w_id, sum(d_ytd) AS d_ytd_sum FROM bmsql_district GROUP BY d_w_id) b ON a.w_id = b.d_w_id AND a.w_ytd = b.d_ytd_sum WHERE b.d_w_id IS; SELECT a.* FROM (SELECT d_w_id, d_id, D_NEXT_O_ID - 1 AS d_n_o_id FROM bmsql_district) a LEFT JOIN (SELECT o_w_id, o_d_id, max(o_id) AS o_id_max FROM bmsql_oorder GROUP BY o_w_id, o_d_id) b ON a.d_w_id = b.o_w_id AND a.d_id = b.o_d_id AND a.d_n_o_id = b.o_id_max WHERE b.o_w_id IS NULL; SELECT a.* FROM (SELECT d_w_id, d_id, D_NEXT_O_ID - 1 AS d_n_o_id FROM bmsql_district) a LEFT JOIN (SELECT no_w_id, no_d_id, max(no_o_id) AS no_id_max FROM bmsql_new_order GROUP BY no_w_id, no_d_id) b ON a.d_w_id = b.no_w_id AND a.d_id = b.no_d_id AND a.d_n_o_id = b.no_id_max WHERE b.no_id_max IS NULL; SELECT * FROM (SELECT (count(no_o_id)-(max(no_o_id)-min(no_o_id)+1)) AS diff FROM bmsql_new_order GROUP BY no_w_id, no_d_id) a WHERE diff != 0; SELECT a.* FROM (SELECT o_w_id, o_d_id, sum(o_ol_cnt) AS o_ol_cnt_cnt FROM bmsql_oorder GROUP BY o_w_id, o_d_id) a LEFT JOIN (SELECT ol_w_id, ol_d_id, count(ol_o_id) AS ol_o_id_cnt FROM bmsql_order_line GROUP BY ol_w_id, ol_d_id) b ON a.o_w_id = b.ol_w_id AND a.o_d_id = b.ol_d_id AND a.o_ol_cnt_cnt = b.ol_o_id_cnt WHERE b.ol_w_id IS NULL; SELECT a.* FROM (SELECT d_w_id, sum(d_ytd) AS d_ytd_sum FROM bmsql_district GROUP BY d_w_id) a LEFT JOIN (SELECT w_id, w_ytd FROM bmsql_warehouse) b ON a.d_w_id = b.w_id AND a.d_ytd_sum = b.w_ytd WHERE b.w_id IS NULL;
步骤四:执行压测
在benchmarksql/run
目录下,执行以下命令运行TPC-C测试。终端会实时显示tpmC(每分钟事务数),测试结束后会输出最终的平均值。
cd benchmarksql/run
./runBenchmark.sh props.mysql