Zum Inhalt springen
Deutsch

Serialization im Überblick

Zwei Szenarien erfordern es, JS-Werte in Bytes zu verwandeln:

  1. Cluster-Wire — ein tell an einen Remote-Actor braucht die Nachricht serialisiert für die TCP-Übertragung.
  2. Persistenz — Events / Snapshots / Durable State auf der Platte oder im Journal gespeichert.

Das Serializer-Interface des Frameworks ist die Abstraktion. Zwei eingebaute werden mitgeliefert:

SerializerFormatWann
JsonSerializerJSONDefault. Menschenlesbar debugbar, weit verbreitet.
CborSerializerCBOR (RFC 8949)Kompakt, binärnativ, schneller.

Plus ein Extension-Point: implementiere Serializer<T> für Protobuf, Avro, MessagePack usw.

Sender-Seite:
tell(remoteRef, msg)
→ SerializationExtension wählt Serializer für typeof(msg)
→ serializer.toBinary(msg) → Uint8Array
→ mit serializerId + manifest + bytes umhüllt
→ Cluster-Transport sendet über die Leitung
Empfänger-Seite:
Cluster-Transport empfängt Bytes
→ SerializationExtension wählt Serializer per serializerId
→ serializer.fromBinary(bytes, manifest) → rekonstruierter Wert
→ an onReceive des Actors ausgeliefert

Die serializerId + das manifest sagen dem Empfänger, welchen Serializer er verwenden soll + welcher Typ zu rekonstruieren ist.

interface Serializer<T = unknown> {
readonly id: number; // pro Serializer eindeutig
readonly name: string; // menschenlesbar
includesManifest: boolean;
manifest(obj: T): string; // Type-Tag
toBinary(obj: T): Uint8Array;
fromBinary(bytes: Uint8Array, manifest: string): T;
}

Kleine Oberfläche — encoden, decoden, identifizieren. Die SerializationExtension des Frameworks mappt Klassen auf Serializer (über bind); bei der Serialisierung schlägt die Extension nach, welcher Serializer für die Klasse des Werts zu verwenden ist.

const system = ActorSystem.create('my-app');
// → JsonSerializer als Default registriert
// → Jeder Wert wird als JSON serialisiert, solange kein spezifischer Serializer gebunden ist

Wenn du nichts tust, sind die Bytes jedes Wertes JSON. Plain- Objekte, Arrays, Strings, Zahlen — alles funktioniert. Klasseninstanzen werden als Plain-Objekte serialisiert (Methoden gehen verloren).

AspektJSONCBOR
Wire-GrößeGrößer~20–40 % kleiner
GeschwindigkeitLangsamer als CBOR für BinärdatenSchneller
DebuggingTrivial (Text)Braucht ein CBOR-fähiges Tool
Binäre Felderbase64-encoded (verschwenderisch)Native Binärform
Library-SupportUniversalSolide im JS-Land

Für die meisten Apps ist JSON okay — der Perf-Unterschied zählt nicht und die Debugbarkeit ist wertvoll.

Für bandbreitenkritische Fälle (großer Cluster, viele Events, IoT-artige Payloads) gewinnt CBOR spürbar.

Siehe JsonSerializer + CborSerializer für Details.

Für Protobuf / Avro / usw. implementiere Serializer<T> und registriere:

import { SerializationExtensionId } from 'actor-ts';
const ext = system.extension(SerializationExtensionId);
ext.bind(MyEvent, new ProtobufSerializer<MyEvent>(MyEventSchema));

Jetzt verwendet jeder MyEvent-Wert Protobuf für die Serialisierung über die Leitung / ins Journal. Andere Typen nutzen weiterhin JSON.

Siehe Eigene Serializer für das volle Setup.

Der Default-JSON-Serializer behandelt:

  • Plain-Objekte ({ a: 1, b: 'two' }).
  • Arrays.
  • Strings, Zahlen, Booleans, null.
  • Verschachtelte Kombinationen davon.

Lässt sich nicht serialisieren:

  • Funktionen / Closures (keine Methoden-Überlebensgarantie).
  • Klasseninstanzen mit Methoden (Methoden verloren; Datenfelder überleben).
  • Map / Set (von JSON als {} stringified).
  • Date (geht über String-Round-Trip; Typinformation verloren).
  • BigInt (wirft).
  • Symbole (still verworfen).

CBOR kann ein paar mehr (binäre Uint8Array nativ, Map als echte Map), aber keine Funktionen.

Für komplexe Typen konvertier vor dem Senden in Plain-Objekte:

// ✗
ref.tell({ when: new Date() });
// ✓
ref.tell({ when: Date.now() });
1. Cluster-Wire — jedes Cross-Node-tell.
2. PersistentActor.persist(event) — Events ins Journal.
3. DurableStateActor.persist(state) — State in den Store.
4. Snapshot-Writes — Snapshots in den Snapshot-Store.
5. DistributedData — replizierter State über den Cluster.

In-Process-Tells serialisieren nicht — der Empfänger bekommt die exakte In-Memory-Referenz. Serialisierung passiert nur an Prozess- / Disk- / Cluster-Grenzen.