2016-07-11 23 views
2

Ich schreibe einen Server in Erlang, der sehr viele Nachrichten (Datensätze) verarbeitet. Jede Nachricht hat ein Tag (Atom) wie eine Benutzer-ID.Routing von Nachrichten an PIDs in Erlang

Der "Router" erstellt einen dedizierten permanenten Prozess für diesen Benutzer (um Nachrichten für einige Minuten zu sammeln, bevor sie gespeichert und weitergegeben werden), wenn ein solcher Prozess nicht existiert. Andernfalls wird es als Nachricht an das vorhandene Prozesspostfach übergeben.

Das Problem ist die Buchhaltung einer Routing-Tabelle.

Ich könnte denken, Serialisierung des Routers, jede Nachricht wird in ETS-Lookup zu finden, eine PID von userId und schließlich Spawn und ETS einfügen, wenn es nicht beendet. Aber das wurde in wenigen Sekunden verstopft.

Eine Alternative ist es, einen Prozess direkt zu routen, um jede Nachricht zu routen, aber das könnte zu einem Race-Zustand führen, wenn einige Nachrichten an einen einzelnen Benutzer in naher Folge eintraten und ihre entsprechende PID in ETS nicht gefunden und dauerhaft erzeugt wurden Prozesse. Nachrichten gehen verloren und nur der letzte erzeugte Prozess wird gültig sein (andere in der ETS überschreiben), wo die anderen inaktiv und nicht geparkt werden.

Ich denke auch alles falsch. Gibt es einen besseren Weg, dieses Szenario zu bewältigen?

Antwort

1

Es ist ein häufiges Muster, einen Prozess (einen Server) pro Benutzer zu haben, genau wie Sie es vorschlagen.

Manchmal, wenn das verwendete Protokoll es erlaubt, anstatt die Nachrichten an einen "Benutzer" -Prozess von einem Server zu leiten, der alle Benutzer überwacht, wird vor jeder Verbindung ein neuer Prozess erzeugt, der auf eine neue Benutzerverbindung wartet (wartet) anfordern. Wenn eine Anfrage eintrifft, wird ein neuer wartender Prozess erzeugt, und der aktuelle verwaltet die komplette Sitzung mit dem neuen Benutzer (siehe learyousomeerlang: a bucket of socket für ein ausführliches Beispiel).

+0

Genau. Jetzt habe ich einen Prozess pro Nachricht implementiert, um das Routing durchzuführen. und dann einen Prozess pro Benutzer, um diese Nachrichten zu empfangen. und der gen_server führt das Laichen und die Buchhaltung von Benutzerprozessen durch. Nachdem ich Ets Optionen gemäß A. Sarid Antwort gesetzt habe, funktionierte die Lösung gut mit echtem Traffic. – Aus

+0

Sie haben auch den Benutzer Prozess haben die Listenting, so dass kein Routing erforderlich ist. Dies ist in diesem Fall nicht möglich, da die Nachrichten vom selben RPC in Form von Datensätzen kommen. wäre fantastisch, wenn die Nachrichtenquelle einen Socket/PID pro Benutzer hat. – Aus

1

Ihre erste Lösung klingt für diesen Fall richtig. Für mich klingt es nicht richtig, einen Prozess für jede Nachricht zu starten, die Sie erhalten, wenn Sie viele Nachrichten haben. ETS ist schnell und sollte in der Lage sein, große Datenmengen zu verarbeiten.

Sie könnten erwägen, Erlang OTP gen_server zu verwenden. Sie können mehr darüber lesen here, here und here.

Wenn Sie von vielen Prozessen aus auf die ETS zugreifen möchten, sollten Sie die Optionen {read_concurrency, true} und {read_concurrency, true} berücksichtigen. Lesen Sie mehr darüber und here.

+1

Danke. Ich benutze otp gen_server. Ich werde read_concurrency verwenden, wie Sie erwähnen. und wird eine Variante der ersten Lösung implementieren. Ich spawn einen Prozess pro Nachricht nur für die ETS-Lookup. und falls nicht gefunden, wird gen_server einen neuen generierten Arbeiter zur Verfügung stellen und die ETS-Tabelle aktualisieren. Ich werde zurückkommen, um dir zu erzählen, wie es gelaufen ist. – Aus