
Di Mail.ru Group, kami memiliki Tarantool - ini adalah server aplikasi di Lua, yang juga memiliki basis data (atau sebaliknya?). Ini cepat dan keren, tetapi kemampuan satu server masih tidak terbatas. Penskalaan vertikal juga bukan obat mujarab, jadi Tarantool memiliki alat untuk penskalaan horizontal - modul vshard
[1] . Ini memungkinkan Anda untuk mengirim data ke beberapa server, tetapi Anda harus mengotak-atiknya untuk mengkonfigurasinya dan mempercepat logika bisnis.
Berita bagus: kami mengumpulkan kerucut (misalnya
[2] ,
[3] ) dan memotong kerangka kerja lain yang secara signifikan akan menyederhanakan solusi untuk masalah ini.
Tarantool Cartridge adalah kerangka kerja baru untuk mengembangkan sistem terdistribusi yang kompleks. Ini memungkinkan Anda untuk fokus pada penulisan logika bisnis alih-alih menyelesaikan masalah infrastruktur. Di bawah potongan, saya akan memberitahu Anda bagaimana kerangka kerja ini diatur dan bagaimana menulis layanan terdistribusi dengannya.
Dan apa sebenarnya masalahnya?
Kami memiliki tarantula, ada vshard - apa lagi yang Anda inginkan?
Pertama, intinya adalah kenyamanan. Konfigurasi Vshard dikonfigurasi melalui tabel Lua. Agar sistem terdistribusi dari beberapa proses Tarantool berfungsi dengan benar, konfigurasinya harus sama di mana-mana. Tidak ada yang mau melakukan ini secara manual. Oleh karena itu, semua jenis skrip, Ansible, sistem penyebaran digunakan.
Cartridge sendiri mengelola konfigurasi vshard, ia melakukan ini berdasarkan
konfigurasi terdistribusi sendiri . Intinya, ini adalah file YAML sederhana, salinannya disimpan di setiap instance Tarantool. Penyederhanaan terletak pada kenyataan bahwa kerangka itu sendiri memonitor konfigurasinya dan sehingga sama di mana-mana.
Kedua, intinya lagi dalam kenyamanan. Konfigurasi tidak memiliki hubungan dengan pengembangan logika bisnis dan hanya mengalihkan perhatian programmer dari pekerjaan. Ketika kita membahas arsitektur proyek, paling sering kita berbicara tentang komponen individu dan interaksinya. Masih terlalu dini untuk memikirkan meluncurkan cluster ke 3 pusat data.
Kami memecahkan masalah ini berulang-ulang, dan pada titik tertentu kami berhasil mengembangkan pendekatan untuk menyederhanakan pekerjaan dengan 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 dapat dijalankan pada satu instance dari Tarantool, dan ini akan cukup untuk pengujian.
Fitur utama dari Tarantool Cartridge:
- orkestrasi klaster otomatis;
- memperluas fungsionalitas aplikasi dengan peran baru;
- pengembangan aplikasi dan templat penyebaran;
- built-in sharding otomatis;
- integrasi dengan kerangka uji Luatest;
- manajemen cluster menggunakan WebUI dan API;
- alat pengemasan dan penyebaran.
Halo Dunia!
Saya ingin menunjukkan kerangka itu sendiri, jadi mari kita tinggalkan cerita tentang arsitektur untuk nanti, dan mulai dengan yang sederhana. Dengan asumsi Tarantool itu sendiri sudah diinstal, semua yang masih harus dilakukan adalah
$ tarantoolctl rocks install cartridge-cli $ export PATH=$PWD/.rocks/bin/:$PATH
Dua perintah ini akan menginstal utilitas baris perintah dan memungkinkan Anda membuat aplikasi pertama dari templat:
$ 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 "Halo, Dunia!" Yang sudah jadi aplikasi. Mari kita segera mencoba menjalankannya, pra-instal dependensi (termasuk kerangka itu sendiri):
$ tarantoolctl rocks make $ ./init.lua --http-port 8080
Jadi, kami telah meluncurkan satu node dari aplikasi sharded yang akan datang. Orang awam yang ingin tahu dapat segera membuka antarmuka web, menggunakan mouse untuk mengonfigurasi kluster dari satu simpul dan menikmati hasilnya, tetapi terlalu dini untuk bersukacita. Sejauh ini, aplikasi tersebut tidak tahu bagaimana melakukan sesuatu yang berguna, jadi saya akan memberi tahu Anda tentang penerapan nanti, dan sekarang saatnya untuk menulis kode.
Pengembangan aplikasi
Bayangkan saja, kami akan merancang proyek yang harus menerima data, menyimpannya dan membuat laporan sekali sehari.

Kami mulai menggambar diagram, dan menempatkan tiga komponen di atasnya: 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 scheduler tidak akan langsung mengakses repositori, ada router untuk ini, itu dibuat untuk itu.

Skema ini masih belum cukup akurat mencerminkan apa yang akan kita buat dalam proyek, karena komponennya terlihat abstrak. Kita juga perlu melihat bagaimana ini diproyeksikan ke Tarantool yang asli - kita akan mengelompokkan komponen-komponen kita dengan proses.

Menjaga vshard-router dan gateway pada instance yang terpisah tidak masuk akal. Mengapa kita perlu kembali ke jaringan sekali lagi, jika ini sudah menjadi tanggung jawab router? Mereka harus berjalan dalam proses yang sama. Yaitu, dalam satu proses, gateway dan vshard.router.cfg diinisialisasi, dan biarkan mereka berinteraksi secara lokal.
Sangat nyaman untuk bekerja dengan tiga komponen pada tahap desain, tetapi sebagai pengembang, ketika saya menulis kode, saya tidak ingin berpikir untuk meluncurkan tiga instance dari Tarnatool. Saya perlu menjalankan tes dan memverifikasi bahwa saya menulis gateway dengan benar. Atau mungkin saya ingin menunjukkan fitur kepada kolega saya. Mengapa saya harus menderita dengan penyebaran tiga salinan? Begitulah konsep peran dilahirkan. Peran adalah modul Loach reguler yang siklus hidupnya dikelola oleh Cartridge. Dalam contoh ini, ada empat di antaranya - gateway, router, storage, scheduler. Di proyek lain, mungkin ada lebih banyak. Semua peran dapat diluncurkan dalam satu proses, dan ini sudah cukup.

Dan ketika datang ke penerapan ke staging atau ke dalam operasi, maka kami akan menetapkan setiap set peran untuk setiap proses Tarantool, tergantung pada kemampuan perangkat keras:

Manajemen topologi
Informasi tentang di mana peran diluncurkan harus disimpan di suatu tempat. Dan "suatu tempat" ini adalah konfigurasi terdistribusi yang saya sebutkan di atas. Yang paling penting di dalamnya adalah topologi cluster. Berikut adalah 3 grup replikasi dari 5 proses Tarantool:

Kami tidak ingin kehilangan data, oleh karena itu kami dengan hati-hati memperlakukan informasi tentang proses yang sedang berjalan. Cartridge memantau konfigurasi dengan komit dua fase. Segera setelah kami ingin memperbarui konfigurasi, itu terlebih dahulu memeriksa ketersediaan semua contoh dan kesiapan mereka untuk menerima konfigurasi baru. Setelah ini, fase kedua menerapkan konfigurasi. Jadi, bahkan jika satu instance tidak tersedia untuk sementara, maka tidak ada hal buruk yang akan terjadi. Konfigurasi tidak akan berlaku dan Anda akan melihat kesalahan sebelumnya.
Juga di bagian topologi ditunjukkan parameter penting seperti pemimpin dari setiap kelompok replikasi. Biasanya ini adalah contoh yang sedang direkam. Sisanya paling sering hanya baca, meskipun mungkin ada pengecualian. Terkadang pengembang yang berani tidak takut akan konflik dan dapat menulis data ke beberapa replika secara paralel, tetapi ada beberapa operasi yang, meskipun semuanya, tidak boleh dilakukan dua kali. Ada tanda pemimpin untuk ini.

Role life
Agar peran abstrak ada dalam arsitektur seperti itu, kerangka kerja entah bagaimana 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 dikatakan dalam konfigurasi terdistribusi, sehingga menerapkan konfigurasi tersebut ke peran tertentu.
function init() function validate_config() function apply_config() function stop()
Setiap peran memiliki fungsi
init
. Itu disebut sekali, baik ketika peran diaktifkan, atau ketika Tarantool restart. Lebih mudah di sana, misalnya, untuk menginisialisasi box.space.create, atau scheduler dapat menjalankan beberapa serat latar belakang, yang akan melakukan pekerjaan pada interval tertentu.
Fungsi
init
mungkin tidak cukup. Cartridge memungkinkan peran mengambil keuntungan dari konfigurasi terdistribusi yang digunakannya untuk menyimpan topologi. Dalam konfigurasi yang sama, kita dapat mendeklarasikan bagian baru dan menyimpan sebagian dari konfigurasi bisnis di dalamnya. Dalam contoh saya, ini bisa berupa skema data, atau pengaturan jadwal untuk peran penjadwal.
Cluster memanggil
validate_config
dan
apply_config
setiap kali konfigurasi terdistribusi berubah. Ketika konfigurasi diterapkan oleh komit dua fase, klaster memverifikasi bahwa setiap peran siap untuk menerima konfigurasi baru ini dan, jika perlu, melaporkan kesalahan kepada pengguna. Ketika semua orang sepakat bahwa konfigurasi itu normal,
apply_config
.
Peran juga memiliki metode
stop
, yang diperlukan untuk menghapus tanda-tanda vital peran. Jika kita mengatakan bahwa penjadwal pada server ini tidak lagi diperlukan, ia dapat menghentikan serat yang dimulai dengan
init
.
Peran dapat saling berinteraksi. Kami terbiasa menulis panggilan fungsi di Lua, tetapi mungkin saja kami tidak memiliki peran yang kami butuhkan dalam proses ini. Untuk memfasilitasi akses jaringan, kami menggunakan modul tambahan rpc (panggilan prosedur jarak jauh), yang dibangun berdasarkan netbox standar yang dibangun di Tarantool. Ini bisa bermanfaat jika, misalnya, gateway Anda ingin langsung meminta penjadwal untuk melakukan pekerjaan itu sekarang, daripada menunggu sehari.
Poin penting lainnya adalah memastikan toleransi kesalahan. Cartridge menggunakan protokol SWIM
[4] untuk memantau kesehatan. Singkatnya, proses saling bertukar βrumorβ dengan satu sama lain melalui UDP - setiap proses memberitahu tetangga mereka berita terbaru, dan mereka merespons. Jika jawabannya tidak datang, Tarantool mulai curiga ada sesuatu yang salah, dan setelah beberapa saat ia membacakan kematian dan mulai memberi tahu semua orang tentang berita ini.

Berdasarkan protokol ini, Cartridge mengatur failover otomatis. Setiap proses memantau lingkungannya, dan jika pemimpin tiba-tiba berhenti merespons, replika dapat mengambil perannya sendiri, dan Cartridge akan mengkonfigurasi peran yang berjalan sesuai.

Anda harus berhati-hati di sini karena sering bolak-balik dapat menyebabkan konflik data selama replikasi. Nyalakan failover otomatis secara acak, tentu saja, tidak sepadan. Anda perlu memahami dengan jelas apa yang sedang terjadi dan memastikan bahwa replikasi tidak akan rusak setelah pemimpin pulih dan mahkota dikembalikan kepadanya.
Dari semua yang telah dikatakan, tampaknya perannya mirip dengan layanan mikro. Dalam arti, mereka, hanya sebagai modul dalam proses Tarantool. Tetapi ada sejumlah perbedaan mendasar. Pertama, semua peran proyek harus hidup dalam satu basis kode. Dan semua proses Tarantool harus diluncurkan dari satu basis kode, sehingga tidak ada kejutan seperti ketika kita mencoba menginisialisasi penjadwal, tetapi itu tidak terjadi. Juga, jangan biarkan perbedaan dalam versi kode, karena perilaku sistem dalam situasi seperti ini sangat sulit untuk diprediksi dan didebug.
Tidak seperti Docker, kita tidak bisa hanya mengambil "gambar" dari sebuah peran, membawanya ke komputer lain dan menjalankannya di sana. Peran kami tidak terisolasi seperti wadah Docker. Selain itu, kami tidak dapat menjalankan dua peran yang identik pada instance yang sama. Peran itu ada di sana atau tidak, dalam arti itu adalah singleton. Dan ketiga, perannya harus sama di dalam seluruh grup replikasi, karena jika tidak maka akan menjadi konyol - datanya sama, dan konfigurasinya berbeda.
Alat penyebaran
Saya berjanji untuk menunjukkan bagaimana Cartridge membantu menyebarkan aplikasi. Untuk membuat hidup lebih mudah bagi orang lain, framework 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 membawa hampir semua yang Anda butuhkan: baik aplikasi dan dependensi lauch yang diinstal. Tarantool juga akan datang ke 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 dari setiap proses. Tiga misalnya sudah cukup.
$ 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 yang menarik di sini. Alih-alih hanya menentukan port protokol biner, kami menentukan alamat publik dari seluruh proses termasuk nama host. Hal ini diperlukan agar node-node cluster mengetahui bagaimana menghubungkan satu sama lain. Ini adalah ide yang buruk untuk menggunakan alamat 0.0.0.0 sebagai advertise_uri, itu harus alamat IP eksternal, bukan bind socket. Tanpa itu, tidak ada yang akan berfungsi, jadi Cartridge tidak akan membiarkan simpul dengan advertise_uri yang salah dimulai.
Sekarang setelah konfigurasi siap, Anda dapat memulai proses. Karena unit systemd reguler tidak memungkinkan memulai lebih dari satu proses, aplikasi pada Cartridge menginstal apa yang disebut unit instantiated 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 bahas dan lihat:

Kami melihat bahwa proses, meskipun sedang berjalan, belum dikonfigurasi. Kartrid belum tahu siapa yang harus mereplikasi dengan siapa dan tidak bisa memutuskan sendiri, jadi menunggu tindakan kami. Dan pilihan kita tidak besar: kehidupan cluster baru dimulai dengan konfigurasi node pertama. Kemudian kami menambahkan sisanya ke cluster, menetapkan peran padanya, dan pada penyebaran ini dapat dianggap berhasil diselesaikan.
Tuangkan segelas minuman favorit Anda dan bersantai setelah seminggu yang panjang. Aplikasi dapat dieksploitasi.

Ringkasan
Dan apa hasilnya? Coba, gunakan, tinggalkan umpan balik, mulai 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 Selanjutnya: Transisi ke Tarantool[4]
SWIM - protokol bangunan cluster[5]
GitHub - tarantool / cartridge-cli[6]
GitHub - tarantool / kartrid