Self Hosted Langfuse and Clickhouse: How to increase the replica #13311
Describe your questionWe have a self hosted langfuse deployed on open shift cluster. Currently the Clickhouse is single sharded and has only one replica.
Langfuse version: 3.143 Langfuse Cloud or Self-Hosted?Self-Hosted If Self-Hosted3.143 If Langfuse CloudNo response SDK and integration versionsNo response Pre-Submission Checklist
|
Replies: 2 comments 1 reply
|
Increasing ClickHouse replicas from 1 to 3 in your self-hosted Langfuse deployment requires careful planning. Here's what you need to know based on the Langfuse documentation: Required Configuration ChangesFor Kubernetes deployments using the Bitnami ClickHouse Helm chart, you need to update your values.yaml(1): clickhouse:
deploy: true
shards: 1 # Fixed: Langfuse does not support multi-shard clusters
replicaCount: 3
resourcesPreset: large # or more
persistence:
size: 100Gi
auth:
username: default
password: changemeImportant: The number of replicas cannot be increased at runtime without manual intervention or downtime(1). Langfuse requires certain ClickHouse configuration parameters for database migrations, specifically the Backup Strategy Before ChangesBefore increasing replicas, implement a comprehensive backup strategy(2): Volume Snapshots (recommended for Kubernetes): # Create a VolumeSnapshot for each ClickHouse replica
kubectl apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: clickhouse-backup-$(date +%Y%m%d-%H%M%S)
namespace: langfuse
spec:
source:
persistentVolumeClaimName: data-langfuse-clickhouse-0
volumeSnapshotClassName: csi-hostpath-snapclass
EOFEnsure you're also adding snapshots for the ClickHouse ZooKeeper volumes(2). Persistent Volume ConsiderationsYour storage class must have Since you already have 50GB of data in your PV, ensure:
ClickHouse Keeper DeploymentThe documentation mentions that ClickHouse Keeper (ZooKeeper) is necessary for replicated setups. When using the Bitnami Helm chart with Minimizing Trace Loss During MigrationTo minimize the risk of losing incoming traces during the replica increase:
The Langfuse worker publishes queue length metrics via statsd ( Additional Precautions
Critical Note: Shards are used for horizontally scaling ClickHouse. Today, Langfuse does not support a multi-shard cluster, i.e. the shards value must be set to 1(1). The documentation advises to contact the Langfuse team if you hit scaling limits of a single shard cluster. 📚 Sources: Have another question? Just tag @inkeep. |
|
We use ecs. Its likely easier with EKS but here was our migration strategy. ClickHouse Cluster Migration: Overview for Engineering ReviewWhy Are We Doing This?Our current Langfuse deployment runs a single ClickHouse instance on ECS Fargate. This is a single point of failure — if that container dies, restarts, or EFS has issues, all trace ingestion and dashboard queries stop. There is no replication, no failover, and no way to scale reads. We are migrating to a 3-replica ClickHouse cluster (1 shard × 3 replicas) coordinated by a 3-node ClickHouse Keeper quorum. This gives us:
ArchitectureCurrent (Single-Node)Target (Clustered)Key Infrastructure Components
What Needs to Happen for Each StageThe migration is a 3-phase process per stage. All phases are decoupled and zero-downtime — Langfuse never stops serving traffic. Phase 1: Deploy Cluster Infrastructure (No Langfuse Impact)CDK config change in DatabaseStackProps: {
clickhouseClustered: true,
deployClusterServices: true,
clusterReplicaCpu: 2048, // tune per stage
clusterReplicaMemoryMiB: 8192, // tune per stage
}What happens: 3 Keeper + 3 Replica Fargate services boot alongside the existing single-node. Langfuse continues using the single-node. Zero customer impact. Validation: Keeper quorum ( Phase 2: Pre-Seed Schema + Backfill Data (No Langfuse Impact)While Langfuse continues running on the single-node, we prepare the cluster:
Why we can run migrations ourselves: Langfuse's migration SQL files are available in the Docker image ( Risk mitigation: If a new Langfuse version ships additional migrations between when we pre-seed and when we flip, Langfuse will detect the delta and run only the new migrations on startup. This is safe — it's how Langfuse normally handles incremental updates. Phase 3: Flip Langfuse to Cluster (Zero-Downtime Rolling Deploy)CDK config change: LangfuseStackProps: {
useClustered: true, // ← the flip switch
}What happens:
Challenges We Discovered1. Cross-Stack CloudFormation Export Issue (Resolved ✅)The problem: Our CDK uses two stacks — The fix: Added a Deploy order for prod: Deploy LangfuseStack first (to update the import), then ClickhouseStack. 2. Table Engine Conversion (Non-Trivial)Langfuse maintains two separate SQL migration directories:
Tables created in unclustered mode cannot be converted in-place to replicated engines. ClickHouse does not support Our approach: Run the 3.
|
| Data Volume | Backfill Time | Notes |
|---|---|---|
| < 1 GB (dev/beta) | ~2 min | Near-instant |
| 10-50 GB (gamma) | ~15-30 min | Run and verify |
| 100 GB+ (prod) | 30-120 min | Run catch-up sync after |
4. No Official Migration Path from Langfuse
Langfuse does not provide a documented unclustered→clustered migration procedure. Our backup-and-replay approach is custom and was validated on the personal stack first.
5. EFS Performance
ClickHouse is I/O-intensive. EFS has higher latency than EBS (which we'd get with EKS/PVCs). We chose EFS because:
- Already in use for single-node
- No Kubernetes expertise on team
- EFS Elastic throughput mode handles burst workloads
- 3 replicas distribute read load
We should monitor EFS IOPS and latency after migration and evaluate if EBS (via EKS) is needed later.
POC / Testing Done
Personal Stack E2E Test (2026-04-20, account 732406385518)
Full end-to-end migration test on personal stack. Key results:
Phase 1 — Cluster Infrastructure:
- ✅ 3 Keepers formed quorum (all returned
imok) - ✅ 3 Replicas joined cluster (
system.clustersshows 1 shard × 3 replicas) - ✅ Replication functional: created
ReplicatedMergeTreetable, inserted rows on replica-0, verified on all 3
Phase 2 — The Flip:
- ❌ First attempt failed (cross-stack export error) → auto-rolled back, zero impact
- ✅ Applied
CLICKHOUSE_SINGLE_NODE_URLfix → LangfuseStack deployed successfully - ✅ Langfuse auto-migrated 68 schema files → created all tables with
Replicated*engines - ✅ Langfuse immediately started writing new data to cluster
Data Backfill:
- ✅
remote()connectivity: cluster can query single-node over the VPC - ✅ Backfilled 4 tables (~980 rows) in ~2 minutes:
- traces: 179 rows
- observations: 502 rows
- scores: 12 rows
- blob_storage_file_log: 289 rows
- ✅
schema_migrationsmanaged by Langfuse (not manually backfilled)
Post-Backfill Verification:
- ✅ All 7 replicated tables: 3/3 active replicas, queue_size=0, absolute_delay=0
- ✅ Langfuse continued writing (9 new traces appeared during backfill)
Timing:
| Step | Duration |
|---|---|
| Pre-flight validation | 9 min |
| First deploy attempt (failed) | 9 min |
| Diagnosis + fix + redeploy | 15 min |
| Post-flip validation | 10 min |
| Data backfill + verification | 10 min |
| Total | 53 min |
| Backfill only | ~2 min |
What's Left to Test
- Failover: kill one replica → verify Langfuse stays up via NLB
- Recovery: bring replica back → verify replication catches up
- Load test with production-scale data volume
Rollback Plan
During Migration (Before Langfuse Resumes)
- Revert
useClustered: falseinstack-config.ts - Deploy → Langfuse points back at single-node
- Single-node still has all original data (never modified)
After Migration (Langfuse Running on Cluster)
- Scale Langfuse to 0
- Revert
useClustered: false, deploy - Scale Langfuse back up on single-node
- Data written after the flip is on the cluster only — use S3 event backup or
remote()in reverse to recover
Nuclear Option
- Restore single-node EFS from AWS Backup snapshot
- Revert all CDK changes, deploy
- Data since snapshot is lost
Rollout Plan
| Stage | Phase 1 (Infra) | Phase 2 (Schema + Backfill) | Phase 3 (Flip) | Notes |
|---|---|---|---|---|
| Personal () | ✅ Done | ✅ Done | ✅ Done | Full E2E validated |
| Beta | Next | After P1 validation | After P2 verification | Low data volume, fast backfill |
| Gamma | After beta | After P1 validation | After P2 verification | Medium data, ~30 min backfill |
| Prod (us-east-1) | After gamma | After P1 validation | After P2 verification | Largest data, longest backfill |
| Prod (us-west-2) | After us-east-1 | After P1 validation | After P2 verification | Same procedure |
| Prod (eu-south-2) | After us-west-2 | After P1 validation | After P2 verification | Same procedure |
All phases are zero-downtime. No maintenance window required at any stage.
Open Questions for Team Discussion
- Prod data volume — Need to measure actual ClickHouse data size to estimate backfill time
- Monitoring — What CloudWatch alarms/dashboards do we need for the cluster?
- Single-node cleanup — How long to keep the single-node running after migration? (Recommended: 1-2 weeks)
- Keeper resource sizing — Current: 512 CPU / 1024 MiB. Sufficient for prod?
- Catch-up sync strategy — After initial backfill, how many catch-up
remote()syncs before the flip? (Recommended: 1 final sync with timestamp filter, then flip immediately)
Related Documents
- Cluster Implementation Plan — CDK design decisions, file structure, ECS vs EKS rationale
- Migration Playbook — Step-by-step procedure with scripts
- E2E Test Journal — Detailed minute-by-minute test log
- Cluster Debugging Guide — Troubleshooting commands
- Scaling Replicas — How to add/remove replicas
Increasing ClickHouse replicas from 1 to 3 in your self-hosted Langfuse deployment requires careful planning. Here's what you need to know based on the Langfuse documentation:
Required Configuration Changes
For Kubernetes deployments using the Bitnami ClickHouse Helm chart, you need to update your values.yaml(1):
(1)
Important: The number of replicas cannot be increased at runtime without manual intervention or downtime(1). Langfuse requires certain ClickHouse …