blob: 80ae10ab3c8014fa95a6309b3011f3d48134162e [file]
= Overview
This document describes the configuration options available for the bulk reader and bulk writer components.
== Cassandra Sidecar Configuration
Cassandra Analytics library uses https://github.com/apache/cassandra-sidecar[Apache Cassandra Sidecar] to interact
with target cluster. Bulk reader and writer components share common Sidecar configuration properties.
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_sidecar_contact_points_
|yes
|
|Comma-separated list of Cassandra Sidecar contact points. IP addresses and FQDN domain names are supported,
with an optional port number (e.g. `localhost1,localhost2`, `127.0.0.1,127.0.0.2`, `127.0.0.1:9043,127.0.0.2:9043`)
|_sidecar_port_
|no
|`9043`
|Default port on which Cassandra Sidecar listens
|_keystore_path_
|no
|
|Path to keystore used to establish TLS connection with Cassandra Sidecar
|_keystore_base64_encoded_
|no
|
|Base64-encoded keystore used to establish TLS connection with Cassandra Sidecar
|_keystore_password_
|no
|
|Keystore password
|_keystore_type_
|no
|`PKCS12`
|Keystore type, `PKCS12` or `JKS`
|_truststore_path_
|no
|
|Path to truststore used to establish TLS connection with Cassandra Sidecar
|_truststore_base64_encoded_
|no
|
|Base64-encoded truststore used to establish TLS connection with Cassandra Sidecar
|_truststore_password_
|no
|
|Truststore password
|_truststore_type_
|no
|`PKCS12`
|Truststore type, `PKCS12` or `JKS`
|_cassandra_role_
|no
|
|Specific role that Sidecar shall use to authorize the request. For further details consult Sidecar documentation
for `cassandra-auth-role` HTTP header
|===
== Bulk Reader
This section describes configuration properties specific to the bulk reader.
=== Cassandra Sidecar Configuration
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_defaultMillisToSleep_
|no
|`500`
|Number of milliseconds to wait between retry attempts
|_maxMillisToSleep_
|no
|`60000`
|Maximum number of milliseconds to sleep between retries
|_maxPoolSize_
|no
|`64`
|Size of the Vert.x worker thread pool
|_timeoutSeconds_
|no
|`600`
|Request timeout, expressed in seconds
|===
=== Spark Reader Configuration
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_keyspace_
|yes
|
|Keyspace of a table to read
|_table_
|yes
|
|Table to be read
|_dc_
|no
|
|Data center used when `LOCAL_*` consistency level is specified
|_consistencyLevel_
|no
|`LOCAL_QUORUM`
|Read consistency level
|_snapshotName_
|no
|`sbr_\{uuid\}`
|Name of a snapshot to use (for data consistency). By default, unique name is always generated
|_createSnapshot_
|no
|`true`
|Indicates whether a new snapshot should be created prior to performing the read operation
|_clearSnapshotStrategy_
|no
|`OnCompletionOrTTL 2d`
a|Strategy of removing snapshot once read operation completes. This option is enabled always when _createSnapshot_
flag is set to `true`. Value of _clearSnapshotStrategy_ must follow the format: `[strategy] [snapshotTTL]`.
Supported strategies: `NoOp`, `OnCompletion`, `OnCompletionOrTTL`, `TTL`.
TTL value has to match pattern: `\d+(d\|h\|m\|s)`
Example configurations: `OnCompletionOrTTL 2d`, `TTL 2d`, `NoOp`, `OnCompletion`.
|_bigNumberConfig_
|no
|
a|Defines the output scale and precision of `decimal` and `varint` columns. Parameter value is a JSON string
with the following structure:
[source,json]
----
{
"column_name_1" : {"bigDecimalPrecision": 10, "bigDecimalScale": 5},
"column_name_2" : {"bigIntegerPrecision": 10, "bigIntegerScale": 5}
}
----
|_lastModifiedColumnName_
|no
|
|Name of the field to be appended to Spark RDD that represents last modification timestamp of each row
|===
=== Other Properties
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_defaultParallelism_
|recommended
|`1`
|Value of Spark property `spark.default.parallelism`
|_numCores_
|recommended
|`1`
|Total number of cores used by all Spark executors
|_maxBufferSizeBytes_
|no
|`6291456`
a|Maximum amount of bytes per sstable file that may be downloaded and buffered in-memory. This parameter is
global default and can be overridden per sstable file type. Effective defaults are:
- `Data.db`: 6291456
- `Index.db`: 131072
- `Summary.db`: 262144
- `Statistics.db`: 131072
- `CompressionInfo.db`: 131072
- `.log` (commit log): 65536
- `Partitions.db`: 131072
- `Rows.db`: 131072
To override size for `Data.db`, use property `_maxBufferSizeBytes_Data.db_`.
|_chunkBufferSizeBytes_
|no
|`4194304`
a|Default chunk size (in bytes) that will be requested when fetching next portion of sstable file. This parameter is
global default and can be overridden per sstable file type. Effective defaults are:
- `Data.db`: 4194304
- `Index.db`: 32768
- `Summary.db`: 131072
- `Statistics.db`: 65536
- `CompressionInfo.db`: 65536
- `.log` (commit log): 65536
- `Partitions.db`: 4096
- `Rows.db`: 4096
To override size for `Data.db`, use property `_chunkBufferSizeBytes_Data.db_`.
|_sizing_
|no
|`default`
a|Determines how the number of CPU cores is selected during the read operation. Supported options:
* `default`: static number of cores defined by _numCores_ parameter
* `dynamic`: calculates number of cores dynamically based on table size. Improves cost efficiency for processing small
tables (few GBs). Consult JavaDoc of `org.apache.cassandra.spark.data.DynamicSizing` for implementation details.
Relevant configuration properties:
** _maxPartitionSize_: maximum Spark partition size (in GiB)
|_quote_identifiers_
|no
|`false`
|When `true`, keyspace, table and column names are quoted
|_sstable_start_timestamp_micros_ and _sstable_end_timestamp_micros_
|no
|all sstables are selected
|Define an inclusive time-range filter for sstable selection. Both timestamps are expressed in microseconds
|===
== Bulk Writer
This section describes configuration properties specific to the bulk writer.
=== Spark Writer Configuration
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_keyspace_
|yes
|
|Keyspace of a table to write
|_table_
|yes
|
|Table to which rows are written or from which rows are removed depending on _write_mode_
|_local_dc_
|no
|
|Data center used when `LOCAL_*` consistency level is specified
|_bulk_writer_cl_
|no
|`EACH_QUORUM`
|Write consistency level
|_write_mode_
|no
|`INSERT`
a|Determines write mode:
* `INSERT`: Writes new rows to the table. Generated sstables contain the data to be inserted
* `DELETE_PARTITION`: Removes entire partitions from the table. Only partition key columns are required in the input data
|_ttl_
|no
|
|Time-to-live value (in seconds) applied to created records. When specified, all inserted rows will expire after
given duration. Only applicable in `INSERT` mode. Example: `86400` for 1 day TTL
|_timestamp_
|no
|`NOW`
a|Mutation timestamp assigned to generated rows, expressed in microseconds. Options:
* `NOW`: Uses current system time at write execution
* Custom value: Specify exact timestamp in microseconds (e.g., `1609459200000000` for 2021-01-01 00:00:00 UTC)
Custom timestamps affect conflict resolution in Cassandra (last-write-wins)
|_skip_extended_verify_
|no
|`false`
|Every imported sstable is verified for corruption during import process. This property allows to enable extended
checking of all values in the new sstables
|_quote_identifiers_
|no
|`false`
|Option that specifies whether the identifiers (i.e. keyspace, table name, column names) should be quoted to
support mixed case and reserved keyword names for these fields
|_data_transport_
|no
|`DIRECT`
a|Specifies data transport mode. Supported implementations:
* `DIRECT`: Uploads generated sstables directly to Cassandra cluster via Sidecar
* `S3_COMPAT`: Uploads generated sstables to single (or multiple) remote Cassandra clusters with intermediate S3 storage
(see <<Cloud-Storage Transport Properties>>)
|===
=== Cloud-Storage Transport Properties
Cassandra Analytics can import generated sstables to target Cassandra cluster with intermediate S3 storage. This
feature is explicitly useful when importing the same data set to multiple clusters running in remote locations.
Write to multiple clusters involves data replication by S3 and 2-phase coordination protocol:
1. SSTables are staged on all clusters and data consistency checked.
2. Proceed with the import and validate consistency in each cluster.
In case of import to a single cluster, there is no need for coordination and data gets persisted in Cassandra,
as soon as it can be downloaded from S3 storage.
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_coordinated_write_config_
|no
|
a|
Configuration of coordinated write operation in JSON format. Each key is a logical cluster ID that must match
the keys in the read bucket map returned by `StorageTransportExtension.getStorageConfiguration()`. This property
is required only when importing data to multiple targets via the 2-phase coordination protocol.
Two topologies are supported:
*Multiple independent Cassandra clusters* each entry points to a separate Cassandra deployment with its own
Sidecar instances. Set `writeToLocalDcOnly: false` to validate consistency across the whole cluster.
[source,json]
----
{
"cluster-us": {
"sidecarContactPoints": ["us-sidecar-1:9043", "us-sidecar-2:9043"],
"localDc": "us-east",
"writeToLocalDcOnly": false
},
"cluster-eu": {
"sidecarContactPoints": ["eu-sidecar-1:9043", "eu-sidecar-2:9043"],
"localDc": "eu-west",
"writeToLocalDcOnly": false
}
}
----
*Multiple DCs within a single Cassandra cluster* use one entry per DC, pointing to the Sidecar instances
in that DC. Set `localDc` to the DC name and `writeToLocalDcOnly: true` to scope both the write and the
consistency check to that DC. S3 Cross-Region Replication provides a separate read bucket for each DC
(see <<S3 Bucket Topology>>).
[source,json]
----
{
"dc-us-east": {
"sidecarContactPoints": ["us-sidecar-1:9043", "us-sidecar-2:9043"],
"localDc": "us-east",
"writeToLocalDcOnly": true
},
"dc-eu-west": {
"sidecarContactPoints": ["eu-sidecar-1:9043", "eu-sidecar-2:9043"],
"localDc": "eu-west",
"writeToLocalDcOnly": true
}
}
----
|_data_transport_extension_class_
|yes
|
|Fully qualified class name that implements `StorageTransportExtension` interface. Consult JavaDoc for
implementation details
|_storage_credential_type_
|no
|`STATIC`
a|Controls how Spark executors and Sidecar authenticate to S3. Accepted values (case-insensitive):
* `STATIC`: STS access key / secret / session token credentials are passed to Sidecar. The `StorageTransportExtension`
must supply a `StorageCredentialPair` built with `StorageCredentials`.
* `IAM`: No credentials are passed. Both the Spark executors and Sidecar use the AWS SDK default provider chain
(EC2 instance profile, EKS IRSA, ECS task role). The `StorageTransportExtension` must supply a
`StorageCredentialPair` built with `StorageCredentialPair.iamPair(writeRegion, readRegion)`.
|_storage_client_endpoint_override_
|no
|
|Property overrides S3 endpoint
|_storage_client_https_proxy_
|no
|
|HTTPS proxy for S3 client
|_max_size_per_sstable_bundle_in_bytes_s3_transport_
|no
|`5368709120`
|Limits the maximum size of uploaded S3 object
|_storage_client_max_chunk_size_in_bytes_
|no
|`104857600`
|Specifies maximum chunk size for multipart S3 upload
|_storage_client_concurrency_
|no
|`CPU cores * 2`
|Controls the max parallelism of the thread pool used by S3 client
|_storage_client_thread_keep_alive_seconds_
|no
|60
|Idle storage thread timeout in seconds
|_storage_client_nio_http_client_connection_acquisition_timeout_seconds_
|no
|`300`
|Option to tune the connection acquisition timeout for NIO HTTP component employed in S3 client
|_storage_client_nio_http_client_max_concurrency_
|no
|`50`
|Specifies concurrency of the NIO HTTP component employed in S3 client
|===
=== S3 Bucket Topology
The library separates write and read access into distinct `StorageAccessConfiguration` objects, each with its own
bucket, region, and credentials. This maps to the following topology:
* **Write bucket**: a single S3 bucket in one region where all Spark executors upload SSTable bundles.
* **Read bucket per cluster**: each target Cassandra cluster reads from a bucket in its own region. In a
cross-region setup this is a replica of the write bucket, configured externally via S3 Cross-Region Replication.
The library does not manage replication it only tells each Sidecar instance which bucket and region to pull from.
For a single-cluster write, write and read buckets may be the same bucket in the same region, or different buckets
when Sidecar should read from a regional replica.
=== Implementing StorageTransportExtension
The `StorageTransportExtension` interface is the integration point where bucket names, regions, and credentials
are supplied. The library calls `getStorageConfiguration()` once on startup, then registers a
`CredentialChangeListener` via `setCredentialChangeListener()` so the extension can push refreshed credentials
during long-running jobs without restarting.
==== Static credentials (STS tokens)
Use `StorageCredentials` when a credential vending service issues short-lived STS tokens. Store the listener
and call `onCredentialsChanged()` on each refresh.
[source,java]
----
public class MyStorageTransportExtension implements StorageTransportExtension {
private String jobId;
private CredentialChangeListener credentialChangeListener;
@Override
public void initialize(String jobId, SparkConf conf, boolean isOnDriver) {
this.jobId = jobId;
}
@Override
public StorageTransportConfiguration getStorageConfiguration() {
StorageCredentialPair credentials = new StorageCredentialPair(
"us-east-1",
new StorageCredentials("writeAccessKeyId", "writeSecretKey", "writeSessionToken"),
"eu-west-1",
new StorageCredentials("readAccessKeyId", "readSecretKey", "readSessionToken"));
return new StorageTransportConfiguration(
"my-write-bucket", // Spark executors upload here
"us-east-1",
"my-read-bucket-eu", // Sidecar in eu-west-1 reads from this S3 replica
"eu-west-1",
"job-prefix",
credentials,
Map.of());
}
@Override
public void setCredentialChangeListener(CredentialChangeListener listener) {
this.credentialChangeListener = listener;
startTokenRefreshScheduler();
}
private void onTokenRefresh(StorageCredentialPair newCredentials) {
credentialChangeListener.onCredentialsChanged(jobId, newCredentials);
}
// ... remaining lifecycle methods
}
----
Set `storage_credential_type=STATIC` (or omit it; STATIC is the default).
==== IAM credentials (instance profile / IRSA / ECS task role)
Use IAM mode when Spark executors and Sidecar instances have AWS identity attached at the infrastructure level.
Only regions are required no credentials are passed in the configuration.
[source,java]
----
public class MyIamStorageTransportExtension implements StorageTransportExtension {
@Override
public void initialize(String jobId, SparkConf conf, boolean isOnDriver) { }
@Override
public StorageTransportConfiguration getStorageConfiguration() {
return new StorageTransportConfiguration(
"my-write-bucket",
"us-east-1",
"my-read-bucket-eu",
"eu-west-1",
"job-prefix",
StorageCredentialPair.iamPair("us-east-1", "eu-west-1"),
Map.of());
}
@Override
public void setCredentialChangeListener(CredentialChangeListener listener) {
// no-op: credentials are resolved by the AWS SDK default provider chain
}
// ... remaining lifecycle methods
}
----
Set `storage_credential_type=IAM` in your write options.
==== Multi-cluster (coordinated write)
For coordinated writes to multiple clusters, use the constructor that accepts a read-configuration map keyed by
`clusterId`. Each entry must have its own bucket and region. The `clusterId` keys must match those in
`coordinated_write_config`.
[source,java]
----
@Override
public StorageTransportConfiguration getStorageConfiguration() {
return new StorageTransportConfiguration(
"job-prefix",
Map.of(),
new StorageAccessConfiguration("us-east-1", "my-write-bucket", IamStorageAuth.INSTANCE),
Map.of(
"cluster-eu", new StorageAccessConfiguration("eu-west-1", "my-read-bucket-eu", IamStorageAuth.INSTANCE),
"cluster-ap", new StorageAccessConfiguration("ap-southeast-1", "my-read-bucket-ap", IamStorageAuth.INSTANCE)
));
}
----
For static credentials, replace `IamStorageAuth.INSTANCE` with a `StorageCredentials` instance and call
`credentialChangeListener.onCredentialsChanged(jobId, clusterId, newCredentials)` per cluster on refresh.
=== Other Properties
[cols="2,1,1,3"]
|===
|Property name|Required|Default|Description
|_number_splits_
|no
|`-1`
|User defined number of token range splits. By default, library will dynamically calculate number of splits based
on Spark properties `spark.default.parallelism`, `spark.executor.cores` and `spark.executor.instances`
|_sstable_data_size_in_mib_
|no
|`160`
|Maximum sstable size (in MiB)
|_digest_
|no
|`XXHash32`
|Digest algorithm used to compute when uploading sstables for checksum validation. Supported values: `XXHash32`, `MD5`
|_job_timeout_seconds_
|no
|`-1`
a|Specifies a timeout in seconds for bulk write jobs. Disabled by default. When configured, job exceeding
the timeout is:
* successful when the desired consistency level is achieved
* failed otherwise
|_job_id_
|no
|
|User-defined identifier for the bulk write job
|===