# Benchmark Cassandra performance

## In this learning path

- [Introduction](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/)
- [Get started with Cassandra on Google Axion C4A](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/background/)
- [Create a Google Axion C4A Arm virtual machine](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/instance/)
- [Install Apache Cassandra](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/installation/)
- [Test Cassandra baseline functionality](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/baseline/)
- [Benchmark Cassandra performance](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/benchmarking/)
- [Next Steps](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cassandra-on-gcp/_next-steps/)

## Benchmark Cassandra with cassandra-stress
You can perform Cassandra benchmarking using the built-in `cassandra-stress` tool, which measures database performance under different workloads such as write, read, and mixed operations.

## Verify cassandra-stress installation
Cassandra comes with a built-in tool called `cassandra-stress` that is used for testing performance. It’s located in the `tools/bin/` folder of your Cassandra installation.

```
ls ~/cassandra/tools/bin | grep cassandra-stress
```

If you see `cassandra-stress` in the list, the tool is installed and ready to use.

Check the tool’s help options to verify it works correctly:

```
~/cassandra/tools/bin/cassandra-stress help
```

The output is similar to:

```
__output__
Usage:      cassandra-stress <command> [options]
__output__
Help usage: cassandra-stress help <command>
__output__
---Commands---
read                 : Multiple concurrent reads - the cluster must first be populated by a write test
write                : Multiple concurrent writes against the cluster
mixed                : Interleaving of any basic commands, with configurable ratio and distribution - the cluster must first be populated by a write test
counter_write        : Multiple concurrent updates of counters.
counter_read         : Multiple concurrent reads of counters. The cluster must first be populated by a counterwrite test.
user                 : Interleaving of user provided queries, with configurable ratio and distribution
help                 : Print help for a command or option
print                : Inspect the output of a distribution definition
version              : Print the version of cassandra stress
```

The list of commands and options confirms that your setup is correct and you’re ready to start testing Cassandra’s performance.

## Run a basic write test
Insert 10,000 rows with 50 concurrent threads using `cassandra-stress`:

```
~/cassandra/tools/bin/cassandra-stress write n=10000 -rate threads=50
```

- **write** → Performs only write operations on the Cassandra cluster.
- **n=10000** → Specifies the number of rows to insert during the benchmark test.
- **-rate threads=50** → Sets the number of concurrent worker threads simulating multiple clients writing to the cluster.

The output is similar to:

```
__output__
******************** Stress Settings ********************
__output__
Command:
__output__
  Type: write
__output__
  Count: 10,000
__output__
  No Warmup: false
__output__
  Consistency Level: LOCAL_ONE
__output__
  Target Uncertainty: not applicable
__output__
  Key Size (bytes): 10
__output__
  Counter Increment Distibution: add=fixed(1)
__output__
Rate:
__output__
  Auto: false
__output__
  Thread Count: 50
__output__
  OpsPer Sec: 0
__output__
Population:
__output__
  Sequence: 1..10000
__output__
  Order: ARBITRARY
__output__
  Wrap: true
__output__
Insert:
__output__
  Revisits: Uniform:  min=1,max=1000000
__output__
  Visits: Fixed:  key=1
__output__
  Row Population Ratio: Ratio: divisor=1.000000;delegate=Fixed:  key=1
__output__
  Batch Type: not batching
__output__
Columns:
__output__
  Max Columns Per Key: 5
__output__
  Column Names: [C0, C1, C2, C3, C4]
__output__
  Comparator: AsciiType
__output__
  Timestamp: null
__output__
  Variable Column Count: false
__output__
  Slice: false
__output__
  Size Distribution: Fixed:  key=34
__output__
  Count Distribution: Fixed:  key=5
__output__
Errors:
__output__
  Ignore: false
__output__
  Tries: 10
__output__
Log:
__output__
  No Summary: false
__output__
  No Settings: false
__output__
  File: null
__output__
  Interval Millis: 1000
__output__
  Level: NORMAL
__output__
Mode:
__output__
  API: JAVA_DRIVER_NATIVE
__output__
  Connection Style: CQL_PREPARED
__output__
  Protocol Version: V5
__output__
  Username: null
__output__
  Password: null
__output__
  Max Pending Per Connection: 128
__output__
  Connections Per Host: 8
__output__
  Compression: NONE
__output__
Node:
__output__
  Nodes: [localhost]
__output__
  Is White List: false
__output__
  Datacenter: null
__output__
Schema:
__output__
  Keyspace: keyspace1
__output__
  Replication Strategy: org.apache.cassandra.locator.SimpleStrategy
__output__
  Replication Strategy Options: {replication_factor=1}
__output__
  Table Compression: null
__output__
  Table Compaction Strategy: null
__output__
  Table Compaction Strategy Options: {}
__output__
Transport:
__output__
  Truststore: null
__output__
  Truststore Password: null
__output__
  Keystore: null
__output__
  Keystore Password: null
__output__
  SSL Protocol: TLS
__output__
  SSL Algorithm: null
__output__
  SSL Ciphers: TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
__output__
Port:
__output__
  Native Port: 9042
__output__
  JMX Port: 7199
__output__
JMX:
__output__
  Username: null
__output__
  Password: *not set*
__output__
Graph:
__output__
  File: null
__output__
  Revision: unknown
__output__
  Title: null
__output__
  Operation: WRITE
__output__
TokenRange:
__output__
  Wrap: false
__output__
  Split Factor: 1
__output__
Credentials file:
__output__
  File: *not set*
__output__
  CQL username: *not set*
__output__
  CQL password: *not set*
__output__
  JMX username: *not set*
__output__
  JMX password: *not set*
__output__
  Transport truststore password: *not set*
__output__
  Transport keystore password: *not set*
__output__
Reporting:
__output__
  Output frequency: 1s
__output__
  Header frequency: *not set*
__output__

Connected to cluster: Test Cluster, max pending requests per connection 128, max connections per host 8
__output__
Datacenter: datacenter1; Host: localhost/127.0.0.1:9042; Rack: rack1
__output__
Created keyspaces. Sleeping 1s for propagation.
__output__
Sleeping 2s...
__output__
Warming up WRITE with 2500 iterations...
__output__
Running WRITE with 50 threads for 10000 iteration
__output__
type                                               total ops,    op/s,    pk/s,   row/s,    mean,     med,     .95,     .99,    .999,     max,   time,   stderr, errors,  gc: #,  max ms,  sum ms,  sdv ms,      mb
__output__
total,                                                 10000,   10690,   10690,   10690,     3.7,     2.8,     9.5,    16.7,    28.9,    38.4,    0.9,  0.00000,      0,      0,       0,       0,       0,       0
__output__

Results:
__output__
Op rate                   :   10,690 op/s  [WRITE: 10,690 op/s]
__output__
Partition rate            :   10,690 pk/s  [WRITE: 10,690 pk/s]
__output__
Row rate                  :   10,690 row/s [WRITE: 10,690 row/s]
__output__
Latency mean              :    3.7 ms [WRITE: 3.7 ms]
__output__
Latency median            :    2.8 ms [WRITE: 2.8 ms]
__output__
Latency 95th percentile   :    9.5 ms [WRITE: 9.5 ms]
__output__
Latency 99th percentile   :   16.7 ms [WRITE: 16.7 ms]
__output__
Latency 99.9th percentile :   28.9 ms [WRITE: 28.9 ms]
__output__
Latency max               :   38.4 ms [WRITE: 38.4 ms]
__output__
Total partitions          :     10,000 [WRITE: 10,000]
__output__
Total errors              :          0 [WRITE: 0]
__output__
Total GC count            : 0
__output__
Total GC memory           : 0 B
__output__
Total GC time             :    0.0 seconds
__output__
Avg GC time               :    NaN ms
__output__
StdDev GC time            :    0.0 ms
__output__
Total operation time      : 00:00:00
__output__

END
```

## Run a read test
Run a read benchmark on your Cassandra database using `cassandra-stress`. This simulates multiple clients reading from the cluster at the same time and records performance metrics such as throughput and latency.

```
~/cassandra/tools/bin/cassandra-stress read n=10000 -rate threads=50
```

The output is similar to:

```
__output__
******************** Stress Settings ********************
__output__
Command:
__output__
  Type: read
__output__
  Count: 10,000
__output__
  No Warmup: false
__output__
  Consistency Level: LOCAL_ONE
__output__
  Target Uncertainty: not applicable
__output__
  Key Size (bytes): 10
__output__
  Counter Increment Distibution: add=fixed(1)
__output__
Rate:
__output__
  Auto: false
__output__
  Thread Count: 50
__output__
  OpsPer Sec: 0
__output__
Population:
__output__
  Distribution: Gaussian:  min=1,max=10000,mean=5000.500000,stdev=1666.500000
__output__
  Order: ARBITRARY
__output__
  Wrap: false
__output__
Insert:
__output__
  Revisits: Uniform:  min=1,max=1000000
__output__
  Visits: Fixed:  key=1
__output__
  Row Population Ratio: Ratio: divisor=1.000000;delegate=Fixed:  key=1
__output__
  Batch Type: not batching
__output__
Columns:
__output__
  Max Columns Per Key: 5
__output__
  Column Names: [C0, C1, C2, C3, C4]
__output__
  Comparator: AsciiType
__output__
  Timestamp: null
__output__
  Variable Column Count: false
__output__
  Slice: false
__output__
  Size Distribution: Fixed:  key=34
__output__
  Count Distribution: Fixed:  key=5
__output__
Errors:
__output__
  Ignore: false
__output__
  Tries: 10
__output__
Log:
__output__
  No Summary: false
__output__
  No Settings: false
__output__
  File: null
__output__
  Interval Millis: 1000
__output__
  Level: NORMAL
__output__
Mode:
__output__
  API: JAVA_DRIVER_NATIVE
__output__
  Connection Style: CQL_PREPARED
__output__
  Protocol Version: V5
__output__
  Username: null
__output__
  Password: null
__output__
  Max Pending Per Connection: 128
__output__
  Connections Per Host: 8
__output__
  Compression: NONE
__output__
Node:
__output__
  Nodes: [localhost]
__output__
  Is White List: false
__output__
  Datacenter: null
__output__
Schema:
__output__
  Keyspace: keyspace1
__output__
  Replication Strategy: org.apache.cassandra.locator.SimpleStrategy
__output__
  Replication Strategy Options: {replication_factor=1}
__output__
  Table Compression: null
__output__
  Table Compaction Strategy: null
__output__
  Table Compaction Strategy Options: {}
__output__
Transport:
__output__
  Truststore: null
__output__
  Truststore Password: null
__output__
  Keystore: null
__output__
  Keystore Password: null
__output__
  SSL Protocol: TLS
__output__
  SSL Algorithm: null
__output__
  SSL Ciphers: TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
__output__
Port:
__output__
  Native Port: 9042
__output__
  JMX Port: 7199
__output__
JMX:
__output__
  Username: null
__output__
  Password: *not set*
__output__
Graph:
__output__
  File: null
__output__
  Revision: unknown
__output__
  Title: null
__output__
  Operation: READ
__output__
TokenRange:
__output__
  Wrap: false
__output__
  Split Factor: 1
__output__
Credentials file:
__output__
  File: *not set*
__output__
  CQL username: *not set*
__output__
  CQL password: *not set*
__output__
  JMX username: *not set*
__output__
  JMX password: *not set*
__output__
  Transport truststore password: *not set*
__output__
  Transport keystore password: *not set*
__output__
Reporting:
__output__
  Output frequency: 1s
__output__
  Header frequency: *not set*
__output__

Sleeping 2s...
__output__
Warming up READ with 2500 iterations...
__output__
Connected to cluster: Test Cluster, max pending requests per connection 128, max connections per host 8
__output__
Datacenter: datacenter1; Host: localhost/127.0.0.1:9042; Rack: rack1
__output__
Running READ with 50 threads for 10000 iteration
__output__
type                                               total ops,    op/s,    pk/s,   row/s,    mean,     med,     .95,     .99,    .999,     max,   time,   stderr, errors,  gc: #,  max ms,  sum ms,  sdv ms,      mb
__output__
total,                                                  1540,    1540,    1540,    1540,     8.1,     6.2,    19.2,    38.4,    73.3,    80.9,    1.0,  0.00000,      0,      0,       0,       0,       0,       0
__output__
total,                                                  9935,    8395,    8395,    8395,     5.9,     4.2,    16.7,    33.1,    57.3,    86.0,    2.0,  0.48892,      0,      0,       0,       0,       0,       0
__output__
total,                                                 10000,    4217,    4217,    4217,     8.5,     4.2,    27.1,    27.4,    27.4,    27.4,    2.0,  1.89747,      0,      0,       0,       0,       0,       0
__output__

Results:
__output__
Op rate                   :    4,962 op/s  [READ: 4,962 op/s]
__output__
Partition rate            :    4,962 pk/s  [READ: 4,962 pk/s]
__output__
Row rate                  :    4,962 row/s [READ: 4,962 row/s]
__output__
Latency mean              :    6.3 ms [READ: 6.3 ms]
__output__
Latency median            :    4.5 ms [READ: 4.5 ms]
__output__
Latency 95th percentile   :   17.4 ms [READ: 17.4 ms]
__output__
Latency 99th percentile   :   33.4 ms [READ: 33.4 ms]
__output__
Latency 99.9th percentile :   59.6 ms [READ: 59.6 ms]
__output__
Latency max               :   86.0 ms [READ: 86.0 ms]
__output__
Total partitions          :     10,000 [READ: 10,000]
__output__
Total errors              :          0 [READ: 0]
__output__
Total GC count            : 0
__output__
Total GC memory           : 0 B
__output__
Total GC time             :    0.0 seconds
__output__
Avg GC time               :    NaN ms
__output__
StdDev GC time            :    0.0 ms
__output__
Total operation time      : 00:00:02
__output__

END
```

## Understand benchmark results
The metrics below explain what each value in the `cassandra-stress` output represents:

- Op rate (operations per second): the number of read operations Cassandra successfully executed per second.
- Partition rate: the number of partitions read per second. Since this is a read test, the partition rate equals the op rate.
- Row rate: the number of rows read per second. Again, for this test it equals the op rate.
- Latency mean: the average time taken for each read request to complete.
- Latency median: the 50th percentile latency - half of the operations completed faster than this time.
- Latency max: the slowest single read request during the test.
- Total partitions: the total number of partitions read during the test.
- Total errors: the number of failed read operations.
- GC metrics (Garbage Collection): shows whether JVM garbage collection paused Cassandra during the test.
- Total operation time: the total wall-clock time taken to run the benchmark.

## Benchmark summary for Arm64
Results from the run on the `c4a-standard-4` (4 vCPU, 16 GB memory) Arm64 VM in GCP (SUSE shown; Ubuntu results were very similar):

| Metric                      | Write Test | Read Test |
|-----------------------------|------------|-----------|
| Operation Rate (op/s)      | 10,690     | 4,962     |
| Partition Rate (pk/s)      | 10,690     | 4,962     |
| Row Rate (row/s)           | 10,690     | 4,962     |
| Latency Mean                | 3.7 ms     | 6.3 ms    |
| Latency Median              | 2.8 ms     | 4.5 ms    |
| Latency 95th Percentile     | 9.5 ms     | 17.4 ms   |
| Latency 99th Percentile     | 16.7 ms    | 33.4 ms   |
| Latency 99.9th Percentile   | 28.9 ms    | 59.6 ms   |
| Latency Max                 | 38.4 ms    | 86.0 ms   |
| Total Partitions            | 10,000     | 10,000    |
| Total Errors                | 0          | 0         |
| Total GC Count              | 0          | 0         |
| Total GC Memory             | 0 B        | 0 B       |
| Total GC Time               | 0.0 s      | 0.0 s     |
| Total Operation Time        | 0:00:00    | 0:00:02   |

## What you’ve accomplished and what’s next
You’ve successfully deployed Apache Cassandra 5.0.5 on a Google Axion C4A Arm-based virtual machine, validated its functionality, and measured its performance using cassandra-stress. The benchmark results on Google Axion C4A Arm-based instances demonstrate strong performance characteristics.

Write operations achieved high throughput of 10,690 op/s, while read operations reached 4,962 op/s on the `c4a-standard-4` Arm64 VM. Write latency was notably low with a mean of 3.7 ms compared to reads at 6.3 ms, indicating fast write processing on this Arm64 VM. The 95th and 99th percentile latencies show consistent performance, with writes significantly faster than reads. Zero errors or GC overhead confirm stable and reliable benchmarking results.

The Arm64 VM provides efficient and predictable performance, making it suitable for high-throughput Cassandra workloads. The low write latencies and high operation rates demonstrate that Arm-based infrastructure can effectively handle database operations that require both speed and consistency. These results provide a solid baseline for evaluating Cassandra performance on Arm64 architecture and can guide decisions about instance sizing and configuration for production deployments.

To continue building on this foundation, you can explore advanced Cassandra configurations such as multi-node cluster deployments, replication strategies for high availability, or performance tuning for specific workload patterns. You might also investigate integrating Cassandra with application frameworks or comparing performance across different Arm-based instance types to optimize for your use case.
