Citymobil - ein Handbuch zur Verbesserung der Verfügbarkeit bei Unternehmenswachstum für Startups. Teil 3



Dies ist der nächste Artikel der Reihe, der beschreibt, wie wir unsere Serviceverfügbarkeit in Citymobil erhöhen (Sie können die vorherigen Teile hier und hier lesen). In weiteren Abschnitten werde ich ausführlich auf die Unfälle und Ausfälle eingehen. Aber lassen Sie mich zuerst etwas hervorheben, über das ich im ersten Artikel hätte sprechen sollen, aber nicht. Ich habe es aus dem Feedback meiner Leser herausgefunden. Dieser Artikel gibt mir die Möglichkeit, dieses lästige Manko zu beheben.

1. Prolog


Ein Leser stellte mir eine sehr faire Frage: "Was ist so kompliziert am Backend des Ride-Hagel-Dienstes?" Das ist eine gute Frage. Letzten Sommer habe ich mir genau diese Frage gestellt, bevor ich bei Citymobil angefangen habe. Ich dachte: "Das ist nur ein Taxiservice mit seiner Drei-Tasten-App." Wie schwer könnte das sein? Es wurde ein sehr Hightech-Produkt. Um ein wenig zu klären, wovon ich spreche und was für eine riesige technologische Sache es ist, werde ich Ihnen einige Produktanweisungen bei Citymobil erzählen:

  • Preisgestaltung. Unser Preisteam befasst sich zu jedem Zeitpunkt und zu jedem Zeitpunkt mit dem Problem des besten Fahrpreises. Der Preis wird durch die Vorhersage des Angebots- und Nachfragegleichgewichts auf der Grundlage von Statistiken und einigen anderen Daten bestimmt. Dies alles wird durch einen komplizierten und sich ständig weiterentwickelnden Service erledigt, der auf maschinellem Lernen basiert. Das Preisteam befasst sich auch mit der Implementierung verschiedener Zahlungsmethoden, zusätzlichen Gebühren nach Abschluss einer Reise, Rückbuchungen, Abrechnung, Interaktion mit Partnern und Fahrern.
  • Versand von Bestellungen. Welches Auto vervollständigt die Bestellung des Kunden? Zum Beispiel ist eine Option zur Auswahl des nächstgelegenen Fahrzeugs im Hinblick auf die Maximierung einer Anzahl von Fahrten nicht die beste. Eine bessere Option besteht darin, Autos und Kunden so zusammenzubringen, dass die Anzahl der Fahrten unter Berücksichtigung der Wahrscheinlichkeit, dass dieser bestimmte Kunde seine Bestellung unter diesen besonderen Umständen storniert (weil die Wartezeit zu lang ist) und der Wahrscheinlichkeit, dass dieser bestimmte Fahrer die Bestellung storniert oder sabotiert, maximiert wird ( zB weil der Abstand zu groß oder der Preis zu klein ist).
  • Geo. Alles über das Suchen und Vorschlagen von Adressen, Abholpunkte, Anpassungen der geschätzten Ankunftszeit (unsere Kartenlieferpartner liefern uns nicht immer genaue ETA-Informationen unter Berücksichtigung des Verkehrs), die Erhöhung der direkten und umgekehrten Geokodierungsgenauigkeit und die Genauigkeit der Ankunftspunkte des Autos. Es gibt viele Daten, viele Analysen, viele auf maschinellem Lernen basierende Dienste.
  • Betrugsbekämpfung Der Unterschied in den Reisekosten für einen Passagier und einen Fahrer (z. B. bei Kurzreisen) schafft einen wirtschaftlichen Anreiz für Eindringlinge, die versuchen, unser Geld zu stehlen. Der Umgang mit Betrug ähnelt dem Umgang mit E-Mail-Spam - sowohl Präzision als auch Rückruf sind sehr wichtig. Wir müssen die maximale Anzahl von Betrugsfällen blockieren (Rückruf), aber gleichzeitig können wir keine guten Benutzer für Betrugsfälle halten (Präzision).
  • Das Team für Fahreranreize überwacht die Entwicklung von allem, was die Nutzung unserer Plattform durch Fahrer und die Loyalität der Fahrer aufgrund verschiedener Arten von Anreizen erhöhen kann. Schließen Sie beispielsweise X-Trips ab und erhalten Sie zusätzliches Y-Geld. Oder kaufen Sie eine Schicht für Z und fahren Sie ohne Provision herum.
  • Treiber-App-Backend. Liste der Bestellungen, Bedarfskarte (sie zeigt einem Fahrer, wohin er gehen muss, um seine Gewinne zu maximieren), Statusänderungen, Kommunikationssystem mit den Fahrern und viele andere Dinge.
  • Client-App-Backend (dies ist wahrscheinlich der offensichtlichste Teil und wird normalerweise als "Taxi-Backend" bezeichnet): Auftragserteilung, Informationen zum Bestellstatus, Bereitstellung der Bewegung kleiner Autos auf der Karte, Tipps-Backend usw.

Dies ist nur die Spitze des Eisbergs. Es gibt viel mehr Funktionen. Es gibt einen riesigen Unterwasserteil des Eisbergs hinter einer scheinbar recht einfachen Oberfläche.

Und jetzt gehen wir zurück zu den Unfällen. Die sechsmonatige Protokollierung der Unfallhistorie führte zu folgender Klassifizierung:

  • fehlerhafte Version: 500 interne Serverfehler;
  • fehlerhafte Version: Datenbanküberlastung;
  • unglückliche manuelle Systembetriebsinteraktion;
  • Ostereier;
  • externe Gründe;
  • schlechte Version: defekte Funktionalität.

Im Folgenden werde ich detailliert auf die Schlussfolgerungen eingehen, die wir in Bezug auf unsere häufigsten Unfalltypen gezogen haben.

2. Fehlerhafte Version: 500 interne Serverfehler


Unser Backend ist größtenteils in PHP geschrieben - einer schwach typisierten interpretierten Sprache. Wir würden einen Code veröffentlichen, der aufgrund des Fehlers im Klassen- oder Funktionsnamen abgestürzt ist. Und das ist nur ein Beispiel, wenn 500 Fehler auftreten. Dies kann auch durch einen logischen Fehler im Code verursacht werden. falscher Zweig wurde freigegeben; Ordner mit dem Code wurde versehentlich gelöscht; temporäre Artefakte, die zum Testen benötigt wurden, wurden im Code belassen; Die Tabellenstruktur wurde nicht gemäß dem Code geändert. Die erforderlichen Cron-Skripte wurden nicht neu gestartet oder gestoppt.

Wir haben dieses Problem schrittweise angegangen. Die durch eine schlechte Veröffentlichung verlorenen Fahrten sind offensichtlich proportional zur Produktionszeit. Daher sollten wir unser Bestes geben und sicherstellen, dass die Produktionszeit für fehlerhafte Veröffentlichungen so gering wie möglich gehalten wird. Jede Änderung im Entwicklungsprozess, die die durchschnittliche Betriebszeit für fehlerhafte Versionen sogar um 1 Sekunde verkürzt, ist gut für das Geschäft und muss implementiert werden.

Eine schlechte Veröffentlichung und in der Tat jeder Unfall in der Produktion hat zwei Zustände, die wir als "passive Stufe" und "aktive Stufe" bezeichnet haben. Während der passiven Phase ist uns noch kein Unfall bekannt. Die aktive Phase bedeutet, dass wir bereits wissen. Ein Unfall beginnt im passiven Stadium; Mit der Zeit geht es in die aktive Phase - dann erfahren wir es und beginnen, es anzugehen: Zuerst diagnostizieren wir es und dann - beheben wir es.

Um die Dauer eines Ausfalls zu verkürzen, müssen wir die Dauer der aktiven und passiven Phasen verkürzen. Das gleiche gilt für eine schlechte Veröffentlichung, da dies als eine Art Ausfall angesehen wird.

Wir haben begonnen, den Verlauf der Fehlerbehebung bei Ausfällen zu analysieren. Schlechte Veröffentlichungen, die wir hatten, als wir gerade mit der Analyse der Unfälle begannen, verursachten durchschnittlich 20-25 Minuten Ausfallzeiten (vollständig oder teilweise). Die passive Phase dauert normalerweise 15 Minuten und die aktive 10 Minuten. Während der passiven Phase erhielten wir Benutzerbeschwerden, die von unserem Callcenter bearbeitet wurden. und nach einer bestimmten Schwelle würde sich das Callcenter in einem Slack-Chat beschweren. Manchmal beschwerte sich einer unserer Kollegen darüber, kein Taxi bekommen zu können. Die Beschwerde des Kollegen würde auf ein ernstes Problem hinweisen. Nachdem eine fehlerhafte Version in die aktive Phase eingetreten war, begannen wir mit der Problemdiagnose und analysierten die letzten Versionen, verschiedene Grafiken und Protokolle, um die Ursache des Unfalls herauszufinden. Nach dem Ermitteln der Ursachen würden wir ein Rollback durchführen, wenn die fehlerhafte Version die neueste war, oder eine neue Bereitstellung mit dem zurückgesetzten Commit durchführen.

Dies ist der schlechte Release-Handling-Prozess, den wir verbessern wollten.

Passive Etappe: 20 Minuten.
Aktive Phase: 10 Minuten.

3. Passive Stufenreduzierung


Zunächst stellten wir fest, dass bei einer fehlerhaften Veröffentlichung mit 500 Fehlern festgestellt werden konnte, dass ein Problem auch ohne Beschwerden der Benutzer aufgetreten war. Glücklicherweise wurden alle 500 Fehler in New Relic protokolliert (dies ist eines der von uns verwendeten Überwachungssysteme), und wir mussten lediglich SMS- und IVR-Benachrichtigungen über das Überschreiten einer bestimmten Anzahl von 500 Fehlern hinzufügen. Die Schwelle würde im Laufe der Zeit kontinuierlich gesenkt.

Der Prozess in Zeiten eines Unfalls würde so aussehen:

  1. Ein Ingenieur stellt eine Version bereit.
  2. Die Freilassung führt zu einem Unfall (massive Menge von 500s).
  3. Textnachricht wird empfangen.
  4. Ingenieure und Entwickler beginnen, sich damit zu befassen. Manchmal nicht sofort, aber in 2-3 Minuten: Textnachrichten können sich verzögern, Telefonsounds sind möglicherweise ausgeschaltet. und natürlich kann die Gewohnheit der sofortigen Reaktion nach Erhalt dieses Textes nicht über Nacht gebildet werden.
  5. Die unfallaktive Phase beginnt und dauert die gleichen 10 Minuten wie zuvor.

Infolgedessen würde die aktive Phase des Unfalls "Fehlerhafte Version: 500 interne Serverfehler" 3 Minuten nach einer Veröffentlichung beginnen. Daher wurde die passive Stufe von 15 Minuten auf 3 Minuten reduziert.

Ergebnis:

Passive Etappe: 3 Minuten.
Aktive Phase: 10 Minuten.

4. Weitere Reduzierung einer passiven Stufe


Obwohl die passive Phase auf 3 Minuten reduziert wurde, hat es uns immer noch mehr gestört als die aktive, da wir während der aktiven Phase etwas unternommen haben, um das Problem zu beheben, und während der passiven Phase war der Service ganz oder teilweise ausgefallen, und wir waren absolut ahnungslos.

Um die passive Phase weiter zu reduzieren, haben wir uns entschlossen, nach jeder Veröffentlichung 3 Minuten der Zeit unserer Ingenieure zu opfern. Die Idee war sehr einfach: Wir haben Code bereitgestellt und drei Minuten später nach 500 Fehlern in New Relic, Sentry und Kibana gesucht. Sobald wir dort ein Problem sahen, gingen wir davon aus, dass es sich um Code handelt, und begannen mit der Fehlerbehebung.

Wir haben diesen Zeitraum von drei Minuten aufgrund von Statistiken gewählt: Manchmal traten die Probleme innerhalb von 1-2 Minuten in Diagrammen auf, jedoch nie später als in 3 Minuten.

Diese Regel wurde zu den Do's und Dont's hinzugefügt. Anfangs wurde es nicht immer befolgt, aber im Laufe der Zeit gewöhnten sich unsere Ingenieure an diese Regel wie an die Grundhygiene: Das morgendliche Zähneputzen dauert auch einige Zeit, ist aber immer noch notwendig.

Infolgedessen wurde die passive Stufe auf 1 Minute reduziert (die Grafiken waren manchmal noch zu spät). Es reduzierte auch die aktive Stufe als schönen Bonus. Denn jetzt würde sich ein Ingenieur dem vorbereiteten Problem stellen und bereit sein, ihren Code sofort zurückzusetzen. Auch wenn es nicht immer geholfen hat, da das Problem möglicherweise durch eine Version verursacht wurde, die gleichzeitig von jemand anderem bereitgestellt wurde. Die aktive Phase reduzierte sich jedoch im Durchschnitt auf fünf Minuten.

Ergebnis:

Passive Etappe: 1 Minuten.
Aktive Phase: 5 Minuten.

5. Weitere Reduktion einer aktiven Stufe


Wir waren mehr oder weniger zufrieden mit der 1-minütigen passiven Phase und begannen darüber nachzudenken, wie wir eine aktive Phase weiter reduzieren können. Zunächst konzentrierten wir uns auf die Geschichte der Ausfälle (dies ist zufällig ein Eckpfeiler in einem Gebäude unserer Verfügbarkeit!) Und stellten fest, dass wir in den meisten Fällen eine Veröffentlichung nicht sofort zurücksetzen, da wir es nicht wissen Für welche Version wir uns entscheiden sollten: Es gibt viele parallele Releases. Um dieses Problem zu lösen, haben wir die folgende Regel eingeführt (und in die Do's und Dont's geschrieben): Unmittelbar vor einer Veröffentlichung sollte jeder in einem Slack-Chat darüber informiert werden, was Sie bereitstellen möchten und warum. Im Falle eines Unfalls sollte man schreiben: "Unfall, nicht einsetzen!" Wir haben auch damit begonnen, diejenigen, die den Chat nicht lesen, per SMS über die Veröffentlichungen zu informieren.

Diese einfache Regel reduzierte die Anzahl der Freisetzungen während eines laufenden Unfalls drastisch, verkürzte die Dauer der Fehlerbehebung und reduzierte die aktive Phase von 5 Minuten auf 3 Minuten.

Ergebnis:

Passive Etappe: 1 Minuten.
Aktive Phase: 3 Minuten.

6. Noch größere Reduzierung einer aktiven Stufe


Trotz der Tatsache, dass wir im Chat Warnungen bezüglich aller Veröffentlichungen und Unfälle veröffentlicht haben, traten manchmal immer noch Rennbedingungen auf - jemand schrieb über eine Veröffentlichung und ein anderer Ingenieur war in diesem Moment im Einsatz; oder ein Unfall ist passiert, wir haben darüber im Chat geschrieben, aber jemand hat gerade ihren Code bereitgestellt. Solche Umstände verlängerten die Fehlerbehebung. Um dieses Problem zu lösen, haben wir ein automatisches Verbot paralleler Releases implementiert. Es war eine sehr einfache Idee: Für 5 Minuten nach jeder Veröffentlichung verbietet das CI / CD-System eine andere Bereitstellung für alle außer der neuesten Release-Autorin (damit sie bei Bedarf einen Rollback durchführen oder Hotfix bereitstellen kann) und mehreren erfahrenen Entwicklern (in Notfall). Darüber hinaus verhindert das CI / CD-System Bereitstellungen in Zeiten von Unfällen (dh vom Eintreffen der Benachrichtigung über den Beginn des Unfalls bis zum Eintreffen der Benachrichtigung über dessen Ende).

Unser Prozess sah also folgendermaßen aus: Ein Ingenieur stellt eine Version bereit, überwacht die Diagramme drei Minuten lang und danach kann niemand mehr zwei Minuten lang etwas bereitstellen. Im Falle eines Problems rollt der Techniker die Freigabe zurück. Diese Regel vereinfachte die Fehlerbehebung drastisch und reduzierte die Gesamtdauer der aktiven und passiven Stufen von 3 + 1 = 4 Minuten auf 1 + 1 = 2 Minuten.

Aber selbst ein zweiminütiger Unfall war zu viel. Deshalb haben wir weiter an unserer Prozessoptimierung gearbeitet.

Ergebnis:

Passive Etappe: 1 Minute.
Aktive Phase: 1 Minute.

7. Automatische Unfallermittlung und Rollback


Wir hatten eine Weile darüber nachgedacht, wie wir die Dauer der durch schlechte Veröffentlichungen verursachten Unfälle verkürzen können. Wir haben sogar versucht, uns zu zwingen, nach tail -f error_log | grep 500 zu suchen tail -f error_log | grep 500 . Am Ende haben wir uns jedoch für eine drastische automatische Lösung entschieden.

Kurz gesagt, es ist ein automatischer Rollback. Wir haben einen separaten Webserver und haben ihn über den Balancer zehnmal weniger geladen als die übrigen Webserver. Jede Version wird automatisch von CI / CD-Systemen auf diesem separaten Server bereitgestellt (wir haben sie als Preprod bezeichnet, aber trotz ihres Namens würde sie von den realen Benutzern eine echte Last erhalten). Dann würde das Skript tail -f error_log | grep 500 tail -f error_log | grep 500 . Wenn innerhalb einer Minute kein 500-Fehler auftrat, stellte CI / CD die neue Version in der Produktion auf anderen Webservern bereit. Im Fehlerfall hat das System alles zurückgesetzt. Auf Balancer-Ebene wurden alle Anforderungen, die zu 500 Fehlern bei der Vorproduktion führten, auf einem der Produktionswebserver erneut gesendet.

Diese Maßnahme reduzierte die Auswirkung von 500 Fehlern auf Null. Das heißt, nur für den Fall von Fehlern in der automatischen Steuerung haben wir unsere Drei-Minuten-Regel zur Überwachung von Graphen nicht abgeschafft. Das ist alles über schlechte Releases und 500 Fehler. Kommen wir zur nächsten Art von Unfällen.

Ergebnis:

Passive Etappe: 0 Minuten.
Aktive Phase: 0 Minuten.



In weiteren Abschnitten werde ich über andere Arten von Ausfällen in Citymobil sprechen und auf jede Art von Ausfall eingehen. Ich erzähle Ihnen auch von den Schlussfolgerungen, die wir zu den Ausfällen gezogen haben, wie wir den Entwicklungsprozess geändert haben und welche Automatisierung wir eingeführt haben. Bleib dran!

Source: https://habr.com/ru/post/de449708/


All Articles