Tarantool Cartridge: Sharding Lua Backend dalam Three Lines


Di Mail.ru Group, kami memiliki Tarantool, server aplikasi berbasis Lua dan database yang disatukan. Ini cepat dan berkelas, tetapi sumber daya dari satu server selalu terbatas. Penskalaan vertikal juga bukan obat mujarab. Itulah sebabnya Tarantool memiliki beberapa alat untuk penskalaan horizontal, atau modul vshard [1] . Ini memungkinkan Anda untuk menyebar data ke banyak server, tetapi Anda harus mengotak-atiknya untuk sementara waktu untuk mengkonfigurasinya dan mengaitkannya dengan logika bisnis.

Kabar baik: kami mendapat bagian masalah (misalnya, [2] , [3] ) dan membuat kerangka kerja lain, yang secara signifikan menyederhanakan solusi untuk masalah ini.

Tarantool Cartridge adalah kerangka kerja baru untuk mengembangkan sistem terdistribusi yang kompleks. Ini memungkinkan Anda berkonsentrasi pada penulisan logika bisnis alih-alih menyelesaikan masalah infrastruktur. Di bawah potongan, saya akan memberi tahu Anda bagaimana kerangka kerja ini bekerja dan bagaimana itu bisa membantu dalam menulis layanan terdistribusi.

Jadi apa sebenarnya masalahnya?


Kami memiliki Tarantool dan vshard - apa lagi yang kami inginkan?

Pertama, ini adalah masalah kenyamanan. Vshard dikonfigurasi dalam tabel Lua. Tetapi agar sistem terdistribusi dari beberapa proses Tarantool berfungsi dengan benar, konfigurasinya harus sama di mana-mana. Tidak ada yang ingin melakukannya secara manual, jadi semua jenis skrip, Ansible, dan sistem penyebaran digunakan.

Cartridge sendiri mengelola konfigurasi vshard berdasarkan konfigurasi terdistribusi sendiri . Sebenarnya, ini adalah file YAML sederhana, dan salinannya disimpan pada setiap instance Tarantool. Dengan kata lain, framework memonitor konfigurasinya sehingga akan sama di mana-mana.

Kedua, ini lagi-lagi masalah kenyamanan. Konfigurasi Vshard tidak terkait dengan pengembangan logika bisnis dan hanya mengalihkan pengembang dari pekerjaannya. Ketika kita membahas arsitektur suatu proyek, masalah tersebut kemungkinan besar berkaitan dengan komponen yang terpisah dan interaksinya. Masih terlalu dini untuk berpikir untuk menggunakan cluster untuk 3 pusat data.

Kami memecahkan masalah ini berulang-ulang, dan pada titik tertentu, kami berhasil mengembangkan pendekatan untuk menyederhanakan bekerja dengan aplikasi di seluruh siklus hidupnya: pembuatan, pengembangan, pengujian, CI / CD, pemeliharaan.

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

Fitur utama dari Tarantool Cartridge:

  • orkestrasi klaster otomatis;
  • fungsionalitas aplikasi diperluas dengan peran baru;
  • templat aplikasi untuk pengembangan dan penyebaran;
  • built-in sharding otomatis;
  • integrasi dengan kerangka kerja Luatest;
  • manajemen cluster menggunakan WebUI dan API;
  • alat pengemasan dan penyebaran.

Halo Dunia!


Saya tidak sabar untuk menunjukkan kepada Anda kerangka itu sendiri, jadi mari kita simpan cerita tentang arsitektur untuk nanti, dan mulai dengan tugas yang mudah. Dengan asumsi bahwa Tarantool sudah diinstal, yang harus kita lakukan adalah

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

Akibatnya, utilitas baris perintah diinstal, yang 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 "Hello, World!" Yang siap digunakan. aplikasi. Mari kita coba jalankan setelah menginstal dependensi (termasuk kerangka itu sendiri):

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

Kami telah meluncurkan sebuah simpul dari aplikasi kami di masa yang akan datang. Jika Anda penasaran, Anda dapat langsung membuka antarmuka web, yang berjalan di localhost : 8080, gunakan mouse untuk mengonfigurasi kluster satu-simpul dan menikmati hasilnya, tetapi jangan terlalu bersemangat. Aplikasi belum tahu bagaimana melakukan sesuatu yang berguna dulu, jadi saya akan memberitahu Anda tentang penyebaran nanti, dan sekarang saatnya untuk menulis beberapa kode.

Mengembangkan aplikasi


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


Jadi kami menggambar diagram dengan tiga komponen: gateway, penyimpanan, dan penjadwal. Mari kita terus bekerja pada arsitektur. Karena kita menggunakan vshard sebagai penyimpanan, mari tambahkan vshard-router dan vshard-storage ke diagram. Baik gateway maupun scheduler tidak akan langsung mengakses penyimpanan - router secara eksplisit dibuat untuk tugas ini.


Diagram ini terlihat abstrak karena komponen-komponennya masih belum mencerminkan apa yang akan kita buat dalam proyek. Kita harus melihat bagaimana proyek ini sesuai dengan Tarantool asli, jadi kami mengelompokkan komponen kami dengan proses.


Tidak ada banyak akal dalam menjaga vshard-router dan gateway pada instance yang terpisah. Mengapa kita pergi melalui jaringan sekali lagi, jika ini sudah menjadi tanggung jawab router? Mereka harus dijalankan dalam proses yang sama, yaitu, gateway dan vshard.router.cfg harus diinisialisasi dalam proses yang sama, dan berinteraksi secara lokal.

Selama fase desain, itu nyaman untuk bekerja dengan tiga komponen, tetapi sebagai pengembang, saya tidak ingin berpikir tentang meluncurkan tiga contoh Tarantool saat menulis kode. Saya perlu menjalankan tes dan memverifikasi bahwa saya menulis kode gateway dengan benar. Atau saya mungkin ingin menunjukkan fitur baru kepada rekan kerja saya. Mengapa saya mengambil masalah dengan penyebaran tiga contoh? Maka lahirlah konsep peran. Peran adalah modul Lua biasa, dan Cartridge mengelola siklus hidupnya. Dalam contoh ini, ada empat di antaranya: gateway, router, storage, dan scheduler. Proyek lain mungkin memiliki lebih banyak peran. Semua peran dapat diluncurkan dalam satu proses, dan itu sudah cukup.


Dan ketika masalah tersebut terkait dengan penyebaran ke panggung atau produksi, maka kami menetapkan satu set peran terpisah untuk setiap proses Tarantool tergantung pada kemampuan perangkat keras yang mendasarinya:


Manajemen topologi


Kita juga harus menyimpan informasi tentang peran yang berjalan di suatu tempat. Dan "suatu tempat" berarti konfigurasi terdistribusi yang disebutkan di atas. Yang paling penting di sini adalah topologi cluster. Di sini Anda dapat melihat 3 grup replikasi dari 5 proses Tarantool:


Kami tidak ingin kehilangan data, jadi kami memperlakukan informasi tentang proses yang berjalan dengan hati-hati. Cartridge memantau konfigurasi menggunakan komit dua fase. Segera setelah kami ingin memperbarui konfigurasi, pertama-tama memeriksa apakah instans tersedia dan siap untuk menerima konfigurasi baru. Setelah itu, konfigurasi diterapkan pada fase kedua. Jadi, bahkan jika satu instance sementara tidak tersedia, maka tidak ada yang salah. Konfigurasi tidak akan diterapkan, dan Anda akan melihat kesalahan sebelumnya.

Bagian topologi juga memiliki parameter penting seperti pemimpin setiap kelompok replikasi. Biasanya, ini adalah contoh yang menerima penulisan. 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 bersamaan. Meskipun demikian, beberapa operasi tidak boleh dilakukan dua kali. Itu sebabnya kami memiliki seorang pemimpin.


Siklus hidup peran


Agar arsitektur proyek mengandung peran abstrak, kerangka kerja entah bagaimana harus dapat mengelolanya. Secara alami, peran dikelola tanpa memulai kembali proses Tarantool. Ada empat panggilan balik yang dirancang untuk manajemen peran. Cartridge sendiri memanggil mereka tergantung pada informasi dari konfigurasi yang didistribusikan, sehingga menerapkan konfigurasi tersebut ke peran tertentu.

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

Setiap peran memiliki fungsi init . Disebut sekali: baik ketika peran diaktifkan, atau ketika Tarantool restart. Di sini nyaman, misalnya, untuk menginisialisasi box.space.create, atau penjadwal dapat menjalankan beberapa serat latar belakang yang akan menyelesaikan tugas secara berkala.

Fungsi init saja mungkin tidak cukup. Cartridge memungkinkan peran untuk mengakses konfigurasi terdistribusi yang digunakan untuk menyimpan topologi. Dalam konfigurasi yang sama, kita dapat mendeklarasikan bagian baru dan menyimpan bagian dari konfigurasi bisnis di sana. 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 dalam komit dua fase, klaster memverifikasi bahwa setiap peran di setiap server siap untuk menerima konfigurasi baru ini dan, jika perlu, melaporkan kesalahan kepada pengguna. Ketika semua orang setuju dengan konfigurasi, apply_config dipanggil.

Peran juga mendukung metode stop untuk membersihkan sampah. Jika kita mengatakan bahwa tidak perlu untuk scheduler di server ini, itu dapat menghentikan serat yang mulai digunakan init .

Peran dapat saling berinteraksi. Kami terbiasa menulis panggilan fungsi Lua, tetapi prosesnya mungkin tidak memiliki peran yang diperlukan. Untuk memfasilitasi akses jaringan, kami menggunakan modul tambahan yang disebut rpc (panggilan prosedur jarak jauh), yang dibangun berdasarkan pada modul Tarantool net.box standar. Ini bisa bermanfaat, misalnya, jika gateway Anda ingin meminta penjadwal secara langsung untuk melakukan tugas sekarang, daripada dalam sehari.

Poin penting lainnya adalah memastikan toleransi kesalahan. Cartridge menggunakan protokol SWIM [4] untuk memantau kesehatan. Singkatnya, proses bertukar "rumor" satu sama lain melalui UDP, yaitu, setiap proses memberitahu tetangga mereka berita terbaru, dan mereka merespons. Jika tiba-tiba tidak ada jawaban, Tarantool menduga ada sesuatu yang salah, dan setelah beberapa saat, itu menyatakan kematian dan mengirimkan pesan ini kepada semua orang.


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


Anda harus berhati-hati di sini karena sering berganti-ganti dapat mengakibatkan konflik data selama replikasi. Kegagalan otomatis tentu saja tidak boleh dihidupkan secara acak. Anda harus memiliki gagasan yang jelas tentang apa yang sedang terjadi, dan pastikan replikasi tidak akan crash ketika pemimpin pulih dan mendapatkan kembali mahkotanya.

Dari semua yang telah dikatakan, perannya mungkin tampak mirip dengan layanan-layanan microser. Dalam arti, mereka hanya sebagai modul dalam proses Tarantool, dan ada beberapa perbedaan mendasar. Pertama, semua peran proyek harus hidup dalam basis kode yang sama. Dan semua proses Tarantool harus dijalankan dari basis kode yang sama, sehingga tidak akan ada kejutan, seperti ketika kita mencoba menginisialisasi scheduler, tetapi tidak ada scheduler. Juga, kita tidak boleh membiarkan perbedaan dalam versi kode karena perilaku sistem rumit untuk diprediksi dan didebug dalam situasi seperti itu.

Tidak seperti Docker, kita tidak bisa hanya mengambil "gambar" dari sebuah peran, mentransfernya 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 contoh yang sama. Peran itu ada atau tidak; dalam arti tertentu, itu adalah singleton. Dan ketiga, peran harus sama dalam seluruh kelompok replikasi karena, jika tidak, itu akan terlihat konyol: datanya sama, tetapi perilakunya berbeda.

Alat penyebaran


Saya berjanji untuk menunjukkan kepada Anda bagaimana Cartridge dapat membantu menyebarkan aplikasi. Untuk membuat hidup lebih mudah, kerangka kerja membuat paket RPM:

 $ cartridge pack rpm myapp # will create ./myapp-0.1.0-1.rpm $ sudo yum install ./myapp-0.1.0-1.rpm 

Paket yang terinstal berisi hampir semua yang Anda butuhkan: baik aplikasi dan dependensi Lua yang diinstal. Tarantool juga datang ke server sebagai ketergantungan paket RPM, dan layanan kami siap diluncurkan. Ini semua dilakukan dengan menggunakan systemd, tetapi pertama-tama, kita harus melakukan beberapa konfigurasi, setidaknya tentukan URI dari setiap proses. Tiga akan cukup untuk contoh kita.

 $ 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 aspek menarik yang harus dipertimbangkan: alih-alih hanya menentukan port protokol biner, kami menentukan alamat publik dari keseluruhan proses, termasuk nama host. Kami melakukan ini karena node cluster harus tahu cara terhubung satu sama lain. Ini akan menjadi ide yang buruk untuk menggunakan alamat 0.0.0.0 sebagai advertise_uri, karena itu harus alamat IP eksternal, daripada mengikat socket. Tidak ada yang berfungsi tanpa itu sehingga Cartridge tidak akan membiarkan simpul dengan advertise_uri yang salah mulai.

Sekarang setelah konfigurasi siap, kita dapat memulai proses. Karena unit systemd reguler tidak memungkinkan memulai beberapa proses, unit instantiated yang disebut menginstal aplikasi pada Cartridge:

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

Kami telah menentukan port HTTP untuk antarmuka web Cartridge dalam konfigurasi: 8080. Mari kita ke sana dan melihatnya:


Kita dapat melihat bahwa prosesnya belum terkonfigurasi, meskipun sudah berjalan. Cartridge belum tahu bagaimana replikasi harus dilakukan dan tidak dapat memutuskan sendiri, sehingga menunggu tindakan kami. Kami tidak memiliki banyak pilihan: kehidupan cluster baru dimulai dengan konfigurasi node pertama. Kemudian kami menambahkan node lain ke cluster, menetapkan peran padanya, dan penyebaran dapat dianggap berhasil diselesaikan.

Mari kita minum dan bersantai setelah seminggu yang panjang. Aplikasi siap digunakan.


Hasil


Bagaimana dengan hasilnya? Silakan uji, gunakan, tinggalkan umpan balik, dan buat tiket di Github.

Referensi


[1] Tarantool Β»2.2Β» Referensi Β»Referensi batuanΒ» Modul vshard
[2] Bagaimana Kami Menerapkan Inti Bisnis Investasi Alfa-Bank Berbasis Tarantool
[3] Arsitektur Penagihan Generasi Selanjutnya: Transisi ke Tarantool
[4] SWIM - Protokol Bangunan Cluster
[5] GitHub - tarantool / cartridge-cli
[6] GitHub - tarantool / kartrid

Source: https://habr.com/ru/post/id470812/


All Articles