本报告提供了PolarDB PostgreSQL版在多种典型工作负载下的性能基准测试结果。测试基于业界标准的 YCSB(Yahoo! Cloud Serving Benchmark)工具进行,旨在为您的技术选型、应用设计和容量规划提供量化的数据参考。测试结果表明,该功能在各种数据规模下均能提供稳定且高性能的读写服务。尤其在单点查询(Point Lookup)场景下表现优异,峰值 OPS(每秒操作数)可达 983,524(64 核 256 GB 规格,10 GB 数据量下的 100% 读取场景)。
测试方法与环境
测试环境配置
组件 | 规格与配置 |
测试集群(PolarDB) |
|
压测客户端(ECS) |
|
基准测试工具
性能指标:OPS (Operations Per Second),即数据库每秒处理的操作数。
工作负载模型
通过配置YCSB的CoreWorkload来模拟五种典型的业务场景。测试数据模型为单表usertable,主键类型HASH,字段包含10个100 字节的随机字符串(每个记录约1 KB)。
YCSB Workload | 场景描述 | 核心参数配置 |
| 100%写入 |
|
| 100%更新 |
|
| 100%单点查询 |
|
| 50%读+50%更新 |
|
| 100%范围查询 |
|
其他压测方式
压测方式 | 说明 |
数据量 | 分别预加载1 M / 10 M / 100 M / 1 B条记录后进行压测(对应约1 GB / 10 GB / 100 GB / 1 TB数据)。 |
压测时长 | 每轮5分钟(maxexecutiontime=300s) |
取值方式 | 不同压测并发线程下的最佳吞吐量。 |
分规格详细测试结果
以下三组数据分别展示 8 核 32 GB、32 核 128 GB、64 核 256 GB 三种集群规格下,不同数据规模与不同工作负载的吞吐量(OPS)。取不同压测并发线程下的最佳吞吐量。
8 核 32 GB 规格
测试场景 | 1 GB 数据量(OPS) | 10 GB 数据量(OPS) | 100 GB 数据量(OPS) | 1 TB 数据量(OPS) |
100% 读取(Read) | 243,067 | 238,188 | 140,199 | 116,189 |
100% 范围扫描(Scan) | 37,142 | 36,945 | 5,626 | 4,857 |
50% 读 + 50% 更新 | 89,119 | 84,636 | 65,903 | 57,164 |
100% 更新(Update) | 45,401 | 42,869 | 34,741 | 29,907 |
100% 写入(Insert) | 57,806 | 46,621 | 44,428 | 44,359 |
32 核 128 GB 规格
测试场景 | 1 GB 数据量(OPS) | 10 GB 数据量(OPS) | 100 GB 数据量(OPS) | 1 TB 数据量(OPS) |
100% 读取(Read) | 578,397 | 575,689 | 462,904 | 373,101 |
100% 范围扫描(Scan) | 90,256 | 89,789 | 25,986 | 10,278 |
50% 读 + 50% 更新 | 221,826 | 216,588 | 164,912 | 120,688 |
100% 更新(Update) | 114,770 | 114,696 | 92,479 | 78,317 |
100% 写入(Insert) | 128,332 | 121,148 | 117,396 | 112,275 |
64 核 256 GB 规格
测试场景 | 1 GB 数据量(OPS) | 10 GB 数据量(OPS) | 100 GB 数据量(OPS) | 1 TB 数据量(OPS) |
100% 读取(Read) | 894,926 | 983,524 | 980,197 | 653,825 |
100% 范围扫描(Scan) | 138,609 | 142,560 | 140,653 | 14,171 |
50% 读 + 50% 更新 | 318,094 | 312,043 | 288,028 | 189,536 |
100% 更新(Update) | 171,349 | 170,789 | 154,085 | 115,961 |
100% 写入(Insert) | 171,682 | 176,069 | 167,877 | 165,308 |
附录:测试步骤
本附录提供了复现上述性能测试所需的详细步骤,供需要进行二次验证或定制化的测试参考。
1. 配置YCSB
在运行测试前,需要对YCSB的DynamoDB客户端进行配置。
配置身份凭证
编辑
dynamodb/conf/AWSCredentials.properties文件,填入您在PolarDB控制台创建的DynamoDB专用账号信息。# 账号名即为AccessKey ID accessKey = <YOUR_ACCESS_KEY_ID> # 密钥 secretKey = <YOUR_SECRET_ACCESS_KEY>配置连接属性
编辑
dynamodb/conf/dynamodb.properties文件,指定要连接的PolarDB集群连接信息。# 认证文件的绝对路径 dynamodb.awsCredentialsFile = /path/to/your/AWSCredentials.properties # 您需要提前在集群中创建一个usertable表。此处创建仅有分区键的usertable表,分区键名为pk。 dynamodb.primaryKey = pk # PolarDB的DynamoDB访问地址,必须包含http://前缀 dynamodb.endpoint = http://<your-polardb-ddb-endpoint>:<port> # region参数必须设置为空 dynamodb.region = # 测试所用的表主键名和类型,需与测试表保持一致 dynamodb.primaryKey = HASH
2. 适配YCSB的Update操作
YCSB官方的DynamoDB客户端默认使用已废弃的AttributeUpdates参数执行更新。为兼容PolarDB所支持的新版UpdateExpression参数,您需要修改YCSB源码。
文件路径:
dynamodb/src/main/java/site/ycsb/db/DynamoDBClient.java修改方法:
update()
修改前(原始代码)
@Override
public Status update(String table, String key, Map<String, ByteIterator> values) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("updatekey: " + key + " from table: " + table);
}
Map<String, AttributeValueUpdate> attributes = new HashMap<>(values.size());
for (Entry<String, ByteIterator> val : values.entrySet()) {
AttributeValue v = new AttributeValue(val.getValue().toString());
attributes.put(val.getKey(), new AttributeValueUpdate().withValue(v).withAction("PUT"));
}
UpdateItemRequest req = new UpdateItemRequest(table, createPrimaryKey(key), attributes);
try {
dynamoDB.updateItem(req);
} catch (AmazonServiceException ex) {
LOGGER.error(ex);
return Status.ERROR;
} catch (AmazonClientException ex) {
LOGGER.error(ex);
return CLIENT_ERROR;
}
return Status.OK;
}修改后(使用UpdateExpression)
@Override
public Status update(String table, String key, Map<String, ByteIterator> values) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("updatekey: " + key + " from table: " + table);
}
StringBuilder updateExp = new StringBuilder("SET ");
Map<String, String> attrNames = new HashMap<>();
Map<String, AttributeValue> attrValues = new HashMap<>();
boolean first = true;
for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
String attr = entry.getKey();
if (!first) {
updateExp.append(", ");
}
String attrName = "#" + attr;
String valueName = ":" + attr;
updateExp.append(attrName).append(" = ").append(valueName);
attrNames.put(attrName, attr);
attrValues.put(valueName, new AttributeValue(entry.getValue().toString()));
first = false;
}
UpdateItemRequest req = new UpdateItemRequest()
.withTableName(table)
.withKey(createPrimaryKey(key))
.withUpdateExpression(updateExp.toString())
.withExpressionAttributeNames(attrNames)
.withExpressionAttributeValues(attrValues);
try {
dynamoDB.updateItem(req);
} catch (AmazonServiceException ex) {
LOGGER.error(ex);
return Status.ERROR;
} catch (AmazonClientException ex) {
LOGGER.error(ex);
return CLIENT_ERROR;
}
return Status.OK;
}3. 执行测试
测试分为load(加载初始数据)和run(运行工作负载)两个阶段。以1 GB数据量(100万条记录)、128并发线程、只读模型为例:
在其他数据量场景下,请修改命令中的recordcount和operationcount参数。
加载数据(Load Phase)
# 解释: # -s: 显示状态更新 # -P workloads/workload_read_only: 指定基础workload文件 # -P /path/to/dynamodb.properties: 指定数据库连接配置文件 # -p recordcount=1000000: 定义总记录数 # -p operationcount=1000000: 定义本次运行要执行的操作总数 # -threads 128: 指定并发线程数 nohup ./bin/ycsb load dynamodb -s \ -P workloads/workload_read_only \ -P /path/to/dynamodb.properties \ -p recordcount=1000000 \ -p operationcount=1000000 \ -threads 128 \ > load.log 2>&1 &运行测试(Run Phase)
nohup ./bin/ycsb run dynamodb -s \ -P workloads/workload_read_only \ -P /path/to/dynamodb.properties \ -p recordcount=1000000 \ -p operationcount=1000000 \ -threads 128 \ > run.log 2>&1 &