Performance testing report

更新时间:
复制 MD 格式

This report presents YCSB (Yahoo! Cloud Serving Benchmark) benchmark results for PolarDB for PostgreSQL's DynamoDB-compatible API across five workload types and four data scales. Use these results for technology selection, application design, and capacity planning.

Point query performance peaks at 983,524 OPS (Operations Per Second) (64-core 256 GB specification, 10 GB data volume, 100% read workload).

Test environment

Environment configuration

Component

Specifications

Test cluster (PolarDB)

  • Number of clusters: 1

  • Kernel version: PostgreSQL 16

  • Product edition: Enterprise Edition

  • Node specifications: Dedicated specifications (one read/write node and one read-only node), tested at 8-core 32 GB, 32-core 128 GB, and 64-core 256 GB

Stress testing client (ECS)

  • Number of clients: Multiple ECS instances in the same VPC as the test cluster.

  • Stress tests were run sequentially with 16, 32, 64, 96, 128, 160, 192, 256, 512, and 1,024 threads.

  • Client specifications: 64 cores and 256 GB.

Benchmark tool

Workload model

All workloads use YCSB CoreWorkload. The test data model uses a single table usertable with a HASH primary key, and each record contains 10 fields of 100-byte random strings (approximately 1 KB per record).

YCSB workload

Scenario

Core parameter

workload_insert_only

100% write

insertproportion=1.0

workload_update_only

100% update

updateproportion=1.0

workload_read_only

100% point query

readproportion=1.0

workload_read_update

50% read + 50% update

readproportion=0.5, updateproportion=0.5

workload_scan_only

100% range scan

scanproportion=1.0

Other stress testing methods

Stress testing method

Description

Data volume

Preload 1 M / 10 M / 100 M / 1 B records respectively before running the stress test (approximately 1 GB / 10 GB / 100 GB / 1 TB of data).

Test duration

5 minutes per round (maxexecutiontime=300s)

Value source

The best throughput across different concurrent thread counts in the stress tests.

Per-specification detailed test results

The following three tables show the throughput (OPS) for different data scales and workloads across three cluster specifications: 8-core 32 GB, 32-core 128 GB, and 64-core 256 GB. The best throughput across different concurrent thread counts in the stress tests is used.

8-core 32 GB specification

Test scenario

1 GB (OPS)

10 GB (OPS)

100 GB (OPS)

1 TB (OPS)

100% read (Read)

243,067

238,188

140,199

116,189

100% range scan (Scan)

37,142

36,945

5,626

4,857

50% read + 50% update

89,119

84,636

65,903

57,164

100% update (Update)

45,401

42,869

34,741

29,907

100% write (Insert)

57,806

46,621

44,428

44,359

32-core 128 GB specification

Test scenario

1 GB (OPS)

10 GB (OPS)

100 GB (OPS)

1 TB (OPS)

100% read (Read)

578,397

575,689

462,904

373,101

100% range scan (Scan)

90,256

89,789

25,986

10,278

50% read + 50% update

221,826

216,588

164,912

120,688

100% update (Update)

114,770

114,696

92,479

78,317

100% write (Insert)

128,332

121,148

117,396

112,275

64-core 256 GB specification

Test scenario

1 GB (OPS)

10 GB (OPS)

100 GB (OPS)

1 TB (OPS)

100% read (Read)

894,926

983,524

980,197

653,825

100% range scan (Scan)

138,609

142,560

140,653

14,171

50% read + 50% update

318,094

312,043

288,028

189,536

100% update (Update)

171,349

170,789

154,085

115,961

100% write (Insert)

171,682

176,069

167,877

165,308

Appendix: Reproduce the tests

Follow these steps to reproduce the performance tests for secondary validation or custom testing.

Step 1: Configure YCSB

Before running the tests, configure the YCSB DynamoDB client.

  1. Configure identity credentials

    Edit dynamodb/conf/AWSCredentials.properties and enter the credentials for your PolarDB consolededicated DynamoDB account.

    # The account name is the AccessKey ID
    accessKey = <YOUR_ACCESS_KEY_ID>
    
    # Secret key
    secretKey = <YOUR_SECRET_ACCESS_KEY>
  2. Configure connection properties

    Edit dynamodb/conf/dynamodb.properties and specify the PolarDB cluster connection information.

    # The absolute path of the authentication file
    dynamodb.awsCredentialsFile = /path/to/your/AWSCredentials.properties
    
    # Create a usertable table in the cluster in advance.
    # This example creates a usertable table with only a partition key named pk.
    dynamodb.primaryKey = pk
    
    # The DynamoDB endpoint for PolarDB. Must include the http:// prefix.
    dynamodb.endpoint = http://<your-polardb-ddb-endpoint>:<port>
    
    # Leave the region parameter blank.
    dynamodb.region =
    
    # The primary key name and type for the test table. Must match the test table.
    dynamodb.primaryKey = HASH

Step 2: Patch the YCSB update operation

Important

The official YCSB DynamoDB client uses the deprecated AttributeUpdates parameter by default. PolarDB requires the UpdateExpression parameter. You must apply the following change before running any update workloads.

  • File path: dynamodb/src/main/java/site/ycsb/db/DynamoDBClient.java

  • Method to modify: update()

Replace the original implementation:

@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;
}

After the change (using 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;
}

Step 3: Run the test

Each test run has two phases: load (populate test data) and run (execute the workload). The examples below use a 1 GB dataset (1 million records), 128 concurrent threads, and the read-only workload.

Note

To test other data volumes, modify the recordcount and operationcount parameters in the commands.

  1. Load data (Load Phase)

    # -s: Displays status updates during loading.
    # -P workloads/workload_read_only: Specifies the workload file.
    # -P /path/to/dynamodb.properties: Specifies the database connection configuration.
    # -p recordcount=1000000: Total number of records to load (1 GB).
    # -p operationcount=1000000: Total number of operations.
    # -threads 128: Number of concurrent threads.
    
    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 &
  2. Run the test (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 &