Quickstart: YU02-lmax-kubernetes
TraderX on Kubernetes with an LMAX-architecture Business Logic Processor (BLP): single-threaded, in-memory order matching, journaled to disk, with periodic snapshots for fast recovery.
Local (kind)β
First runβ
bash pipeline/generate-state.sh YU02-lmax-kubernetes
bash generated/code/target-generated/scripts/start-state-YU02-lmax-kubernetes-generated.sh \
--provider kind --without-sail
UI at http://127.0.0.1:8080. The script generates state, builds all images, loads them into
the kind cluster (traderx-state-014), applies manifests, and waits for all services to be ready.
If you already have the cluster running from a previous GKE-rendered deploy, the base kustomization will create an
order-matcherDeployment that conflicts with any leftover StatefulSet. Use--recreate-clusterto wipe and rebuild cleanly:bash generated/code/target-generated/scripts/start-state-YU02-lmax-kubernetes-generated.sh \--provider kind --without-sail --recreate-cluster
Subsequent runs (skip rebuild if code unchanged)β
bash generated/code/target-generated/scripts/start-state-YU02-lmax-kubernetes-generated.sh \
--provider kind --without-sail --skip-build
Validateβ
bash scripts/test-state-YU02-lmax-kubernetes.sh
Validated closeout path:
bash pipeline/generate-state.sh YU02-lmax-kubernetes
bash generated/code/target-generated/scripts/test-state-YU02-lmax-kubernetes.sh
Stopβ
bash generated/code/target-generated/scripts/stop-state-YU02-lmax-kubernetes-generated.sh
# or delete the cluster entirely:
kind delete cluster --name traderx-state-014
GKEβ
One-time cluster setupβ
gcloud container clusters create traderx-lmax \
--zone us-east1-b \
--machine-type e2-standard-2 \
--num-nodes 3 \
--release-channel regular
gcloud container clusters get-credentials traderx-lmax --zone us-east1-b
Install ingress-nginx and cert-manager, then apply cluster-level addons:
kubectl apply -f cluster-addons/
Deploy (normal redeploy flow)β
Generate state, push images, render GKE manifests, and apply:
bash pipeline/generate-state.sh YU02-lmax-kubernetes
bash scripts/push-state-YU02-lmax-kubernetes-gke-images.sh \
us-east1-docker.pkg.dev/traderx-501015/traderx
bash scripts/deploy-state-YU02-lmax-kubernetes-gke.sh \
us-east1-docker.pkg.dev/traderx-501015/traderx
kubectl apply -f cluster-addons/
deploy-state-YU02-lmax-kubernetes-gke.sh runs the prepare script then kubectl apply -k. The prepare
script (scripts/prepare-state-YU02-lmax-kubernetes-gke-manifests.sh) rewrites the base manifests for
GKE:
- Rewrites image tags to the Artifact Registry prefix
- Converts
edge-proxyfromNodePorttoClusterIP(ingress-nginx handles external access) - Folds
order-matcher-statefulset.yaml+ headless service into the kustomization (replacing the baseorder-matcher-deployment.yaml+ PVC) - Injects pod anti-affinity on all Deployments
Override CORS if needed:
TRADERX_CORS_ALLOWED_ORIGINS=https://yaakovseif.dev \
bash scripts/deploy-state-YU02-lmax-kubernetes-gke.sh \
us-east1-docker.pkg.dev/traderx-501015/traderx
Accessing the clusterβ
| Endpoint | URL |
|---|---|
| TraderX UI | https://yaakovseif.dev |
| Grafana | https://grafana.yaakovseif.dev (DNS A record needed) |
| Grafana (port-forward) | kubectl port-forward svc/grafana 3000:3000 -n traderx |
Failover testβ
# BLP pod restart β journal replay:
kubectl delete pod order-matcher-0 -n traderx
kubectl logs -f order-matcher-0 -n traderx # watch for "LIVE RECOVERY [journal]"
# Node drain β pod reschedule:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
kubectl uncordon <node-name>
# HA mode (BLP_REPLICATION_ENABLED=true, 2 replicas) β leader failover:
kubectl get pods -n traderx -l app=order-matcher --show-labels # find blp-role=primary
kubectl delete pod <primary-pod> -n traderx --grace-period=0
# expect: standby promotes in ~2-3s (pod-GET fast path); watch the lease flip:
kubectl get lease order-matcher-leader -n traderx -w
# election health (renew age must stay well under RENEW_DEADLINE_SECONDS=10):
curl -s localhost:18110/metrics | grep blp_lease
Full HA election contract, failure modes, and tradeoffs: LMAX-BLP-FAILOVER.md at the repo root.
Runtime notesβ
- Database: MariaDB 11.4 (port 3306,
--lower-case-table-names=1). Read-model only; the BLP journal is the source of truth. - BLP recovery:
RECOVERY_SOURCE=journal. On restart, replays the binary journal from the last snapshot boundary. Readiness probe gates traffic until replay completes. - Journal/snapshot path:
/var/lib/traderx-lmax/journalon the StatefulSet PVC (lmax-runtime-data-order-matcher-0). Snapshot interval: 5 min (SNAPSHOT_INTERVAL_MS=300000). - BLP performance: journal write-coalescing (
journal.batch.records=1024), bounded terminal retention (blp.terminal.retain=262144). - Local kind note: images are cached as
docker.io/traderx/<name>:state009. After any image rebuild you must reload them:kind load docker-image <image> --name traderx-state-014.