Pengalaman migrasi Cassandra kami antara cluster Kubernetes tanpa kehilangan data



Selama ~ enam bulan terakhir, kami telah menggunakan operator Rook untuk bekerja dengan Cassandra di Kubernetes . Namun, ketika kami perlu melakukan yang sangat sepele, tampaknya, operasi: mengubah parameter dalam konfigurasi Cassandra, ternyata operator tidak memberikan fleksibilitas yang memadai. Untuk membuat perubahan, perlu mengkloning repositori, membuat perubahan pada sumber dan membangun kembali operator (konfigurasi dibangun ke dalam operator itu sendiri, sehingga pengetahuan Go masih berguna). Semua ini membutuhkan banyak waktu.

Kami sudah melakukan tinjauan terhadap operator yang ada , dan kali ini kami berhenti di CassKop dari Orange , yang mendukung fitur yang diperlukan, khususnya, konfigurasi khusus dan pemantauan di luar kotak.

Tugas


Dalam kisah nyata, yang akan dibahas nanti, diputuskan untuk menggabungkan perubahan operator dengan kebutuhan mendesak untuk mentransfer seluruh infrastruktur klien ke cluster baru. Setelah migrasi dari beban kerja utama dari aplikasi penting, hanya Cassandra yang tersisa, kehilangan data yang, tentu saja, tidak dapat diterima.

Persyaratan untuk migrasi:

  • Waktu idle maksimum adalah 2-3 menit untuk benar-benar melakukan transfer ini pada saat yang sama ketika aplikasi itu sendiri digulirkan ke cluster baru;
  • Transfer semua data tanpa kehilangan dan sakit kepala (mis. Tanpa manipulasi tambahan).

Bagaimana cara melakukan operasi seperti itu? Dengan analogi dengan RabbitMQ dan MongoDB , kami memutuskan untuk meluncurkan instalasi baru Cassandra di cluster Kubernetes baru, kemudian menggabungkan dua Cassandra dalam kelompok yang berbeda dan mentransfer data, mengakhiri seluruh proses dengan hanya menonaktifkan instalasi asli.

Namun, itu diperumit oleh fakta bahwa jaringan di dalam Kubernetes berpotongan, jadi tidak mudah untuk mengkonfigurasi koneksi. Itu diperlukan untuk mendaftarkan rute untuk setiap pod pada setiap node, yang sangat memakan waktu dan tidak dapat diandalkan sama sekali. Faktanya adalah bahwa komunikasi melalui pod IP hanya berfungsi dengan master, dan Cassandra berjalan pada node khusus. Dengan demikian, Anda harus terlebih dahulu mengkonfigurasi rute ke master dan sudah di master - ke cluster lain. Selain itu, memulai ulang pod memerlukan perubahan dalam IP, dan ini adalah masalah lain ... Mengapa? Baca tentang itu nanti di artikel.

Pada bagian praktis berikutnya dari artikel, tiga notasi untuk cluster Cassandra akan digunakan:

  • Cassandra-new - instalasi baru yang akan kami luncurkan di cluster Kubernetes baru;
  • Cassandra-current - instalasi lama yang saat ini aplikasi sedang bekerja;
  • Cassandra-temporary adalah instalasi sementara yang kami jalankan di samping Cassandra-current dan menggunakannya hanya untuk proses migrasi itu sendiri.

Bagaimana menjadi?


Karena Cassandra-current menggunakan penyimpanan lokal, migrasi sederhana datanya ke cluster baru - ini bisa, misalnya, dalam kasus disk vSphere ... - tidak mungkin. Untuk mengatasi masalah ini, kami akan membuat cluster sementara, menggunakannya sebagai semacam buffer untuk migrasi.

Urutan umum tindakan dikurangi menjadi langkah-langkah berikut:

  1. Naikkan Cassandra-baru dengan operator baru di cluster baru.
  2. Skala ke 0 Cassandra- cluster baru .
  3. , PVC, .
  4. Cassandra-temporary Cassandra-current , Cassandra-new.
  5. Cassandra-temporary 0 ( ) Cassandra-temporary , Cassandra-temporary Cassandra-current. Cassandra - ( Cassandra ).
  6. Transfer data antara pusat data Cassandra-sementara dan Cassandra-saat ini .
  7. Skala cluster Cassandra-saat ini dan sementara-Cassandra ke 0 dan jalankan Cassandra-baru di cluster baru, tidak lupa untuk membuang disk. Secara paralel, kami menggulung aplikasi ke cluster baru.

Sebagai akibat dari manipulasi semacam itu, downtime akan menjadi minimal.

Secara terperinci


Seharusnya tidak ada masalah dengan 3 langkah pertama - semuanya dilakukan dengan cepat dan mudah.

Pada titik ini, gugus Cassandra-current akan terlihat seperti ini:

Datacenter: x1
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns    Host ID                               Rack
UN  10.244.6.5  790.7 GiB  256          ?       13cd0c7a-4f91-40d0-ac0e-e7c4a9ad584c  rack1
UN  10.244.7.5  770.9 GiB  256          ?       8527813a-e8df-4260-b89d-ceb317ef56ef  rack1
UN  10.244.5.5  825.07 GiB  256          ?       400172bf-6f7c-4709-81c6-980cb7c6db5c  rack1

Untuk memverifikasi bahwa semuanya berfungsi seperti yang diharapkan, buat ruang kunci di Cassandra-saat ini . Ini dilakukan sebelum peluncuran Cassandra-temporary :

create keyspace example with replication ={'class' : 'NetworkTopologyStrategy', 'x1':2};

Selanjutnya, buat tabel dan isi dengan data:

use example;
CREATE TABLE example(id int PRIMARY KEY, name text, phone varint);
INSERT INTO example(id, name, phone) VALUES(1,'Masha', 983123123);
INSERT INTO example(id, name, phone) VALUES(2,'Sergey', 912121231);
INSERT INTO example(id, name, phone) VALUES(3,'Andrey', 914151617);

Jalankan Cassandra-temporary , ingat bahwa sebelum itu, di cluster baru, kami sudah meluncurkan Cassandra-new (langkah # 1) dan sekarang dimatikan (langkah # 2).

Catatan:

  1. Ketika kita memulai Cassandra-temporary , kita harus menentukan nama cluster yang sama (dengan Cassandra-current ). Ini bisa dilakukan melalui variabel CASSANDRA_CLUSTER_NAME.
  2. Agar Cassandra-sementara untuk melihat cluster saat ini, Anda perlu mengatur benih. Ini dilakukan melalui variabel CASSANDRA_SEEDSatau melalui konfigurasi.

Perhatian! Sebelum Anda mulai memindahkan data, Anda harus memastikan bahwa jenis konsistensi baca dan tulis diatur ke LOCAL_ONEatau LOCAL_QUORUM.

Setelah Cassandra-temporary dimulai , klaster akan terlihat seperti ini (perhatikan tampilan pusat data kedua dengan 3 node):

Datacenter: x1
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns    Host ID                               Rack
UN  10.244.6.5  790.7 GiB  256          ?       13cd0c7a-4f91-40d0-ac0e-e7c4a9ad584c  rack1
UN  10.244.7.5  770.9 GiB  256          ?       8527813a-e8df-4260-b89d-ceb317ef56ef  rack1
UN  10.244.5.5  825.07 GiB  256          ?       400172bf-6f7c-4709-81c6-980cb7c6db5c  rack1

Datacenter: x2
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address       Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.244.16.96  267.07 KiB  256          64.4%             3619841e-64a0-417d-a497-541ec602a996  rack1
UN  10.244.18.67  248.29 KiB  256          65.8%             07a2f571-400c-4728-b6f7-c95c26fe5b11  rack1
UN  10.244.16.95  265.85 KiB  256          69.8%             2f4738a2-68d6-4f9e-bf8f-2e1cfc07f791  rack1

Sekarang Anda dapat melakukan transfer. Untuk melakukan ini, pertama-tama transfer ruang uji kunci - pastikan semuanya baik-baik saja:

ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', x1: 2, x2: 2};


Setelah itu, di setiap pod Cassandra-temporer , jalankan perintah:

nodetool rebuild -ks example x1

Mari kita pergi ke pod Cassandra-temporer dan memeriksa apakah data telah ditransfer. Anda juga dapat menambahkan 1 entri lagi ke Cassandra-current untuk memverifikasi bahwa data baru sudah mulai direplikasi:

SELECT * FROM example;

 id | name   | phone
----+--------+-----------
  1 |  Masha | 983123123
  2 | Sergey | 912121231
  3 | Andrey | 914151617

(3 rows)

Setelah itu, Anda dapat melakukan ALTERsemua keypaces di Cassandra-saat ini dan mengeksekusi nodetool rebuild.

Kurangnya ruang dan memori


Pada tahap ini, penting untuk diingat bahwa ketika membangun kembali sedang berjalan, file sementara dibuat dengan ukuran yang setara dengan ukuran ruang kunci! Kami mengalami masalah bahwa ruang tombol terbesar adalah 350 GB, dan ada lebih sedikit ruang disk kosong.

Itu tidak mungkin untuk memperluas disk, karena penyimpanan lokal digunakan. Perintah berikut datang untuk menyelamatkan (dijalankan di setiap pod Cassandra-saat ini ):

nodetool clearsnapshot

Jadi tempat itu dibebaskan: dalam kasus kami, 500 GB ruang disk kosong diperoleh alih-alih 200 GB yang tersedia sebelumnya.

Namun, terlepas dari kenyataan bahwa ada ruang yang cukup, operasi pembangunan kembali terus-menerus menyebabkan restart pod -Cassandra-temporer dengan kesalahan:

failed; error='Cannot allocate memory' (errno=12)

Kami memutuskannya dengan membuat DaemonSet, yang diluncurkan hanya ke node dengan Cassandra-temporary dan melakukan:

sysctl -w vm.max_map_count=262144

Akhirnya, semua data telah dimigrasikan!

Peralihan klaster


Tinggal mengganti Cassandra, yang dilakukan dalam 5 tahap:

  1. Skala Cassandra-sementara dan Cassandra-saat ini (jangan lupa bahwa operator masih bekerja di sini!) Untuk 0.
  2. Beralih disk (turun ke pengaturan PV untuk Cassandra-new ).
  3. Kami memulai Cassandra-new , melacak bahwa disk yang diperlukan terhubung.
  4. Kami melakukan ALTERsemua tabel untuk menghapus kluster lama:

    ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', 'x2': 2};
  5. Hapus semua node dari cluster lama. Untuk melakukan ini, jalankan perintah ini di salah satu podnya:

    nodetool removenode 3619841e-64a0-417d-a497-541ec602a996

Total downtime Cassandra adalah sekitar 3 menit - ini adalah waktu kontainer berhenti dan mulai, karena disk sudah disiapkan sebelumnya.

Sentuhan terakhir dengan Prometheus


Namun, ini tidak berakhir di sana. Ada eksportir built-in dengan Cassandra-new (lihat dokumentasi operator baru ) - kami, tentu saja, menggunakannya. Sekitar 1 jam setelah peluncuran, peringatan tentang tidak dapat diaksesnya Prometheus mulai berdatangan. Setelah memeriksa beban, kami melihat bahwa konsumsi memori pada node dengan Prometheus telah meningkat.

Studi lebih lanjut tentang masalah ini menunjukkan bahwa jumlah metrik yang dikumpulkan meningkat 2,5 kali (!). Kesalahannya adalah Cassandra, yang mengumpulkan lebih dari 500 ribu metrik.

Kami melakukan audit terhadap metrik dan menonaktifkan metrik yang kami anggap tidak perlu - melalui ConfigMap (di dalamnya, omong-omong, eksportir dikonfigurasikan). Hasilnya adalah 120 ribu metrik dan beban yang berkurang secara signifikan di Prometheus (terlepas dari kenyataan bahwa metrik penting tetap ada).

Kesimpulan


Jadi kami berhasil mentransfer Cassandra ke cluster lain, praktis tanpa mempengaruhi fungsi instalasi produksi Cassandra dan tanpa mengganggu pekerjaan aplikasi klien. Sepanjang jalan, kami sampai pada kesimpulan bahwa menggunakan jaringan pod yang sama bukanlah ide yang baik (sekarang kami lebih memperhatikan perencanaan awal untuk menginstal cluster).

Akhirnya: mengapa kita tidak menggunakan alat yang nodetool snapshotdisebutkan dalam artikel sebelumnya? Faktanya adalah bahwa perintah ini menciptakan snapshot keyspace di negara itu sebelum perintah dijalankan. Selain:

  • butuh lebih banyak waktu untuk mengambil gambar dan mentransfernya;
  • semua yang ditulis pada saat ini di Cassandra akan hilang;
  • sederhana dalam kasus kami akan menjadi sekitar satu jam - bukannya 3 menit, yang ternyata berhasil digabungkan dengan penyebaran aplikasi ke cluster baru.

PS


Baca juga di blog kami:


All Articles