Cassandra Stress

The cassandra-stress tool is used to benchmark and load-test a Cassandra cluster. cassandra-stress supports testing arbitrary CQL tables and queries, allowing users to benchmark their own data model.

This documentation focuses on user mode to test personal schema.

Usage

There are several operation types:

  • write-only, read-only, and mixed workloads of standard data

  • write-only and read-only workloads for counter columns

  • user configured workloads, running custom queries on custom schemas

The syntax is cassandra-stress <command> [options]. For more information on a given command or options, run cassandra-stress help <command|option>.

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

    legacy:

    Legacy support mode

Primary Options

  • -pop:

    Population distribution and intra-partition visit order

    -insert:

    Insert specific options relating to various methods for batching and splitting partition updates

    -col:

    Column details such as size and count distribution, data generator, names, comparator and if super columns should be used

    -rate:

    Thread count, rate limit or automatic mode (default is auto)

    -mode:

    Thrift or CQL with options

    -errors:

    How to handle errors when encountered during stress

    -sample:

    Specify the number of samples to collect for measuring latency

    -schema:

    Replication settings, compression, compaction, etc.

    -node:

    Nodes to connect to

    -log:

    Where to log progress to, and the interval at which to do it

    -transport:

    Custom transport factories

    -port:

    The port to connect to cassandra nodes on

    -sendto:

    Specify a stress server to send this command to

    -graph:

    Graph recorded metrics

    -tokenrange:

    Token range settings

Suboptions

Every command and primary option has its own collection of suboptions. These are too numerous to list here. For information on the suboptions for each command or option, please use the help command, cassandra-stress help <command|option>.

User mode

User mode allows you to stress your own schemas, to save you time in the long run. Find out if your application can scale using stress test with your schema.

Profile

User mode defines a profile using YAML. Multiple YAML files may be specified, in which case operations in the ops argument are referenced as specname.opname.

An identifier for the profile:

  1. specname: staff_activities

The keyspace for the test:

  1. keyspace: staff

CQL for the keyspace. Optional if the keyspace already exists:

  1. keyspace_definition: |
  2. CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};

The table to be stressed:

  1. table: staff_activities

CQL for the table. Optional if the table already exists:

  1. table_definition: |
  2. CREATE TABLE staff_activities (
  3. name text,
  4. when timeuuid,
  5. what text,
  6. PRIMARY KEY(name, when, what)
  7. )

Optional meta-information on the generated columns in the above table. The min and max only apply to text and blob types. The distribution field represents the total unique population distribution of that column across rows:

  1. columnspec:
  2. - name: name
  3. size: uniform(5..10) # The names of the staff members are between 5-10 characters
  4. population: uniform(1..10) # 10 possible staff members to pick from
  5. - name: when
  6. cluster: uniform(20..500) # Staff members do between 20 and 500 events
  7. - name: what
  8. size: normal(10..100,50)

Supported types are:

An exponential distribution over the range [min..max]:

  1. EXP(min..max)

An extreme value (Weibull) distribution over the range [min..max]:

  1. EXTREME(min..max,shape)

A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng:

  1. GAUSSIAN(min..max,stdvrng)

A gaussian/normal distribution, with explicitly defined mean and stdev:

  1. GAUSSIAN(min..max,mean,stdev)

A uniform distribution over the range [min, max]:

  1. UNIFORM(min..max)

A fixed distribution, always returning the same value:

  1. FIXED(val)

If preceded by ~, the distribution is inverted

Defaults for all columns are size: uniform(4..8), population: uniform(1..100B), cluster: fixed(1)

Insert distributions:

  1. insert:
  2. # How many partition to insert per batch
  3. partitions: fixed(1)
  4. # How many rows to update per partition
  5. select: fixed(1)/500
  6. # UNLOGGED or LOGGED batch for insert
  7. batchtype: UNLOGGED

Currently all inserts are done inside batches.

Read statements to use during the test:

  1. queries:
  2. events:
  3. cql: select * from staff_activities where name = ?
  4. fields: samerow
  5. latest_event:
  6. cql: select * from staff_activities where name = ? LIMIT 1
  7. fields: samerow

Running a user mode test:

  1. cassandra-stress user profile=./example.yaml duration=1m "ops(insert=1,latest_event=1,events=1)" truncate=once

This will create the schema then run tests for 1 minute with an equal number of inserts, latest_event queries and events queries. Additionally the table will be truncated once before the test.

The full example can be found here:

  1. spacenam: example # idenitifier for this spec if running with multiple yaml files
  2. keyspace: example
  3. # Would almost always be network topology unless running something locally
  4. keyspace_definition: |
  5. CREATE KEYSPACE example WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
  6. table: staff_activities
  7. # The table under test. Start with a partition per staff member
  8. # Is this a good idea?
  9. table_definition: |
  10. CREATE TABLE staff_activities (
  11. name text,
  12. when timeuuid,
  13. what text,
  14. PRIMARY KEY(name, when)
  15. )
  16. columnspec:
  17. - name: name
  18. size: uniform(5..10) # The names of the staff members are between 5-10 characters
  19. population: uniform(1..10) # 10 possible staff members to pick from
  20. - name: when
  21. cluster: uniform(20..500) # Staff members do between 20 and 500 events
  22. - name: what
  23. size: normal(10..100,50)
  24. insert:
  25. # we only update a single partition in any given insert
  26. partitions: fixed(1)
  27. # we want to insert a single row per partition and we have between 20 and 500
  28. # rows per partition
  29. select: fixed(1)/500
  30. batchtype: UNLOGGED # Single partition unlogged batches are essentially noops
  31. queries:
  32. events:
  33. cql: select * from staff_activities where name = ?
  34. fields: samerow
  35. latest_event:
  36. cql: select * from staff_activities where name = ? LIMIT 1
  37. fields: samerow

Running a user mode test with multiple yaml files

cassandra-stress user profile=./example.yaml,./example2.yaml duration=1m “ops(ex1.insert=1,ex1.latest_event=1,ex2.insert=2)” truncate=once This will run operations as specified in both the example.yaml and example2.yaml files. example.yaml and example2.yaml can reference the same table, although care must be taken that the table definition is identical (data generation specs can be different).

Lightweight transaction support

cassandra-stress supports lightweight transactions. To use this feature, the command will first read current data from Cassandra, and then uses read values to fulfill lightweight transaction conditions.

Lightweight transaction update query:

  1. queries:
  2. regularupdate:
  3. cql: update blogposts set author = ? where domain = ? and published_date = ?
  4. fields: samerow
  5. updatewithlwt:
  6. cql: update blogposts set author = ? where domain = ? and published_date = ? IF body = ? AND url = ?
  7. fields: samerow

The full example can be found here:

  1. # Keyspace Name
  2. keyspace: stresscql
  3. # The CQL for creating a keyspace (optional if it already exists)
  4. # Would almost always be network topology unless running something locall
  5. keyspace_definition: |
  6. CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
  7. # Table name
  8. table: blogposts
  9. # The CQL for creating a table you wish to stress (optional if it already exists)
  10. table_definition: |
  11. CREATE TABLE blogposts (
  12. domain text,
  13. published_date timeuuid,
  14. url text,
  15. author text,
  16. title text,
  17. body text,
  18. PRIMARY KEY(domain, published_date)
  19. ) WITH CLUSTERING ORDER BY (published_date DESC)
  20. AND compaction = { 'class':'LeveledCompactionStrategy' }
  21. AND comment='A table to hold blog posts'
  22. ### Column Distribution Specifications ###
  23. columnspec:
  24. - name: domain
  25. size: gaussian(5..100) #domain names are relatively short
  26. population: uniform(1..10M) #10M possible domains to pick from
  27. - name: published_date
  28. cluster: fixed(1000) #under each domain we will have max 1000 posts
  29. - name: url
  30. size: uniform(30..300)
  31. - name: title #titles shouldn't go beyond 200 chars
  32. size: gaussian(10..200)
  33. - name: author
  34. size: uniform(5..20) #author names should be short
  35. - name: body
  36. size: gaussian(100..5000) #the body of the blog post can be long
  37. ### Batch Ratio Distribution Specifications ###
  38. insert:
  39. partitions: fixed(1) # Our partition key is the domain so only insert one per batch
  40. select: fixed(1)/1000 # We have 1000 posts per domain so 1/1000 will allow 1 post per batch
  41. batchtype: UNLOGGED # Unlogged batches
  42. #
  43. # A list of queries you wish to run against the schema
  44. #
  45. queries:
  46. singlepost:
  47. cql: select * from blogposts where domain = ? LIMIT 1
  48. fields: samerow
  49. regularupdate:
  50. cql: update blogposts set author = ? where domain = ? and published_date = ?
  51. fields: samerow
  52. updatewithlwt:
  53. cql: update blogposts set author = ? where domain = ? and published_date = ? IF body = ? AND url = ?
  54. fields: samerow

Graphing

Graphs can be generated for each run of stress.

example cassandra-stress graph

To create a new graph:

  1. cassandra-stress user profile=./stress-example.yaml "ops(insert=1,latest_event=1,events=1)" -graph file=graph.html title="Awesome graph"

To add a new run to an existing graph point to an existing file and add a revision name:

  1. cassandra-stress user profile=./stress-example.yaml duration=1m "ops(insert=1,latest_event=1,events=1)" -graph file=graph.html title="Awesome graph" revision="Second run"

FAQ

How do you use NetworkTopologyStrategy for the keyspace?

Use the schema option making sure to either escape the parenthesis or enclose in quotes:

  1. cassandra-stress write -schema "replication(strategy=NetworkTopologyStrategy,datacenter1=3)"

How do you use SSL?

Use the transport option:

  1. cassandra-stress "write n=100k cl=ONE no-warmup" -transport "truststore=$HOME/jks/truststore.jks truststore-password=cassandra"

Is Cassandra Stress a secured tool?

Cassandra stress is not a secured tool. Serialization and other aspects of the tool offer no security guarantees.