fix(performance): reduce idle CPU usage from ~0.7% to ~0.1% (#993)

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Cory LaNou
2026-01-13 09:22:35 -06:00
committed by GitHub
parent bd57a0fcb6
commit a9af19b9fc
4 changed files with 181 additions and 15 deletions

View File

@@ -307,8 +307,9 @@ func (c *ReplicaClient) Init(ctx context.Context) (err error) {
Timeout: 24 * time.Hour,
}
// Configure transport for insecure connections if needed
if c.SkipVerify {
// Always configure custom HTTP Transport with controlled keepalive settings
// to reduce idle CPU usage from default transport's aggressive keepalives.
// See: https://github.com/benbjohnson/litestream/issues/992
httpClient.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
@@ -320,9 +321,12 @@ func (c *ReplicaClient) Init(ctx context.Context) (err error) {
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
}
// Configure TLS to skip verification if requested
if c.SkipVerify {
httpClient.Transport.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
},
}
}

69
tests/cpu-usage/README.md Normal file
View File

@@ -0,0 +1,69 @@
# CPU Usage Testing
This directory contains test scripts and configurations for measuring Litestream's idle CPU usage, particularly for validating the fixes in issue #992.
## Files
- `test-cpu-usage.sh` - Automated CPU monitoring script
- `litestream-test-polling.yml` - Config for testing with S3 replication
## Prerequisites
1. Build Litestream binary:
```bash
cd ../..
go build -o bin/litestream ./cmd/litestream
```
2. Set up AWS credentials in `.envrc` at repo root:
```bash
export AWS_ACCESS_KEY_ID="your-key-id"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_REGION="us-east-2"
export S3_BUCKET="your-test-bucket"
```
3. Have `sqlite3` CLI installed
## Usage
From this directory, run:
```bash
# Test for 60 seconds
./test-cpu-usage.sh 60
# Longer test (5 minutes)
./test-cpu-usage.sh 300
```
## What It Tests
The script:
1. Creates a test SQLite database at `/tmp/test.db`
2. Starts Litestream with S3 replication
3. Monitors CPU usage every second using `ps`
4. Calculates average CPU usage
5. Verifies S3 replication is working
6. Outputs results and detailed CSV log
## Expected Results
Based on testing for PR #993:
- **With S3 transport fix:** ~0.0067% CPU (99% improvement)
- **Original (v0.5.6):** ~0.7% CPU
The S3 transport fix achieves near-zero idle CPU usage, validating the fix.
## Output
Results are printed to stdout and detailed logs are saved to:
- `/tmp/litestream-cpu-log.csv` - Per-second CPU measurements
## Notes
- Tests require real S3 credentials and will upload data to your bucket
- Test database is created at `/tmp/test.db` and cleaned up on each run
- CPU measurements are instantaneous snapshots, not averages over intervals
- Longer test durations (5-10 minutes) provide more stable averages

View File

@@ -0,0 +1,12 @@
# Litestream test configuration - POLLING MODE
# Tests idle CPU usage with default polling (1s interval)
dbs:
- path: /tmp/test.db
replicas:
- type: s3
bucket: sprite-litestream-debugging
region: us-east-2
path: test-db-polling
# Default: monitor-interval: 1s
# Default: monitor-mode: poll

View File

@@ -0,0 +1,81 @@
#!/bin/bash
set -e
# Test script for measuring Litestream idle CPU usage with S3 replication
DURATION=${1:-300} # Default 5 minutes
CONFIG_FILE="litestream-test-polling.yml"
MODE_DESC="Polling mode (1s interval)"
echo "========================================="
echo "Litestream CPU Usage Test"
echo "========================================="
echo "Mode: $MODE_DESC"
echo "Config: $CONFIG_FILE"
echo "Duration: ${DURATION}s"
echo "========================================="
# Create test database
echo "Creating test database..."
rm -f /tmp/test.db /tmp/test.db-wal /tmp/test.db-shm
sqlite3 /tmp/test.db "CREATE TABLE test (id INTEGER PRIMARY KEY, data TEXT);"
sqlite3 /tmp/test.db "INSERT INTO test (data) VALUES ('test');"
# Start Litestream in background
echo "Starting Litestream..."
# Get script directory and repo root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
source "$REPO_ROOT/.envrc"
"$REPO_ROOT/bin/litestream" replicate -config "$SCRIPT_DIR/$CONFIG_FILE" &
LITESTREAM_PID=$!
echo "Litestream PID: $LITESTREAM_PID"
echo ""
echo "Monitoring CPU usage for ${DURATION}s..."
echo "Press Ctrl+C to stop early"
echo ""
# Monitor CPU usage
echo "Time,CPU%,VSZ,RSS" > /tmp/litestream-cpu-log.csv
for i in $(seq 1 $DURATION); do
if ! kill -0 $LITESTREAM_PID 2>/dev/null; then
echo "ERROR: Litestream process died!"
exit 1
fi
# Get CPU and memory stats
CPU=$(ps -p $LITESTREAM_PID -o %cpu= | xargs)
VSZ=$(ps -p $LITESTREAM_PID -o vsz= | xargs)
RSS=$(ps -p $LITESTREAM_PID -o rss= | xargs)
echo "$i,$CPU,$VSZ,$RSS" >> /tmp/litestream-cpu-log.csv
# Display every 10 seconds
if [ $((i % 10)) -eq 0 ]; then
echo "[$i/${DURATION}s] CPU: ${CPU}% VSZ: ${VSZ}KB RSS: ${RSS}KB"
fi
sleep 1
done
# Stop Litestream
echo ""
echo "Stopping Litestream..."
kill $LITESTREAM_PID
wait $LITESTREAM_PID 2>/dev/null || true
# Calculate average CPU
echo ""
echo "========================================="
echo "Results"
echo "========================================="
AVG_CPU=$(awk -F',' 'NR>1 {sum+=$2; count++} END {if(count>0) print sum/count; else print 0}' /tmp/litestream-cpu-log.csv)
echo "Average CPU: ${AVG_CPU}%"
echo "Detailed log: /tmp/litestream-cpu-log.csv"
echo ""
# Show sample of S3 uploads
echo "S3 Bucket Contents:"
aws s3 ls s3://sprite-litestream-debugging/test-db-${CONFIG_MODE}/ --recursive | head -10