
Hello, Habr! Saya Artem Karamyshev, ketua pasukan pentadbiran sistem . Kami telah mempunyai banyak pelancaran produk baharu sepanjang tahun lalu. Kami ingin memastikan bahawa perkhidmatan API mudah berskala, bertolak ansur dengan kesalahan dan bersedia untuk pertumbuhan pesat dalam beban pengguna. Platform kami dilaksanakan pada OpenStack, dan saya ingin memberitahu anda masalah toleransi kesalahan komponen yang perlu kami selesaikan untuk mendapatkan sistem toleransi kesalahan. Saya fikir ini akan menjadi menarik bagi mereka yang turut membangunkan produk di OpenStack.
Toleransi kesalahan keseluruhan platform terdiri daripada daya tahan komponennya. Jadi kami akan secara beransur-ansur melalui semua peringkat di mana kami mengenal pasti risiko dan menutupnya.
Versi video cerita ini, yang sumber utamanya ialah laporan pada persidangan Uptime day 4, yang dianjurkan oleh , awak boleh lihat .
Ketahanan seni bina fizikal
Bahagian awam awan MCS kini berpangkalan di dua pusat data Tahap III, di antara mereka terdapat gentian gelapnya sendiri, dikhaskan pada tahap fizikal melalui laluan yang berbeza, dengan daya pemprosesan 200 Gbit/s. Tahap III menyediakan tahap toleransi kesalahan yang diperlukan untuk infrastruktur fizikal.
Gentian gelap dikhaskan pada tahap fizikal dan logik. Proses tempahan saluran adalah berulang, masalah timbul, dan kami sentiasa meningkatkan komunikasi antara pusat data.
Sebagai contoh, tidak lama dahulu, semasa bekerja di telaga berhampiran salah satu pusat data, sebuah jengkaut memecahkan paip, dan di dalam paip ini terdapat kabel optik utama dan sandaran. Saluran komunikasi toleransi kesalahan kami dengan pusat data ternyata terdedah pada satu ketika, di dalam telaga. Sehubungan itu, kami telah kehilangan sebahagian daripada infrastruktur. Kami membuat kesimpulan dan mengambil beberapa tindakan, termasuk memasang optik tambahan di telaga bersebelahan.
Di pusat data terdapat tempat kehadiran penyedia komunikasi yang kami siarkan awalan kami melalui BGP. Untuk setiap arah rangkaian, metrik terbaik dipilih, yang membolehkan pelanggan yang berbeza diberikan kualiti sambungan terbaik. Jika komunikasi melalui satu pembekal terputus, kami membina semula penghalaan kami melalui penyedia yang tersedia.
Jika pembekal gagal, kami bertukar secara automatik kepada pembekal seterusnya. Sekiranya berlaku kegagalan salah satu pusat data, kami mempunyai salinan cermin perkhidmatan kami di pusat data kedua, yang mengambil keseluruhan beban.

Ketahanan infrastruktur fizikal
Perkara yang kami gunakan untuk toleransi kesalahan peringkat aplikasi
Perkhidmatan kami dibina di atas beberapa komponen sumber terbuka.
ExaBGP ialah perkhidmatan yang melaksanakan beberapa fungsi menggunakan protokol penghalaan dinamik berasaskan BGP. Kami menggunakannya secara aktif untuk mengiklankan alamat IP kami yang disenarai putih yang melaluinya pengguna mengakses API.
HAProxy ialah pengimbang beban tinggi yang membolehkan anda mengkonfigurasi peraturan pengimbangan trafik yang sangat fleksibel pada tahap model OSI yang berbeza. Kami menggunakannya untuk mengimbangi di hadapan semua perkhidmatan: pangkalan data, broker mesej, perkhidmatan API, perkhidmatan web, projek dalaman kami - semuanya berada di belakang HAProxy.
aplikasi API — aplikasi web yang ditulis dalam python, yang dengannya pengguna menguruskan infrastruktur dan perkhidmatannya.
Permohonan pekerja (selepas ini hanya pekerja) - dalam perkhidmatan OpenStack, ini adalah daemon infrastruktur yang membolehkan anda menyiarkan arahan API ke infrastruktur. Sebagai contoh, penciptaan cakera berlaku dalam pekerja, dan permintaan penciptaan berlaku dalam API aplikasi.
Senibina Aplikasi OpenStack Standard
Kebanyakan perkhidmatan yang dibangunkan untuk OpenStack cuba mengikuti satu paradigma. Perkhidmatan biasanya terdiri daripada 2 bahagian: API dan pekerja (pelaksana bahagian belakang). Sebagai peraturan, API ialah aplikasi WSGI dalam python, yang dilancarkan sama ada sebagai proses bebas (daemon), atau menggunakan pelayan web Nginx atau Apache siap pakai. API memproses permintaan pengguna dan menyampaikan arahan selanjutnya kepada aplikasi pekerja untuk dilaksanakan. Pemindahan berlaku menggunakan broker mesej, biasanya RabbitMQ, yang lain kurang disokong. Apabila mesej sampai kepada broker, ia diproses oleh pekerja dan, jika perlu, mengembalikan respons.
Paradigma ini melibatkan titik kegagalan biasa yang terpencil: RabbitMQ dan pangkalan data. Tetapi RabbitMQ diasingkan dalam satu perkhidmatan dan, secara teori, boleh menjadi individu untuk setiap perkhidmatan. Jadi di MCS kami memisahkan perkhidmatan ini sebanyak mungkin; untuk setiap projek individu kami mencipta pangkalan data yang berasingan, RabbitMQ yang berasingan. Pendekatan ini bagus kerana sekiranya berlaku kemalangan di beberapa tempat yang terdedah, bukan keseluruhan perkhidmatan rosak, tetapi hanya sebahagian daripadanya.
Bilangan aplikasi pekerja adalah tidak terhad, jadi API boleh dengan mudah menskala secara mendatar di belakang pengimbang untuk meningkatkan prestasi dan toleransi kesalahan.
Sesetengah perkhidmatan memerlukan penyelarasan dalam perkhidmatan apabila operasi berurutan yang kompleks berlaku antara API dan pekerja. Dalam kes ini, pusat penyelarasan tunggal digunakan, sistem kluster seperti Redis, Memcache, dll, yang membolehkan seorang pekerja memberitahu yang lain bahawa tugas ini diberikan kepadanya ("tolong jangan ambil"). Kami menggunakan etcd. Sebagai peraturan, pekerja secara aktif berkomunikasi dengan pangkalan data, menulis dan membaca maklumat dari sana. Kami menggunakan mariadb sebagai pangkalan data, yang terletak dalam kelompok multimaster.
Perkhidmatan tunggal klasik ini disusun mengikut cara yang diterima umum untuk OpenStack. Ia boleh dianggap sebagai sistem tertutup, yang mana kaedah penskalaan dan toleransi kesalahan agak jelas. Sebagai contoh, untuk toleransi kesalahan API, sudah cukup untuk meletakkan pengimbang di hadapan mereka. Penskalaan pekerja dicapai dengan menambah bilangan mereka.
Titik lemah dalam keseluruhan skema ialah RabbitMQ dan MariaDB. Seni bina mereka patut mendapat artikel yang berasingan. Dalam artikel ini saya ingin memfokuskan pada toleransi kesalahan API.

Senibina Aplikasi Openstack. Pengimbangan dan toleransi kesalahan platform awan
Menjadikan pengimbang HAProxy tahan kerosakan menggunakan ExaBGP
Untuk menjadikan API kami berskala, pantas dan tahan terhadap kesalahan, kami meletakkan pengimbang beban di hadapannya. Kami memilih HAProxy. Pada pendapat saya, ia mempunyai semua ciri yang diperlukan untuk tugas kami: mengimbangi pada beberapa peringkat OSI, antara muka pengurusan, fleksibiliti dan skalabiliti, sejumlah besar kaedah pengimbangan, sokongan untuk jadual sesi.
Masalah pertama yang perlu diselesaikan ialah toleransi kesalahan pengimbang itu sendiri. Hanya memasang pengimbang juga mewujudkan titik kegagalan: pengimbang pecah dan perkhidmatan ranap. Untuk mengelakkan perkara ini berlaku, kami menggunakan HAProxy bersama-sama dengan ExaBGP.
ExaBGP membolehkan anda melaksanakan mekanisme untuk menyemak keadaan perkhidmatan. Kami menggunakan mekanisme ini untuk menyemak kefungsian HAProxy dan, sekiranya berlaku masalah, lumpuhkan perkhidmatan HAProxy daripada BGP.
Skim ExaBGP+HAProxy
- Kami memasang perisian yang diperlukan, ExaBGP dan HAProxy, pada tiga pelayan.
- Kami mencipta antara muka gelung balik pada setiap pelayan.
- Pada ketiga-tiga pelayan kami memberikan alamat IP putih yang sama kepada antara muka ini.
- Alamat IP putih diiklankan ke Internet melalui ExaBGP.
Toleransi kesalahan dicapai dengan mengiklankan alamat IP yang sama daripada ketiga-tiga pelayan. Dari sudut pandangan rangkaian, alamat yang sama boleh diakses dari tiga lompatan seterusnya yang berbeza. Penghala melihat tiga laluan yang sama, memilih keutamaan tertinggi berdasarkan metriknya sendiri (ini biasanya pilihan yang sama), dan trafik pergi hanya ke salah satu pelayan.
Sekiranya terdapat masalah dengan pengendalian HAProxy atau kegagalan pelayan, ExaBGP berhenti mengumumkan laluan dan trafik beralih ke pelayan lain dengan lancar.
Oleh itu, kami mencapai toleransi kesalahan pengimbang.

Toleransi kesalahan pengimbang HAProxy
Skim ini ternyata tidak sempurna: kami belajar cara menempah HAProxy, tetapi tidak belajar cara mengagihkan beban dalam perkhidmatan. Oleh itu, kami mengembangkan sedikit skim ini: kami beralih kepada mengimbangi antara beberapa alamat IP putih.
Mengimbangi berdasarkan DNS ditambah BGP
Isu pengimbangan beban untuk HAProxy kami masih belum dapat diselesaikan. Walau bagaimanapun, ia boleh diselesaikan dengan mudah, seperti yang kami lakukan di sini.
Untuk mengimbangi tiga pelayan, anda memerlukan 3 alamat IP putih dan DNS lama yang baik. Setiap alamat ini ditentukan pada antara muka gelung balik setiap HAProxy dan diiklankan ke Internet.
Dalam OpenStack, untuk mengurus sumber, direktori perkhidmatan digunakan, yang menentukan API titik akhir perkhidmatan tertentu. Dalam direktori ini kami mendaftarkan nama domain - public.infra.mail.ru, yang diselesaikan melalui DNS oleh tiga alamat IP yang berbeza. Akibatnya, kami mendapat pengagihan beban antara tiga alamat melalui DNS.
Tetapi kerana apabila mengumumkan alamat IP putih kami tidak mengawal keutamaan pemilihan pelayan, ini belum mengimbangi lagi. Biasanya, hanya satu pelayan akan dipilih berdasarkan kekananan alamat IP, dan dua lagi akan melahu kerana tiada metrik dinyatakan dalam BGP.
Kami mula menghantar laluan melalui ExaBGP dengan metrik yang berbeza. Setiap pengimbang mengiklankan ketiga-tiga alamat IP putih, tetapi salah satu daripadanya, yang utama untuk pengimbang ini, diiklankan dengan metrik minimum. Jadi semasa ketiga-tiga pengimbang sedang beroperasi, panggilan ke alamat IP pertama pergi ke pengimbang pertama, panggilan ke kedua ke kedua dan panggilan ke ketiga ke ketiga.
Apa yang berlaku apabila salah satu pengimbang jatuh? Jika mana-mana pengimbang gagal, alamat utamanya masih diiklankan daripada dua yang lain, dan trafik diagihkan semula di antara mereka. Oleh itu, kami memberi pengguna beberapa alamat IP sekaligus melalui DNS. Dengan mengimbangi dengan DNS dan metrik yang berbeza, kami mendapat pengagihan beban yang sekata merentas ketiga-tiga pengimbang. Dan pada masa yang sama kita tidak kehilangan toleransi kesalahan.

Mengimbangi HAProxy berdasarkan DNS + BGP
Interaksi antara ExaBGP dan HAProxy
Jadi, kami melaksanakan toleransi kesalahan sekiranya pelayan keluar, berdasarkan menghentikan pengumuman laluan. Tetapi HAProxy boleh ditutup atas sebab lain selain daripada kegagalan pelayan: ralat pentadbiran, kegagalan dalam perkhidmatan. Kami mahu mengeluarkan pengimbang yang rosak dari bawah beban dalam kes ini juga, dan kami memerlukan mekanisme yang berbeza.
Oleh itu, mengembangkan skim sebelumnya, kami melaksanakan degupan jantung antara ExaBGP dan HAProxy. Ini ialah pelaksanaan perisian interaksi antara ExaBGP dan HAProxy, apabila ExaBGP menggunakan skrip tersuai untuk menyemak status aplikasi.
Untuk melakukan ini, anda perlu mengkonfigurasi pemeriksa kesihatan dalam konfigurasi ExaBGP, yang boleh menyemak status HAProxy. Dalam kes kami, kami mengkonfigurasi bahagian belakang kesihatan dalam HAProxy, dan dari sisi ExaBGP kami menyemak dengan permintaan GET yang mudah. Jika pengumuman berhenti berlaku, maka kemungkinan besar HAProxy tidak berfungsi dan tidak perlu mengiklankannya.

Pemeriksaan Kesihatan HAProxy
HAProxy Peers: penyegerakan sesi
Perkara seterusnya yang perlu dilakukan ialah menyegerakkan sesi. Apabila bekerja melalui pengimbang teragih, sukar untuk mengatur penyimpanan maklumat tentang sesi pelanggan. Tetapi HAProxy adalah salah satu daripada beberapa pengimbang yang boleh melakukan ini kerana fungsi Peers - keupayaan untuk memindahkan jadual sesi antara proses HAProxy yang berbeza.
Terdapat kaedah pengimbangan yang berbeza: yang mudah seperti , dan dilanjutkan, apabila sesi pelanggan diingati, dan setiap kali dia berakhir pada pelayan yang sama seperti sebelumnya. Kami mahu melaksanakan pilihan kedua.
HAProxy menggunakan jadual kayu untuk menyimpan sesi pelanggan mekanisme ini. Mereka menyimpan alamat IP asal pelanggan, alamat sasaran yang dipilih (belakang) dan beberapa maklumat perkhidmatan. Biasanya, jadual kayu digunakan untuk menyimpan pasangan sumber-IP + destinasi-IP, yang amat berguna untuk aplikasi yang tidak dapat memindahkan konteks sesi pengguna apabila bertukar kepada pengimbang lain, contohnya, dalam mod pengimbangan RoundRobin.
Jika meja kayu diajar untuk bergerak antara proses HAProxy yang berbeza (antara pengimbangan berlaku), pengimbang kami akan dapat berfungsi dengan satu kumpulan meja kayu. Ini akan membolehkan anda menukar rangkaian pelanggan dengan lancar jika salah satu pengimbang gagal; bekerja dengan sesi pelanggan akan diteruskan pada hujung belakang yang sama yang telah dipilih sebelum ini.
Untuk operasi yang betul, masalah alamat IP sumber pengimbang dari mana sesi itu ditubuhkan mesti diselesaikan. Dalam kes kami, ini ialah alamat dinamik pada antara muka gelung balik.
Kerja yang betul rakan sebaya dicapai hanya dalam keadaan tertentu. Iaitu, tamat masa TCP mestilah cukup besar atau penukaran mesti cukup pantas supaya sesi TCP tidak mempunyai masa untuk ditamatkan. Walau bagaimanapun, ia membolehkan penukaran lancar.
Dalam IaaS kami mempunyai perkhidmatan yang dibina menggunakan teknologi yang sama. ini , yang dipanggil Octavia. Ia berdasarkan dua proses HAProxy dan pada mulanya termasuk sokongan untuk rakan sebaya. Mereka telah membuktikan diri mereka cemerlang dalam perkhidmatan ini.
Gambar secara skematik menunjukkan pergerakan jadual rakan sebaya antara tiga contoh HAProxy, konfigurasi dicadangkan tentang cara ini boleh dikonfigurasikan:

HAProxy Peers (penyegerakan sesi)
Jika anda melaksanakan skim yang sama, operasinya mesti diuji dengan teliti. Ia bukan fakta bahawa ia akan berfungsi dengan cara yang sama 100% sepanjang masa. Tetapi sekurang-kurangnya anda tidak akan kehilangan jadual kayu apabila anda perlu mengingati IP sumber pelanggan.
Mengehadkan bilangan permintaan serentak daripada pelanggan yang sama
Sebarang perkhidmatan yang tersedia secara umum, termasuk API kami, boleh tertakluk kepada permintaan yang tidak terkawal. Sebabnya boleh berbeza sama sekali, daripada ralat pengguna kepada serangan yang disasarkan. Kami secara berkala DDoSed oleh alamat IP. Pelanggan sering membuat kesilapan dalam skrip mereka dan memberi kami mini-DDoS.
Satu cara atau yang lain, perlindungan tambahan mesti disediakan. Penyelesaian yang jelas adalah untuk mengehadkan bilangan permintaan API dan tidak membuang masa CPU memproses permintaan berniat jahat.
Untuk melaksanakan sekatan sedemikian, kami menggunakan had kadar, disusun berdasarkan HAProxy, menggunakan jadual kayu yang sama. Menyediakan had adalah agak mudah dan membolehkan anda mengehadkan pengguna dengan bilangan permintaan kepada API. Algoritma mengingati IP sumber dari mana permintaan dibuat dan mengehadkan bilangan permintaan serentak daripada seorang pengguna. Sudah tentu, kami mengira purata profil beban API untuk setiap perkhidmatan dan menetapkan had ≈ 10 kali nilai ini. Kami terus memantau keadaan dengan teliti dan mengekalkan nadi kami.
Apakah rupa ini dalam amalan? Kami mempunyai pelanggan yang kerap menggunakan API kami untuk autoscale. Mereka mencipta kira-kira dua hingga tiga ratus mesin maya pada waktu pagi dan memadamkannya pada waktu petang. Untuk OpenStack, mencipta mesin maya, juga dengan perkhidmatan PaaS, memerlukan sekurang-kurangnya 1000 permintaan API, kerana interaksi antara perkhidmatan juga berlaku melalui API.
Pemindahan tugas sedemikian menyebabkan beban yang agak besar. Kami menilai beban ini, mengumpul puncak harian, meningkatkannya sepuluh kali ganda, dan ini menjadi had kadar kami. Kami mengekalkan jari kami pada nadi. Kami sering melihat bot dan pengimbas yang cuba melihat kami untuk melihat sama ada kami mempunyai skrip CGA yang boleh dijalankan, kami sedang secara aktif memotongnya.
Cara mengemas kini pangkalan kod anda tanpa disedari oleh pengguna
Kami juga melaksanakan toleransi kesalahan pada tahap proses penggunaan kod. Mungkin terdapat gangguan semasa pelancaran, tetapi kesannya terhadap ketersediaan perkhidmatan boleh diminimumkan.
Kami sentiasa mengemas kini perkhidmatan kami dan mesti memastikan pangkalan kod dikemas kini tanpa menjejaskan pengguna. Kami berjaya menyelesaikan masalah ini menggunakan keupayaan pengurusan HAProxy dan pelaksanaan Graceful Shutdown dalam perkhidmatan kami.
Untuk menyelesaikan masalah ini, adalah perlu untuk memastikan kawalan pengimbang dan penutupan perkhidmatan "betul":
- Dalam kes HAProxy, kawalan dilakukan melalui fail statistik, yang pada asasnya adalah soket dan ditakrifkan dalam konfigurasi HAProxy. Anda boleh menghantar arahan kepadanya melalui stdio. Tetapi alat kawalan konfigurasi utama kami adalah ansible, jadi ia mempunyai modul terbina dalam untuk mengurus HAProxy. Yang kami gunakan secara aktif.
- Kebanyakan perkhidmatan API dan Enjin kami menyokong teknologi penutupan yang anggun: apabila ditutup, mereka menunggu tugasan semasa selesai, sama ada permintaan http atau beberapa tugas perkhidmatan. Perkara yang sama berlaku dengan pekerja. Ia mengetahui semua tugas yang sedang dilakukannya dan berakhir apabila ia telah berjaya menyelesaikan semuanya.
Terima kasih kepada dua perkara ini, algoritma selamat untuk penggunaan kami kelihatan seperti ini.
- Pembangun memasang pakej kod baharu (bagi kami ini ialah RPM), mengujinya dalam persekitaran pembangun, mengujinya di peringkat dan meninggalkannya dalam repositori peringkat.
- Pembangun menetapkan tugas untuk penempatan dengan penerangan paling terperinci tentang "artifak": versi pakej baharu, penerangan tentang fungsi baharu dan butiran lain tentang penggunaan jika perlu.
- Pentadbir sistem memulakan kemas kini. Melancarkan buku main Ansible, yang seterusnya melakukan perkara berikut:
- Mengambil pakej dari repositori peringkat dan menggunakannya untuk mengemas kini versi pakej dalam repositori produk.
- Menyusun senarai hujung belakang perkhidmatan yang dikemas kini.
- Mematikan perkhidmatan pertama yang akan dikemas kini dalam HAProxy dan menunggu prosesnya selesai dijalankan. Terima kasih kepada penutupan yang anggun, kami yakin bahawa semua permintaan pelanggan semasa akan diselesaikan dengan jayanya.
- Selepas API dan pekerja dihentikan sepenuhnya, dan HAProxy dimatikan, kod tersebut dikemas kini.
- Ansible menjalankan perkhidmatan.
- Untuk setiap perkhidmatan, "pemegang" tertentu ditarik, yang menjalankan ujian unit pada beberapa ujian utama yang telah ditetapkan. Pemeriksaan asas kod baharu berlaku.
- Jika tiada ralat ditemui dalam langkah sebelumnya, bahagian belakang diaktifkan.
- Mari kita beralih ke bahagian belakang seterusnya.
- Selepas semua bahagian belakang dikemas kini, ujian berfungsi dilancarkan. Jika ia tiada, maka pembangun melihat mana-mana fungsi baharu yang dibuatnya.
Ini melengkapkan penempatan.

Kitaran kemas kini perkhidmatan
Skim ini tidak akan berfungsi jika kita tidak mempunyai satu peraturan. Kami menyokong kedua-dua versi lama dan baharu dalam pertempuran. Terdahulu, pada peringkat pembangunan perisian, ditetapkan bahawa walaupun terdapat perubahan dalam pangkalan data perkhidmatan, mereka tidak akan memecahkan kod sebelumnya. Akibatnya, pangkalan kod dikemas kini secara beransur-ansur.
Kesimpulan
Berkongsi pemikiran saya sendiri tentang seni bina WEB yang toleran terhadap kesalahan, saya ingin sekali lagi ambil perhatian perkara utamanya:
- toleransi kesalahan fizikal;
- toleransi kerosakan rangkaian (pengimbang, BGP);
- toleransi kesalahan perisian yang digunakan dan dibangunkan.
Masa up stabil semua!
Sumber: www.habr.com
