0

A user reports that the range query throughput is far higher than expected when setting spark.cassandra.input.readsPerSec in the spark-cassandra-connector.

Job dependencies. The Java driver version is set to 4.13.0.

    <dependency>
        <groupId>com.datastax.spark</groupId>
        <artifactId>spark-cassandra-connector_2.12</artifactId>
        <version>3.2.0</version>
        <exclusions>
            <exclusion>
                <groupId> com.datastax.oss</groupId>
                <artifactId>java-driver-core-shaded</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

...

    <dependency>
        <groupId>com.datastax.oss</groupId>
        <artifactId>java-driver-core</artifactId>
        <version>4.13.0</version>
    </dependency>

There are two steps in the job (both an FTS):

Dataset<Row> dataset = sparkSession.sqlContext().read()
.format("org.apache.spark.sql.cassandra")
.option("table", "inbox_user_msg_dummy")
.option("keyspace", "ssmp_inbox2").load();

-and-

Dataset<Row> olderDataset = sparkSession.sql("SELECT * FROM inbox_user_msg_dummy where app_uuid = 'cb663e07-7bcc-4039-ae97-8fb8e8a9ff77' AND " +
"create_hour < '" + minus180DaysInstant + "'");

Job configuration:

SparkConf sparkConf = new SparkConf()
        .setMaster("local[*]") //uncomment while running in local
        .setAppName("inbox-gateway-spark-job")
       .set("spark.scheduler.mode", "FAIR")
        .set("spark.cassandra.connection.port", "9042")
        .set("keyspace", "ssmp_inbox2")
        .set("spark.cassandra.connection.host", "cass-556799284-1-1276056270.stg.ssmp-inbox2-stg.ms-df-cassandra.stg-az-southcentralus-6.prod.us.walmart.net,
        cass-556799284-2-1276056276.stg.ssmp-inbox2-stg.ms-df-cassandra.stg-az-southcentralus-6.prod.us.walmart.net,
        cass-556799284-3-1276056282.stg.ssmp-inbox2-stg.ms-df-cassandra.stg-az-southcentralus-6.prod.us.walmart.net")
        .set("spark.cassandra.auth.username", "ssmp-inbox-app-v2")
        .set("spark.cassandra.auth.password", "*")
        .set("spark.cassandra.input.consistency.level", "LOCAL_ONE")
        .set("spark.cassandra.concurrent.reads", "1")
        .set("spark.cassandra.input.readsPerSec", "10")
        .set("spark.cassandra.input.fetch.sizeInRows", "10")
        .set("spark.cassandra.input.split.sizeInMB", "10")
        .set("spark.cores.max", "20")
        .set("spark.executor.memory", "20G")
        .set("spark.yarn.executor.memoryOverhead", "12000")
        .set("spark.cassandra.read.timeoutMS", "200000")
        .set("spark.task.maxFailures", "10")
        .set("spark.cassandra.connection.localDC", "southcentral");

Note that Spark is limiting the actual cores to 16 because workers have 8 cores. There is 1 executor.

When the job runs, it's observed that there are ~22k range queries/s for the first FTS nearly saturating CPU on the cluster, and for the second FTS, there are ~725 range queries/s on the table.

The expectation is that with 16 total Spark cores, the range query throughput would be limited to 160/s (spark.cassandra.input.readsPerSec * spark cores).

Is this reasoning correct? What is the recommendation for controlling read throughput from the spark-cassandra-connector?

I know we've had other users successfully configure this throttle before, but we've never looked closely at what the resulting throughput is. This one does seem to be a big discrepancy though because the two steps are essentially running the same operation - a full table scan. The queries the connector ultimately runs are the same.

The schema:

CREATE TABLE ssmp_inbox2.inbox_user_msg_dummy (    
  user_id text,    
  create_hour timestamp,    
  app_uuid text,    
  message_id text,    
  app_name text,    
  create_ts bigint,    
  is_actiontaken boolean,    
  is_compensable boolean,    
  is_deleted boolean,    
  is_read boolean,    
  message_payload text,    
  mini_app_name text,    
  notification text,    
  PRIMARY KEY ((user_id, create_hour, app_uuid), message_id)    
) WITH CLUSTERING ORDER BY (message_id DESC)    
  AND additional_write_policy = '99p'    
  AND bloom_filter_fp_chance = 0.01    
  AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}    
  AND cdc = false    
  AND comment = ''    
  AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}    
  AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}    
  AND crc_check_chance = 1.0    
  AND default_time_to_live = 0    
  AND extensions = {}    
  AND gc_grace_seconds = 864000    
  AND max_index_interval = 2048    
  AND memtable_flush_period_in_ms = 0    
  AND min_index_interval = 128
  AND read_repair = 'BLOCKING'
  AND speculative_retry = '99p';

The query:

SELECT * FROM ssmp_inbox2.inbox_user_msg_dummy WHERE token(user_id, create_hour, app_uuid) >= token(G9e7Y4Y, 2023-08-10T04:17:27.234Z, cb663e07-7bcc-4039-ae97-8fb8e8a9ff77) AND token(user_id, create_hour, app_uuid) <= 9121832956220923771 LIMIT 10

FWIW, avg partition size is 649 bytes, max is 2.7kb.

1 Answer 1

2

The best way to start is to look here: Spark Cassandra Connector | Read Tuning Parameters (Github).

The table is isn't very clear, but spark.cassandra.concurrent.reads and spark.cassandra.input.readsPerSec are used for joining.

To throttle the full scan you need to use spark.cassandra.input.throughputMBPerSec.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.