Configure ScyllaDB with specialized optimizations for time-series workloads including partitioning strategies, compaction settings, and memory tuning. Set up monitoring with Prometheus and Grafana for production performance insights.
Prerequisites
- ScyllaDB cluster installed
- 16GB+ RAM
- SSD storage
- Root access
What this solves
Time-series data creates unique performance challenges with high write volumes, sequential reads, and specific retention patterns. ScyllaDB's default configuration works well for general workloads but needs optimization for time-series scenarios where you're ingesting thousands of data points per second and running analytical queries across time ranges.
Prerequisites
You need a ScyllaDB cluster already running. If you don't have one set up, start with our ScyllaDB cluster installation guide. You'll also need at least 16GB RAM and SSD storage for optimal time-series performance.
Step-by-step configuration
Configure system-level optimizations
Time-series workloads benefit from specific kernel and system settings that prioritize write throughput and reduce latency spikes.
sudo sysctl -w vm.swappiness=1
sudo sysctl -w vm.dirty_background_ratio=5
sudo sysctl -w vm.dirty_ratio=10
sudo sysctl -w net.core.rmem_max=134217728
sudo sysctl -w net.core.wmem_max=134217728
Make these changes permanent:
vm.swappiness = 1
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
Optimize ScyllaDB memory settings
Time-series workloads need more memory allocated to the write path and less to caching since data access patterns are typically sequential.
# Increase memory for write buffers (75% of available)
memtable_heap_space_in_mb: 6144
memtable_offheap_space_in_mb: 6144
Reduce cache sizes for time-series patterns
row_cache_size_in_mb: 512
key_cache_size_in_mb: 256
Optimize for high write throughput
concurrent_writes: 128
concurrent_counter_writes: 128
memtable_flush_writers: 4
Configure compaction for time-series
Time-series data benefits from time-window compaction strategy that groups data by time ranges and enables efficient TTL-based deletion.
# Enable time-window compaction globally
compaction_throughput_mb_per_sec: 256
compaction_large_partition_warning_threshold_mb: 1000
Increase concurrent compactions for time-series
concurrent_compactors: 8
Tune I/O settings for time-series workloads
Configure I/O schedulers and disk settings optimized for the sequential write patterns common in time-series data.
# Set I/O scheduler to deadline for better time-series performance
echo deadline | sudo tee /sys/block/sda/queue/scheduler
Increase read-ahead for sequential patterns
echo 4096 | sudo tee /sys/block/sda/queue/read_ahead_kb
Make I/O settings persistent:
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="deadline"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/read_ahead_kb}="4096"
Create optimized keyspace and table schema
Design your schema with time-series specific partitioning and compaction strategies for optimal performance.
cqlsh -e "CREATE KEYSPACE IF NOT EXISTS timeseries_data
WITH replication = {
'class': 'NetworkTopologyStrategy',
'datacenter1': 3
} AND durable_writes = true;"
Create a time-series optimized table:
cqlsh -e "CREATE TABLE IF NOT EXISTS timeseries_data.metrics (
metric_name text,
time_bucket timestamp,
timestamp timestamp,
value double,
tags map,
PRIMARY KEY ((metric_name, time_bucket), timestamp)
) WITH CLUSTERING ORDER BY (timestamp ASC)
AND compaction = {
'class': 'TimeWindowCompactionStrategy',
'compaction_window_unit': 'DAYS',
'compaction_window_size': 1
}
AND gc_grace_seconds = 86400
AND default_time_to_live = 2592000;"
Configure batch and consistency settings
Optimize batch sizes and consistency levels for time-series ingestion patterns.
# Increase batch size limits for time-series ingestion
batch_size_warn_threshold_in_kb: 64
batch_size_fail_threshold_in_kb: 640
Optimize for write performance
write_request_timeout_in_ms: 10000
range_request_timeout_in_ms: 20000
Enable and configure monitoring
Set up Prometheus monitoring to track time-series specific metrics and performance indicators.
# Enable Prometheus monitoring
prometheus_port: 9180
prometheus_address: 0.0.0.0
Install and configure Prometheus:
wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz
tar xzf prometheus-2.45.0.linux-amd64.tar.gz
sudo mv prometheus-2.45.0.linux-amd64/prometheus /usr/local/bin/
sudo mv prometheus-2.45.0.linux-amd64/promtool /usr/local/bin/
Configure Prometheus for ScyllaDB monitoring
Create a Prometheus configuration that scrapes ScyllaDB metrics and focuses on time-series performance indicators.
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'scylladb'
static_configs:
- targets: ['localhost:9180']
scrape_interval: 10s
metrics_path: /metrics
params:
format: ['prometheus']
- job_name: 'scylladb-manager'
static_configs:
- targets: ['localhost:5090']
scrape_interval: 30s
Create Prometheus user and directories:
sudo useradd --no-create-home --shell /bin/false prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
Install and configure Grafana
Set up Grafana with time-series optimized dashboards for ScyllaDB monitoring.
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafana
Create systemd services and start monitoring
Configure systemd services for Prometheus and Grafana with automatic startup.
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle
[Install]
WantedBy=multi-user.target
Start the monitoring services:
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl enable --now grafana-server
sudo systemctl restart scylla-server
Configure time-series retention and TTL
Set up automated data retention policies to manage storage growth in time-series workloads.
cqlsh -e "ALTER TABLE timeseries_data.metrics WITH default_time_to_live = 2592000;"
Create a cleanup script for old time buckets:
#!/bin/bash
Remove data older than 30 days
OLD_DATE=$(date -d '30 days ago' '+%Y-%m-%d %H:%M:%S')
cqlsh -e "DELETE FROM timeseries_data.metrics WHERE time_bucket < '$OLD_DATE';"
echo "Cleanup completed for data older than $OLD_DATE"
Make the script executable and add to cron:
sudo chmod +x /usr/local/bin/cleanup-timeseries.sh
echo "0 2 * /usr/local/bin/cleanup-timeseries.sh" | sudo crontab -
Verify your setup
Test the optimized configuration and monitor performance metrics.
# Check ScyllaDB status
sudo systemctl status scylla-server
Verify configuration
nodetool status
nodetool compactionstats
Test write performance
cqlsh -e "INSERT INTO timeseries_data.metrics (metric_name, time_bucket, timestamp, value) VALUES ('cpu.usage', '2024-01-01', now(), 75.5);"
Check Prometheus metrics
curl http://localhost:9180/metrics | grep scylla_transport
Verify Grafana is running
curl http://localhost:3000/api/health
Performance benchmarking
Use these commands to benchmark your time-series optimizations and compare performance.
# Install cassandra-stress for benchmarking
sudo apt install -y cassandra-tools
Run time-series write benchmark
cassandra-stress write n=100000 -rate threads=50 -node localhost
Test read performance with time range queries
cassandra-stress read n=10000 -rate threads=10 -node localhost
Monitoring key time-series metrics
Access Grafana at http://your-server:3000 (admin/admin) and monitor these critical metrics for time-series workloads:
| Metric | What it shows | Optimal range |
|---|---|---|
| scylla_transport_requests_served | Write throughput | >1000 ops/sec |
| scylla_storage_proxy_coordinator_write_latency | Write latency | <5ms p95 |
| scylla_memtables_pending_flushes | Memtable pressure | <10 |
| scylla_compaction_manager_pending_tasks | Compaction backlog | <100 |
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| High write latency spikes | Memtable flushing blocking writes | Increase memtable_flush_writers to 8 |
| Compaction falling behind | Too few concurrent compactors | Set concurrent_compactors: 16 |
| Memory pressure warnings | Memtable sizes too large | Reduce memtable_heap_space_in_mb by 25% |
| Prometheus scraping fails | Wrong port or binding address | Check prometheus_address: 0.0.0.0 |
| Time-based queries slow | Wrong clustering key order | Ensure CLUSTERING ORDER BY (timestamp ASC) |
Next steps
- Configure ScyllaDB SSL encryption and authentication
- Implement ScyllaDB disaster recovery with cross-region replication
- Configure ScyllaDB backup and restore with automation
- Set up ScyllaDB multi-datacenter replication for high availability
- Optimize ScyllaDB query performance with materialized views and secondary indexes
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# ScyllaDB Time-Series Performance Optimization Script
# Configures ScyllaDB for optimal time-series workloads
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_status() { echo -e "${GREEN}[INFO]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -m, --memory-gb MEMORY Total memory in GB (default: auto-detect)"
echo " -d, --datacenter NAME Datacenter name (default: datacenter1)"
echo " -r, --replication NUM Replication factor (default: 3)"
echo " -h, --help Show this help"
exit 1
}
cleanup() {
if [ $? -ne 0 ]; then
print_error "Script failed. Check logs and manual configuration may be required."
fi
}
trap cleanup ERR
# Parse arguments
MEMORY_GB=""
DATACENTER="datacenter1"
REPLICATION=3
while [[ $# -gt 0 ]]; do
case $1 in
-m|--memory-gb) MEMORY_GB="$2"; shift 2 ;;
-d|--datacenter) DATACENTER="$2"; shift 2 ;;
-r|--replication) REPLICATION="$2"; shift 2 ;;
-h|--help) usage ;;
*) print_error "Unknown option: $1"; usage ;;
esac
done
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root"
exit 1
fi
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
SCYLLA_CONFIG="/etc/scylla/scylla.yaml"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
SCYLLA_CONFIG="/etc/scylla/scylla.yaml"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
SCYLLA_CONFIG="/etc/scylla/scylla.yaml"
;;
*)
print_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
print_error "Cannot detect distribution"
exit 1
fi
# Auto-detect memory if not provided
if [ -z "$MEMORY_GB" ]; then
MEMORY_MB=$(free -m | awk 'NR==2{print $2}')
MEMORY_GB=$((MEMORY_MB / 1024))
print_status "Auto-detected ${MEMORY_GB}GB of system memory"
fi
# Calculate memory settings
MEMTABLE_HEAP=$((MEMORY_GB * 1024 * 3 / 4 / 2))
MEMTABLE_OFFHEAP=$((MEMORY_GB * 1024 * 3 / 4 / 2))
print_status "[1/8] Checking ScyllaDB installation..."
if ! systemctl is-enabled scylla-server >/dev/null 2>&1; then
print_error "ScyllaDB is not installed or not enabled. Please install ScyllaDB first."
exit 1
fi
print_status "[2/8] Applying system-level optimizations..."
# Apply kernel parameters
sysctl -w vm.swappiness=1
sysctl -w vm.dirty_background_ratio=5
sysctl -w vm.dirty_ratio=10
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728
# Make persistent
cat > /etc/sysctl.d/99-scylla-timeseries.conf << 'EOF'
vm.swappiness = 1
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
EOF
chmod 644 /etc/sysctl.d/99-scylla-timeseries.conf
print_status "[3/8] Configuring I/O optimizations..."
# Set I/O scheduler for all block devices
for dev in /sys/block/sd*; do
if [ -d "$dev" ]; then
device=$(basename "$dev")
echo deadline > "/sys/block/$device/queue/scheduler" 2>/dev/null || true
echo 4096 > "/sys/block/$device/queue/read_ahead_kb" 2>/dev/null || true
fi
done
# Make I/O settings persistent
cat > /etc/udev/rules.d/60-scylla-timeseries.rules << 'EOF'
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="deadline"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/read_ahead_kb}="4096"
EOF
chmod 644 /etc/udev/rules.d/60-scylla-timeseries.rules
print_status "[4/8] Backing up ScyllaDB configuration..."
cp "$SCYLLA_CONFIG" "${SCYLLA_CONFIG}.backup.$(date +%Y%m%d_%H%M%S)"
print_status "[5/8] Optimizing ScyllaDB memory and performance settings..."
# Update ScyllaDB configuration
python3 << EOF
import yaml
config_file = "$SCYLLA_CONFIG"
try:
with open(config_file, 'r') as f:
config = yaml.safe_load(f) or {}
except:
config = {}
# Memory settings
config['memtable_heap_space_in_mb'] = $MEMTABLE_HEAP
config['memtable_offheap_space_in_mb'] = $MEMTABLE_OFFHEAP
config['row_cache_size_in_mb'] = 512
config['key_cache_size_in_mb'] = 256
# Write performance
config['concurrent_writes'] = 128
config['concurrent_counter_writes'] = 128
config['memtable_flush_writers'] = 4
# Compaction settings
config['compaction_throughput_mb_per_sec'] = 256
config['compaction_large_partition_warning_threshold_mb'] = 1000
config['concurrent_compactors'] = 8
# Batch and timeout settings
config['batch_size_warn_threshold_in_kb'] = 64
config['batch_size_fail_threshold_in_kb'] = 640
config['write_request_timeout_in_ms'] = 10000
config['range_request_timeout_in_ms'] = 20000
# Monitoring
config['prometheus_port'] = 9180
config['prometheus_address'] = '0.0.0.0'
with open(config_file, 'w') as f:
yaml.dump(config, f, default_flow_style=False)
EOF
chown scylla:scylla "$SCYLLA_CONFIG"
chmod 644 "$SCYLLA_CONFIG"
print_status "[6/8] Installing required packages..."
case "$PKG_MGR" in
apt)
apt update
$PKG_INSTALL python3-pip
;;
dnf|yum)
$PKG_INSTALL python3-pip
;;
esac
print_status "[7/8] Restarting ScyllaDB service..."
systemctl restart scylla-server
sleep 10
# Wait for ScyllaDB to be ready
print_status "Waiting for ScyllaDB to be ready..."
for i in {1..30}; do
if cqlsh -e "DESCRIBE KEYSPACES" >/dev/null 2>&1; then
break
fi
if [ $i -eq 30 ]; then
print_error "ScyllaDB failed to start properly"
exit 1
fi
sleep 2
done
print_status "[8/8] Creating optimized keyspace and table schema..."
cqlsh -e "CREATE KEYSPACE IF NOT EXISTS timeseries_data
WITH replication = {
'class': 'NetworkTopologyStrategy',
'$DATACENTER': $REPLICATION
} AND durable_writes = true;"
cqlsh -e "CREATE TABLE IF NOT EXISTS timeseries_data.metrics (
metric_name text,
time_bucket timestamp,
timestamp timestamp,
value double,
tags map<text,text>,
PRIMARY KEY ((metric_name, time_bucket), timestamp)
) WITH CLUSTERING ORDER BY (timestamp ASC)
AND compaction = {
'class': 'TimeWindowCompactionStrategy',
'compaction_window_unit': 'DAYS',
'compaction_window_size': 1
}
AND gc_grace_seconds = 86400
AND default_time_to_live = 2592000;"
print_status "Verifying configuration..."
if systemctl is-active scylla-server >/dev/null 2>&1; then
print_status "✓ ScyllaDB service is running"
else
print_error "✗ ScyllaDB service is not running"
exit 1
fi
if cqlsh -e "DESCRIBE KEYSPACE timeseries_data" >/dev/null 2>&1; then
print_status "✓ Time-series keyspace created successfully"
else
print_warning "⚠ Could not verify keyspace creation"
fi
echo -e "${GREEN}ScyllaDB time-series optimization complete!${NC}"
echo "Configuration backup saved to: ${SCYLLA_CONFIG}.backup.*"
echo "Prometheus monitoring available on port 9180"
echo "Time-series keyspace 'timeseries_data' created with optimized settings"
echo ""
echo "Next steps:"
echo "1. Configure your application to use the 'timeseries_data.metrics' table"
echo "2. Set up Prometheus to scrape metrics from port 9180"
echo "3. Monitor performance and adjust settings as needed"
Review the script before running. Execute with: bash install.sh