Zum Inhalt springen
Deutsch

Discovery im Überblick

“Discovery” in actor-ts umfasst zwei getrennte Anliegen:

AnliegenMechanismusWann
Cluster-BootstrapSeed ProviderEinmal beim Start des Nodes — wie dieser Node seine Peers findet.
Runtime-Service-LookupReceptionistWährend des Betriebs — wie Actors einander per Service Key finden.

Beide teilen den Namen “Discovery”, weil beide Lookup-basiertes Addressing sind, aber die Protokolle und Anwendungsfälle sind verschieden.

Seed Provider beantworten: “Welche Adressen soll ich beim Join-Zeitpunkt als Cluster-Seeds probieren?”

import { Cluster, ClusterOptions, KubernetesApiSeedProvider, KubernetesApiSeedProviderOptions } from 'actor-ts';
const kubernetesApiSeedProviderOptions = KubernetesApiSeedProviderOptions.create()
.withNamespace('my-app')
.withServiceName('actor-ts')
.withSystemName('my-app')
.withPort(2552);
const provider = new KubernetesApiSeedProvider(
kubernetesApiSeedProviderOptions,
);
const addresses = await provider.lookup();
const seeds = addresses.map((address) => address.toString());
const clusterOptions = ClusterOptions.create()
.withHost(host)
.withPort(port)
.withSeeds(seeds);
await Cluster.join(system, clusterOptions);

Vier Provider werden mitgeliefert:

ProviderVerwendung
ConfigSeedProviderStatische Liste aus Env-Vars / Config.
DnsSeedProviderDNS-SRV-Record-Auflösung.
KubernetesApiSeedProviderLive-Pod-Listing via K8s-API.
AggregateSeedProviderMehrere Provider mit Fallback verketten.

Wähle nach deiner Deployment-Umgebung:

  • K8sKubernetesApiSeedProvider.
  • VMs mit DNS-SDDnsSeedProvider.
  • Statische Deployments / Docker ComposeConfigSeedProvider.
  • Mehrere Umgebungen / DR-SzenarienAggregateSeedProvider.

Für die meisten Apps wählst du einen Provider, konfigurierst ihn einmal und gehst weiter. Siehe Joining und Seeds für das vollständige Join-Protokoll.

Ein Provider liefert, was er gerade jetzt sieht. Bei einem gleichzeitigen Start ist das auf jedem Node eine andere Menge — DNS ist mitten in der Propagation, ein Pod ist Ready, bevor seine IP veröffentlicht ist, die K8s-API paginiert eine unvollständige Liste — und ein Node, der auf die erste Antwort hin joint, bildet einen Cluster aus seiner eigenen Teilsicht.

Wenn deine Nodes gemeinsam mit dynamischen Adressen starten, konsumiere lookup() nicht direkt. Der Cluster-Bootstrap umschließt jeden Provider von dieser Seite: er pollt, bis sich die zurückgegebene Menge nicht mehr ändert, und lässt dann genau einen Node den Cluster bilden. Die Provider hier bleiben exakt wie sie sind — Bootstrap ist eine Phase darüber, kein Ersatz.

Der Receptionist beantwortet: “Welche Actors sind unter diesem Service Key registriert, irgendwo im Cluster?”

import { Find, ReceptionistId, Register, ServiceKey } from 'actor-ts';
// Auf node-A:
const receptionist = system.extension(ReceptionistId).start(cluster);
const key = ServiceKey.of<MyMessage>('my-service');
receptionist.tell(new Register(key, myActor));
// Auf node-B — Find antwortet mit einem Listing (dessen .refs sind die
// passenden Actors über den ganzen Cluster) an den als Reply-Ziel
// angegebenen Actor:
receptionist.tell(new Find(key, replyTo));

Ein cluster-weites Service-Registry. Jeder Node hostet einen Receptionist-Actor; Registrierungen sind lokal autoritativ; Peers erfahren über Gossip von fremden Registrierungen.

Nimm den Receptionist, wenn:

  • Actor-Location ist dynamisch — Actors kommen und gehen, und Consumer sollen keine Pfade hartkodieren.
  • Mehrere Actors teilen sich einen Service — N Worker registrieren sich alle unter demselben Key; Consumer sehen sie alle.
  • Cross-Node-Discovery wird gebraucht — einen Actor finden, unabhängig davon, welcher Node ihn hostet.

Siehe Receptionist für die vollständige API.

FrageWerkzeug
Wie findet DIESER Node Peers zum Joinen?Seed Provider
Wie findet ein Actor zur Laufzeit einen anderen Actor?Receptionist
Wie routet ein HTTP-Loadbalancer Requests an meine Pods?K8s Service (nicht das hier)
Wie entdeckt ein Service-Mesh-Proxy Backends?Service Mesh (nicht das hier)

Die Discovery des Frameworks ist für Cluster-Internes. Externer Service Discovery (Consul, Eureka, Service Meshes) ist Sache deiner Infrastruktur; actor-ts holt sich daraus beim Start seine Peer-Adressen, beteiligt sich sonst aber nicht.

Ein typisches K8s-Deployment:

// 1. Seed Discovery — wie dieser Pod beim Start Peers findet
const kubernetesApiSeedProviderOptions = KubernetesApiSeedProviderOptions.create()
.withNamespace(process.env.K8S_NAMESPACE!)
.withServiceName('actor-ts')
.withSystemName('my-app')
.withPort(2552);
const addresses = await new KubernetesApiSeedProvider(
kubernetesApiSeedProviderOptions,
).lookup();
const seeds = addresses.map((address) => address.toString());
const clusterOptions = ClusterOptions.create()
.withHost(host)
.withPort(port)
.withSeeds(seeds);
await Cluster.join(system, clusterOptions);
// 2. Receptionist — für Runtime-Actor-Lookup
const receptionist = system.extension(ReceptionistId).start(cluster);
// Den API-Actor dieses Pods registrieren:
receptionist.tell(new Register(
ServiceKey.of<ApiMessage>('api'),
system.spawn(ApiActor, 'api'),
));
// Andere Actors finden ihn — das Listing wird an das Reply-Ziel geliefert:
receptionist.tell(new Find(ServiceKey.of<ApiMessage>('api'), replyTo));

Seed Provider laufen einmal; der Receptionist läuft kontinuierlich.