Tarantool Cartridge: membagi backend Lua dalam tiga baris

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Di Mail.ru Group kami memiliki Tarantool - ini adalah server aplikasi di Lua, yang juga berfungsi sebagai database (atau sebaliknya?). Memang cepat dan keren, namun kemampuan satu server tetap tidak terbatas. Penskalaan vertikal juga bukan obat mujarab, jadi Tarantool memiliki alat untuk penskalaan horizontal - modul vshard [1]. Ini memungkinkan Anda untuk membagi data di beberapa server, tetapi Anda harus mengotak-atiknya untuk mengaturnya dan melampirkan logika bisnis.

Kabar baik: kami telah mengumpulkan beberapa hasil penting (mis [2], [3]) dan membuat kerangka kerja lain yang akan menyederhanakan solusi masalah ini secara signifikan.

Kartrid Tarantool adalah kerangka kerja baru untuk mengembangkan sistem terdistribusi yang kompleks. Hal ini memungkinkan Anda untuk fokus menulis logika bisnis daripada menyelesaikan masalah infrastruktur. Di bawah ini saya akan memberi tahu Anda cara kerja kerangka ini dan cara menulis layanan terdistribusi menggunakannya.

Dan apa, tepatnya, masalahnya?

Kami punya tarantula, kami punya vshard - apa lagi yang Anda inginkan?

Pertama, ini masalah kenyamanan. Konfigurasi vshard dikonfigurasi melalui tabel Lua. Agar sistem terdistribusi dari beberapa proses Tarantool dapat bekerja dengan benar, konfigurasinya harus sama di semua tempat. Tidak ada yang mau melakukan ini secara manual. Oleh karena itu, segala macam skrip, Ansible, dan sistem penerapan digunakan.

Kartrid sendiri mengelola konfigurasi vshard, ia melakukan ini berdasarkan konfigurasinya konfigurasi terdistribusi sendiri. Ini pada dasarnya adalah file YAML sederhana, salinannya disimpan di setiap instance Tarantool. Penyederhanaannya adalah kerangka kerja itu sendiri memantau konfigurasinya dan memastikan bahwa konfigurasinya sama di semua tempat.

Kedua, ini lagi-lagi soal kenyamanan. Konfigurasi vshard tidak ada hubungannya dengan pengembangan logika bisnis dan hanya mengalihkan perhatian programmer dari pekerjaannya. Ketika kita membahas arsitektur suatu proyek, kita paling sering berbicara tentang masing-masing komponen dan interaksinya. Masih terlalu dini untuk mempertimbangkan peluncuran cluster ke 3 pusat data.

Kami memecahkan masalah ini berulang kali, dan pada titik tertentu kami berhasil mengembangkan pendekatan yang menyederhanakan penggunaan aplikasi di seluruh siklus hidupnya: pembuatan, pengembangan, pengujian, CI/CD, pemeliharaan.

Cartridge memperkenalkan konsep peran untuk setiap proses Tarantool. Peran adalah konsep yang memungkinkan pengembang untuk fokus pada penulisan kode. Semua peran yang tersedia dalam proyek ini dapat dijalankan pada satu instance Tarantool, dan ini akan cukup untuk pengujian.

Fitur utama Kartrid Tarantool:

  • orkestrasi cluster otomatis;
  • memperluas fungsionalitas aplikasi menggunakan peran baru;
  • templat aplikasi untuk pengembangan dan penerapan;
  • sharding otomatis bawaan;
  • integrasi dengan kerangka pengujian Luatest;
  • manajemen cluster menggunakan WebUI dan API;
  • alat pengemasan dan penyebaran.

Halo Dunia!

Saya tidak sabar untuk menunjukkan kerangkanya, jadi kita tinggalkan cerita tentang arsitekturnya nanti dan mulai dengan sesuatu yang sederhana. Jika kita berasumsi bahwa Tarantool sendiri sudah terinstal, maka yang tersisa hanyalah melakukan

$ tarantoolctl rocks install cartridge-cli
$ export PATH=$PWD/.rocks/bin/:$PATH

Kedua perintah ini akan menginstal utilitas baris perintah dan memungkinkan Anda membuat aplikasi pertama dari template:

$ cartridge create --name myapp

Dan inilah yang kami dapatkan:

myapp/
├── .git/
├── .gitignore
├── app/roles/custom.lua
├── deps.sh
├── init.lua
├── myapp-scm-1.rockspec
├── test
│   ├── helper
│   │   ├── integration.lua
│   │   └── unit.lua
│   ├── helper.lua
│   ├── integration/api_test.lua
│   └── unit/sample_test.lua
└── tmp/

Ini adalah repositori git dengan pesan “Halo, Dunia!” aplikasi. Mari kita coba segera menjalankannya, setelah sebelumnya menginstal dependensi (termasuk framework itu sendiri):

$ tarantoolctl rocks make
$ ./init.lua --http-port 8080

Jadi, kami memiliki satu node yang berjalan untuk aplikasi sharded di masa depan. Orang awam yang ingin tahu dapat segera membuka antarmuka web, mengkonfigurasi cluster satu node dengan mouse dan menikmati hasilnya, tetapi masih terlalu dini untuk bersukacita. Sejauh ini, aplikasi tersebut tidak dapat melakukan sesuatu yang berguna, jadi saya akan memberi tahu Anda tentang penerapannya nanti, tetapi sekarang saatnya menulis kode.

Pengembangan Aplikasi

Bayangkan saja, kita sedang merancang sebuah proyek yang harus menerima data, menyimpannya dan membuat laporan sekali sehari.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Kami mulai menggambar diagram dan menempatkan tiga komponen di dalamnya: gateway, penyimpanan, dan penjadwal. Kami sedang mengerjakan arsitektur lebih lanjut. Karena kami menggunakan vshard sebagai penyimpanan, kami menambahkan vshard-router dan vshard-storage ke skema. Baik gateway maupun penjadwal tidak akan mengakses penyimpanan secara langsung; itulah gunanya router, untuk itulah ia diciptakan.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Diagram ini masih belum mewakili secara tepat apa yang akan kita bangun dalam proyek karena komponennya terlihat abstrak. Kita masih perlu melihat bagaimana hal ini akan diproyeksikan ke Tarantool yang sebenarnya - mari kelompokkan komponen kita berdasarkan proses.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Tidak ada gunanya menyimpan vshard-router dan gateway pada instance yang terpisah. Mengapa kita perlu menjelajahi jaringan sekali lagi jika ini sudah menjadi tanggung jawab router? Mereka harus dijalankan dalam proses yang sama. Artinya, gateway dan vshard.router.cfg diinisialisasi dalam satu proses, dan membiarkannya berinteraksi secara lokal.

Pada tahap desain, nyaman untuk bekerja dengan tiga komponen, tetapi saya, sebagai pengembang, saat menulis kode, tidak ingin memikirkan untuk meluncurkan tiga contoh Tarnatool. Saya perlu menjalankan tes dan memeriksa apakah saya menulis gateway dengan benar. Atau mungkin saya ingin mendemonstrasikan suatu fitur kepada rekan-rekan saya. Mengapa saya harus bersusah payah menerapkan tiga salinan? Dari sinilah konsep peran lahir. Peran adalah modul luash reguler yang siklus hidupnya dikelola oleh Cartridge. Dalam contoh ini ada empat di antaranya - gateway, router, penyimpanan, penjadwal. Mungkin ada lebih banyak lagi di proyek lain. Semua peran dapat dijalankan dalam satu proses, dan ini sudah cukup.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Dan jika menyangkut penerapan ke pementasan atau produksi, maka kami akan menetapkan setiap proses Tarantool serangkaian perannya sendiri tergantung pada kemampuan perangkat keras:

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Manajemen topologi

Informasi tentang di mana peran mana yang dijalankan harus disimpan di suatu tempat. Dan “di suatu tempat” ini adalah konfigurasi terdistribusi, yang telah saya sebutkan di atas. Hal terpenting tentangnya adalah topologi cluster. Berikut adalah 3 grup replikasi dari 5 proses Tarantool:

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Kami tidak ingin kehilangan data, jadi kami memperlakukan informasi tentang proses yang berjalan dengan hati-hati. Kartrid melacak konfigurasi menggunakan penerapan dua fase. Setelah kami ingin memperbarui konfigurasi, pertama-tama kami memeriksa apakah semua instance tersedia dan siap menerima konfigurasi baru. Setelah ini, tahap kedua menerapkan konfigurasi. Jadi, meskipun satu salinan tidak tersedia untuk sementara, tidak ada hal buruk yang akan terjadi. Konfigurasi tidak akan diterapkan dan Anda akan melihat kesalahan sebelumnya.

Juga di bagian topologi, parameter penting seperti pemimpin setiap grup replikasi ditunjukkan. Biasanya salinan inilah yang direkam. Sisanya paling sering bersifat read-only, meskipun mungkin ada pengecualian. Terkadang pengembang pemberani tidak takut dengan konflik dan dapat menulis data ke beberapa replika secara paralel, namun ada beberapa operasi yang, apa pun yang terjadi, tidak boleh dilakukan dua kali. Untuk ini ada tanda seorang pemimpin.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Kehidupan peran

Agar peran abstrak ada dalam arsitektur seperti itu, kerangka kerja harus mengelolanya. Secara alami, kontrol terjadi tanpa memulai ulang proses Tarantool. Ada 4 panggilan balik untuk mengelola peran. Cartridge sendiri akan memanggil mereka tergantung pada apa yang tertulis dalam konfigurasi terdistribusinya, sehingga menerapkan konfigurasi tersebut ke peran tertentu.

function init()
function validate_config()
function apply_config()
function stop()

Setiap peran mempunyai fungsi init. Ini dipanggil sekali ketika peran diaktifkan atau ketika Tarantool dimulai ulang. Di sana akan lebih mudah, misalnya, untuk menginisialisasi box.space.create, atau penjadwal dapat meluncurkan beberapa fiber latar belakang yang akan melakukan pekerjaan pada interval waktu tertentu.

Satu fungsi init mungkin tidak cukup. Cartridge memungkinkan peran untuk memanfaatkan konfigurasi terdistribusi yang digunakannya untuk menyimpan topologi. Kita dapat mendeklarasikan bagian baru dalam konfigurasi yang sama dan menyimpan sebagian konfigurasi bisnis di dalamnya. Dalam contoh saya, ini bisa berupa skema data atau pengaturan jadwal untuk peran penjadwal.

Panggilan klaster validate_config и apply_config setiap kali konfigurasi terdistribusi berubah. Ketika konfigurasi diterapkan oleh penerapan dua fase, klaster memeriksa apakah setiap peran siap menerima konfigurasi baru ini dan, jika perlu, melaporkan kesalahan kepada pengguna. Ketika semua orang setuju bahwa konfigurasinya normal, maka apply_config.

Peran juga mempunyai metode stop, yang diperlukan untuk membersihkan keluaran peran. Jika kita mengatakan bahwa penjadwal tidak lagi diperlukan di server ini, itu dapat menghentikan serat-serat yang mulai digunakannya init.

Peran dapat berinteraksi satu sama lain. Kita terbiasa menulis pemanggilan fungsi di Lua, namun mungkin saja proses tertentu tidak mempunyai peran yang kita perlukan. Untuk memfasilitasi panggilan melalui jaringan, kami menggunakan modul tambahan rpc (panggilan prosedur jarak jauh), yang dibangun berdasarkan netbox standar yang dibangun di Tarantool. Hal ini berguna jika, misalnya, gateway Anda ingin langsung meminta penjadwal untuk melakukan pekerjaannya sekarang, daripada menunggu sehari.

Poin penting lainnya adalah memastikan toleransi kesalahan. Kartrid menggunakan protokol SWIM untuk memantau kesehatan [4]. Singkatnya, proses bertukar “rumor” satu sama lain melalui UDP—setiap proses memberitahukan berita terbaru kepada tetangganya, dan mereka merespons. Jika tiba-tiba jawabannya tidak datang, Tarantool mulai curiga ada yang tidak beres, dan setelah beberapa saat ia membacakan kematian dan mulai memberi tahu semua orang di sekitar berita ini.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Berdasarkan protokol ini, Cartridge mengatur pemrosesan kegagalan otomatis. Setiap proses memantau lingkungannya, dan jika pemimpin tiba-tiba berhenti merespons, replika dapat mengambil alih perannya, dan Cartridge mengonfigurasikan peran yang berjalan sesuai dengan itu.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Anda perlu berhati-hati di sini, karena seringnya berpindah-pindah dapat menyebabkan konflik data selama replikasi. Tentu saja, Anda tidak boleh mengaktifkan failover otomatis secara acak. Kita harus memahami dengan jelas apa yang terjadi dan memastikan bahwa replikasi tidak akan terhenti setelah pemimpin dipulihkan dan mahkota dikembalikan kepadanya.

Dari semua ini, Anda mungkin merasa bahwa peran mirip dengan layanan mikro. Dalam arti tertentu, mereka hanyalah modul di dalam proses Tarantool. Namun ada juga sejumlah perbedaan mendasar. Pertama, semua peran proyek harus berada dalam basis kode yang sama. Dan semua proses Tarantool harus diluncurkan dari basis kode yang sama, sehingga tidak ada kejutan seperti itu ketika kita mencoba menginisialisasi penjadwal, tetapi ternyata tidak ada. Selain itu, Anda tidak boleh membiarkan perbedaan versi kode, karena perilaku sistem dalam situasi seperti ini sangat sulit untuk diprediksi dan di-debug.

Berbeda dengan Docker, kita tidak bisa begitu saja mengambil peran "image", membawanya ke komputer lain dan menjalankannya di sana. Peran kami tidak terisolasi seperti container Docker. Selain itu, kami tidak dapat menjalankan dua peran identik dalam satu contoh. Suatu peran ada atau tidak; dalam arti tertentu, itu adalah peran tunggal. Dan ketiga, peran dalam seluruh grup replikasi harus sama, karena jika tidak maka akan menjadi tidak masuk akal - datanya sama, tetapi konfigurasinya berbeda.

Alat penerapan

Saya berjanji untuk menunjukkan bagaimana Cartridge membantu menyebarkan aplikasi. Untuk membuat hidup lebih mudah bagi orang lain, kerangka kerja ini mengemas paket RPM:

$ cartridge pack rpm myapp -- упакует для нас ./myapp-0.1.0-1.rpm
$ sudo yum install ./myapp-0.1.0-1.rpm

Paket yang terinstal berisi hampir semua yang Anda perlukan: baik aplikasi maupun dependensi yang terinstal. Tarantool juga akan tiba di server sebagai ketergantungan paket RPM, dan layanan kami siap diluncurkan. Ini dilakukan melalui systemd, tetapi pertama-tama Anda perlu menulis sedikit konfigurasi. Minimal, tentukan URI setiap proses. Tiga sudah cukup misalnya.

$ sudo tee /etc/tarantool/conf.d/demo.yml <<CONFIG
myapp.router: {"advertise_uri": "localhost:3301", "http_port": 8080}
myapp.storage_A: {"advertise_uri": "localhost:3302", "http_enabled": False}
myapp.storage_B: {"advertise_uri": "localhost:3303", "http_enabled": False}
CONFIG

Ada nuansa menarik di sini. Daripada hanya menentukan port protokol biner, kami menentukan seluruh alamat publik dari proses termasuk nama host. Hal ini diperlukan agar node cluster mengetahui cara terhubung satu sama lain. Merupakan ide buruk untuk menggunakan 0.0.0.0 sebagai alamat Advertiser; alamat tersebut harus berupa alamat IP eksternal, bukan pengikatan soket. Tanpanya, tidak ada yang akan berhasil, jadi Cartridge tidak akan membiarkan Anda meluncurkan node dengan Advertiser_uri yang salah.

Sekarang konfigurasi sudah siap, Anda dapat memulai prosesnya. Karena unit systemd biasa tidak mengizinkan lebih dari satu proses untuk dimulai, aplikasi pada Kartrid diinstal oleh apa yang disebut. unit yang dipakai yang bekerja seperti ini:

$ sudo systemctl start myapp@router
$ sudo systemctl start myapp@storage_A
$ sudo systemctl start myapp@storage_B

Dalam konfigurasi, kami menentukan port HTTP tempat Cartridge melayani antarmuka web - 8080. Mari kita buka dan lihat:

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Kami melihat bahwa meskipun proses sedang berjalan, namun belum dikonfigurasi. Kartrid belum tahu siapa yang harus meniru dengan siapa dan tidak bisa mengambil keputusan sendiri, sehingga menunggu tindakan kita. Namun kita tidak punya banyak pilihan: kehidupan cluster baru dimulai dengan konfigurasi node pertama. Kemudian kami akan menambahkan yang lain ke cluster, menetapkan peran kepada mereka, dan pada titik ini penerapan dapat dianggap berhasil diselesaikan.

Ayo tuangkan segelas minuman favoritmu dan bersantai setelah seharian bekerja. Aplikasi dapat digunakan.

Tarantool Cartridge: membagi backend Lua dalam tiga baris

Hasil

Apa hasilnya? Cobalah, gunakan, tinggalkan masukan, buat tiket di Github.

referensi

[1] Tarantool » 2.2 » Referensi » Referensi batuan » Modul vshard

[2] Bagaimana kami menerapkan inti bisnis investasi Alfa-Bank berdasarkan Tarantool

[3] Arsitektur penagihan generasi baru: transformasi dengan transisi ke Tarantool

[4] SWIM - protokol konstruksi cluster

[5] GitHub - tarantool/cartridge-cli

[6] GitHub - tarantool/kartrid

Sumber: www.habr.com

Tambah komentar