Migração ao vivo para a Instância Gerenciada do Azure para Apache Cassandra usando um proxy de gravação dupla

Sempre que possível, recomendamos usar o recurso nativo do Apache Cassandra para migrar dados do cluster existente para a Instância Gerenciada do Azure para Apache Cassandra configurando um cluster híbrido. Esse recurso usa o protocolo de fofocas do Apache Cassandra para replicar dados do seu datacenter de origem para o novo datacenter de instância gerenciada de forma perfeita. No entanto, pode haver alguns cenários em que a versão do banco de dados de origem não seja compatível ou uma configuração de cluster híbrido não seja viável.

Este tutorial descreve como migrar dados para a Instância Gerenciada do Azure para Apache Cassandra de forma ao vivo usando um proxy de gravação dupla e o Apache Spark. O proxy de gravação dupla é usado para capturar alterações em tempo real, enquanto os dados históricos são copiados em massa usando o Apache Spark. Os benefícios desta abordagem são:

  • Alterações mínimas no aplicativo. O proxy pode aceitar conexões do código do seu aplicativo com poucas ou nenhuma alteração de configuração. Ele encaminhará todas as solicitações para o banco de dados de origem e roteará as gravações de forma assíncrona para um destino secundário.
  • Dependência do protocolo de fio do cliente. Como essa abordagem não depende de recursos de back-end ou protocolos internos, ela pode ser usada com qualquer sistema Cassandra de origem ou destino que implemente o protocolo de fio Apache Cassandra.

A imagem a seguir ilustra a abordagem.

Animação que mostra a migração ao vivo de dados para a Instância Gerenciada do Azure para Apache Cassandra.

Pré-requisitos

  • Provisione uma Instância Gerenciada do Azure para cluster Apache Cassandra usando o portal do Azure ou a CLI do Azure. Certifique-se de que você pode se conectar ao cluster com CQLSH.

  • Provisione uma conta do Azure Databricks dentro de sua rede virtual Cassandra gerenciada. Certifique-se de que a conta tem acesso de rede ao cluster Cassandra de origem. Criaremos um cluster do Spark nesta conta para a carga de dados históricos.

  • Certifique-se de que você já migrou o esquema keyspace/table do banco de dados Cassandra de origem para o banco de dados de instância gerenciada Cassandra de destino.

Provisionar um cluster do Spark

Recomendamos selecionar o tempo de execução do Azure Databricks versão 7.5, que dá suporte ao Spark 3.0.

Captura de tela que mostra como localizar a versão de tempo de execução do Azure Databricks.

Adicionar dependências do Spark

Você precisa adicionar a biblioteca Apache Spark Cassandra Connector ao seu cluster para se conectar a qualquer endpoint Apache Cassandra compatível com protocolo de fio. No cluster, selecione Bibliotecas>Instalar Novo>Maven e adicione com.datastax.spark:spark-cassandra-connector-assembly_2.12:3.0.0 as coordenadas do Maven.

Importante

Se você tiver um requisito para preservar o Apache Cassandra writetime para cada linha durante a migração, recomendamos usar este exemplo. O jar de dependência neste exemplo também contém o conector Spark, portanto, você deve instalá-lo em vez do conjunto de conector acima. Este exemplo também é útil se você quiser executar uma validação de comparação de linha entre origem e destino após a conclusão do carregamento de dados históricos. Consulte as seções "executar a carga de dados históricos" e "validar a origem e o destino" abaixo para obter mais detalhes.

Captura de ecrã que mostra a procura de pacotes Maven no Azure Databricks.

Selecione Instalar e reinicie o cluster quando a instalação estiver concluída.

Nota

Certifique-se de reiniciar o cluster do Azure Databricks após a instalação da biblioteca Cassandra Connector.

Instalar o proxy de gravação dupla

Para um desempenho ideal durante gravações duplas, recomendamos instalar o proxy em todos os nós do cluster Cassandra de origem.

#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

Inicie o proxy de gravação dupla

Recomendamos que você instale o proxy em todos os nós do cluster Cassandra de origem. No mínimo, execute o seguinte comando para iniciar o proxy em cada nó. Substitua <target-server> por um IP ou endereço de servidor de um dos nós no cluster de destino. Substitua <path to JKS file> pelo caminho para um arquivo .jks local e substitua <keystore password> pela senha correspondente.

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>

Iniciar o proxy dessa maneira pressupõe que o seguinte seja verdadeiro:

  • Os pontos de extremidade de origem e de destino têm o mesmo nome de usuário e senha.
  • Os endpoints de origem e destino implementam Secure Sockets Layer (SSL).

Se seus pontos de extremidade de origem e de destino não puderem atender a esses critérios, continue lendo para obter mais opções de configuração.

Configurar o SSL

Para SSL, você pode implementar um keystore existente (por exemplo, aquele que o cluster de origem usa) ou criar um certificado autoassinado usando keytool:

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

Você também pode desabilitar o SSL para pontos de extremidade de origem ou de destino se eles não implementarem SSL. Use as --disable-source-tls bandeiras 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 

Nota

Certifique-se de que seu aplicativo cliente usa o mesmo armazenamento de chaves e senha que os usados para o proxy de gravação dupla quando você estiver criando conexões SSL para o banco de dados por meio do proxy.

Configurar as credenciais e a porta

Por padrão, as credenciais de origem serão passadas do seu aplicativo cliente. O proxy usará as credenciais para fazer conexões com os clusters de origem e destino. Como mencionado anteriormente, esse processo pressupõe que as credenciais de origem e de destino são as mesmas. Se necessário, você pode especificar um nome de usuário e senha diferentes para o ponto de extremidade Cassandra de destino separadamente ao iniciar o 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>

As portas de origem e destino padrão, quando não especificadas, serão 9042. Se o destino ou o ponto de extremidade Cassandra de origem for executado em uma porta diferente, você poderá usar --source-port ou --target-port especificar um número de porta diferente:

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>

Implantar o proxy remotamente

Pode haver circunstâncias em que você não queira instalar o proxy nos próprios nós do cluster e prefira instalá-lo em uma máquina separada. Nesse cenário, você precisa especificar o endereço IP de <source-server>:

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

Aviso

Se você preferir executar o proxy remotamente em uma máquina separada (em vez de executá-lo em todos os nós do cluster Apache Cassandra de origem), recomendamos implantar o proxy no mesmo número de máquinas que você tem nós em seu cluster e configurar uma substituição para seus endereços IP em system.peers usando a configuração no proxy mencionado aqui. Se você não fizer isso, isso poderá afetar o desempenho enquanto a migração ao vivo ocorre, pois o driver do cliente não poderá abrir conexões com todos os nós dentro do cluster.

Permitir zero alterações no código do aplicativo

Por padrão, o proxy escuta na porta 29042. O código do aplicativo deve ser alterado para apontar para essa porta. No entanto, você pode alterar a porta que o proxy escuta. Você pode fazer isso se quiser eliminar as alterações de código no nível do aplicativo:

  • Ter o servidor Cassandra de origem executado em uma porta diferente.
  • Ter o proxy executado na porta Cassandra padrão 9042.
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --proxy-port 9042

Nota

A instalação do proxy em nós de cluster não requer a reinicialização dos nós. No entanto, se você tiver muitos clientes de aplicativos e preferir ter o proxy em execução na porta padrão Cassandra 9042 para eliminar quaisquer alterações de código no nível do aplicativo, você precisará alterar a porta padrão do Apache Cassandra. Em seguida, você precisa reiniciar os nós no cluster e configurar a porta de origem para ser a nova porta definida para o cluster Cassandra de origem.

No exemplo a seguir, alteramos o cluster Cassandra de origem para ser executado na porta 3074 e iniciamos o cluster na porta 9042:

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

Forçar protocolos

O proxy tem funcionalidade para forçar protocolos, o que pode ser necessário se o ponto de extremidade de origem for mais avançado do que o destino ou não for suportado. Nesse caso, você pode especificar --protocol-version e --cql-version forçar o protocolo a cumprir com o destino:

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

Depois que o proxy de gravação dupla estiver em execução, você precisará alterar a porta no cliente do aplicativo e reiniciar. (Ou altere a porta Cassandra e reinicie o cluster se tiver escolhido essa abordagem.) O proxy começará a encaminhar gravações para o ponto de extremidade de destino. Você pode aprender sobre monitoramento e métricas disponíveis na ferramenta de proxy.

Executar a carga de dados históricos

Para carregar os dados, crie um bloco de anotações Scala em sua conta do Azure Databricks. Substitua as configurações Cassandra de origem e de destino pelas credenciais correspondentes e substitua os espaços-chave e tabelas de origem e destino. Adicione mais variáveis para cada tabela, conforme necessário, ao exemplo a seguir e execute. Depois que seu aplicativo começar a enviar solicitações para o proxy de gravação dupla, você estará pronto para migrar dados históricos.

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" -> "9042",
    "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

Nota

No exemplo de Scala anterior, você notará que timestamp está sendo definido para a hora atual antes de ler todos os dados na tabela de origem. Então, writetime está sendo definido para este carimbo de data/hora retroativo. Isso garante que os registros gravados da carga de dados históricos para o ponto de extremidade de destino não possam substituir atualizações que chegam com um carimbo de data/hora posterior do proxy de gravação dupla enquanto os dados históricos estão sendo lidos.

Importante

Se você precisar preservar carimbos de data/hora exatos por qualquer motivo, deverá adotar uma abordagem de migração de dados históricos que preserve carimbos de data/hora, como este exemplo. O jar de dependência no exemplo também contém o conector Spark, portanto, você não precisa instalar o conjunto do conector Spark mencionado nos pré-requisitos anteriores - ter ambos instalados no cluster Spark causará conflitos.

Validar a origem e o destino

Após a conclusão do carregamento de dados históricos, seus bancos de dados devem estar sincronizados e prontos para substituição. No entanto, recomendamos que você valide a origem e o destino para garantir que eles correspondam antes de finalmente cortar.

Nota

Se você usou o exemplo de migrador cassandra mencionado acima para preservar, writetimeisso inclui a capacidade de validar a migração comparando linhas na origem e no destino com base em determinadas tolerâncias.

Próximos passos