
Visoka razpoložljivost storitev je danes zahtevana vedno in povsod, ne le pri velikih dragih projektih. Začasno nedostopna spletna mesta s sporočilom »Oprostite, vzdrževanje je v teku« so še vedno pogosta, vendar običajno povzročijo prizanesljiv nasmeh. Temu življenju v oblaku dodajmo, ko za zagon dodatnega strežnika potrebujete samo en klic API-ju in vam ni treba razmišljati o delovanju »strojne opreme«. In ni več izgovorov, zakaj kritični sistem ni bil zgrajen zanesljivo z uporabo grozdnih tehnologij in redundance.
Povedali vam bomo, katere rešitve smo upoštevali za zagotavljanje zanesljivosti baz podatkov v naših storitvah in do česa smo prišli. Plus predstavitev z daljnosežnimi zaključki.
Zapuščina v arhitekturi visoke razpoložljivosti
Še bolje se to vidi v kontekstu razvoja različnih odprtokodnih sistemov. Podedovane rešitve so bile zaradi povečanega povpraševanja prisiljene dodati tehnologije visoke razpoložljivosti. In njihova kakovost je bila različna. Rešitve naslednje generacije postavljajo visoko razpoložljivost v jedro svoje arhitekture. Na primer, MongoDB pozicionira združevanje v gruče kot svoj primarni primer uporabe. Grozd se skalira vodoravno, kar je močna konkurenčna prednost tega DBMS.
Vrnimo se k PostgreSQL. To je eden najstarejših priljubljenih odprtokodnih projektov, katerega prva izdaja je bila v 95. letu prejšnjega stoletja. Projektna skupina dolgo časa ni menila, da je visoka razpoložljivost problem, ki bi ga moral sistem obravnavati. Zato je tehnologija podvajanja za ustvarjanje kopij podatkov postala vgrajena šele v različici 8.2 leta 2006, vendar je temeljila na datotekah (log shipping). Leta 2010 je različica 9.0 uvedla pretočno replikacijo in je osnova za ustvarjanje najrazličnejših gruč. To je pravzaprav zelo presenetljivo za ljudi, ki se s PostgreSQL seznanijo po Enterprise SQL ali sodobnem NoSQL - standardna rešitev skupnosti je preprosto par master-replika s sinhrono ali asinhrono replikacijo. Hkrati se na zalogi preklapljanje nadrejenega izvaja ročno, vprašanje preklopa odjemalcev pa se predlaga tudi samostojno reševanje.
Kako smo se odločili narediti zanesljiv PostgreSQL in kaj smo za to izbrali
Vendar PostgreSQL ne bi postal tako priljubljen, če ne bi bilo ogromno projektov in orodij, ki pomagajo zgraditi rešitev, odporno na napake, ki ne zahteva stalne pozornosti. V oblaku (MCS) posamezni strežniki PostgreSQL in pari glavna replika z asinhronim podvajanjem so na voljo od lansiranja DBaaS.
Seveda smo želeli olajšati življenje vsem in dati na voljo namestitev PostgreSQL, ki bi lahko služila kot osnova za visoko razpoložljive storitve, ne da bi bilo treba nenehno spremljati in se ponoči zbujati, da izvedemo preklop. V tem segmentu so stare preizkušene rešitve in generacije novih pripomočkov, ki uporabljajo najnovejše dosežke.
Danes problem visoke razpoložljivosti ne temelji na odvečnosti (to je samoumevno), ampak na soglasju – volilnem algoritmu Leader. Najpogosteje se večje nesreče ne zgodijo zaradi pomanjkanja strežnikov, temveč zaradi težav s konsenzom: nov vodja ni bil izbran, dva voditelja sta se pojavila v različnih podatkovnih centrih itd. Primer – nesreča na gruči Github MySQL – so zapisali .
Matematična podlaga v tej zadevi je zelo resna. Po eni strani obstaja , ki nalaga teoretične omejitve na možnosti konstruiranja HA rešitev, na drugi strani pa matematično preverjene algoritme za ugotavljanje konsenza, kot je npr. и . Na tej podlagi so precej priljubljeni DCS (decentralizirani konsenzni sistemi) - Zookeeper itd., Consul. Torej, če sistem odločanja deluje na nekem algoritmu, ki je napisan neodvisno, morate z njim ravnati zelo previdno. Po analizi ogromnega števila sistemov smo se odločili za Patroni, odprtokodni sistem, ki ga je v glavnem razvil Zalando.
Kot lirično digresijo bom povedal, da smo razmišljali tudi o multimaster rešitvah, torej grozdih, ki jih je mogoče vodoravno skalirati za snemanje. Vendar so se zaradi dveh glavnih razlogov odločili, da takšnega grozda ne bodo ustvarili. Prvič, takšne rešitve imajo visoko kompleksnost in s tem večjo ranljivost. Težko bo narediti stabilno rešitev za vse primere. Drugič, v tem primeru PostgreSQL preneha biti čist (izvoren), nekatere funkcije ne bodo na voljo, nekatere aplikacije pa bodo med delovanjem morda imele skrite napake.
Patroni
Kako torej Patroni deluje? Razvijalci niso znova izumljali kolesa in so kot osnovo predlagali uporabo ene od preverjenih rešitev DCS. Vsa vprašanja s sinhronizacijo konfiguracij, volitvami vodje in sklepčnostjo so prepuščena njemu. Za to smo izbrali etcd.
Nato se Patroni ukvarja s pravilno uporabo vseh nastavitev na PostgreSQL in nastavitvami replikacije ter izvajanjem ukazov na preklop in preklop (torej redni in zasilni preklop glavnega). Natančneje v oblaku MCS lahko ustvarite gručo masterja, sinhrone replike in ene ali več asinhronih replik. Prisotnost sinhrone replike zagotavlja varnost podatkov na vsaj 2 strežnikih in prav ta replika bo glavni "glavni kandidat".
Ker je etcd nameščen na istih strežnikih, je priporočeno število strežnikov 3 ali 5 za optimalen kvorum. Takšna gruča se vodoravno skalira za branje (o skaliranju za pisanje sem pisal zgoraj). Vendar se zavedajte, da so asinhrone replike nagnjene k zakasnitvi, zlasti pri visokih obremenitvah.
Uporaba takšnih replik za branje (hot standby) je upravičena za naloge poročanja ali analitike in razbremeni glavni strežnik.
Če želite sami narediti takšno gručo, boste potrebovali:
- pripravite 3 ali več strežnikov, konfigurirajte naslavljanje IP in pravila požarnega zidu med njimi;
- namestite pakete za storitve etcd, Patroni, PostgreSQL;
- konfigurirajte gručo etcd;
- konfigurirajte storitev patroni za delo s PostgreSQL.
To pomeni, da morate skupaj pravilno sestaviti ducat konfiguracijskih datotek in se nikjer ne zmotiti. Za to vsekakor uporabite orodje za upravljanje konfiguracije, kot je na primer Ansible. Vendar še vedno ni visoko razpoložljivega uravnotežilnika TCP. Izdelava je ločeno delo.
Za tiste, ki potrebujejo že pripravljeno gručo, a se ne želijo ukvarjati z vsem tem, smo poskušali poenostaviti življenje in naredili pripravljeno gručo na Patroni v našem oblaku, lahko jo brezplačno preizkusite. Poleg samega grozda smo naredili še:
- TCP uravnoteženje; na različnih vratih vedno kaže na trenutno glavno, sinhrono ali asinhrono repliko;
- API za preklapljanje aktivnega glavnega Patroni.
Do njih lahko dostopate prek API-ja v oblaku MCS in spletne konzole.
Demo
Da preizkusimo zmogljivosti gruče PostgreSQL v oblaku MCS, poglejmo, kako se aplikacija v živo obnaša v primeru težav z DBMS.
Spodaj je koda za aplikacijo, ki bo beležila umetne dogodke in jih poročala na zaslon. V primeru napak bo to javil in nadaljeval svoje delo v zanki, dokler ga ne ustavimo s kombinacijo 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("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")
Za delovanje aplikacije je potreben PostgreSQL. Ustvarimo gručo v oblaku MCS z uporabo API-ja. V običajnem terminalu, kjer spremenljivka OS_TOKEN vsebuje žeton za dostop do API-ja (dobimo ga lahko z ukazom openstack token issue), bomo vnesli naslednje ukaze:
Ustvarite gručo:
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

Ko grozd preklopi v stanje AKTIVNO, bodo vsa polja prejela trenutne vrednosti - grozd je pripravljen.
V GUI:

Poskusimo se povezati in ustvariti tabelo:
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=>

V aplikaciji bomo navedli trenutne nastavitve za povezavo s PostgreSQL. Določili bomo naslov TCP uravnoteženja, s čimer bomo odpravili potrebo po ročnem preklopu na glavni naslov. Zaženimo ga. Kot lahko vidite, so dogodki uspešno prijavljeni v bazo podatkov.

Načrtovani glavni preklop
Zdaj pa preizkusimo delovanje naše aplikacije med načrtovanim glavnim stikalom:

Aplikacijo spremljamo. Vidimo, da je aplikacija res prekinjena, vendar traja le nekaj sekund, v tem primeru največ 9.

Prometna nesreča
Zdaj pa poskusimo simulirati zrušitev virtualnega stroja, trenutnega glavnega. Lahko bi preprosto izklopili virtualni stroj prek vmesnika Horizon, vendar bi bila to redna zaustavitev. Tak preklop bodo obdelale vse storitve, vključno s Patronijem.
Potrebujemo nepredvidljivo zaustavitev. Zato sem prosil naše skrbnike, da za testne namene na nestandarden način zaustavijo virtualni stroj - trenutni master.

Hkrati je naša aplikacija delovala naprej. Seveda tak zasilni preklop glavnega sistema ne more ostati neopažen.
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
Kot lahko vidite, je aplikacija lahko nadaljevala svoje delo v manj kot 30 sekundah. Da, določeno število uporabnikov storitev bo imelo čas opaziti težave. Vendar je to resna napaka strežnika; to se ne zgodi prav pogosto. V tem primeru bi človek (administrator) komaj imel čas za tako hiter odziv, razen če bi sedel v konzoli s pripravljenim preklopnim skriptom.
Izhod
Zdi se mi, da takšna gruča predstavlja izjemno prednost za skrbnike. Dejansko resne okvare in okvare strežnikov baz podatkov ne bodo opazne za aplikacijo in s tem za uporabnika. Ničesar vam ne bo treba popravljati na hitro in preklopiti na začasne konfiguracije, strežnike itd. In če se taka rešitev uporablja kot že pripravljena storitev v oblaku, potem vam ne bo treba izgubljati časa s pripravo. Se bo dalo narediti še kaj zanimivega.
Vir: www.habr.com
