Vor einigen Tagen fand die statt. Die Leute von JUG.ru Group hatten Traumsprecher eingeladen (Leslie Lamport! Cliff Click! Martin Kleppmann!) und widmeten zwei Tage den Themen verteilte Systeme und Berechnungen. Kontur war einer der drei Partner der Konferenz. Wir hatten am Stand GesprÀche, erzÀhlten von unseren verteilten Speicherlösungen, spielten Bingo und lösten Aufgaben.
Dieser Beitrag ist eine Analyse der Aufgaben am Kontur-Stand, verfasst von einem der Autoren. Wer bei Hydra war, hat einen Grund, schöne Erinnerungen wachzurufen. Wer nicht da war, hat die Chance, seine grauen Zellen zu aktivieren. big O-Notation.
Es gab sogar Teilnehmer, die das Flipchart in Folien zerlegten, um ihre Lösung aufzuschreiben. Ich mache keinen Scherz â sie haben ein solches Stapel Papier zur ĂberprĂŒfung abgegeben:

Es gab insgesamt drei Aufgaben:
- zum WĂ€hlen von Replikaten nach Gewicht zur Lastenverteilung
- zur Sortierung der Ergebnisse einer Abfrage an einer In-Memory-Datenbank
- zur Ăbertragung des Zustands in einem verteilten System mit Ringtopologie
Aufgabe 1. ClusterClient
Es war erforderlich, einen Algorithmus fĂŒr die effektive Auswahl von K aus N gewichteten Replikaten eines verteilten Systems vorzuschlagen:
Ihr Team hat die Aufgabe, eine Client-Bibliothek fĂŒr einen massiv verteilten Cluster von N Knoten zu entwickeln. Diese Bibliothek verfolgt verschiedene Metadaten, die mit den Knoten verbunden sind (z. B. deren Latenzen, 4xx/5xx-Antwortraten usw.) und weist ihnen FlieĂkomma-Gewichte W1..WN zu. Um die gleichzeitige AusfĂŒhrungsstrategie zu unterstĂŒtzen, sollte die Bibliothek in der Lage sein, K von N Knoten zufĂ€llig auszuwĂ€hlen â die Auswahlchance sollte proportional zum Gewicht eines Knotens sein.
Schlagen Sie einen Algorithmus vor, um Knoten effizient auszuwÀhlen. SchÀtzen Sie die rechnerische KomplexitÀt mit der Big-O-Notation.
Warum ist alles auf Englisch?
Weil in dieser Form die Teilnehmer der Konferenz damit konfrontiert wurden und weil Englisch die offizielle Sprache von Hydra war. So sahen die Aufgabenstellungen aus:

Nehmen Sie Papier und Stift, denken Sie nach, eilen Sie nicht sofort zu den Spoilern đ
Lösungsanalyse (Video)
Beginn um 5:53, insgesamt 4 Minuten:

So haben die Jungs mit dem Flipchart ihre Lösung prÀsentiert:

Lösungsanalyse (Text)
Eine mögliche Lösung besteht darin, die Gewichte aller Replikate zu summieren, eine Zufallszahl zwischen 0 und der Summe aller Gewichte zu generieren und dann das i-te Replikat auszuwĂ€hlen, sodass die Summe der Gewichte der Replikate von 0 bis (i-1) kleiner ist als die Zufallszahl, wĂ€hrend die Summe der Gewichte von 0 bis i gröĂer ist. Auf diese Weise kann ein Replikat ausgewĂ€hlt werden. Um das nĂ€chste auszuwĂ€hlen, muss das gesamte Verfahren wiederholt werden, ohne das gewĂ€hlte Replikat zu berĂŒcksichtigen. Bei diesem Algorithmus betrĂ€gt die KomplexitĂ€t der Auswahl eines Replikats O(N), wĂ€hrend die KomplexitĂ€t fĂŒr die Auswahl von K Replikaten O(N·K) ~ O(NÂČ) betrĂ€gt.

Eine quadratische KomplexitĂ€t ist problematisch, doch sie lĂ€sst sich verbessern. DafĂŒr bauen wir fĂŒr die Gewichtsummen. Es entsteht ein Baum mit einer Tiefe von lg N, dessen BlĂ€tter die Gewichte der Replikate darstellen, wĂ€hrend die anderen Knoten die Teilsummen bis zur Gesamtsumme aller Gewichte im Wurzelknoten enthalten. AnschlieĂend generieren wir eine Zufallszahl von 0 bis zur Gesamtsumme der Gewichte, finden das i-te Replikat, entfernen es aus dem Baum und wiederholen das Verfahren, um die verbleibenden Replikate zu suchen. Mit diesem Algorithmus wird die KomplexitĂ€t zum Erstellen des Baums O(N), die KomplexitĂ€t zum Finden des i-ten Replikats und dessen Entfernung aus dem Baum O(lg N), und die KomplexitĂ€t zur Auswahl von K Replikaten betrĂ€gt O(N + K lg N) ~ O(N lg N).

Die linear-logarithmische KomplexitĂ€t ist angenehmer als die quadratische, insbesondere fĂŒr groĂe K.
Genau dieser Algorithmus der ClusterClient-Bibliothek aus dem Projekt ââ. (Dort wird der Baum in O(N lg N) aufgebaut, aber dies hat keinen Einfluss auf die endgĂŒltige KomplexitĂ€t des Algorithmus.)
Aufgabe 2. Zebra
Es sollte ein Algorithmus zur effizienten Sortierung von Dokumenten im Speicher nach einem beliebigen, nicht indizierten Feld vorgeschlagen werden:
Ihr Team hat die Aufgabe, eine partitionierte, im Speicher befindliche Dokumentendatenbank zu entwickeln. Eine hĂ€ufige Arbeitslast wĂ€re die Auswahl der besten N Dokumente, die nach einem beliebigen (nicht indizierten) numerischen Feld aus einer Sammlung der GröĂe M (normalerweise N < 100 << M) sortiert sind. Eine etwas weniger hĂ€ufige Arbeitslast wĂ€re die Auswahl der besten N, nachdem die obersten S Dokumente ĂŒbersprungen wurden (S ~ N).
Schlagen Sie einen Algorithmus vor, um solche Anfragen effizient auszufĂŒhren. SchĂ€tzen Sie die BerechnungskomplexitĂ€t mithilfe der groĂen O-Notation fĂŒr den Durchschnitts- und den schlimmsten Fall.
Lösungsanalyse (Video)
Beginn bei 34:50, insgesamt 6 Minuten:

Lösungsanalyse (Text)
Die Lösung liegt auf der Hand: Alle Dokumente sortieren (zum Beispiel mit ), dann N+S Dokumente nehmen. In diesem Fall betrĂ€gt die durchschnittliche SortierkomplexitĂ€t O(M lg M), im schlimmsten Fall O(MÂČ).
Offensichtlich ist es ineffizient, alle M Dokumente zu sortieren, nur um dann einen kleinen Teil davon zu entnehmen. Um nicht alle Dokumente zu sortieren, eignet sich der Algorithmus , der N+S benötigte Dokumente auswÀhlt (diese können mit jedem Algorithmus sortiert werden). In diesem Fall wird die KomplexitÀt im Durchschnitt auf O(M) reduziert, wÀhrend der schlimmste Fall gleich bleibt.
Es kann jedoch noch effizienter sein â nutzen Sie den Algorithmus . In diesem Fall werden die ersten N+S Dokumente in einem Min- oder Max-Heap (je nach Sortierrichtung) abgelegt, und jedes nachfolgende Dokument wird mit der Wurzel des Baumes verglichen, wo das aktuell minimale oder maximale Dokument enthalten ist, und wird bei Bedarf in den Baum hinzugefĂŒgt. In diesem Fall ist die KomplexitĂ€t im schlimmsten Fall, wenn der Baum stĂ€ndig neu aufgebaut werden muss â O(M lg M), die durchschnittliche KomplexitĂ€t bleibt bei O(M), wie beim Einsatz von Quickselect.
Heap Streaming erweist sich jedoch als effizienter, da in der Praxis die meisten Dokumente verworfen werden können, ohne den Heap neu zu strukturieren, nach einem einzigen Vergleich mit dessen Wurzelelement. Diese Sortierung ist in der dokumentenbasierten In-Memory-Datenbank Zebra implementiert, die von Kontur entwickelt und genutzt wird.
Aufgabe 3. Zustandswechsel
Es sollte der effizienteste Algorithmus fĂŒr Zustandsverschiebungen vorgeschlagen werden:
Ihr Team hat die Aufgabe, einen eleganten ZustandsĂŒbergmechanismus fĂŒr ein verteiltes Cluster von N Knoten zu entwickeln. Der Zustand des i-ten Knotens sollte an den (i+1)-ten Knoten ĂŒbertragen werden, wĂ€hrend der Zustand des N-ten Knotens an den ersten Knoten ĂŒbergeben werden soll. Die einzige unterstĂŒtzte Operation ist der Zustandswechsel, bei dem zwei Knoten ihre ZustĂ€nde atomar austauschen. Es ist bekannt, dass ein Zustandswechsel M Millisekunden dauert. Jeder Knoten kann zu jedem Zeitpunkt an einem einzigen Zustandswechsel teilnehmen.
Wie lange dauert es, die ZustĂ€nde aller Knoten in einem Cluster zu ĂŒbertragen?
Lösungsanalyse (Text)
Die Lösung auf der OberflĂ€che: den Zustand des ersten und zweiten Elements tauschen, dann den ersten mit dem dritten, dann mit dem vierten und so weiter. Nach jedem Tausch wird der Zustand eines Elements an der richtigen Position landen. Es mĂŒssen O(N) Vertauschungen vorgenommen werden, was O(N·M) Zeit in Anspruch nehmen wird.

Lineare Zeit ist zu lang, daher kann man die ZustĂ€nde der Elemente paarweise tauschen: den ersten mit dem zweiten, den dritten mit dem vierten und so weiter. Nach jedem Tausch wird der Zustand jedes zweiten Elements an der richtigen Position landen. Es mĂŒssen O(lg N) Vertauschungen vorgenommen werden, was O(M lg N) Zeit in Anspruch nehmen wird.

Es ist jedoch möglich, den Shift noch effizienter zu gestalten â nicht in linearer, sondern in konstanter Zeit. DafĂŒr muss im ersten Schritt der Zustand des ersten Elements mit dem letzten, des zweiten mit dem vorletzten und so weiter getauscht werden. Der Zustand des letzten Elements befindet sich dann an der gewĂŒnschten Position. Jetzt muss der Zustand des zweiten Elements mit dem letzten, des dritten mit dem vorletzten und so weiter getauscht werden. Nach dieser Runde des Tauschens befinden sich alle Elemente an den richtigen Positionen. Insgesamt werden O(2M) ~ O(1) TauschvorgĂ€nge durchgefĂŒhrt.

Eine solche Lösung wird einen Mathematiker, der sich noch erinnert, dass eine Drehung die Komposition zweier Achsenspiegelungen ist, nicht ĂŒberraschen. Ăbrigens lĂ€sst sie sich trivial fĂŒr einen Shift nicht nur um eine, sondern um K < N Positionen verallgemeinern. (Schreiben Sie in die Kommentare, wie genau.)
Hat Ihnen diese Aufgaben gefallen? Kennen Sie andere Lösungen? Teilen Sie sie in den Kommentaren.
Hier sind einige nĂŒtzliche Links zum Schluss:
- erfahren Sie mehr ĂŒber bei Kontur
- sehen Sie sich die Aufzeichnungen interner ĂŒber verteilte Systeme
- sehen Sie sich die Videovortragsreihe «»
- abonnieren Sie unseren
Quelle: habr.com
