Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

V dnešní době je vysoká dostupnost služeb vyžadována vždy a všude, nejen v rámci velkých drahých projektů. Dočasně nedostupné weby se zprávou „Omlouváme se, provádí se technická údržba“ se sice stále objevují, ale obvykle vyvolávají jen shovívavou úsměv. K tomu přidejme život v cloudu, kdy pro spuštění dalšího serveru stačí jen jeden API hovor, přičemž není třeba přemýšlet o „hardwarovém“ provozu. A už nejsou žádné výmluvy, proč kritický systém nebyl vytvořen spolehlivě s využitím clusterových technologií a zálohování.

Povíme si, jaká řešení jsme zvažovali pro zajištění spolehlivosti databází ve svých službách a k čemu jsme dospěli. Plus demo s dalekosáhlými závěry.

Legacy v architektuře zajištění vysoké dostupnosti

Ještě lépe je to vidět v kontextu vývoje různých open-source systémů. Starší řešení byla nucena přidávat technologie vysoké dostupnosti v souladu se vzrůstající poptávkou. A jejich kvalita byla různá. Řešení nové generace staví vysokou dostupnost na základ své architektury. Například MongoDB se profiluje jako klíčová možnost použití clusteru. Cluster se horizontálně škáluje, což představuje silnou konkurenční výhodu této databáze.

Vrátíme se k PostgreSQL. To je jeden z nejstarších populárních open-source projektů, jehož první vydání proběhlo v roce 1995. Tým projektu dlouho nepovažoval vysokou dostupnost za úkol, který je třeba řešit na úrovni systému. Technologie replikace pro vytváření kopií dat byla integrována až od verze 8.2 v roce 2006, a to byl souborový (log shipping) přístup. V roce 2010 byla ve verzi 9.0 zavedena streamová replikace, která se stala základem pro vytváření různých clusterů. To v zásadě velice překvapuje lidi, kteří se seznamují s PostgreSQL po Enterprise SQL nebo moderních NoSQL — standardním řešením od komunity je prostě pár master-replica se synchronní nebo asynchronní replikací. Přitom v zásobníku je přepínání mastera prováděno ručně a otázka přepínání klientů je také nabízena k řešení samostatně.

Jak jsme se rozhodli vytvořit spolehlivý PostgreSQL a co jsme pro to vybrali

Nicméně PostgreSQL by se nestal tak populárním, kdyby neexistovalo obrovské množství projektů a nástrojů, které pomáhají vybudovat spolehlivé řešení, které nevyžaduje neustálou pozornost. V cloudu Mail.ru Cloud Solutions (MCS) od samotného spuštění DBaaS byly k dispozici samostatné servery PostgreSQL a páry master-replika s asynchronní replikací.

Přirozeně jsme chtěli usnadnit všem život a učinit dostupnou takovou instalaci PostgreSQL, která mohla sloužit jako základ pro vysoce dostupné služby, o které by nebylo třeba neustále pečovat a probouzet se v noci, abyste provedli přepnutí. V tomto segmentu existují jak stará osvědčená řešení, tak generace nových utilit, které využívají nejnovější poznatky.

Dnes se problém vysoké dostupnosti neobrací na redundanci (to je samozřejmost), ale na konsensus — algoritmus pro výběr vůdce (Leader election). Nejčastěji dochází k velkým haváriím nikoli kvůli nedostatku serverů, ale kvůli problémům s konsensem: nebyl zvolen nový vůdce, objevili se dva vůdci v různých datových centrech atd. Příklad — havárie na MySQL clusteru Github — napsali podrobný postmortem.

Matematický základ v této otázce je velmi vážný. Na jedné straně existuje CAP teorie, která ukládá teoretická omezení na možnosti budování HA řešení, na straně druhé — matematicky prokázané algoritmy určení konsensu, jako je Paxos a Raft. Na jejím základě existují poměrně populární DCS (systémy decentralizovaného konsensu) — Zookeeper, etcd, Consul. Proto pokud systém rozhodování funguje na nějakém svém algoritmu, napsaném samostatně, je třeba k němu přistupovat velmi opatrně. Po analýze obrovského množství systémů jsme se rozhodli pro Patroni — opensource systém, který především vyvíjí společnost Zalando.

Jako liryckou odbočku mohu říci, že jsme zvažovali také multi-master řešení, tedy clustery, které lze horizontálně škálovat pro zápis. Nicméně z dvou hlavních důvodů jsme se rozhodli takový cluster neimplementovat. Za prvé, tato řešení mají vysokou složitost a tím pádem více zranitelných míst. Bude těžké vytvořit stabilní řešení pro všechny situace. Za druhé, v takovém případě PostgreSQL přestává být čistě (nativní), některé funkce nebudou dostupné a některé aplikace mohou mít při provozu skryté chyby.

Patroni

Jak tedy funguje Patroni? Vývojáři se rozhodli nevynalézat kolo a navrhli použít jako základ jedno z osvědčených DCS řešení. Všechny otázky týkající se synchronizace konfigurací, výběru vůdce a kvóra se přenechávají jemu. Pro to jsme vybrali etcd.

Dále se Patroni stará o správné použití všech nastavení na PostgreSQL a o nastavení replikace, stejně jako o provádění příkazů na switchover a failover (tedy o plánované a neplánované přepínání hlavního uzlu). Konkrétně v cloudu MCS lze vytvořit cluster z hlavního uzlu, synchronní repliky a jedné nebo více asynchronních replik. Přítomnost synchronní repliky zajišťuje ochranu dat alespoň na 2 serverech a tato replikace bude hlavním "kandidátem na hlavní uzel."

Protože etcd běží na stejných serverech, doporučuje se mít 3 nebo 5 serverů pro optimální hodnotu kvóra. Takový cluster se horizontálně škáluje na čtení (o škálování pro zápis jsem psal výše). Je však třeba mít na paměti, že asynchronní repliky mají tendenci zaostávat, zejména při vysokých zátěžích.

Použití těchto replik pro čtení (hot standby) je opodstatněné pro úlohy reportingu nebo analýzy a odlehčuje hlavnímu serveru.

Pokud se rozhodnete vytvořit takový cluster sami, budete potřebovat:

  • připravit 3 nebo více serverů, nastavit IP adresaci a pravidla firewall mezi nimi;
  • nainstalovat balíčky pro služby etcd, Patroni, PostgreSQL;
  • nastavit etcd cluster;
  • nastavit službu patroni pro práci s PostgreSQL.

To summarize, it is essential to correctly create around ten configuration files without making any mistakes. For this purpose, it is definitely worth using a configuration management tool such as Ansible. However, a highly available TCP load balancer is still missing here. Creating one is a separate task.

For those who need a ready-made cluster but don't want to delve into all of this, we have tried to simplify life and made a ready-to-use cluster on Patroni in our cloud, which can be tested for free. Besides the cluster itself, we have created:

  • A TCP load balancer; it always points to the current master, synchronous or asynchronous replica, respectively, through different ports;
  • An API for switching the active Patroni master.

They can be configured both through the MCS cloud API and the web console.

Demo

To test the capabilities of the PostgreSQL cluster in the MCS cloud, let's see how a live application behaves under database issues.

Below is the code for the application that will log artificial events and report them on the screen. In case of errors, it will report them and continue to work in a loop until we stop it using the Ctrl + C combination.

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")

The application requires PostgreSQL to function. We will create a cluster in the MCS cloud using the API. In a regular terminal, where the OS_TOKEN variable contains the token for API access (which can be obtained with the command openstack token issue), we will enter the commands:

Creating a cluster:

cat < 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

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Když přejde cluster do stavu ACTIVE, všechna pole obdrží aktuální hodnoty — cluster je připraven.

V GUI:

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Zkusíme se připojit a vytvořit tabulku:

psql -h 89.208.87.38 -U admin -d myproddb
Heslo pro uživatele admin:
psql (11.1, server 10.7)
Pro pomoc zadejte "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=>

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

V aplikaci nastavíme aktuální parametry pro připojení k PostgreSQL. Uvedeme adresu TCP-load balanceru, čímž se vyhneme nutnosti ručního přepínání na adresu mastera. Spustíme ho. Jak vidno, události se úspěšně logují do databáze.

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Plánované přepnutí mastera

Nyní otestujeme funkčnost naší aplikace při plánovaném přepnutí mastera:

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Sledujeme aplikaci. Vidíme, že funkčnost aplikace se skutečně přerušuje, ale trvá to jen několik sekund, v tomto konkrétním případě maximálně 9.

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Pád stroje

Nyní se pokusíme simulovat pád virtuálního stroje, aktuálního mastera. Mohli bychom jednoduše vypnout virtuální stroj prostřednictvím rozhraní Horizon, ale to by bylo standardní vypnutí. Takové přepnutí bude zpracováno všemi službami, včetně Patroni.

Potřebujeme však nepředvídatelné vypnutí. Proto jsem požádal naše administrátory, aby z testovacích důvodů vypnuli virtuální stroj — aktuálního mastera — neštandardním způsobem.

Jak jsme vybudovali spolehlivý klastr PostgreSQL na Patroni

Během této doby pokračovala činnost naší aplikace. Samozřejmě, že takové nouzové přepnutí mastera nemůže proběhnout bez povšimnutí.

2019-03-29 10:45:56.071234
Připojení otevřeno k PostgreSQL 10.7 na x86_64-pc-linux-gnu, zkompilováno nástrojem gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Zaznamenána hodnota, celkový počet: 453
Připojení uzavřeno
2019-03-29 10:45:59.205463
Připojení otevřeno k PostgreSQL 10.7 na x86_64-pc-linux-gnu, zkompilováno nástrojem gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Zaznamenána hodnota, celkový počet: 454

Připojení uzavřeno
2019-03-29 10:46:02.661440
Chyba při připojování k PostgreSQL serveru, připojení bylo uzavřeno neočekávaně
        To pravděpodobně znamená, že server ukončil činnost abnormálně
        před nebo během zpracování požadavku.

Zachycena chyba:
 lokální proměnná 'connection' byla odkazována před přiřazením
……………………………………………………….. - zde je nějaké množství chyb
2019-03-29 10:46:30.930445
Chyba při připojování k PostgreSQL serveru, připojení bylo uzavřeno neočekávaně
        To pravděpodobně znamená, že server ukončil činnost abnormálně
        před nebo během zpracování požadavku.

Zachycena chyba:
 lokální proměnná 'connection' byla odkazována před přiřazením
2019-03-29 10:46:31.954399
Připojení otevřeno k PostgreSQL 10.7 na x86_64-pc-linux-gnu, zkompilováno nástrojem gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Zaznamenána hodnota, celkový počet: 455
Připojení uzavřeno
2019-03-29 10:46:35.409800
Připojení otevřeno k PostgreSQL 10.7 na x86_64-pc-linux-gnu, zkompilováno nástrojem gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Zaznamenána hodnota, celkový počet: 456
Připojení uzavřeno
^Cexit

Jak je vidět, aplikace byla schopná pokračovat ve své činnosti za méně než 30 sekund. Ano, určité množství uživatelů služby si může povšimnout problémů. Nicméně, jedná se o vážnou poruchu serveru, k takovým situacím nedochází příliš často. Člověk (administrátor) by pravděpodobně nezareagoval tak rychle, pokud by neseděl u konzole připravený se skriptem pro přepnutí.

Výstup

Myslím, že takový klastr dává obrovskou výhodu pro administrátory. V podstatě vážné poruchy a výpadky databázových serverů nebudou pro aplikaci a tedy ani pro uživatele patrné. Nebude třeba něco naléhavě opravovat a přepínat na dočasné konfigurace, servery atd. A pokud bude tento systém využíván jako hotová služba v cloudu, nebude třeba trávit čas jeho přípravou. Bude možné se věnovat něčemu zajímavějšímu.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster