Partager via


Migrer des données de manière dynamique d’Apache Cassandra vers Azure Cosmos DB for Apache Cassandra en utilisant un proxy à double écriture et Azure Spark

L’API pour Cassandra dans Azure Cosmos DB est un excellent choix pour les charges de travail d’entreprise qui s’exécutent sur Apache Cassandra pour différentes raisons :

  • Aucune surcharge de gestion et de surveillance : Il élimine la surcharge liée à la gestion et à la surveillance d’une multitude de paramètres entre les systèmes d’exploitation, les machines virtuelles Java et les fichiers yaml et leurs interactions.
  • Économies significatives sur les coûts : Vous pouvez économiser des coûts avec Azure Cosmos DB, qui inclut le coût des machines virtuelles, de la bande passante et de toutes les licences applicables. Vous n’avez pas besoin de gérer les centres de données, les serveurs, le stockage SSD, la mise en réseau et les coûts d’électricité.
  • Possibilité d'utiliser le code et les outils existants : Azure Cosmos DB fournit une compatibilité au niveau du protocole filaire avec les SDK et outils Cassandra existants. Cette compatibilité garantit la possibilité d’utiliser votre codebase avec Azure Cosmos DB for Apache Cassandra sans changements majeurs.

Microsoft Azure Cosmos DB ne prend pas en charge le protocole de bavardage Apache Cassandra natif pour la réplication. Là où aucun temps d’arrêt est requis pour la migration, une approche différente est nécessaire. Ce tutoriel explique comment migrer des données de manière dynamique vers Azure Cosmos DB for Apache Cassandra à partir d’un cluster Apache Cassandra natif en utilisant un proxy à double écriture et Apache Spark.

L’approche est illustrée dans l’image suivante. Le proxy de double écriture est utilisé pour capturer les modifications en temps réel. Les données historiques sont copiées en bloc à l’aide d’Apache Spark. Le proxy peut accepter des connexions depuis votre code d’application avec peu ou pas de modifications de configuration. Il route toutes les requêtes vers votre base de données source et route de manière asynchrone les écritures dans l’API pour Cassandra pendant que la copie en bloc se produit.

Animation montrant la migration dynamique de données vers Azure Managed Instance pour Apache Cassandra.

Prérequis

Important

Si vous devez conserver Apache Cassandra writetime lors de la migration, les indicateurs suivants doivent être définies lors de la création des tables :

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

Par exemple :

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;

Approvisionner un cluster Spark

Nous vous recommandons d’utiliser Azure Databricks. Utilisez un runtime qui prend en charge Spark 3.0 ou supérieur.

Important

Vous devez vérifier que votre compte Azure Databricks dispose d’une connectivité réseau à votre cluster Apache Cassandra source. Cette configuration peut nécessiter une injection de réseau virtuel. Pour plus d’informations, consultez Déployer Azure Databricks dans votre propre réseau virtuel Azure (injection de réseau virtuel).

Capture d’écran montrant où trouver la version du runtime Azure Databricks.

Ajouter des dépendances Spark

Ajoutez la bibliothèque du connecteur Apache Spark Cassandra à votre cluster pour vous connecter aux points de terminaison Cassandra natifs et Azure Cosmos DB. Dans votre cluster, sélectionnez Bibliothèques>Installer nouveau>Maven, puis ajoutez com.datastax.spark:spark-cassandra-connector-assembly_2.12:3.0.0 dans les coordonnées Maven.

Important

Si vous devez conserver le writetime Apache Cassandra de chaque ligne pendant la migration, nous vous recommandons d’utiliser cet exemple. Le fichier JAR de dépendance dans cet exemple contient également le connecteur Spark. Vous devez donc installer cette version au lieu de l’assembly de connecteur décrit précédemment.

Cet exemple est également utile si vous voulez valider une comparaison de lignes entre la source et la cible une fois le chargement des données historiques terminé. Pour plus d’informations, consultez Exécuter le chargement des données historiques et valider la source et la cible.

Capture d’écran montrant la recherche de packages Maven dans Azure Databricks.

Sélectionnez Installer, puis redémarrez le cluster une fois l’installation terminée.

Notes

Veillez à redémarrer le cluster Azure Databricks après l’installation de la bibliothèque du connecteur Cassandra.

Installer le proxy de double écriture

Pour des performances optimales pendant les écritures doubles, nous vous recommandons d’installer le proxy sur tous les nœuds de votre cluster Cassandra source.

#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

Démarrer le proxy de double écriture

Nous vous recommandons d’installer le proxy sur tous les nœuds dans votre cluster Cassandra source. Au minimum, exécutez la commande suivante pour démarrer le proxy sur chaque nœud. Remplacez <target-server> par l’adresse IP ou de serveur de l’un des nœuds dans le cluster cible. Remplacez <path to JKS file> par le chemin vers un fichier .jks local, et remplacez <keystore password> par le mot de passe correspondant.

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>

Démarrer le proxy de cette façon suppose que les conditions suivantes sont réunies :

  • Les points de terminaison source et cible ont le même nom d’utilisateur et le même mot de passe.
  • Les points de terminaison source et cible implémentent SSL (Secure Sockets Layer).

Si vos points de terminaison source et cible ne peuvent pas répondre à ces critères, consultez les informations ci-dessous pour d’autres options de configuration.

Configuration du chiffrement SSL

Pour SSL, vous pouvez implémenter un magasin de clés existant, par exemple celui utilisé par votre cluster source ou créer un certificat auto-signé à l’aide keytoolde :

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

Vous pouvez aussi désactiver SSL pour les points de terminaison source ou cible s’ils n’implémentent pas SSL. Utilisez les indicateurs --disable-source-tls ou --disable-target-tls :

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 

Notes

Assurez-vous que votre application cliente utilise le même magasin de clés et le même mot de passe que ceux utilisés pour le proxy double écriture lorsque vous générez des connexions SSL à la base de données via le proxy.

Configurer les informations d’identification et le port

Par défaut, votre application cliente transmet les informations d'identification d'origine. Le proxy utilise les informations d’identification pour établir des connexions aux clusters source et cible. Comme mentionné plus haut, ce processus suppose que les informations d’identification de la source et de la cible sont identiques. Vous devez spécifier un nom d’utilisateur et un mot de passe différents pour l’API cible pour le point de terminaison Cassandra séparément lors du démarrage du proxy :

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>

Les ports source et cible par défaut, lorsqu’ils ne sont pas spécifiés, sont 9042. Dans ce cas, l’API pour Cassandra s’exécute sur le port 10350. Utilisez --source-port ou --target-port spécifiez les numéros de 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>

Déployer le proxy à distance

Il peut y avoir des circonstances dans lesquelles vous ne souhaitez pas installer le proxy sur les nœuds de cluster eux-mêmes. Vous préférerez peut-être l’installer sur un ordinateur distinct. Dans ce scénario, spécifiez l’adresse IP de <source-server>:

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

Avertissement

L’installation et l’exécution du proxy à distance sur un ordinateur distinct plutôt que de l’exécuter sur tous les nœuds de votre cluster Apache Cassandra source affectent les performances pendant la migration dynamique. Bien que cette configuration fonctionne correctement, le pilote client ne peut pas ouvrir de connexions à tous les nœuds du cluster. Le client s’appuie sur le nœud coordinateur unique où le proxy est installé pour établir des connexions.

Autoriser les modifications sans aucun code d’application

Par défaut, le proxy écoute sur le port 29042. Modifiez le code de l’application pour qu’il pointe vers ce port. Vous pouvez, à la place, modifier le port sur lequel le proxy écoute. Vous pouvez apporter cette modification si vous souhaitez éliminer les modifications du code au niveau de l’application en procédant comme suit :

  • Faire en sorte que le serveur Cassandra source s’exécute sur un port différent.
  • Faire en sorte que le proxy s’exécute sur le port Cassandra standard 9042.
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --proxy-port 9042

Notes

L’installation du proxy sur les nœuds de cluster ne nécessite pas de redémarrage des nœuds. Si vous avez de nombreux clients d’application et que vous préférez exécuter le proxy sur le port Cassandra standard 9042 afin d’éliminer les modifications de code au niveau de l’application, modifiez le port par défaut Apache Cassandra. Vous devez ensuite redémarrer les nœuds de votre cluster et configurer le port source comme nouveau port que vous avez défini pour votre cluster Cassandra source.

Dans l’exemple suivant, nous modifions le cluster Cassandra source pour qu’il s’exécute sur le port 3074 et nous démarrons le cluster sur le port 9042 :

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

Forcer les protocoles

Le proxy dispose de fonctionnalités pour forcer les protocoles, ce qui peut être nécessaires si le point de terminaison source est plus avancé que la cible ou s’il n’est pas pris en charge. Dans ce cas, vous pouvez spécifier --protocol-version et --cql-version pour forcer le protocole à se conformer à la cible :

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

Une fois que le proxy double écriture est en cours d’exécution, vous devez modifier le port sur votre client d’application et redémarrer. Ou modifiez le port Cassandra et redémarrez le cluster, si vous choisissez cette approche. Le proxy commence à transférer des écritures dans le point de terminaison cible. Pour plus d’informations, consultez surveillance et métriques.

Effectuer le chargement des données d’historique

Pour charger les données, créez un notebook Scala dans votre compte Azure Databricks. Remplacez vos configurations Cassandra source et cible par les informations d’identification correspondantes, et remplacez les espaces de clés et les tables sources et cibles. Ajoutez des variables à l’exemple ci-dessous pour chaque table en fonction des besoins, puis lancez l’exécution. Une fois que votre application a commencé à envoyer des demandes au proxy de double écriture, vous êtes prêt à migrer les données d’historique.

Important

Avant de migrer les données, augmentez le débit du conteneur jusqu’à la quantité requise pour que votre application migre rapidement. La mise à l’échelle du débit avant de commencer la migration vous permet de migrer vos données en moins de temps. Pour vous protéger contre la limitation de débit pendant le chargement des données historiques, vous pouvez activer la relance côté serveur (SSR) dans l'API pour Cassandra. Pour obtenir des instructions sur l’activation de SSR et plus d’informations, consultez Empêcher les erreurs de limitation de débit pour les opérations Azure Cosmos DB pour Apache Cassandra.

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

Notes

Dans l’exemple Scala précédent, vous remarquez que timestamp est paramétré à l'heure actuelle avant la lecture de toutes les données de la table source. Ensuite writetime est défini sur cet horodatage antidaté. Cette approche garantit que les enregistrements écrits depuis le chargement des données d’historique sur le point de terminaison cible ne peuvent pas remplacer les mises à jour qui arrivent avec un horodatage ultérieur en provenance du proxy de double écriture pendant la lecture des données d’historique.

Important

Si pour une raison quelconque, vous devez conserver les horodatages exacts, il vous faut adopter une approche de la migration des données d’historique qui conserve les horodatages, comme dans cet exemple. Le fichier JAR de dépendance dans l’exemple contient également le connecteur Spark. Vous n’avez donc pas besoin d’installer l’assembly de connecteur Spark mentionné dans les prérequis précédents. L’installation des deux dans votre cluster Spark provoque des conflits.

Vérifier la source et la cible

Une fois le chargement des données d’historique terminé, vos bases de données doivent être synchronisées et prêtes pour le basculement. Nous vous recommandons de vérifier que la source et la cible correspondent bien avant d’effectuer le basculement final.

Notes

Si vous avez utilisé l’exemple de migration Cassandra mentionné précédemment pour la conservation writetime, cet exemple inclut la possibilité de valider la migration en comparant les lignes dans la source et la cible en fonction de certaines tolérances.

Étape suivante