性能测试报告

本文介绍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_stock1亿行。

  • 性能指标: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(1632 GB)

2 * 432 GB

4 * ecs.c7.4xlarge(1632 GB)

4 * 864 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 * 432 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 * 864 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驱动自身的性能影响,在不开启任何加密的情况下,对比了标准JDBCEncJDBC的客户端资源消耗。结果显示,主要的额外开销在于CPU。

测试条件

客户端规格(ECS实例)为ecs.c7.4xlarge(1632 GB),并发数为1024。

测试结果

规格

CPU使用率

内存使用率(MB)

标准JDBC

EncJDBC

标准JDBC

EncJDBC

2 * 432 GB

21.37%

28.00%

+31%

1077

1001

-7.06%

4 * 864 GB

47.09%

69.90%

+48%

1048

1024

-2.29%

开启加密后客户端资源消耗

开启100%列加密后,客户端(ECS实例)的CPU消耗显著增加,这是全密态功能性能开销的主要部分。为达到最佳性能,应用侧需要预留充足的CPU资源。

测试条件

并发数为1024。

测试结果

规格

CPU使用率 (加密前)

CPU使用率 (100%加密)

CPU增幅

2 * 432 GB

13.01%

33.45%

+157%

4 * 432 GB

20.60%

32.07%

+56%

2 * 864 GB

19.93%

36.77%

+85%

4 * 864 GB

17.73%

43.59%

+146%

结论

综合不同实例规格,开启全密态加密后,客户端的CPU资源消耗增幅在56%至157%之间,最大增幅超过1.5倍。

不同加密比例对性能和资源的影响

加密列的数量直接影响性能和客户端CPU消耗。下表数据展示了随着加密列比例的增加,性能损耗和客户端CPU使用率的变化。

测试条件

并发数为1024。

测试结果

  • 2 * 432 GB

    加密比例

    客户端CPU使用率

    TPS

    性能损耗

    20%

    20.01%

    96,792

    2%

    50%

    22.23%

    96,639

    2%

    100%

    33.45%

    95,182

    4%

  • 4 * 864 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实例

  1. 创建一个PolarDB-X实例

    说明

    创建PolarDB-X实例时,请将实例和压力机ECS实例放至同一个专有网络VPC内。

  2. 将压力机ECS实例的内网地址添加至PolarDB-X实例的白名单中。

  3. 在实例中创建一个待压测的数据库,此处以tpcc_1000为例。

    CREATE DATABASE tpcc_1000 MODE = 'auto';

步骤3:准备压测数据

  1. 准备压测工具

    1. 在压力机ECS上,下载并解压压测工具包benchmarksql.tar.gz

      tar xzvf benchmarksql.tar.gz
    2. 下载全密态驱动包aliyun-encdb-mysql-jdbc-1.0.9-2-20240910.094626-1.jar,并将其放置在benchmarksql/lib目录下。

  2. 配置压测参数

    1. 进入benchmarksql/run目录,编辑props.mysql配置文件。

      cd benchmarksql/run
      vi props.mysql
    2. 根据您的环境修改配置。以下为配置示例及关键参数说明:

      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: 压测持续时间(分钟)。

  3. 导入数据 在benchmarksql/run目录下,执行以下命令开始导入数据。

    cd benchmarksql/run/sql.common
    cp tableCreates.sql.auto  tableCreates.sql
    cd ..
    nohup ./runDatabaseBuild.sh props.mysql &
  4. 验证数据完整性 数据导入完成后,通过命令行连接到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