Joining und Seeds
Ein Node tritt einem Cluster bei, indem er einen Seed-Node
kontaktiert. Der Seed sendet per Gossip seine aktuelle
Mitgliedschaftssicht zurück; der Joiner wird als joining
hinzugefügt, propagiert per Gossip, und sobald der Leader ihn sieht
(plus Konvergenz), wechselt er zu up.
Diese Seite behandelt die Mechanik dieses Handshakes plus die Seed-Discovery-Ebene darüber.
Der einfachste Fall — explizite Seeds
Abschnitt betitelt „Der einfachste Fall — explizite Seeds“import { ActorSystem, Cluster } from 'actor-ts';
const system = ActorSystem.create('my-app');
const cluster = await Cluster.join(system, { host: '10.0.0.5', port: 2552, seeds: ['10.0.0.5:2552', '10.0.0.6:2552', '10.0.0.7:2552'],});Drei Seeds. Der Joiner kontaktiert sie der Reihe nach, bis einer
antwortet. Sobald irgendein Seed akzeptiert, propagiert der Gossip
des Clusters das neue Mitglied; Konvergenz zu up geschieht
innerhalb weniger Sekunden in einem gesunden Netzwerk.
Die Seed-Liste ist nur ein Bootstrap-Hinweis — sobald der Node beigetreten ist, lernt er alle anderen Peers per Gossip kennen. Seeds müssen nach dem Join nicht mehr besonders sein.
Konfiguration
Abschnitt betitelt „Konfiguration“interface ClusterSettings { host: string; // Adresse dieses Nodes port: number; // TCP-Port dieses Nodes seeds?: string[]; // Peer-Adressen fürs Bootstrap roles?: string[]; // Rollen-Tags failureDetector?: Partial<...>; transport?: Transport; gossipIntervalMs?: number; seedRetryIntervalMs?: number; // Retry-Intervall, falls kein Seed antwortet // ...}Die seed-bezogenen Knöpfe:
| Einstellung | Standard | Was |
|---|---|---|
seeds | [] | Liste von "host:port"-Strings. Leer = “ich bin der erste”. |
seedRetryIntervalMs | 3000 | Falls kein Seed antwortet, wiederhole die Liste so oft, bis einer antwortet. |
Der erste Node
Abschnitt betitelt „Der erste Node“const cluster = await Cluster.join(system, { host: '0.0.0.0', port: 2552, seeds: [],});Eine leere seeds-Liste (oder eine, die komplett unerreichbar ist)
bedeutet, dass dieser Node den Cluster selbst bootstrapt. Er
befördert sich automatisch zum Leader; künftige Joiner kontaktieren
ihn.
Das macht die Single-Node-Entwicklung trivial — keine zu pflegende Seed-Liste. Füge später einen zweiten Node hinzu, indem du ihm die Adresse des ersten als Seed gibst.
Für Produktion gib jedem Node dieselbe Seed-Liste (3-5 Adressen, idealerweise bekannte Nodes, von denen du keinen Wechsel erwartest). Reihenfolge spielt keine Rolle; der Joiner probiert jeden.
Selbst-seedende Nodes — das Bootstrap-Rennen
Abschnitt betitelt „Selbst-seedende Nodes — das Bootstrap-Rennen“Wenn ein Cluster aus dem Kaltstart hochfährt (alle Nodes kommen gleichzeitig hoch), liefern sich die Joiner ein Rennen. Die Seed-Retry-Logik des Frameworks regelt das:
- Jeder Node wiederholt seine Seed-Liste in
seedRetryIntervalMs. - Irgendwann kontaktiert ein Node zuerst sich selbst; das ist der Bootstrap.
- Der Rest konvergiert auf den jetzt existierenden Cluster.
Der Standard-Retry von 3 Sekunden macht die Kaltstart-Konvergenz in wenigen Runden zuverlässig.
Seed-Discovery — jenseits einer statischen Liste
Abschnitt betitelt „Seed-Discovery — jenseits einer statischen Liste“Eine hartcodierte Seed-Liste reicht für Tests und kleine Cluster. Für Produktion, in der Nodes dynamische IPs haben (Container, K8s Pods), nutze einen Seed-Provider:
| Provider | Wann |
|---|---|
| Config | Statische Liste (der Fall oben). |
| DNS | Löst _actor-ts._tcp.example.com SRV-Records auf. |
| Kubernetes API | Listet Pods, die einem Label-Selector entsprechen. |
| Aggregate | Fällt durch mehrere Provider durch (z. B. K8s, dann DNS). |
import { KubernetesApiSeedProvider } from 'actor-ts/discovery';
const seedProvider = new KubernetesApiSeedProvider({ namespace: 'default', labelSelector: 'app=actor-ts', containerPort: 2552,});
const seeds = await seedProvider.discover();
const cluster = await Cluster.join(system, { host: process.env.POD_IP!, port: 2552, seeds,});Der Provider liefert eine Momentaufnahme von Seed-Adressen; das Framework nutzt sie, um den Join zu bootstrappen. Siehe Discovery-Überblick für das Seed-Provider-Modell.
Den Join-Fortschritt beobachten
Abschnitt betitelt „Den Join-Fortschritt beobachten“import { SelfUp, MemberUp } from 'actor-ts';
cluster.subscribe(SelfUp, (evt) => { console.log(`dieser Node ist jetzt Up`);});
cluster.subscribe(MemberUp, (evt) => { console.log(`Peer ${evt.member.address} hat Up erreicht`);});Zwei zentrale Events:
SelfUpfeuert einmal, wenn dieser Node aufupübergeht. Nützliches Gate, um Arbeit zu starten, die Cluster-Mitgliedschaft erfordert.MemberUpfeuert jedes Mal, wenn irgendein Mitglieduperreicht.
Für Startup-Logik, die andere Mitglieder braucht (“warte, bis
mindestens 3 Nodes up sind, bevor Traffic bedient wird”), zähle
MemberUps nach SelfUp.
Was schiefgehen kann
Abschnitt betitelt „Was schiefgehen kann“Wohin als Nächstes
Abschnitt betitelt „Wohin als Nächstes“- Cluster-Überblick — das größere Bild.
- Weakly-up — Gradual-Join-Semantik für langsame Konvergenz.
- Failure Detector — wie Heartbeats die Mitgliedschaftssicht nach dem Join frisch halten.
- Discovery-Überblick — Seed-Provider für dynamische Umgebungen.
- Downing-Strategien — Split-Brain-Auflösung nach der Cluster-Bildung.