
Saat ini, ketersediaan layanan yang tinggi diperlukan selalu dan di mana-mana, tidak hanya dalam proyek besar yang mahal. Situs sementara tidak tersedia dengan pesan "Maaf, pemeliharaan sedang dilakukan" masih terjadi, tetapi biasanya menyebabkan senyum merendahkan. Tambahkan ke kehidupan ini di awan, ketika memulai server tambahan Anda hanya perlu satu panggilan ke API, dan Anda tidak perlu memikirkan operasi "besi". Dan tidak ada lagi alasan mengapa sistem kritis tidak dibuat andal menggunakan teknologi cluster dan redundansi.
Kami akan memberi tahu Anda solusi apa yang kami pertimbangkan untuk memastikan keandalan basis data dalam layanan kami dan apa yang kami tuju. Ditambah demo dengan kesimpulan yang luas.
Warisan dalam arsitektur ketersediaan tinggi
Ini bahkan lebih baik dilihat dalam konteks pengembangan berbagai sistem sumber terbuka. Solusi lama terpaksa menambahkan teknologi ketersediaan tinggi karena permintaan meningkat. Dan kualitas mereka berbeda. Solusi generasi mendatang menempatkan ketersediaan tinggi di inti arsitektur mereka. Sebagai contoh, MongoDB memposisikan cluster sebagai use case utama. Cluster berskala horizontal, yang merupakan keunggulan kompetitif yang kuat dari DBMS ini.
Kembali ke PostgreSQL. Ini adalah salah satu proyek opensource populer tertua, rilis pertama yang berlangsung pada tahun ke-95 abad terakhir. Untuk waktu yang lama, tim proyek tidak menganggap ketersediaan tinggi sebagai tugas yang perlu ditangani oleh sistem. Oleh karena itu, teknologi replikasi untuk membuat salinan data menjadi terintegrasi hanya dalam versi 8.2 pada tahun 2006, tetapi diajukan (pengiriman log). Pada 2010, replikasi streaming muncul di versi 9.0, dan itu adalah dasar untuk membuat berbagai kluster. Ini, pada kenyataannya, sangat mengejutkan bagi orang-orang yang mengenal PostgreSQL setelah Enterprise SQL atau NoSQL modern - solusi standar dari komunitas hanyalah beberapa master-replika dengan replikasi sinkron atau asinkron. Pada saat yang sama, wizard diaktifkan secara manual di saluran, dan masalah berpindah klien juga diusulkan untuk diselesaikan secara mandiri.
Bagaimana kami memutuskan untuk membuat PostgreSQL yang andal dan apa yang kami pilih untuk ini
Namun, PostgreSQL tidak akan menjadi begitu populer jika tidak ada banyak proyek dan alat yang membantu membangun solusi toleran kesalahan yang tidak memerlukan perhatian terus-menerus. Sejak peluncuran DBaaS, satu server PostgreSQL dan pasangan master replika dengan replikasi asinkron telah tersedia di
Mail.ru Cloud Solutions (MCS).
Secara alami, kami ingin menyederhanakan kehidupan semua orang dan membuat instalasi PostgreSQL tersedia, yang dapat berfungsi sebagai dasar untuk layanan yang sangat mudah diakses yang Anda tidak harus terus memantau dan bangun di malam hari untuk beralih. Di segmen ini ada solusi lama terbukti dan generasi utilitas baru yang menggunakan perkembangan terbaru.
Saat ini, masalah ketersediaan tinggi tidak bergantung pada redundansi (tidak perlu dikatakan lagi), tetapi pada konsensus - sebuah algoritma untuk memilih pemimpin (pemilihan Pemimpin). Paling sering, kecelakaan besar terjadi bukan karena kurangnya server, tetapi karena masalah dengan konsensus: pemimpin baru tidak keluar, dua pemimpin muncul di pusat data yang berbeda, dll. Contohnya adalah crash pada cluster Github MySQL - mereka menulis
post mortem yang terperinci .
Basis matematika dalam hal ini sangat serius. Di satu sisi, ada
teorema CAP , yang memaksakan pembatasan teoritis pada kemungkinan membangun solusi HA, dan di sisi lain, algoritma penentuan konsensus yang terbukti secara matematis seperti
Paxos dan
Raft . Atas dasar ini, ada DCS yang cukup populer (sistem konsensus desentralisasi) - Zookeeper, etcd, Consul. Karena itu, jika sistem pengambilan keputusan bekerja pada beberapa algoritmanya sendiri, ditulis secara independen, Anda harus sangat berhati-hati mengenai hal itu. Setelah menganalisis sejumlah besar sistem, kami memilih Patroni - sistem sumber terbuka, terutama dikembangkan oleh Zalando.
Sebagai penyimpangan liris, saya akan mengatakan bahwa kami juga mempertimbangkan solusi multi-master, yaitu, cluster yang dapat diskalakan secara horizontal ke rekaman. Namun, karena dua alasan utama, mereka memutuskan untuk tidak membuat cluster seperti itu. Pertama, solusi tersebut memiliki kompleksitas tinggi dan, karenanya, lebih banyak kerentanan. Akan sulit untuk membuat keputusan yang stabil untuk semua kasus. Kedua, dalam hal ini, PostgreSQL tidak lagi murni (asli), beberapa fungsi tidak akan tersedia, beberapa aplikasi mungkin mengalami bug tersembunyi ketika bekerja.
Patroni
Jadi bagaimana cara kerja Patroni? Pengembang tidak menemukan kembali roda dan menyarankan menggunakan salah satu solusi DCS yang terbukti sebagai dasar. Semua masalah dengan sinkronisasi konfigurasi, pilihan pemimpin dan kuorum diberikan kepadanya. Kami telah memilih etcd untuk ini.
Kemudian Patroni berurusan dengan aplikasi yang benar dari semua pengaturan pada PostgreSQL dan pengaturan replikasi, serta eksekusi perintah pada switchover dan failover (yaitu, penyihir switching biasa dan non-standar). Secara khusus, di cloud MCS, Anda dapat membuat cluster dari wizard, replika sinkron, dan satu atau lebih replika asinkron. Kehadiran replika sinkron memastikan keamanan data pada setidaknya 2 server, dan replika ini akan menjadi "kandidat utama master."
Karena etcd digunakan pada server yang sama, disarankan agar jumlah server menjadi 3 atau 5, untuk nilai kuorum optimal. Cluster seperti ini diskalakan secara horizontal untuk membaca (saya menulis tentang penskalaan untuk penulisan di atas). Namun demikian, harus diingat bahwa replika asinkron tertinggal, terutama pada beban tinggi.
Penggunaan replika siaga baca semacam itu dibenarkan untuk melaporkan atau menganalisis tugas dan menurunkan server master.
Jika Anda ingin membuat cluster sendiri, maka Anda perlu:
- menyiapkan 3 atau lebih server, mengkonfigurasi alamat IP dan aturan firewall di antara mereka;
- instal paket untuk layanan etcd, Patroni, PostgreSQL;
- mengkonfigurasi etcd cluster;
- konfigurasikan layanan patroni agar berfungsi dengan PostgreSQL.
Secara total, Anda harus membuat lusinan file konfigurasi dengan benar dan tidak membuat kesalahan di mana pun. Untuk melakukan ini, tentu saja layak menggunakan alat manajemen konfigurasi seperti Ansible, misalnya. Namun, masih belum ada penyeimbang TCP yang sangat tersedia. Melakukannya adalah pekerjaan terpisah.
Bagi mereka yang membutuhkan cluster siap pakai, tetapi tidak ingin mengotak-atik semua ini, kami mencoba menyederhanakan hidup kami dan membuat cluster siap pakai di Patroni di cloud kami, itu dapat diuji secara gratis. Selain cluster itu sendiri, kami melakukan:
- Penyeimbang TCP pada port yang berbeda, masing-masing selalu menunjuk ke replika master, sinkron atau asinkron, masing-masing;
- API untuk mengganti wizard Patroni aktif.
Mereka dapat dihubungkan baik melalui MCS cloud API dan konsol web.
Demo
Untuk menguji kemampuan cluster PostgreSQL di cloud MCS, mari kita lihat bagaimana aplikasi live berperilaku jika ada masalah dengan DBMS.
Berikut ini adalah kode untuk aplikasi yang akan mencatat peristiwa buatan dan melaporkannya ke layar. Jika terjadi kesalahan, ia akan melaporkan ini dan melanjutkan kerjanya dalam siklus hingga kami menghentikannya dengan kombinasi 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")
Aplikasi membutuhkan PostgreSQL agar berfungsi. Buat cluster di cloud MCS menggunakan API. Di terminal reguler, tempat variabel OS_TOKEN berisi token untuk mengakses API (Anda bisa mendapatkannya dengan perintah openstack token issue), kami mengetikkan perintah:
Buat sebuah kluster:
cat <<EF > 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

Ketika cluster memasuki status AKTIF, semua bidang akan menerima nilai saat ini - cluster siap.
Di GUI:

Mari kita coba sambungkan dan buat tabel:
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=>

Dalam aplikasi, kami menunjukkan pengaturan saat ini untuk menghubungkan ke PostgreSQL. Kami akan menentukan alamat penyeimbang TCP, sehingga menghilangkan kebutuhan untuk beralih secara manual ke alamat penyihir. Jalankan itu. Seperti yang Anda lihat, peristiwa-peristiwa tersebut berhasil masuk ke dalam basis data.

Sakelar master terjadwal
Sekarang kita akan menguji operasi aplikasi kita selama perpindahan wizard yang direncanakan:

Kami sedang menonton aplikasi. Kami melihat bahwa aplikasi ini benar-benar terganggu, tetapi hanya perlu beberapa detik, dalam kasus khusus ini, maksimum 9.

Mobil jatuh
Sekarang mari kita coba mensimulasikan kejatuhan mesin virtual, master saat ini. Mungkin saja mematikan mesin virtual melalui antarmuka Horizon, hanya saja itu akan menjadi shutdown biasa. Switch semacam itu akan diproses oleh semua layanan, termasuk Patroni.
Kami membutuhkan shutdown yang tidak terduga. Oleh karena itu, saya meminta administrator kami untuk tujuan pengujian mematikan mesin virtual - master saat ini - dengan cara yang tidak normal.

Pada saat yang sama, aplikasi kami terus bekerja. Secara alami, sakelar darurat master seperti itu tidak dapat lewat tanpa diketahui.
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
Seperti yang Anda lihat, aplikasi dapat melanjutkan pekerjaannya dalam waktu kurang dari 30 detik. Ya, sejumlah pengguna layanan tertentu akan memiliki waktu untuk melihat masalah. Namun, ini adalah kegagalan server yang serius, ini tidak terjadi begitu sering. Pada saat yang sama, orang (administrator) akan sulit bereaksi dengan cepat, kecuali dia sedang duduk di konsol siap dengan skrip switching.
Kesimpulan
Tampak bagi saya bahwa cluster seperti itu memberikan keuntungan luar biasa bagi administrator. Bahkan, gangguan serius dan malfungsi server database tidak akan terlihat untuk aplikasi dan, oleh karena itu, untuk pengguna. Anda tidak perlu memperbaiki sesuatu dengan tergesa-gesa dan beralih ke konfigurasi sementara, server, dll. Dan jika Anda menggunakan solusi ini dalam bentuk layanan siap pakai di cloud, maka Anda tidak perlu membuang waktu untuk menyiapkannya. Dimungkinkan untuk melakukan sesuatu yang lebih menarik.