Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

Idag krÀvs hög tillgÀnglighet för tjÀnster alltid och överallt, inte bara i stora dyra projekt. TillfÀlligt otillgÀngliga webbplatser med meddelandet "FörlÄt, tekniskt underhÄll pÄgÄr" förekommer fortfarande, men framkallar vanligtvis en överseende leende. LÀgg dÀrtill livet i molnet, dÀr det bara krÀvs ett API-anrop för att starta en extra server, utan att behöva tÀnka pÄ 'hÄrdvaru' drift. Det finns dÀrmed inga ursÀkter för varför ett kritiskt system inte har byggts pÄ ett tillförlitligt sÀtt med hjÀlp av klusterteknologier och redundans.

Vi kommer att berÀtta om de lösningar vi övervÀgde för att sÀkerstÀlla pÄlitlighet i databaser i vÄra tjÀnster och vad vi kom fram till. Plus en demo med lÄngtgÄende slutsatser.

Legacy i arkitektur för hög tillgÀnglighet

Detta blir tydligare nÀr man ser pÄ utvecklingen av olika opensource-system. Gamla lösningar tvingades att lÀgga till teknologier för hög tillgÀnglighet i takt med att efterfrÄgan ökade. Kvaliteten pÄ dessa lösningar varierade. Nyare generationers lösningar bygger hög tillgÀnglighet i grunden av sin arkitektur. Till exempel positionerar MongoDB kluster som det primÀra anvÀndningsomrÄdet. Kluster kan skalas horisontellt, vilket utgör en stark konkurrensfördel för denna databashanterare.

LÄt oss tillbaka till PostgreSQL. Det Àr ett av de Àldsta populÀra opensource-projekten, vars första version slÀpptes 1995. Projektteamet ansÄg lÀnge inte att hög tillgÀnglighet var en uppgift som behövde lösas frÄn systemets sida. DÀrför blev replikationstekniken för att skapa datakopior först inbyggd i version 8.2 2006, men det var en filbaserad (log shipping). I version 9.0 2010 introducerades strömreplikation, och den Àr grundlÀggande för att skapa olika kluster. Detta förvÄnar faktiskt mÀnniskor som lÀr kÀnna PostgreSQL efter Enterprise SQL eller moderna NoSQL - standardlösningen frÄn communityn Àr helt enkelt ett par master-replica med synkron eller asynkron replikation. Vid det hÀr laget görs vÀxling av master manuellt, och frÄgan om klientvÀxling uppmanas ocksÄ att lösas sjÀlvstÀndigt.

Hur vi beslutade att skapa en pÄlitlig PostgreSQL och vad vi valde för det

Trots allt skulle inte PostgreSQL vara sÄ populÀrt om det inte fanns ett stort antal projekt och verktyg som hjÀlper till att bygga en hög tillgÀnglighetslösning som inte krÀver stÀndig uppmÀrksamhet. I molnet Mail.ru Cloud Solutions (MCS) har enskilda PostgreSQL-servrar och par av master-replikor med asynkron replikering varit tillgÀngliga sedan starten av DBaaS.

SjÀlvklart ville vi förenkla livet för alla och göra installationen av PostgreSQL tillgÀnglig, sÄ att den kunde fungera som grund för hög tillgÀngliga tjÀnster, utan att man hela tiden behövde övervaka den eller vakna pÄ natten för att göra en failover. I detta segment finns bÄde gamla beprövade lösningar och en generation av nya verktyg som anvÀnder de senaste framstegen.

I dag handlar problemet med hög tillgĂ€nglighet inte om redundans (det Ă€r en sjĂ€lvklarhet) utan om konsensus – algoritmen för ledarval (Leader election). Oftast intrĂ€ffar stora haverier inte pĂ„ grund av brist pĂ„ servrar, utan pĂ„ grund av problem med konsensus: ingen ny ledare valdes, det fanns tvĂ„ ledare i olika datacenter, etc. Ett exempel Ă€r haveriet pĂ„ MySQL-klustret Github – de skrev ett detaljerat post-mortem.

Den matematiska grunden för denna frĂ„ga Ă€r mycket seriös. Å ena sidan finns det CAP-satsen, som stĂ€ller teoretiska begrĂ€nsningar för möjligheterna att bygga HA-lösningar, och Ă„ den andra sidan finns det matematiskt bevisade algoritmer för att avgöra konsensus, sĂ„som Paxos och Raft. PĂ„ dessa grunder finns det ganska populĂ€ra DCS (decentraliserade konsensusystem) – Zookeeper, etcd, Consul. DĂ€rför, om beslutsfattande-systemet arbetar med nĂ„gon egen algoritm som skrivits sjĂ€lvstĂ€ndigt, bör man vara extremt försiktig med den. Efter att ha analyserat ett stort antal system valde vi Patroni – ett open-source-system som huvudsakligen utvecklas av företaget Zalando.

Som ett lyriskt avsnitt kan jag sÀga att vi ocksÄ övervÀgde multi-master-lösningar, det vill sÀga kluster som kan skalas horisontellt för skrivning. Men av tvÄ huvudskÀl beslutade vi oss för att inte göra ett sÄdant kluster. För det första har sÄdana lösningar hög komplexitet och dÀrmed fler sÄrbara punkter. Det kommer att vara svÄrt att skapa en stabil lösning för alla situationer. För det andra slutar PostgreSQL att vara rent (native), vissa funktioner kommer att vara otillgÀngliga och vissa applikationer kan fÄ dolda buggar under drift.

Patroni

SÄ hur fungerar Patroni? Utvecklarna valde att inte uppfinna hjulet pÄ nytt och föreslog att anvÀnda en av de beprövade DCS-lösningarna som grund. Allt som rör synkronisering av konfigurationer, val av ledare och kvorum lÀmnas till det. Vi valde etcd för detta.

DÀrefter ansvarar Patroni för korrekt tillÀmpning av alla instÀllningar pÄ PostgreSQL och instÀllning av replikering samt utförande av kommandon för switchover och failover (det vill sÀga - planerat och oplanerat byte av master). Specifikt i molnet MCS kan man skapa ett kluster av en master, en synkron replik och en eller flera asynkrona replikar. NÀrvaron av en synkron replik sÀkerstÀller dataskydd pÄ minst 2 servrar, och just denna replik kommer att vara den frÀmsta "kandidaten till master".

Eftersom etcd körs pÄ samma servrar rekommenderas antalet servrar att vara 3 eller 5 för ett optimalt kvorum. Ett sÄdant kluster kan skalas horisontellt för lÀsning (om horizontal skalning för skrivning har jag skrivit ovan). Det bör dock beaktas att asynkrona replikar kan ha efterslÀpning, sÀrskilt vid hög belastning.

AnvÀndningen av sÄdana lÀsreplikar (hot standby) Àr rimlig för rapporterings- eller analyssyften och avlastar masterservrar.

Om du vill skapa ett sÄdant kluster sjÀlv behöver du:

  • förbereda 3 eller fler servrar, konfigurera IP-adressering och brandvĂ€ggsregler mellan dem;
  • installera paket för tjĂ€nsterna etcd, Patroni, PostgreSQL;
  • konfigurera etcd-klustret;
  • konfigurera patroni-tjĂ€nsten för att arbeta med PostgreSQL.

Det vill sÀga, i stort sett behöver du korrekt skapa ett tiotal konfigurationsfiler och inte göra nÄgra misstag. För detta Àr det definitivt vÀrt att anvÀnda ett verktyg för konfigurationshantering, som Ansible till exempel. Samtidigt saknas fortfarande en högtillgÀnglig TCP-lastbalanserare. Att skapa en sÄdan Àr ett separat arbete.

För dem som behöver en fÀrdig klusterlösning, men inte vill grÀva sig ner i allt detta, har vi försökt förenkla livet och gjort en fÀrdig klusterlösning pÄ Patroni i vÄrt moln, som kan testas kostnadsfritt. Förutom sjÀlva klustret har vi ocksÄ skapat:

  • En TCP-lastbalanserare; den pekar alltid pĂ„ den aktuella masterservern via olika portar, samt en synkron eller asynkron replik, beroende pĂ„ situationen;
  • Ett API för att byta aktiv master pĂ„ Patroni.

De kan anslutas bÄde via MCS-molnets API och via webbkonsolet.

Demo

För att testa möjligheterna hos PostgreSQL-klustret i MCS-molnet, lÄt oss se hur en levande applikation beter sig vid problem med databashanteringssystemet.

Nedan presenteras koden för en applikation som kommer att logga konstgjorda hÀndelser och rapportera detta pÄ skÀrmen. Vid eventuella fel kommer den att meddela detta och fortsÀtta sitt arbete i en loop tills vi stoppar den med en Ctrl + C.

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("Anslutning öppen till", 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("En vÀrde har registrerats, totalt antal: {}".format(record[0]))
    except Exception as error:
        print ("Fel vid anslutning till PostgreSQL", error)
    finally:
        if connection:
            cursor.close()
            connection.close()
            print("Anslutning stÀngd")


if __name__ == '__main__':
    try:
        while True:
            try:
                print(datetime.now())
                main()
                sleep(3)
            except Exception as e:
                print("FÄngad fel:n", e)
                sleep(1)
    except KeyboardInterrupt:
        print("avsluta")

Applikationen för arbete behöver PostgreSQL. LÄt oss skapa ett kluster i MCS-molnet med hjÀlp av API:et. I en vanlig terminal, dÀr OS_TOKEN-variabeln innehÄller token för Ätkomst till API:et (kan fÄs med kommandot openstack token issue), skriver vi in kommandona:

Vi skapar ett kluster:

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

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

NÀr klustret gÄr in i status ACTIVE kommer alla fÀlt att fÄ aktuella vÀrden - klustret Àr redo.

I GUI:

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

LÄt oss försöka ansluta och skapa en tabell:

psql -h 89.208.87.38 -U admin -d myproddb
Lösenord för anvÀndare admin:
psql (11.1, server 10.7)
Skriv "help" för hjÀlp.

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

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

I applikationen anger vi aktuella instÀllningar för att ansluta till PostgreSQL. Vi anger TCP-balancerarens adress, vilket innebÀr att vi slipper byta manuellt till mÀstarens adress. Vi startar den. Som syns, loggas hÀndelserna framgÄngsrikt i databasen.

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

Planerat byte av mÀstare

Nu testar vi vÄr applikations funktionalitet vid planerat byte av mÀstare:

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

Vi observerar applikationen. Vi ser att applikationens funktionalitet faktiskt avbryts, men det tar bara nÄgra sekunder, i det hÀr specifika fallet, max 9.

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

NedstÀngning av maskin

Nu ska vi försöka simulera nedstÀngning av den virtuella maskinen, som för nÀrvarande Àr mÀstare. Man skulle enkelt kunna stÀnga av den virtuella maskinen via Horizon-grÀnssnittet, men det skulle vara en normal avstÀngning. En sÄdan omkoppling kommer att hanteras av alla tjÀnster, inklusive Patroni.

Vi behöver en oförutsĂ€gbar avstĂ€ngning. DĂ€rför har jag bett vĂ„ra administratörer att för testĂ€ndamĂ„l stĂ€nga av den virtuella maskinen — den nuvarande mĂ€staren — pĂ„ ett onormalt sĂ€tt.

Hur vi byggde en pÄlitlig PostgreSQL-kluster pÄ Patroni

Under tiden fortsatte vÄr applikation att fungera. Naturligtvis kan ett sÄdant akut byte av mÀstare inte ske utan att mÀrkas.

2019-03-29 10:45:56.071234
Anslutning öppnad till PostgreSQL 10.7 pÄ x86_64-pc-linux-gnu, kompilerad av gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Loggad ett vÀrde, totalt antal: 453
Anslutning stÀngd
2019-03-29 10:45:59.205463
Anslutning öppnad till PostgreSQL 10.7 pÄ x86_64-pc-linux-gnu, kompilerad av gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Loggad ett vÀrde, totalt antal: 454

Anslutning stÀngd
2019-03-29 10:46:02.661440
Fel vid anslutning till PostgreSQL-servern stÀngde anslutningen ovÀntat
        Detta betyder troligtvis att servern avslutades onormalt
        innan eller medan begÀran behandlades.

Hittat fel:
 lokal variabel 'connection' refererad innan tilldelning





















.. - hÀr Àr ett antal fel
2019-03-29 10:46:30.930445
Fel vid anslutning till PostgreSQL-servern stÀngde anslutningen ovÀntat
        Detta betyder troligtvis att servern avslutades onormalt
        innan eller medan begÀran behandlades.

Hittat fel:
 lokal variabel 'connection' refererad innan tilldelning
2019-03-29 10:46:31.954399
Anslutning öppnad till PostgreSQL 10.7 pÄ x86_64-pc-linux-gnu, kompilerad av gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Loggad ett vÀrde, totalt antal: 455
Anslutning stÀngd
2019-03-29 10:46:35.409800
Anslutning öppnad till PostgreSQL 10.7 pÄ x86_64-pc-linux-gnu, kompilerad av gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
Loggad ett vÀrde, totalt antal: 456
Anslutning stÀngd
^Cexit

Som framgÄr kunde applikationen fortsÀtta sitt arbete pÄ mindre Àn 30 sekunder. Ja, vissa anvÀndare av tjÀnsten kommer att mÀrka problemen. Men det hÀr Àr en allvarlig serverkrasch, nÄgot som inte intrÀffar sÄ ofta. Dessutom skulle en person (administratören) troligtvis inte ha kunnat reagera sÄ snabbt, om hen inte satt vid konsolen med ett skript för att byta.

Utdata

Enligt min Äsikt ger en sÄdan kluster en enorm fördel för administratörer. I princip kommer allvarliga krasch och systemfel pÄ databasservrarna inte att mÀrkas av applikationen och dÀrmed inte av anvÀndaren. Det blir inte nödvÀndigt att snabbt ÄtgÀrda nÄgot och byta till temporÀra konfigurationer, servrar etc. Om en sÄdan lösning anvÀnds som en fÀrdig tjÀnst i molnet, behöver man inte lÀgga tid pÄ förberedelse. Man kan istÀllet fokusera pÄ mer intressanta uppgifter.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster