Die grĂ¶ĂŸten Fehler von Cian

Die grĂ¶ĂŸten Fehler von Cian

Allen gute WĂŒnsche! 

Mein Name ist Nikita, ich bin Teamleiter der Ingenieurmannschaft von Cian. Eine meiner Aufgaben im Unternehmen ist es, die Anzahl der incidents im Zusammenhang mit der Infrastruktur im Produktionsumfeld auf null zu reduzieren.
Was als NÀchstes zur Sprache kommt, hat uns viel Schmerz bereitet, und das Ziel dieses Artikels ist es, anderen zu helfen, unsere Fehler nicht zu wiederholen oder zumindest ihren Einfluss zu minimieren. 

PrÀambel

Vor langer Zeit, als Cian aus Monolithen bestand und es noch keine Anzeichen von Mikrodiensten gab, haben wir die VerfĂŒgbarkeit des Dienstes gemessen, indem wir 3–5 Seiten ĂŒberprĂŒften. 

Wenn sie antworteten – war alles in Ordnung, antworteten sie ĂŒber einen lĂ€ngeren Zeitraum nicht – dann gab es einen Alert. Wie lange sie nicht funktionieren mussten, um als Incident betrachtet zu werden, wurde in Meetings entschieden. Das Ingenieurteam war immer an der Untersuchung des Incidents beteiligt. Nach Abschluss der Untersuchung wurde ein Postmortem geschrieben – eine Art Bericht per E-Mail im Format: was passiert ist, wie lange es gedauert hat, was wir in dem Moment gemacht haben, was wir in Zukunft tun werden. 

Die Hauptseiten der Website oder wie wir erkennen, dass wir den Tiefpunkt erreicht haben

 
Um die PrioritĂ€t eines Fehlers zu verstehen, haben wir die kritischsten Seiten der Website fĂŒr die GeschĂ€ftsanforderungen identifiziert. Anhand dieser messen wir die Anzahl der erfolgreichen und nicht erfolgreichen Anfragen sowie Timeouts. So messen wir die Uptime. 

Angenommen, wir haben festgestellt, dass es eine Reihe von superwichtigen Bereichen der Website gibt, die die Hauptdienste — die Suche und die Einreichung von Anzeigen — betreffen. Wenn die Anzahl der Anfragen, die mit einem Fehler enden, ĂŒber 1 % steigt, ist das ein kritischer Incident. Wenn wĂ€hrend der Hauptzeit in 15 Minuten der Fehleranteil ĂŒber 0,1 % steigt, wird das ebenfalls als kritischer Incident angesehen. Diese Kriterien decken den Großteil der Incidents ab, die ĂŒbrigen fallen außerhalb dieses Artikels.

Die grĂ¶ĂŸten Fehler von Cian

Die Top der besten Incidents von Cian

Also, wir haben definitiv gelernt zu erkennen, dass ein Incident passiert ist. 

Jetzt ist jeder Incident bei uns detailliert beschrieben und in einem Epic in Jira festgehalten. Übrigens: DafĂŒr haben wir ein eigenes Projekt eingerichtet, das wir FAIL genannt haben — in dem können nur Epics erstellt werden. 

Wenn man alle FehlschlĂ€ge der letzten Jahre zusammenfasst, fĂŒhren an die Spitze: 

  • Incidents, die mit mssql verbunden sind;
  • Incidents, die durch externe Faktoren verursacht werden;
  • Fehler des Administrators.

Lassen Sie uns detaillierter auf die Fehler der Administratoren und einige andere interessante FehlschlÀge eingehen.

Platz fĂŒnf — „Ordnung im DNS schaffen“

Es war ein ungemĂŒtlicher Dienstag. Wir beschlossen, Ordnung in den DNS-Cluster zu bringen. 

Wir wollten die internen DNS-Server von BIND auf PowerDNS umstellen, indem wir dafĂŒr komplett separate Server bereitstellten, auf denen außer DNS nichts lĂ€uft. 

Wir haben in jedem unserer Rechenzentren einen DNS-Server platziert, und der Moment fĂŒr den Umzug der Zonen von BIND zu PowerDNS sowie die Umschaltung der Infrastruktur auf die neuen Server kam. 

Inmitten des Umzugs blieb nur einer der DNS-Server ĂŒbrig, Server, der in den lokalen zwischengespeicherten BINDs auf allen Servern angegeben war und sich im Rechenzentrum in Sankt Petersburg befand. Dieses Rechenzentrum war ursprĂŒnglich als nicht kritisch fĂŒr uns deklariert worden, wurde aber plötzlich zum Single Point of Failure.
Genau in dieser Phase des Umzugs fiel die Verbindung zwischen Moskau und Sankt Petersburg aus. Wir standen faktisch fĂŒr fĂŒnf Minuten ohne DNS da und liefen wieder hoch, als Hoster die Störungen behoben waren. 

Fazit:

FrĂŒher haben wir externe Faktoren wĂ€hrend der Vorbereitung auf die Arbeiten vernachlĂ€ssigt, aber jetzt haben wir sie ebenfalls in die Liste aufgenommen, auf die wir uns vorbereiten. Und jetzt streben wir danach, dass alle Komponenten n-2 reserviert sind, wĂ€hrend wir in der Arbeitsphase dieses Niveau auf n-1 absenken können.

  • WĂ€hrend der Erstellung des Aktionsplans sollten Sie Punkte markieren, an denen der Service ausfallen kann, und ein Szenario durchdenken, in dem alles "schlimmer geht's nicht".
  • Verteilen Sie die internen DNS-Server auf verschiedene Geolokationen/Rechenzentren/Racks/Switches/EingĂ€nge.
  • Installieren Sie auf jedem Server einen lokalen zwischenspeichernden DNS-Server, der Anfragen an die Haupt-DNS-Server weiterleitet und im Falle seiner Nichterreichbarkeit aus dem Cache antwortet. 

Der vierte Punkt — "Ordnung in Nginx schaffen"

Eines schönen Tages beschloss unser Team, dass "es reicht, das zu ertragen", und der Prozess der Refaktorisierung der Nginx-Konfigurationen begann. Das Hauptziel war es, die Konfigurationen in eine intuitiv verstĂ€ndliche Struktur zu bringen. FrĂŒher war alles "historisch gewachsen" und trug keine Logik in sich. Jetzt haben wir jeden server_name in eine gleichnamige Datei ausgelagert und alle Konfigurationen in Ordner verteilt. Übrigens — die Konfiguration enthĂ€lt 253949 Zeilen oder 7836520 Zeichen und ist fast 7 Megabyte groß. Die oberste Ebene der Struktur: 

Nginx-Struktur

├── Zugriff
│   ├── allow.list
...
│   └── whitelist.conf
├── Geobase
│   ├── exclude.conf
...
│   └── geo_ip_to_region_id.conf
├── Geodb
│   ├── GeoIP.dat
│   ├── GeoIP2-Country.mmdb
│   └── GeoLiteCity.dat
├── inc
│   ├── error.inc
...
│   └── proxy.inc
├── lists.d
│   ├── bot.conf
...
│   ├── dynamisch
│   └── geo.conf
├── lua
│   ├── cookie.lua
│   ├── log
│   │   └── log.lua
│   ├── logics
│   │   ├── include.lua
│   │   ├── ...
│   │   └── utils.lua
│   └── prom
│       ├── stats.lua
│       └── stats_prometheus.lua
├── map.d
│   ├── access.conf
│   ├── .. 
│   └── zones.conf
├── nginx.conf
├── robots.txt
├── server.d
│   ├── cian.ru
│   │   ├── cian.ru.conf
│   │   ├── ...
│   │   └── my.cian.ru.conf
├── service.d
│   ├── ...
│   └── status.conf
└── upstream.d
    ├── cian-mcs.conf
    ├── ...
    └── wafserver.conf

Es hat sich deutlich verbessert, aber wĂ€hrend der Umbenennung und Verteilung der Konfigurationen hatten einige davon die falsche Erweiterung und wurden nicht in die Direktive include *.conf aufgenommen. Infolgedessen wurden einige Hosts nicht erreichbar und gaben einen 301-Redirect zur Hauptseite zurĂŒck. Da der Antwortcode nicht 5xx/4xx war, fiel dies nicht sofort auf, sondern erst morgens. Danach begannen wir mit dem Schreiben von Tests zur ÜberprĂŒfung der Infrastrukturkomponenten.

Fazit: 

  • Strukturieren Sie die Konfigurationen (nicht nur nginx) richtig und denken Sie bereits in der frĂŒhen Projektphase ĂŒber die Struktur nach. So machen Sie sie fĂŒr das Team verstĂ€ndlicher, was wiederum die Time-to-Market reduziert.
  • FĂŒr einige Infrastrukturkomponenten schreiben Sie Tests. Zum Beispiel: ÜberprĂŒfen Sie, dass alle wichtigen server_name den richtigen Status zurĂŒckgeben, + den Antwortkörper. Es genĂŒgt, einfach einige Skripte bereitzuhalten, die die grundlegenden Funktionen der Komponente ĂŒberprĂŒfen, damit Sie nicht um 3 Uhr nachts in Panik versuchen mĂŒssen, sich zu erinnern, was Sie noch ĂŒberprĂŒfen sollten. 

Dritter Platz — "Plötzlich war der Speicher in Cassandra voll"

Die Daten wuchsen kontinuierlich, und alles war gut, bis im Cassandra-Cluster große Keyspaces wĂ€hrend des Repairs ausfielen, weil die Compaction nicht arbeiten konnte. 

An einem nebligen Tag verwandelte sich der Cluster fast in einen KĂŒrbis, und zwar:

  • Es waren nur noch etwa 20 % des Gesamtplatzes im Cluster verfĂŒgbar;
  • Knoten können nicht hinzugefĂŒgt werden, da der Cleanup nach der HinzufĂŒgung eines Knotens aufgrund von Platzmangel nicht durchgefĂŒhrt wird;
  • Die Leistung sinkt allmĂ€hlich, da die Compaction nicht funktioniert; 
  • Der Cluster lĂ€uft im Notbetrieb.

Die grĂ¶ĂŸten Fehler von Cian

Der Ausstieg — wir haben weiteren 5 Knoten ohne Cleanup hinzugefĂŒgt, danach begannen wir schrittweise, aus dem Cluster auszusteigen und erneut einzufĂŒhren, als leere Knoten, auf denen kein Platz mehr war. Die aufgebrachte Zeit war viel grĂ¶ĂŸer als gewĂŒnscht. Es bestand das Risiko einer partiellen oder vollstĂ€ndigen Nichterreichbarkeit des Clusters. 

Fazit:

  • Auf allen Cassandra-Servern sollte auf jeder Partition nicht mehr als 60 % des Speichers belegt sein. 
  • Sie sollten nicht zu mehr als 50 % ausgelastet sein, was die CPU betrifft.
  • Man sollte das Capacity Planning nicht vernachlĂ€ssigen, und es sollte fĂŒr jede Komponente unter BerĂŒcksichtigung ihrer Besonderheiten durchdacht werden.
  • Je mehr Knoten im Cluster sind, desto besser. Server mit einem kleinen Datenvolumen können schneller neu konfiguriert werden, und ein solcher Cluster ist einfacher wiederherzustellen. 

Der zweite Punkt — „Daten aus dem Consul-Key-Value-Speicher sind verschwunden“

FĂŒr das Service Discovery verwenden wir, wie viele andere, Consul. Aber wir nutzen dessen Key-Value auch fĂŒr die Blue-Green-Bereitstellung des Monolithen. Dort wird die Information ĂŒber aktive und inaktive Upstream verĂ€ndert, wĂ€hrend des Deployments. DafĂŒr wurde ein Bereitstellungsdienst geschrieben, der mit KV interagierte. Irgendwann sind die Daten aus dem KV verschwunden. Wir haben sie aus dem GedĂ€chtnis wiederhergestellt, jedoch mit einigen Fehlern. Infolgedessen wurde beim Deployment die Last auf die Upstreams ungleich verteilt, und wir erhielten viele 502-Fehler aufgrund einer Überlastung der Backends durch die CPU. Letztendlich sind wir von Consul KV auf Postgres umgestiegen, von wo es nicht so einfach ist, sie zu entfernen.  

Fazit:

  • Dienste ohne jegliche Authentifizierung sollten keine kritischen Daten fĂŒr den Betrieb der Website enthalten. Wenn Sie beispielsweise in ES keine Authentifizierung haben, wĂ€re es besser, den Zugriff auf Netzwerkebene von ĂŒberall dort zu verbieten, wo er nicht benötigt wird, nur die notwendigen zu lassen und action.destructive_requires_name: true zu setzen.
  • Üben Sie den Mechanismus fĂŒr Backup und Wiederherstellung im Voraus. Erstellen Sie beispielsweise im Voraus ein Skript (zum Beispiel in Python), das sowohl Backups erstellen als auch wiederherstellen kann.

Der erste Punkt — „Kapitan Offensichtlichkeit“ 

Irgendwann haben wir eine ungleichmĂ€ĂŸige Lastverteilung auf die Upstreams von Nginx bemerkt, wenn im Backend mehr als 10 Server waren. Da das Round-Robin-Schema die Anfragen der Reihe nach dem ersten bis zum letzten Upstream zuwies und jedes Nginx-Reload wieder von vorne begann, hatten die ersten Upstreams immer mehr Anfragen als die anderen. Dies fĂŒhrte dazu, dass sie langsamer arbeiteten und die gesamte Website litt. Mit steigendem Traffic wurde das immer deutlicher. Ein einfaches Update von Nginx zur Aktivierung von Random-Kumulierung brachte nicht den gewĂŒnschten Erfolg — wir mussten eine Menge Lua-Code neu schreiben, der in Version 1.15 nicht funktionierte. Daher mussten wir unser Nginx 1.14.2 patchen und die UnterstĂŒtzung fĂŒr Random-Kumulierung einbauen. Dadurch wurde das Problem behoben. Dieser Bug gewinnt in der Kategorie „Kapitan Offensichtlichkeit“.

Fazit:

Es war sehr interessant und fesselnd, diesen Bug zu untersuchen. 

  • Richten Sie das Monitoring so ein, dass es Ihnen hilft, Ă€hnliche Fluktuationen schnell zu finden. Zum Beispiel könnten Sie ELK verwenden, um die RPS fĂŒr jedes Backend jedes Upstreams zu ĂŒberwachen und deren Antwortzeiten aus der Sicht von Nginx zu verfolgen. In diesem Fall hat uns das geholfen, das Problem zu identifizieren. 

Ein Großteil der Fehler hĂ€tte durch einen sorgfĂ€ltigeren Ansatz vermieden werden können. Man muss immer das Murphy-Gesetz im Hinterkopf behalten: Anything that can go wrong will go wrong, und Komponenten entsprechend gestalten. 

Quelle: habr.com

60GB SSD 8Gb DDR4