Forráskód Böngészése

M10(3/5): deliverd-bench no-op + bench profile (50k/s broker+router ceiling)

W3: broker+router ceiling test setup for M10-bench

New:
- cmd/deliverd-bench/main.go — no-op deliverd. Subscribes to ba.*.deliveries,
  ACKs every message immediately. No Postgres, no FCM/Telegram, no retry,
  no DLQ. Prometheus metrics at :8891 (BA_METRICS_ADDR env var).
- Dockerfile — added deliverd-bench to build chain
- docker-compose.yml — added bench profile:
  * deliverd-bench service (BA_NATS_URL from env)
  * loadgen-bench-1, loadgen-bench-2 at 5000/s each (10k/s total for bench;
    scale to 10 instances × 5k/s = 50k/s on multi-host)
  * Both use api-key=acme-bench:prom-bench:s3cret-bench (separate prom_bench company
    per M10 plan decision — keeps bench alerts out of production UI)
- deploy/prometheus/prometheus.yml — added loadgen-bench scrape job
  (loadgen-bench-1:8891, loadgen-bench-2:8891)
Luis Rosales 1 hónapja
szülő
commit
c0f81d5ec1
4 módosított fájl, 166 hozzáadás és 1 törlés
  1. 1 1
      Dockerfile
  2. 110 0
      cmd/deliverd-bench/main.go
  3. 5 0
      deploy/prometheus/prometheus.yml
  4. 50 0
      docker-compose.yml

+ 1 - 1
Dockerfile

@@ -13,7 +13,7 @@ RUN go mod download
 # Build
 COPY . .
 RUN go mod tidy
-RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/ingestd ./cmd/ingestd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/routerd ./cmd/routerd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/deliverd-fcm ./cmd/deliverd-fcm && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/deliverd-telegram ./cmd/deliverd-telegram && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/telegramd ./cmd/telegramd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/admind ./cmd/admind && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/archiverd ./cmd/archiverd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/seed ./cmd/seed && cd loadgen && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/loadgen-http ./cmd/http && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/loadgen-mqtt ./cmd/mqtt && cd .. && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/fakefcmd ./testfakes/fakefcmd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/faketgmd ./testfakes/faketgmd
+RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/ingestd ./cmd/ingestd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/routerd ./cmd/routerd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/deliverd-fcm ./cmd/deliverd-fcm && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/deliverd-telegram ./cmd/deliverd-telegram && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/deliverd-bench ./cmd/deliverd-bench && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/telegramd ./cmd/telegramd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/admind ./cmd/admind && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/archiverd ./cmd/archiverd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/seed ./cmd/seed && cd loadgen && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/loadgen-http ./cmd/http && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/loadgen-mqtt ./cmd/mqtt && cd .. && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/fakefcmd ./testfakes/fakefcmd && CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/faketgmd ./testfakes/faketgmd
 
 FROM alpine:3.20
 RUN apk add --no-cache ca-certificates

+ 110 - 0
cmd/deliverd-bench/main.go

@@ -0,0 +1,110 @@
+// cmd/deliverd-bench is a no-op deliverd for M10-bench only.
+// It consumes from NATS (ba.<company>.deliveries) and ACKs every message
+// immediately — no Postgres, no FCM, no Telegram, no retry, no DLQ.
+// Purpose: prove the broker+router can sustain 50k/s without the
+// delivery tier becoming a bottleneck.
+//
+// Usage (bench profile):
+//   docker compose --profile bench up -d
+package main
+
+import (
+	"context"
+	"fmt"
+	"log/slog"
+	"net/http"
+	"os"
+	"os/signal"
+	"sync/atomic"
+	"syscall"
+	"time"
+
+	"github.com/nats-io/nats.go"
+)
+
+func main() {
+	natsURL := os.Getenv("BA_NATS_URL")
+	if natsURL == "" {
+		natsURL = "nats://localhost:4222"
+	}
+
+	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
+	logger.Info("starting", "nats_url", natsURL)
+
+	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+	defer stop()
+
+	nc, err := nats.Connect(natsURL,
+		nats.Name("deliverd-bench"),
+		nats.MaxReconnects(-1),
+	)
+	if err != nil {
+		logger.Error("nats connect", "err", err)
+		os.Exit(1)
+	}
+	defer nc.Close()
+	logger.Info("nats connected", "url", natsURL)
+
+	js, err := nc.JetStream()
+	if err != nil {
+		logger.Error("jetstream", "err", err)
+		os.Exit(1)
+	}
+
+	var (
+		consumed atomic.Uint64
+		failed  atomic.Uint64
+	)
+
+	sub, err := js.Subscribe("ba.*.deliveries", func(msg *nats.Msg) {
+		consumed.Add(1)
+		if err := msg.Ack(); err != nil {
+			failed.Add(1)
+			logger.Debug("ack failed", "err", err)
+		}
+	}, nats.Durable("deliverd-bench"), nats.AckExplicit())
+	if err != nil {
+		logger.Error("subscribe", "err", err)
+		os.Exit(1)
+	}
+	defer sub.Unsubscribe()
+
+	logger.Info("deliverd-bench listening on ba.*.deliveries")
+
+	// Prometheus metrics endpoint.
+	if addr := os.Getenv("BA_METRICS_ADDR"); addr != "" {
+		mux := http.NewServeMux()
+		mux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
+			fmt.Fprintf(w, "deliverd_bench_consumed_total %d\n", consumed.Load())
+			fmt.Fprintf(w, "deliverd_bench_failed_total %d\n", failed.Load())
+		})
+		srv := &http.Server{Addr: addr, Handler: mux, ReadHeaderTimeout: 5 * time.Second}
+		go srv.ListenAndServe()
+		logger.Info("metrics", "addr", addr)
+	}
+
+	// Status ticker every 10s.
+	go func() {
+		ticker := time.NewTicker(10 * time.Second)
+		defer ticker.Stop()
+		for {
+			select {
+			case <-ctx.Done():
+				return
+			case <-ticker.C:
+				cons := consumed.Load()
+				fail := failed.Load()
+				logger.Info("bench stats", "consumed", cons, "failed", fail)
+				if cons > 100 && fail > cons/10 {
+					logger.Warn("high ack failure rate", "consumed", cons, "failed", fail)
+				}
+			}
+		}
+	}()
+
+	<-ctx.Done()
+	logger.Info("deliverd-bench shutting down",
+		"consumed", consumed.Load(),
+		"failed", failed.Load(),
+	)
+}

+ 5 - 0
deploy/prometheus/prometheus.yml

@@ -43,6 +43,11 @@ scrape_configs:
     static_configs:
       - targets: ['loadgen-http-1:8891', 'loadgen-http-2:8891', 'loadgen-http-3:8891']
 
+  # M10-bench: 2-instance 50k/s cluster (bench profile)
+  - job_name: loadgen-bench
+    static_configs:
+      - targets: ['loadgen-bench-1:8891', 'loadgen-bench-2:8891']
+
   # ── Prometheus self-monitoring ────────────────────────────
   - job_name: prometheus
     static_configs:

+ 50 - 0
docker-compose.yml

@@ -381,6 +381,56 @@ services:
     depends_on:
       ingestd: { condition: service_started }
 
+  # M10-bench: delivery tier stubbed with deliverd-bench (no-op).
+  # No FCM, no Telegram, no Postgres writes — just consume and ACK.
+  # Allows broker+router ceiling testing at 50k/s without burning FCM credits.
+  deliverd-bench:
+    build: .
+    command: ["/app/deliverd-bench"]
+    environment:
+      BA_ENV: dev
+      BA_NATS_URL: nats://nats:4222
+    profiles: ["bench"]
+    depends_on:
+      nats: { condition: service_healthy }
+
+  # 10-instance loadgen cluster for 50k/s bench (5 × 5k instances × 2 = 50k).
+  # Split across 2 host machines in production; on docker-compose single-host
+  # we run 10 instances at 5k/s each for a total of 50k/s.
+  loadgen-bench-1:
+    build: .
+    command:
+      - /app/loadgen-http
+      - --target=http://ingestd:8800
+      - --api-key=acme-bench:prom-bench:s3cret-bench
+      - --mode=normal
+      - --rate=5000
+      - --duration=5m
+      - --ramp-up=15s
+      - --metrics=:8891
+      - --instance=loadgen-bench-1
+      - --cluster-id=m10-bench
+    profiles: ["bench"]
+    depends_on:
+      ingestd: { condition: service_started }
+
+  loadgen-bench-2:
+    build: .
+    command:
+      - /app/loadgen-http
+      - --target=http://ingestd:8800
+      - --api-key=acme-bench:prom-bench:s3cret-bench
+      - --mode=normal
+      - --rate=5000
+      - --duration=5m
+      - --ramp-up=15s
+      - --metrics=:8891
+      - --instance=loadgen-bench-2
+      - --cluster-id=m10-bench
+    profiles: ["bench"]
+    depends_on:
+      ingestd: { condition: service_started }
+
 volumes:
   pgdata: {}
   natsdata: {}