
Heutzutage ist eine hohe Verfügbarkeit von Diensten immer und überall erforderlich, nicht nur bei großen, teuren Projekten. Vorübergehend nicht verfügbare Websites mit der Meldung „Leider werden Wartungsarbeiten durchgeführt“ werden immer noch angezeigt, lösen aber meist ein herablassendes Lächeln aus. Fügen wir dem Leben Leben in den Clouds hinzu, wenn nur ein Aufruf der API erforderlich ist, um einen zusätzlichen Server zu starten, und keine Notwendigkeit besteht, über den „eisernen“ Betrieb nachzudenken. Und es gibt keine Entschuldigung mehr, warum ein kritisches System mithilfe von Cluster-Technologien und Redundanz nicht zuverlässig gemacht wurde.
Wir erzählen Ihnen, welche Lösungen wir in Betracht gezogen haben, um die Zuverlässigkeit der Datenbanken in unseren Diensten sicherzustellen, und was wir daraus gemacht haben. Dazu eine Demo mit weitreichenden Schlussfolgerungen.
Vermächtnis in der Hochverfügbarkeitsarchitektur
Noch deutlicher wird dies im Kontext der Entwicklung verschiedener Open-Source-Systeme. Bei der steigenden Nachfrage mussten Legacy-Lösungen durch Hochverfügbarkeitstechnologien ergänzt werden. Und ihre Qualität war unterschiedlich. Lösungen der nächsten Generation stellen Hochverfügbarkeit in den Mittelpunkt ihrer Architektur. Beispielsweise positioniert MongoDB Cluster als seinen Hauptanwendungsfall. Der Cluster skaliert horizontal, was einen starken Wettbewerbsvorteil dieses DBMS darstellt.
Kommen wir zurück zu PostgreSQL. Dies ist eines der ältesten populären Open-Source-Projekte, dessen erste Veröffentlichung im 95. Jahr des letzten Jahrhunderts erfolgte. Das Projektteam betrachtete die Hochverfügbarkeit lange Zeit nicht als eine Aufgabe, die das System lösen sollte. Daher wurde die Replikationstechnologie zum Erstellen von Datenkopien erst in Version 8.2 im Jahr 2006 integriert, es handelte sich jedoch um eine Datei (Protokollversand). Im Jahr 2010 erschien die Streaming-Replikation in Version 9.0 und ist die Grundlage für die Erstellung verschiedenster Cluster. Dies ist in der Tat sehr überraschend für Leute, die sich nach Enterprise SQL oder modernem NoSQL mit PostgreSQL vertraut machen – die Standardlösung der Community ist einfach ein Master-Replica-Paar mit synchroner oder asynchroner Replikation. Gleichzeitig wird im Drain der Master manuell umgeschaltet, und es wird auch vorgeschlagen, das Problem des Clientwechsels unabhängig zu lösen.
Wie wir uns entschieden haben, zuverlässiges PostgreSQL zu erstellen und was wir dafür ausgewählt haben
Allerdings wäre PostgreSQL nicht so populär geworden, wenn es nicht eine große Anzahl von Projekten und Tools gäbe, die beim Aufbau einer fehlertoleranten Lösung helfen, die keine ständige Aufmerksamkeit erfordert. In der Wolke (MCS) Seit der Einführung von DBaaS sind einzelne PostgreSQL-Server und Master-Replica-Paare mit asynchroner Replikation verfügbar.
Natürlich wollten wir das Leben für alle einfacher machen und eine PostgreSQL-Installation zur Verfügung stellen, die als Grundlage für hochverfügbare Dienste dienen kann, die nicht ständig überwachen und nachts aufwachen müssen, um einen Wechsel vorzunehmen. In diesem Segment gibt es sowohl altbewährte Lösungen als auch eine Generation neuer Versorgungsunternehmen, die die neuesten Entwicklungen nutzen.
Heutzutage beruht das Problem der Hochverfügbarkeit nicht auf der Reservierung (das versteht sich von selbst), sondern auf dem Konsens – dem Algorithmus zur Auswahl eines Anführers (Leader-Wahl). In den meisten Fällen ereignen sich schwere Unfälle nicht aufgrund fehlender Server, sondern aufgrund von Konsensproblemen: Ein neuer Leiter kam nicht heraus, zwei Leiter tauchten in verschiedenen Rechenzentren auf usw. Ein Beispiel ist ein Absturz auf einem Github-MySQL-Cluster – schrieben sie .
Die mathematische Grundlage in dieser Angelegenheit ist sehr ernst. Einerseits dort , was den Möglichkeiten der Konstruktion von HA-Lösungen theoretische Einschränkungen auferlegt, andererseits mathematisch bewährte Algorithmen zur Konsensbestimmung, wie z и . Auf dieser Basis gibt es recht beliebte DCS (dezentrale Konsenssysteme) – Zookeeper usw., Consul. Wenn das Entscheidungssystem daher auf einigen seiner eigenen, unabhängig geschriebenen Algorithmen basiert, sollte man äußerst vorsichtig sein. Nach der Analyse einer Vielzahl von Systemen haben wir uns für Patroni entschieden, ein Open-Source-System, das hauptsächlich von Zalando entwickelt wurde.
Als lyrischen Exkurs möchte ich sagen, dass wir auch über Multi-Master-Lösungen nachgedacht haben, also Cluster, die für die Aufnahme horizontal skaliert werden können. Aus zwei Hauptgründen haben wir uns jedoch entschieden, keinen solchen Cluster zu erstellen. Erstens weisen solche Lösungen eine hohe Komplexität und dementsprechend mehr Schwachstellen auf. Es wird schwierig sein, für alle Fälle eine stabile Lösung zu finden. Zweitens ist PostgreSQL in diesem Fall nicht mehr rein (nativ), einige Funktionen sind nicht verfügbar und bei einigen Anwendungen können während des Betriebs versteckte Fehler auftreten.
Patron
Wie funktioniert Patroni? Die Entwickler haben das Rad nicht neu erfunden und vorgeschlagen, als Basis eine der bewährten DCS-Lösungen zu verwenden. Ihm sind alle Fragen der Synchronisierung von Konfigurationen, der Wahl eines Leiters und eines Kollegiums ausgeliefert. Wir haben uns hierfür für etcd entschieden.
Als nächstes befasst sich Patroni mit der korrekten Anwendung aller PostgreSQL-Einstellungen und Replikationseinstellungen sowie der Ausführung von Befehlen für Switchover und Failover (also regelmäßige und abnormale Umschaltung des Masters). Insbesondere können Sie in der MCS-Cloud einen Cluster aus einem Master, einem synchronen Replikat und einem oder mehreren asynchronen Replikaten erstellen. Das Vorhandensein eines synchronen Replikats gewährleistet die Sicherheit der Daten auf mindestens zwei Servern, und dieses Replikat wird der wichtigste „Masterkandidat“ sein.
Da etcd auf denselben Servern bereitgestellt wird, werden für ein optimales Quorum 3 oder 5 Server empfohlen. Ein solcher Cluster wird zum Lesen horizontal skaliert (über die Skalierung zum Schreiben habe ich oben geschrieben). Beachten Sie jedoch, dass asynchrone Replikate insbesondere bei hoher Auslastung zu Verzögerungen neigen.
Der Einsatz solcher Replikate zum Lesen (Hot Standby) ist für Reporting- oder Analyseaufgaben sinnvoll und entlastet den Masterserver.
Wenn Sie einen solchen Cluster selbst erstellen möchten, benötigen Sie:
- Bereiten Sie drei oder mehr Server vor und konfigurieren Sie die IP-Adressierung und Firewall-Regeln zwischen ihnen.
- Pakete für etcd-, Patroni- und PostgreSQL-Dienste installieren;
- Richten Sie einen etcd-Cluster ein.
- Konfigurieren Sie den Patroni-Dienst für die Arbeit mit PostgreSQL.
Das heißt, insgesamt müssen Sie ein Dutzend Konfigurationsdateien korrekt erstellen und dürfen nirgendwo einen Fehler machen. Hierzu sollten Sie unbedingt ein Konfigurationsmanagement-Tool nutzen, wie zum Beispiel Ansible. Allerdings gibt es noch keinen hochverfügbaren TCP-Balancer. Es zu machen ist eine separate Aufgabe.
Für diejenigen, die einen vorgefertigten Cluster benötigen, aber nicht in all dem herumstöbern möchten, haben wir versucht, das Leben zu vereinfachen und einen vorgefertigten Cluster auf Patroni in unserer Cloud erstellt, den Sie kostenlos testen können. Zusätzlich zum Cluster selbst haben wir Folgendes getan:
- TCP-Balancer; auf verschiedenen Ports zeigt es immer auf den aktuellen Master, das synchrone bzw. asynchrone Replikat;
- API zum Wechseln des aktiven Patroni-Masters.
Sie können sowohl über die MCS-Cloud-API als auch über die Webkonsole in Unterklassen unterteilt werden.
Demo
Um die Fähigkeiten eines PostgreSQL-Clusters in der MCS-Cloud zu testen, sehen wir uns an, wie sich eine Live-Anwendung bei Problemen mit dem DBMS verhält.
Im Folgenden finden Sie den Anwendungscode, der künstliche Ereignisse protokolliert und auf dem Bildschirm meldet. Bei Fehlern meldet es dies und setzt seine Arbeit in einer Schleife fort, bis wir es mit der Kombination Strg + C stoppen.
from __future__ import print_function
from datetime import datetime
from random import randint
from time import sleep
import psycopg2
def main():
try:
connection = psycopg2.connect(user = "admin",
password = "P@ssw0rd",
host = "89.208.87.38",
port = "5432",
database = "myproddb")
cursor = connection.cursor()
cursor.execute("SELECT version();")
record = cursor.fetchone()
print("Connection opened to", record[0])
cursor.execute(
"INSERT INTO log VALUES ({});".format(randint(1, 10000)))
connection.commit()
cursor.execute("SELECT COUNT(event_id) from log;")
record = cursor.fetchone()
print("Logged a value, overall count: {}".format(record[0]))
except Exception as error:
print ("Error while connecting to PostgreSQL", error)
finally:
if connection:
cursor.close()
connection.close()
print("Connection closed")
if __name__ == '__main__':
try:
while True:
try:
print(datetime.now())
main()
sleep(3)
except Exception as e:
print("Caught error:n", e)
sleep(1)
except KeyboardInterrupt:
print("exit")
Die Anwendung benötigt PostgreSQL, um zu funktionieren. Erstellen wir mithilfe der API einen Cluster in der MCS-Cloud. In einem regulären Terminal, in dem die Variable OS_TOKEN ein Token für den Zugriff auf die API enthält (kann mit dem Befehl openstack token issue abgerufen werden), geben wir die Befehle ein:
Erstellen Sie einen Cluster:
cat <<EОF > pgc10.json
{"cluster":{"name":"postgres10","allow_remote_access":true,"datastore":{"type":"postgresql","version":"10"},"databases":[{"name":"myproddb"}],"users":[{"databases":[{"name":"myproddb"}],"name":"admin","password":"P@ssw0rd"}],"instances":[{"key_name":"shared","availability_zone":"DP1","flavorRef":"d659fa16-c7fb-42cf-8a5e-9bcbe80a7538","nics":[{"net-id":"b91eafed-12b1-4a46-b000-3984c7e01599"}],"volume":{"size":50,"type":"DP1"}},{"key_name":"shared","availability_zone":"DP1","flavorRef":"d659fa16-c7fb-42cf-8a5e-9bcbe80a7538","nics":[{"net-id":"b91eafed-12b1-4a46-b000-3984c7e01599"}],"volume":{"size":50,"type":"DP1"}},{"key_name":"shared","availability_zone":"DP1","flavorRef":"d659fa16-c7fb-42cf-8a5e-9bcbe80a7538","nics":[{"net-id":"b91eafed-12b1-4a46-b000-3984c7e01599"}],"volume":{"size":50,"type":"DP1"}}]}}
EOF
curl -s -H "X-Auth-Token: $OS_TOKEN"
-H 'Accept: application/json'
-H 'Content-Type: application/json'
-d @pgc10.json https://infra.mail.ru:8779/v1.0/ce2a41bbd1434013b85bdf0ba07c770f/clusters

Wenn der Cluster in den Status ACTIVE wechselt, erhalten alle Felder die aktuellen Werte – der Cluster ist bereit.
In der GUI:

Versuchen wir, eine Verbindung herzustellen und eine Tabelle zu erstellen:
psql -h 89.208.87.38 -U admin -d myproddb
Password for user admin:
psql (11.1, server 10.7)
Type "help" for help.
myproddb=> CREATE TABLE log (event_id integer NOT NULL);
CREATE TABLE
myproddb=> INSERT INTO log VALUES (1),(2),(3);
INSERT 0 3
myproddb=> SELECT * FROM log;
event_id
----------
1
2
3
(3 rows)
myproddb=>

In der Anwendung legen wir die aktuellen Einstellungen für die Verbindung zu PostgreSQL fest. Wir geben die Adresse des TCP-Balancers an, sodass kein manuelles Umschalten auf die Adresse des Masters erforderlich ist. Lass es uns starten. Wie Sie sehen, wurden die Ereignisse erfolgreich in der Datenbank protokolliert.

Geplanter Masterwechsel
Testen wir nun den Betrieb unserer Anwendung während der geplanten Umschaltung des Masters:

Wir beobachten die Bewerbung. Wir sehen, dass die Anwendung wirklich unterbrochen wird, aber es dauert nur ein paar Sekunden, in diesem speziellen Fall maximal 9.

Autounfall
Versuchen wir nun, den Sturz der virtuellen Maschine, des aktuellen Masters, zu simulieren. Es wäre möglich, die virtuelle Maschine einfach über die Horizon-Schnittstelle auszuschalten, nur dass es sich hierbei um ein reguläres Herunterfahren handelt. Ein solcher Wechsel wird von allen Diensten, einschließlich Patroni, bearbeitet.
Wir brauchen einen unvorhersehbaren Shutdown. Deshalb habe ich unsere Administratoren zu Testzwecken gebeten, die virtuelle Maschine – den aktuellen Master – auf abnormale Weise herunterzufahren.

Gleichzeitig funktionierte unsere Anwendung weiterhin. Natürlich kann eine solche Notschaltung des Masters nicht unbemerkt bleiben.
2019-03-29 10:45:56.071234
Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Logged a value, overall count: 453
Connection closed
2019-03-29 10:45:59.205463
Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Logged a value, overall count: 454
Connection closed
2019-03-29 10:46:02.661440
Error while connecting to PostgreSQL server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
Caught error:
local variable 'connection' referenced before assignment
……………………………………………………….. - здесь какое-то количество ошибок
2019-03-29 10:46:30.930445
Error while connecting to PostgreSQL server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
Caught error:
local variable 'connection' referenced before assignment
2019-03-29 10:46:31.954399
Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Logged a value, overall count: 455
Connection closed
2019-03-29 10:46:35.409800
Connection opened to PostgreSQL 10.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Logged a value, overall count: 456
Connection closed
^Cexit
Wie Sie sehen, konnte die Anwendung ihre Arbeit in weniger als 30 Sekunden fortsetzen. Ja, eine bestimmte Anzahl von Dienstnutzern wird Zeit haben, Probleme zu bemerken. Allerdings handelt es sich hierbei um einen schwerwiegenden Ausfall des Servers, dieser kommt nicht so oft vor. Gleichzeitig hätte ein Mensch (Administrator) kaum Zeit gehabt, so schnell zu reagieren, wenn er nicht mit einem Schaltskript in der Konsole gesessen hätte.
Abschluss
Mir scheint, dass ein solcher Cluster einen großen Vorteil für Administratoren bietet. Tatsächlich werden schwerwiegende Ausfälle und Ausfälle von Datenbankservern für die Anwendung und damit für den Benutzer nicht spürbar sein. Sie müssen nicht schnell etwas reparieren und auf temporäre Konfigurationen, Server usw. umsteigen. Und wenn eine solche Lösung als fertiger Service in der Cloud genutzt wird, entfällt der Zeitaufwand für die Vorbereitung. Sie können etwas Interessanteres tun.
Source: habr.com
