Migrasi langsung data dari Apache Cassandra ke Azure Cosmos DB for Apache Cassandra dengan menggunakan proksi dual-write dan Apache Spark

API untuk Cassandra di Azure Cosmos DB telah menjadi pilihan yang bagus untuk beban kerja perusahaan yang berjalan di Apache Cassandra karena berbagai alasan seperti:

  • Tidak ada overhead pengelolaan dan pemantauan: Ini menghilangkan overal pengelolaan dan pemantauan berbagai pengaturan di OS, JVM, dan file yaml dan interaksinya.

  • Penghematan biaya yang signifikan: Anda dapat menghemat biaya dengan Azure Cosmos DB, yang mencakup biaya VM, bandwidth, dan lisensi apa pun yang berlaku. Anda tidak perlu mengelola pusat data, server, penyimpanan SSD, jaringan, dan biaya listrik.

  • Kemampuan untuk menggunakan kode dan alat yang ada: Azure Cosmos DB menyediakan kompatibilitas tingkat protokol kawat dengan SDK dan alat Cassandra yang ada. Kompatibilitas ini memastikan Anda dapat menggunakan basis kode yang ada dengan Azure Cosmos DB for Apache Cassandra dengan perubahan sepele.

Azure Cosmos DB tidak mendukung protokol gosip Apache Cassandra asli untuk replikasi. Oleh karena itu, saat waktu henti nol merupakan persyaratan untuk migrasi, diperlukan pendekatan yang berbeda. Tutorial ini menjelaskan cara langsung memigrasikan data ke Azure Cosmos DB for Apache Cassandra dari kluster Apache Cassandra asli menggunakan proksi dual-write dan Apache Spark.

Gambar berikut mengilustrasikan pola tersebut. Proksi tulis ganda digunakan untuk menangkap perubahan langsung, sementara data historis disalin secara massal menggunakan Apache Spark. Proksi dapat menerima koneksi dari kode aplikasi Anda dengan sedikit atau tanpa perubahan konfigurasi. Ini akan merutekan semua permintaan ke database sumber Anda dan secara asinkron merutekan penulisan ke API untuk Cassandra saat salinan massal terjadi.

Animasi yang menampilkan perpindahan data langsung ke Azure Managed Instance for Apache Cassandra.

Prasyarat

  • Memprovisikan akun Azure Cosmos DB untuk Apache Cassandra.

  • Tinjau dasar-dasar menyambungkan ke Azure Cosmos DB for Apache Cassandra.

  • Tinjau fitur yang didukung di Azure Cosmos DB for Apache Cassandra untuk memastikan kompatibilitas.

  • Gunakan cqlsh untuk validasi.

  • Pastikan Anda memiliki konektivitas jaringan antara kluster sumber dan API target untuk titik akhir Cassandra.

  • Pastikan Anda telah memigrasikan skema keyspace/table dari database Cassandra sumber Anda ke API target untuk akun Cassandra.

    Penting

    Jika Anda memiliki persyaratan untuk mempertahankan Apache Cassandra writetime selama migrasi, tanda berikut harus ditetapkan saat membuat tabel:

    with cosmosdb_cell_level_timestamp=true and cosmosdb_cell_level_timestamp_tombstones=true and cosmosdb_cell_level_timetolive=true
    

    Contohnya:

    CREATE KEYSPACE IF NOT EXISTS migrationkeyspace WITH REPLICATION= {'class': 'org.apache.> cassandra.locator.SimpleStrategy', 'replication_factor' : '1'};
    
    CREATE TABLE IF NOT EXISTS migrationkeyspace.users (
     name text,
     userID int,
     address text,
     phone int,
     PRIMARY KEY ((name), userID)) with cosmosdb_cell_level_timestamp=true and > cosmosdb_cell_level_timestamp_tombstones=true and cosmosdb_cell_level_timetolive=true;
    

Provisi kluster Spark

Kami merekomendasikan Azure Databricks. Gunakan runtime yang mendukung Spark 3.0 atau yang lebih tinggi.

Penting

Anda perlu memastikan bahwa akun Azure Databricks Anda memiliki konektivitas jaringan dengan kluster Apache Cassandra sumber Anda. Hal ini mungkin memerlukan injeksi VNet. Lihat artikel di sini untuk informasi selengkapnya.

Cuplikan layar yang menampilkan penemuan versi runtime Azure Databricks.

Tambahkan ketergantungan Spark

Anda perlu menambahkan pustaka Apache Spark Cassandra Connector ke klaster Anda untuk terhubung ke titik akhir asli dan Azure Cosmos DB Cassandra. Di klaster Anda, pilih Pustaka>Pasang Baru>Maven, lalu tambahkan com.datastax.spark:spark-cassandra-connector-assembly_2.12:3.0.0 di koordinat Maven.

Penting

Jika Anda memiliki persyaratan untuk mempertahankan Apache Cassandra writetime untuk setiap baris selama migrasi, sebaiknya gunakan sampel ini. Jar dependensi dalam sampel ini juga berisi konektor Spark, jadi Anda harus menginstal ini, bukan rangkaian konektor di atas. Sampel ini juga berguna jika Anda ingin melakukan validasi perbandingan baris antara sumber dan target setelah pemuatan data historis selesai. Lihat bagian "menjalankan pemuatan data historis" dan "memvalidasi sumber dan target" di bawah untuk detail selengkapnya.

Cuplikan layar yang menampilkan pencarian paket Maven di Azure Databricks.

Pilih Pasang, lalu mulai ulang klaster ketika pemasangan selesai.

Catatan

Pastikan untuk memulai ulang kluster Azure Databricks setelah pustaka Konektor Cassandra terpasang.

Pasang proksi dual-write

Untuk tampilan optimal selama dual writes, kami merekomendasikan untuk menginstal proksi pada seluruh node dalam sumber kluster Cassandra Anda.

#assuming you do not have git already installed
sudo apt-get install git 

#assuming you do not have maven already installed
sudo apt install maven

#clone repo for dual-write proxy
git clone https://github.com/Azure-Samples/cassandra-proxy.git

#change directory
cd cassandra-proxy

#compile the proxy
mvn package

Mulai proksi dual-write

Kami merekomendasikan untuk memasang proksi pada seluruh simpul dalam sumber kluster Cassandra. Pada kondisi minimum, jalankan perintah berikut untuk memulai proksi di setiap simpul. Ganti <target-server> dengan sebuah IP atau alamat server dari satu node dalam kluster target. Ganti <path to JKS file> dengan jalur ke file .jks lokal, dan ganti <keystore password> dengan kata sandi terkait.

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> --proxy-jks-file <path to JKS file> --proxy-jks-password <keystore password>

Mulai proksi dengan cara ini dengan asumsi bahwa poin-poin berikut adalah benar:

  • Titik akhir sumber dan target memiliki nama pengguna dan kata sandi yang sama.
  • Titik akhir sumber dan target mengimplementasikan Secure Sockets Layer (SSL).

Jika titik akhir sumber dan target Anda tidak dapat memenuhi kriteria tersebut, baca terus untuk opsi konfigurasi lebih lanjut.

Konfigurasikan SSL

Untuk SSL, Anda dapat mengimplementasi sebuah keystore yang sudah ada (contohnya, yang digunakan oleh sumber kluster Anda), atau membuat sertifikat dengan tanda tangan sendiri menggunakan keytool:

keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048

Anda juga dapat menonaktifkan SSL untuk titik akhir sumber atau target jika tidak mengimplementasi SSL. Gunakan --disable-source-tls atau --disable-target-tls flags:

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> --source-port 9042 --target-port 10350 --proxy-jks-file <path to JKS file> --proxy-jks-password <keystore password> --target-username <username> --target-password <password> --disable-source-tls true  --disable-target-tls true 

Catatan

Pastikan aplikasi klien Anda menggunakan keystore dan kata sandi yang sama dengan yang digunakan untuk proksi dual-write ketika menyambungkan koneksi SSL ke database melalui proksi tersebut.

Konfigurasikan informasi masuk dan port

Secara default, sumber informasi masuk akan diteruskan melalui aplikasi klien Anda. Proksi akan menggunakan informasi masuk untuk membuat koneksi ke kluster sumber dan target. Seperti disebutkan sebelumnya, proses ini mengasumsikan bahwa informasi masuk sumber dan target adalah sama. Anda harus menentukan nama pengguna dan kata sandi yang berbeda untuk API target untuk titik akhir Cassandra secara terpisah saat memulai proksi:

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> --proxy-jks-file <path to JKS file> --proxy-jks-password <keystore password> --target-username <username> --target-password <password>

Port sumber dan target default, saat tidak ditentukan, akan menjadi 9042. Dalam hal ini, API untuk Cassandra berjalan pada port 10350, jadi Anda perlu menggunakan --source-port atau --target-port untuk menentukan nomor port:

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> --source-port 9042 --target-port 10350 --proxy-jks-file <path to JKS file> --proxy-jks-password <keystore password> --target-username <username> --target-password <password>

Sebarkan proksi dari jarak jauh

Mungkin ada keadaan dimana Anda tidak ingin memasang proksi pada node kluster, dan memilih untuk memasangnya pada komputer terpisah. Dalam skenario itu, Anda perlu menentukan alamat IP <source-server>:

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar <source-server> <destination-server>

Peringatan

Menginstal dan menjalankan proksi dari jarak jauh di mesin terpisah (sebagai ganti menjalankannya di semua node di kluster Apache Cassandra sumber Anda) akan memengaruhi performa saat migrasi langsung terjadi. Meskipun akan bekerja secara fungsional, driver klien tidak akan dapat membuka koneksi ke semua node dalam kluster, dan akan bergantung pada node koordinator tunggal (tempat proksi diinstal) untuk membuat koneksi.

Izinkan perubahan kode aplikasi nol

Secara default, proksi tersebut mengikuti port 29042. Kode aplikasi harus diubah pada titik port ini. Tetapi, Anda juga bisa mengubah port yang diikuti oleh proksi. Anda dapat melakukan ini jika Anda ingin menghilangkan perubahan kode tingkat aplikasi dengan:

  • Menjalankan sumber server Cassandra pada port yang berbeda.
  • Menjalankan proksi pada port Cassandra standar 9042.
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --proxy-port 9042

Catatan

Menginstal proksi pada kluster node tidak membutuhkan restart node. Namun, jika Anda memiliki banyak klien aplikasi dan memilih untuk menjalankan proksi pada port 9042 standar Cassandra untuk menghilangkan perubahan kode level aplikasi, Anda perlu mengubah port default Apache Cassandra. Anda kemudian perlu memulai ulang simpul di kluster Anda, dan mengonfigurasi port sumber untuk menjadi port baru yang Anda tentukan untuk sumber kluster Cassandra Anda.

Dalam contoh berikut, kami mengubah sumber kluster Cassandra untuk dijalankan pada port 3074, dan kami memulai kluster pada port 9042:

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --proxy-port 9042 --source-port 3074

Protokol paksa

Proksi tersebut memiliki beberapa fungsi untuk memaksa protokol-protokol yang mungkin diperlukan jika titik akhir sumber lebih modern daripada target atau jika target tidak mendukung. Dalam hal ini, Anda dapat menentukan --protocol-version dan --cql-version untuk memaksa protokol mematuhi target:

java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --protocol-version 4 --cql-version 3.11

Setelah proksi dual-write berjalan, Anda perlu mengubah port pada aplikasi klien Anda dan memulai ulang. (Atau ubah port Cassandra dan mulai ulang kluster jika Anda telah memilih pendekatan tersebut.) Proksi kemudian akan mulai meneruskan menulis ke titik akhir target. Anda bisa mempelajari tentang pantauan dan metrik tersedia di alat proksi.

Jalankan muatan data riwayat

Untuk memuat data, buatlah catatan Scala di dalam akun Azure Databricks Anda. Ganti konfigurasi Cassandra sumber dan target Anda dengan informasi masuk terkait, dan ganti keyspace dan tabel sumber dan target. Tambahkan variabel lebih untuk tiap tabel sesuai kebutuhan ke contoh berikut, kemudian jalankan. Setelah aplikasi Anda mulai mengirimkan permintaan ke proksi dual-write, Anda siap untuk memindahkan data riwayat.

Penting

Sebelum memigrasikan data, tingkatkan throughput kontainer ke jumlah yang diperlukan agar aplikasi Anda bermigrasi dengan cepat. Menskalakan throughput sebelum memulai migrasi akan membantu Anda melakukan migrasi data dalam waktu yang lebih singkat. Untuk membantu melindungi terhadap pembatasan tarif selama beban data historis, Anda mungkin ingin mengaktifkan percobaan ulang sisi server (SSR) di API untuk Cassandra. Lihat artikel kami di sini untuk informasi selengkapnya, dan petunjuk tentang cara mengaktifkan SSR.

import com.datastax.spark.connector._
import com.datastax.spark.connector.cql._
import org.apache.spark.SparkContext

// source cassandra configs
val sourceCassandra = Map( 
    "spark.cassandra.connection.host" -> "<Source Cassandra Host>",
    "spark.cassandra.connection.port" -> "9042",
    "spark.cassandra.auth.username" -> "<USERNAME>",
    "spark.cassandra.auth.password" -> "<PASSWORD>",
    "spark.cassandra.connection.ssl.enabled" -> "true",
    "keyspace" -> "<KEYSPACE>",
    "table" -> "<TABLE>"
)

//target cassandra configs
val targetCassandra = Map( 
    "spark.cassandra.connection.host" -> "<Source Cassandra Host>",
    "spark.cassandra.connection.port" -> "10350",
    "spark.cassandra.auth.username" -> "<USERNAME>",
    "spark.cassandra.auth.password" -> "<PASSWORD>",
    "spark.cassandra.connection.ssl.enabled" -> "true",
    "keyspace" -> "<KEYSPACE>",
    "table" -> "<TABLE>",
    //throughput related settings below - tweak these depending on data volumes. 
    "spark.cassandra.output.batch.size.rows"-> "1",
    "spark.cassandra.output.concurrent.writes" -> "1000",
    "spark.cassandra.connection.remoteConnectionsPerExecutor" -> "1",
    "spark.cassandra.concurrent.reads" -> "512",
    "spark.cassandra.output.batch.grouping.buffer.size" -> "1000",
    "spark.cassandra.connection.keep_alive_ms" -> "600000000"
)

//set timestamp to ensure it is before read job starts
val timestamp: Long = System.currentTimeMillis / 1000

//Read from source Cassandra
val DFfromSourceCassandra = sqlContext
  .read
  .format("org.apache.spark.sql.cassandra")
  .options(sourceCassandra)
  .load
  
//Write to target Cassandra
DFfromSourceCassandra
  .write
  .format("org.apache.spark.sql.cassandra")
  .options(targetCassandra)
  .option("writetime", timestamp)
  .mode(SaveMode.Append)
  .save

Catatan

Dalam sampel Scala sebelumnya, Anda akan melihat bahwa timestamp sedang diatur ke waktu saat ini sebelum membaca semua data dalam tabel sumber. Kemudian, writetime sedang diatur ke penandaan waktu dengan kondisi.backdated ini. Hal ini untuk meyakinkan bahwa rekaman-rekaman yang dituliskan dari muatan data riwayat ke titik akhir target tidak bisa menimpa pembaruan yang datang dengan penandaan waktu selanjutnya dari proksi dual-write saat riwayat data sedang dibaca.

Penting

Jika Anda butuh mempertahankan penandaan waktu tertentu karena suatu alasan, Anda disarankan untuk melakukan pendekatan pemindahan data riwayat yang mempertahankan penandaan waktu, seperti contoh berikut ini. Jar dependensi dalam sampel juga berisi konektor Spark, jadi Anda tidak perlu menginstal rangkaian konektor Spark yang disebutkan di prasyarat sebelumnya - menginstal keduanya di kluster Spark Anda akan menyebabkan konflik.

Validasi sumber dan target

Saat muatan data riwayat sudah lengkap, database Anda seharusnya sudah sinkron dan siap untuk dipindahkan langsung. Namun, sebaiknya Anda memvalidasi sumber dan target untuk memastikan mereka cocok sebelum akhirnya memotongnya.

Catatan

Jika Anda menggunakan sampel cassandra migrator yang disebutkan di atas untuk mempertahankan writetime, hal ini mencakup kemampuan untuk memvalidasi migrasi dengan membandingkan baris di sumber dan target berdasarkan toleransi tertentu.

Langkah berikutnya