blob: 6bc38e1587d926cf95e66fd6dcce800504cbb82e [file] [log] [blame] [view]
# Configuration
## Load balancing
Load balancing controls how queries are distributed to nodes in a Cassandra
cluster.
Without additional configuration the C/C++ driver defaults to using Datacenter-aware
load balancing with token-aware routing. This means that driver will only send
queries to nodes in the local datacenter (for local consistency levels) and
it will use the primary key of queries to route them directly to the nodes where the
corresponding data is located.
### Round-robin Load Balancing
This load balancing policy equally distributes queries across cluster without
consideration of datacenter locality. This should only be used with
Cassandra clusters where all nodes are located in the same datacenter.
### Datacenter-aware Load Balancing
This load balancing policy equally distributes queries to nodes in the local
datacenter. Nodes in remote datacenters are only used when all local nodes are
unavailable. Additionally, remote nodes are only considered when non-local
consistency levels are used or if the driver is configured to use remote nodes
with the [`allow_remote_dcs_for_local_cl`] setting.
```c
CassCluster* cluster = cass_cluster_new();
const char* local_dc = "dc1"; /* Local datacenter name */
/*
* Use up to 2 remote datacenter nodes for remote consistency levels
* or when `allow_remote_dcs_for_local_cl` is enabled.
*/
unsigned used_hosts_per_remote_dc = 2;
/* Don't use remote datacenter nodes for local consistency levels */
cass_bool_t allow_remote_dcs_for_local_cl = cass_false;
cass_cluster_set_load_balance_dc_aware(cluster,
local_dc,
used_hosts_per_remote_dc,
allow_remote_dcs_for_local_cl);
/* ... */
cass_cluster_free(cluster);
```
### Token-aware Routing
Token-aware routing uses the primary key of queries to route requests directly to
the Cassandra nodes where the data is located. Using this policy avoids having
to route requests through an extra coordinator node in the Cassandra cluster. This
can improve query latency and reduce load on the Cassandra nodes. It can be used
in conjunction with other load balancing and routing policies.
```c
CassCluster* cluster = cass_cluster_new();
/* Enable token-aware routing (this is the default setting) */
cass_cluster_set_token_aware_routing(cluster, cass_true);
/* Disable token-aware routing */
cass_cluster_set_token_aware_routing(cluster, cass_false);
/* ... */
cass_cluster_free(cluster);
```
### Latency-aware Routing
Latency-aware routing tracks the latency of queries to avoid sending new queries
to poorly performing Cassandra nodes. It can be used in conjunction with other
load balancing and routing policies.
```c
CassCluster* cluster = cass_cluster_new();
/* Disable latency-aware routing (this is the default setting) */
cass_cluster_set_latency_aware_routing(cluster, cass_false);
/* Enable latency-aware routing */
cass_cluster_set_latency_aware_routing(cluster, cass_true);
/*
* Configure latency-aware routing settings
*/
/* Up to 2 times the best performing latency is okay */
cass_double_t exclusion_threshold = 2.0;
/* Use the default scale */
cass_uint64_t scale_ms = 100;
/* Retry a node after 10 seconds even if it was performing poorly before */
cass_uint64_t retry_period_ms = 10000;
/* Find the best performing latency every 100 milliseconds */
cass_uint64_t update_rate_ms = 100;
/* Only consider the average latency of a node after it's been queried 50 times */
cass_uint64_t min_measured = 50;
cass_cluster_set_latency_aware_routing_settings(cluster,
exclusion_threshold,
scale_ms,
retry_period_ms,
update_rate_ms,
min_measured);
/* ... */
cass_cluster_free(cluster);
```
### Filtering policies
#### Whitelist
This policy ensures that only hosts from the provided whitelist filter will
ever be used. Any host that is not contained within the whitelist will be
considered ignored and a connection will not be established. It can be used in
conjunction with other load balancing and routing policies.
NOTE: Using this policy to limit the connections of the driver to a predefined
set of hosts will defeat the auto-detection features of the driver. If
the goal is to limit connections to hosts in a local datacenter use
DC aware in conjunction with the round robin load balancing policy.
```c
CassCluster* cluster = cass_cluster_new();
/* Set the list of predefined hosts the driver is allowed to connect to */
cass_cluster_set_whitelist_filtering(cluster,
"127.0.0.1, 127.0.0.3, 127.0.0.5");
/* The whitelist can be cleared (and disabled) by using an empty string */
cass_cluster_set_whitelist_filtering(cluster, "");
/* ... */
cass_cluster_free(cluster);
```
#### Blacklist
This policy is the inverse of the whitelist policy where hosts provided in the
blacklist filter will be ignored and a connection will not be established.
```c
CassCluster* cluster = cass_cluster_new();
/* Set the list of predefined hosts the driver is NOT allowed to connect to */
cass_cluster_set_blacklist_filtering(cluster,
"127.0.0.1, 127.0.0.3, 127.0.0.5");
/* The blacklist can be cleared (and disabled) by using an empty string */
cass_cluster_set_blacklist_filtering(cluster, "");
/* ... */
cass_cluster_free(cluster);
```
#### Datacenter
Filtering can also be performed on all hosts in a datacenter or multiple
datacenters when using the whitelist/blacklist datacenter filtering polices.
```c
CassCluster* cluster = cass_cluster_new();
/* Set the list of predefined datacenters the driver is allowed to connect to */
cass_cluster_set_whitelist_dc_filtering(cluster, "dc2, dc4");
/* The datacenter whitelist can be cleared/disabled by using an empty string */
cass_cluster_set_whitelist_dc_filtering(cluster, "");
/* ... */
cass_cluster_free(cluster);
```
```c
CassCluster* cluster = cass_cluster_new();
/* Set the list of predefined datacenters the driver is NOT allowed to connect to */
cass_cluster_set_blacklist_dc_filtering(cluster, "dc2, dc4");
/* The datacenter blacklist can be cleared/disabled by using an empty string */
cass_cluster_set_blacklist_dc_filtering(cluster, "");
/* ... */
cass_cluster_free(cluster);
```
## Speculative Execution
For certain applications it is of the utmost importance to minimize latency.
Speculative execution is a way to minimize latency by preemptively executing
several instances of the same query against different nodes. The fastest
response is then returned to the client application and the other requests are
cancelled. Speculative execution is <b>disabled</b> by default.
### Query Idempotence
Speculative execution will result in executing the same query several times.
Therefore, it is important that queries are idempotent i.e. a query can be
applied multiple times without changing the result beyond the initial
application. <b>Queries that are not explicitly marked as idempotent will not be
scheduled for speculative executions.</b>
The following types of queries are <b>not</b> idempotent:
* Mutation of `counter` columns
* Prepending or appending to a `list` column
* Use of non-idempotent CQL function e.g. `now()` or `uuid()`
The driver is unable to determine if a query is idempotent therefore it is up to
an application to explicitly mark a statement as being idempotent.
```c
CassStatement* statement = cass_statement_new( "SELECT * FROM table1", 0);
/* Make the statement idempotent */
cass_statement_set_is_idempotent(statement, cass_true);
cass_statement_free(statement);
```
### Enabling speculative execution
Speculative execution is enabled by connecting a `CassSession` with a
`CassCluster` that has a speculative execution policy enabled. The driver
currently only supports a constant policy, but may support more in the future.
#### Constant speculative execution policy
The following will start up to 2 more executions after the initial execution
with the subsequent executions being created 500 milliseconds apart.
```c
CassCluster* cluster = cass_cluster_new();
cass_int64_t constant_delay_ms = 500; /* Delay before a new execution is created */
int max_speculative_executions = 2; /* Number of executions */
cass_cluster_set_constant_speculative_execution_policy(cluster,
constant_delay_ms,
max_speculative_executions);
/* ... */
cass_cluster_free(cluster);
```
### Connection Heartbeats
To prevent intermediate network devices (routers, switches, etc.) from
disconnecting pooled connections the driver sends a lightweight heartbeat
request (using an [`OPTIONS`] protocol request) periodically. By default the
driver sends a heartbeat every 30 seconds. This can be changed or disabled (0
second interval) using the following:
```c
CassCluster* cluster = cass_cluster_new();
/* Change the heartbeat interval to 1 minute */
cass_cluster_set_connection_heartbeat_interval(cluster, 60);
/* Disable heartbeat requests */
cass_cluster_set_connection_heartbeat_interval(cluster, 0);
/* ... */
cass_cluster_free(cluster);
```
Heartbeats are also used to detect unresponsive connections. An idle timeout
setting controls the amount of time a connection is allowed to be without a
successful heartbeat before being terminated and scheduled for reconnection. This
interval can be changed from the default of 60 seconds:
```c
CassCluster* cluster = cass_cluster_new();
/* Change the idle timeout to 2 minute */
cass_cluster_set_connection_idle_timeout(cluster, 120);
/* ... */
cass_cluster_free(cluster);
```
It can be disabled by setting the value to a very long timeout or by disabling
heartbeats.
### Host State Changes
The status and membership of a node can change within the life-cycle of the
cluster. A host listener callback can be used to detect these changes.
**Important**: The driver runs the host listener callback on a thread that is
different from the application. Any data accessed in the
callback must be immutable or synchronized with a mutex,
semaphore, etc.
```c
void on_host_listener(CassHostListenerEvent event, CassInet inet, void* data) {
/* Get the string representation of the inet address */
char address[CASS_INET_STRING_LENGTH];
cass_inet_string(inet, address);
/* Perform application logic for host listener event */
if (event == CASS_HOST_LISTENER_EVENT_ADD) {
printf("Host %s has been ADDED\n", address);
} else if (event == CASS_HOST_LISTENER_EVENT_REMOVE) {
printf("Host %s has been REMOVED\n", address);
} else if (event == CASS_HOST_LISTENER_EVENT_UP) {
printf("Host %s is UP\n", address);
} else if (event == CASS_HOST_LISTENER_EVENT_DOWN) {
printf("Host %s is DOWN\n", address);
}
}
int main() {
CassCluster* cluster = cass_cluster_new();
/* Register the host listener callback */
cass_cluster_set_host_listener_callback(cluster, on_host_listener, NULL);
/* ... */
cass_cluster_free(cluster);
}
```
**Note**: Expensive (e.g. slow) operations should not be performed in host
listener callbacks. Performing expensive operations in a callback
will block or slow the driver's normal operation.
### Reconnection Policy
The reconnection policy controls the interval between each attempt for a given
connection.
#### Exponential Reconnection Policy
The exponential reconnection policy is the default reconnection policy. It
starts by using a base delay in milliseconds which is then exponentially
increased (doubled) during each reconnection attempt; up to the defined maximum
delay.
**Note**: Once the connection is re-established, this policy will restart using
base delay if a reconnection occurs.
#### Constant Reconnection Policy
The constant reconnection policy is a fixed delay for each reconnection
attempt.
### Performance Tips
#### Use a single persistent session
Sessions are expensive objects to create in both time and resources because they
maintain a pool of connections to your Cassandra cluster. An application should
create a minimal number of sessions and maintain them for the lifetime of an
application.
#### Use token-aware and latency-aware policies
The token-aware load balancing can reduce the latency of requests by avoiding an
extra network hop through a coordinator node. When using the token-aware policy
requests are sent to one of the nodes which will retrieved or stored instead of
routing the request through a proxy node (coordinator node).
The latency-aware load balancing policy can also reduce the latency of requests
by routing requests to nodes that historical performing with the lowest latency.
This can prevent requests from being sent to nodes that are underperforming.
Both [latency-aware] and [token-aware] can be use together to obtain the benefits of
both.
#### Use [paging] when retrieving large result sets
Using a large page size or a very high `LIMIT` clause can cause your application
to delay for each individual request. The driver's paging mechanism can be used
to decrease the latency of individual requests.
#### Choose a lower consistency level
Ultimately, choosing a consistency level is a trade-off between consistency and
availability. Performance should not be a large deciding factor when choosing a
consistency level. However, it can affect high-percentile latency numbers
because requests with consistency levels greater than `ONE` can cause requests
to wait for one or more nodes to respond back to the coordinator node before a
request can complete. In multi-datacenter configurations, consistency levels such as
`EACH_QUORUM` can cause a request to wait for replication across a slower cross
datacenter network link. More information about setting the consistency level
can be found [here](https://docs.datastax.com/en/developer/cpp-driver/latest/topics/basics/consistency/).
### Driver Tuning
Beyond the performance tips and best practices considered in the previous
section your application might consider tuning the more fine-grain driver
settings in this section to achieve optimal performance for your application's
specific workload.
#### Increasing core connections
In some workloads, throughput can be increased by increasing the number of core
connections. By default, the driver uses a single core connection per host. It's
recommended that you try increasing the core connections to two and slowly
increase this number while doing performance testing. Two core connections is
often a good setting and increasing the core connections too high will decrease
performance because having multiple connections to a single host inhibits the
driver's ability to coalesce multiple requests into a fewer number of system
calls.
#### Coalesce delay
The coalesce delay is an optimization to reduce the number of system calls
required to process requests. This setting controls how long the driver's I/O
threads wait for requests to accumulate before flushing them on to the wire.
Larger values for coalesce delay are preferred for throughput-based workloads as
it can significantly reduce the number of system calls required to process
requests.
In general, the coalesce delay should be increased for throughput-based
workloads and can be decreased for latency-based workloads. Most importantly,
the delay should consider the responsiveness guarantees of your application.
Note: Single, sporadic requests are not generally affected by this delay and
are processed immediately.
#### New request ratio
The new request ratio controls how much time an I/O thread spends processing new
requests versus handling outstanding requests. This value is a percentage (with
a value from 1 to 100), where larger values will dedicate more time to
processing new requests and less time on outstanding requests. The goal of this
setting is to balance the time spent processing new/outstanding requests and
prevent either from fully monopolizing the I/O thread's processing time. It's
recommended that your application decrease this value if computationally
expensive or long-running future callbacks are used (via
`cass_future_set_callback()`), otherwise this can be left unchanged.
[`allow_remote_dcs_for_local_cl`]: https://docs.datastax.com/en/developer/cpp-driver/latest/api/struct.CassCluster/#1a46b9816129aaa5ab61a1363489dccfd0
[`OPTIONS`]: https://github.com/apache/cassandra/blob/cassandra-3.0/doc/native_protocol_v3.spec
[token-aware]: https://docs.datastax.com/en/developer/cpp-driver/latest/topics/configuration/#latency-aware-routing
[latency-aware]: https://docs.datastax.com/en/developer/cpp-driver/latest/topics/configuration/#token-aware-routing
[paging]: https://docs.datastax.com/en/developer/cpp-driver/latest/topics/basics/handling_results/#paging