Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

今日、倧芏暡な高䟡なプロゞェクトだけでなく、い぀でもどこでもサヌビスの高可甚性が求められおいたす。 「申し蚳ありたせんが、メンテナンス䞭です」ずいうメッセヌゞが衚瀺され、䞀時的に利甚できないサむトは䟝然ずしお存圚したすが、通垞は芋䞋したような笑みを浮かべたす。 このクラりドでの生掻にさらに加えおみたしょう。远加のサヌバヌを起動するずきは、API を XNUMX 回呌び出すだけで枈み、「ハヌドりェア」の操䜜に぀いお考える必芁はありたせん。 そしお、重芁なシステムがクラスタヌ テクノロゞヌず冗長性を䜿甚しお確実に構築されなかった理由は、もはや匁解の䜙地がありたせん。

圓瀟のサヌビスにおけるデヌタベヌスの信頌性を確保するためにどのような゜リュヌションを怜蚎し、どのような結論に至ったのかに぀いお説明したす。 さらに、広範囲にわたる結論を瀺すデモも含たれたす。

高可甚性アヌキテクチャのレガシヌ

これは、さたざたなオヌプン゜ヌス システムの開発のコンテキストでさらによくわかりたす。 埓来の゜リュヌションでは、需芁の増加に応じお高可甚性テクノロゞを远加する必芁がありたした。 そしおその質も様々でした。 次䞖代゜リュヌションは、高可甚性をアヌキテクチャの䞭栞に据えたす。 たずえば、MongoDB はクラスタリングを䞻芁なナヌスケヌスずしお䜍眮付けおいたす。 クラスタヌは氎平方向に拡匵され、これがこの DBMS の匷力な競争䞊の利点ずなりたす。

PostgreSQL に戻りたしょう。 これは最も叀い人気のあるオヌプン゜ヌス プロゞェクトの 95 ぀で、最初のリリヌスは前䞖玀の 8.2 幎に行われたした。 長い間、プロゞェクト チヌムは高可甚性がシステムによっお察凊される必芁がある問題であるずは考えおいたせんでした。 したがっお、デヌタのコピヌを䜜成するレプリケヌション テクノロゞは 2006 幎のバヌゞョン 2010 にのみ組み蟌たれたしたが、それはファむル ベヌス (ログ シッピング) でした。 9.0 幎のバヌゞョン XNUMX ではストリヌミング レプリケヌションが導入され、これがさたざたなクラスタヌを䜜成するための基瀎ずなっおいたす。 実際、これは、Enterprise SQL や最新の NoSQL の埌に PostgreSQL に慣れ芪しんだ人にずっおは非垞に驚くべきこずです。コミュニティの暙準゜リュヌションは、単玔に同期たたは非同期レプリケヌションを備えたマスタヌずレプリカのペアです。 同時に、圚庫ではマスタヌの切り替えが手動で行われ、クラむアントの切り替えの問題も独自に解決されるこずが提案されおいたす。

信頌性の高い PostgreSQL を䜜成するこずをどのように決定したか、そしおそのために䜕を遞択したか

しかし、継続的な泚意を必芁ずしないフォヌルト トレラント ゜リュヌションの構築に圹立぀膚倧な数のプロゞェクトやツヌルがなければ、PostgreSQL はこれほど普及しなかったでしょう。 クラりドの䞭で Mail.ru クラりド ゜リュヌション (MCS) DBaaS の開始以来、非同期レプリケヌションを備えた単䞀の PostgreSQL サヌバヌずマスタヌずレプリカのペアが利甚可胜になりたした。

圓然のこずながら、私たちはすべおの人にずっお䜜業を楜にし、切り替えのために垞に監芖したり倜䞭に起きたりする必芁がなく、高可甚性サヌビスの基盀ずしお機胜する PostgreSQL むンストヌルを利甚できるようにしたいず考えおいたした。 このセグメントには、叀くから実瞟のある゜リュヌションず、最新の開発を䜿甚した新しい䞖代のナヌティリティの䞡方がありたす。

今日、高可甚性の問題は冗長性 (これは蚀うたでもありたせん) に䟝存しおいるのではなく、コンセンサス、぀たりリヌダヌ遞出アルゎリズムに䟝存しおいたす。 ほずんどの堎合、重倧な事故はサヌバヌの䞍足が原因ではなく、コンセンサスの問題が原因で発生したす。぀たり、新しいリヌダヌが遞ばれおいない、XNUMX 人のリヌダヌが異なるデヌタセンタヌに珟れおいるなどです。 䟋 - Github MySQL クラスタヌでの事故 - 圌らはこう曞きたした 詳现な事埌分析.

この問題の数孊的根拠は非垞に深刻です。 䞀方で、 CAP定理、これは HA ゜リュヌションを構築する可胜性に理論的な制限を課したすが、䞀方で、合意を決定するための数孊的に蚌明されたアルゎリズムは次のずおりです。 パクシ О Raft。 これに基づいお、非垞に人気のある DCS (分散型コンセンサス システム)、Zookeeper、etcd、Consul がありたす。 したがっお、意思決定システムが独自に䜜成されたある皮のアルゎリズムで動䜜する堎合は、现心の泚意を払っお扱う必芁がありたす。 膚倧な数のシステムを分析した結果、䞻に Zalando が開発したオヌプン゜ヌス システムである Patroni に萜ち着きたした。

䜙談になりたすが、私たちはマルチマスタヌ ゜リュヌション、぀たり録音甚に氎平方向にスケヌリングできるクラスタヌも怜蚎したず蚀いたす。 ただし、XNUMX ぀の䞻な理由により、そのようなクラスタヌを䜜成しないこずにしたした。 たず、このような゜リュヌションは耇雑さが高く、したがっお脆匱性も倚くなりたす。 すべおのケヌスに察しお安定した解決策を講じるこずは困難です。 第二に、この堎合、PostgreSQL は玔粋 (ネむティブ) ではなくなり、䞀郚の機胜が䜿甚できなくなり、䞀郚のアプリケヌションには動䜜䞭に隠れたバグが存圚する可胜性がありたす。

パトロヌニ

では、パトロヌニはどのように機胜するのでしょうか? 開発者は車茪の再発明を行わず、実瞟のある DCS ゜リュヌションの XNUMX ぀を基瀎ずしお䜿甚するこずを提案したした。 構成の同期、リヌダヌず定足数の遞出に関するすべおの問題は圌に任されおいたす。 このために etcd を遞択したした。

次に、Patroni は、PostgreSQL のすべおの蚭定ずレプリケヌション蚭定の正しい適甚、およびスむッチオヌバヌずフェむルオヌバヌ (぀たり、マスタヌの定期的および緊急切り替え) でのコマンドの実行を凊理したす。 特に MCS クラりドでは、マスタヌ、同期レプリカ、および 2 ぀以䞊の非同期レプリカのクラスタヌを䜜成できたす。 同期レプリカの存圚により、少なくずも XNUMX 台のサヌバヌ䞊のデヌタの安党性が確保され、このレプリカが䞻な「マスタヌ候補」になりたす。

etcd は同じサヌバヌにデプロむされるため、最適なクォヌラムを実珟するには、サヌバヌの掚奚数は 3 たたは 5 です。 このようなクラスタヌは読み取り甚に氎平方向にスケヌリングしたす (曞き蟌み甚のスケヌリングに぀いおは䞊で曞きたした)。 ただし、非同期レプリカは、特に高負荷時に遅延が発生する傟向があるこずに泚意しおください。

このようなリヌドレプリカ (ホットスタンバむ) の䜿甚は、レポヌトタスクや分析タスクに正圓化され、マスタヌサヌバヌの負荷を軜枛したす。

このようなクラスタヌを自分で䜜成したい堎合は、以䞋が必芁になりたす。

  • 3 ぀以䞊のサヌバヌを準備し、サヌバヌ間の IP アドレス指定ずファむアりォヌル ルヌルを構成したす。
  • etcd、Patroni、PostgreSQL サヌビスのパッケヌゞをむンストヌルしたす。
  • etcd クラスタヌを構成したす。
  • PostgreSQL で動䜜するように patroni サヌビスを構成したす。

぀たり、合蚈で XNUMX 個の構成ファむルを正しく䜜成し、どこにもミスをしない必芁がありたす。 このためには、たずえば Ansible などの構成管理ツヌルを必ず䜿甚する必芁がありたす。 ただし、可甚性の高い TCP バランサヌはただありたせん。 䜜るのは別䜜業です。

既補のクラスタヌが必芁だが、あれこれいじくり回したくはないずいう人のために、私たちは䜜業を簡玠化するために、クラりド内の Patroni 䞊に既補のクラスタヌを䜜成したした。無料でテストできたす。 クラスタヌ自䜓に加えお、次のこずを行いたした。

  • TCPバランサ。 異なるポヌトでは、垞に珟圚のマスタヌ、同期レプリカ、たたは非同期レプリカをそれぞれ指したす。
  • アクティブなPatroniマスタヌを切り替えるためのAPI。

これらには、MCS クラりド API および Web コン゜ヌル経由でアクセスできたす。

ДеЌП

MCS クラりドで PostgreSQL クラスタヌの機胜をテストするために、DBMS に問題が発生した堎合にラむブ アプリケヌションがどのように動䜜するかを芋おみたしょう。

以䞋は、人為的なむベントをログに蚘録し、それを画面に報告するアプリケヌションのコヌドです。 ゚ラヌが発生した堎合、これが報告され、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")

アプリケヌションが動䜜するには PostgreSQL が必芁です。 API を䜿甚しお MCS クラりドにクラスタヌを䜜成したしょう。 通垞のタヌミナルでは、OS_TOKEN 倉数に API にアクセスするためのトヌクン (openstack token issue コマンドで取埗できたす) が含たれおおり、次のコマンドを入力したす。

クラスタヌを䜜成したす。

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

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

クラスタヌが ACTIVE ステヌタスに切り替わるず、すべおのフィヌルドが珟圚の倀を受け取りたす。クラスタヌの準備は完了です。

GUI の堎合:

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

接続しおテヌブルを䜜成しおみたしょう。

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

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

アプリケヌションでは、PostgreSQL に接続するための珟圚の蚭定を瀺したす。 TCP バランサヌのアドレスを指定するこずで、マスタヌ アドレスに手動で切り替える必芁がなくなりたす。 起動したしょう。 ご芧のずおり、むベントはデヌタベヌスに正垞に蚘録されおいたす。

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

スケゞュヌルされたマスタヌ切り替え

次に、スケゞュヌルされたマスタヌ切り替え䞭のアプリケヌションの動䜜をテストしおみたしょう。

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

私たちはアプリケヌションを監芖しおいたす。 アプリケヌションが確かに䞭断されおいるこずがわかりたすが、それにかかる時間はわずか数秒、この特定のケヌスでは最倧 9 秒です。

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

自動車事故

次に、珟圚のマスタヌである仮想マシンのクラッシュをシミュレヌトしおみたしょう。 Horizo​​n むンタヌフェむスを介しお仮想マシンを単玔にオフにするこずもできたすが、これは通垞のシャットダりンになりたす。 このような切り替えは、Patroni を含むすべおのサヌビスによっお凊理されたす。

予枬できないシャットダりンが必芁です。 したがっお、私は管理者に、テスト目的で仮想マシン (珟圚のマスタヌ) を非暙準的な方法でシャットダりンするように䟝頌したした。

Patroni 䞊で信頌性の高い PostgreSQL クラスタヌを構築した方法

同時に、アプリケヌションは匕き続き動䜜したした。 圓然のこずながら、このようなマスタヌの緊急切り替えが無芖されるはずはありたせん。

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

ご芧のずおり、アプリケヌションは 30 秒以内に䜜業を続行できたした。 はい、䞀定数のサヌビス ナヌザヌは問題に気づく時間がありたす。 ただし、これは深刻なサヌバヌ障害であり、頻繁に発生するものではありたせん。 この堎合、人 (管理者) は、コン゜ヌルに座っお切り替えスクリプトの準備ができおいない限り、これほど迅速に察応する時間はほずんどありたせんでした。

出力

このようなクラスタヌは管理者にずっお非垞にメリットがあるように思えたす。 実際、デヌタベヌス サヌバヌの重倧な故障や障害は、アプリケヌション、ひいおはナヌザヌには気付かれたせん。 急いで䜕かを修正したり、䞀時的な構成やサヌバヌなどに切り替える必芁はありたせん。 たた、そのような゜リュヌションがクラりド内の既補のサヌビスずしお䜿甚されれば、準備に時間を無駄にする必芁はありたせん。 もっず面癜いこずができるようになるでしょう。

出所 habr.com

DDoS 保護機胜を備えた信頌性の高いサむト甚ホスティング、VPS VDS サヌバヌを賌入する 🔥 DDoS攻撃察策付きの信頌性の高いりェブサむトホスティング、VPS/VDSサヌバヌを賌入したしょう | ProHoster