Como fazer a migração do MySQL para o Cloud Spanner

Neste artigo, explicamos como fazer a migração do seu banco de dados OLTP (Online Transactional Processing) do MySQL para o Cloud Spanner.

Restrições de migração

No Cloud Spanner, determinados conceitos são usados de maneira diferente de outras ferramentas de gerenciamento de bancos de dados corporativos, portanto, talvez seja necessário ajustar a arquitetura do seu aplicativo para aproveitar ao máximo os recursos disponíveis. Talvez você também precise complementar o Cloud Spanner com outros serviços do Google Cloud Platform (GCP) para atender às suas necessidades.

Acionadores e procedimentos armazenados

O Cloud Spanner não é compatível com a execução do código do usuário no nível do banco de dados. Por isso, como parte da migração, você precisa mover para o aplicativo a lógica de negócios implementada pelos acionadores e procedimentos armazenados no nível do banco de dados.

Sequências

O Cloud Spanner não implementa um gerador de sequência e, conforme explicado abaixo, o uso de números monotônicos crescentes como chaves primárias é um antipadrão no Cloud Spanner. O uso de um UUID aleatório é um mecanismo alternativo de geração de uma chave primária exclusiva.

Se, por motivos externos, você precisar de sequências, deverá implementá-las na camada do aplicativo.

Controles de acesso

O Cloud Spanner é compatível apenas com controles de acesso no nível de banco de dados, usando as permissões e papéis de acesso do Gerenciamento de identidade e acesso do Cloud Identity (IAM). Há papéis predefinidos que podem ser usadas para conceder acesso de leitura/gravação ou somente leitura ao banco de dados. Se for imprescindível ter permissões mais refinadas, você precisará implementá-las na camada do aplicativo. Em um cenário normal, somente o aplicativo deve ter permissão de leitura/gravação no banco de dados.

Se você precisar expor seu banco de dados a usuários para geração de relatórios e quiser usar permissões de segurança refinadas, por exemplo, permissões no nível de tabela/visualização, é recomendável exportar seu banco de dados para o BigQuery.

Restrições de validação de dados

O Cloud Spanner suporta um conjunto limitado de restrições de validação de dados na camada do banco de dados. Se você precisar de restrições de dados mais complexas, deverá implementá-las na camada do aplicativo.

Na tabela a seguir, mostramos os tipos de restrições comumente encontrados nos bancos de dados MySQL e como implementá-los com o Cloud Spanner.

Restrição Implementação com Cloud Spanner
Não nulo Restrição de coluna NOT NULL
Exclusivo Índice secundário com restrição UNIQUE
Foreign key (para tabelas normais) Implementada na camada do aplicativo
Chave estrangeira em ações ON DELETE/ON UPDATE Possível somente para tabelas intercaladas. Caso contrário, implementada na camada do aplicativo
Verificações de valor e validação por meio de acionadores ou restrições CHECK Implementada na camada do aplicativo

Tipos de dados compatíveis

O MySQL e o Cloud Spanner são compatíveis com diferentes conjuntos de tipos de dados. Na tabela a seguir, listamos os tipos de dados do MySQL e seus equivalentes no Cloud Spanner. Para ver definições detalhadas de cada tipo de dados do Cloud Spanner, consulte Tipos de dados.

Talvez você tenha de transformar ainda mais seus dados, conforme descrito na coluna "Observações", para ajustar os dados do MySQL no banco de dados do Cloud Spanner. Por exemplo, é possível armazenar um BLOB grande, como um objeto, em um intervalo do Cloud Storage, em vez de armazená-lo no banco de dados e depois armazenar a referência do URI ao objeto do Cloud Storage no banco de dados como uma STRING.

Tipo de dados do MySQL Equivalente do Cloud Spanner Observações
INTEGER, INT, BIGINT MEDIUMINT, SMALLINT INT64
TINYINT, BOOL, BOOLEAN BOOL, INT64 TINYINT(1) são usados para representar valores booleanos de "true" (diferente de zero) ou "false" (0).
FLOAT, DOUBLE FLOAT64
DECIMAL, NUMERIC FLOAT64, INT64, STRING O tipo de dados NUMERIC é compatível com até 65 dígitos de precisão, enquanto o tipo de dados FLOAT64 do Cloud Spanner é compatível com até 16 dígitos de precisão.
Para ver os mecanismos alternativos, consulte Como armazenar dados numéricos de precisão arbitrária.
BIT BYTES
DATE DATE Tanto o Cloud Spanner quanto o MySQL usam o formato "yyyy-mm-dd" para datas, portanto, nenhuma transformação é necessária. Funções SQL são fornecidas para converter datas em uma string formatada.
DATETIME, TIMESTAMP TIMESTAMP O Cloud Spanner armazena o horário independentemente do fuso horário. Se você precisar armazenar um fuso horário, deverá usar uma coluna STRING separada. As funções SQL são fornecidas para converter carimbos de data/hora em uma string formatada, usando fusos horários.
CHAR, VARCHAR STRING Observação: o Cloud Spanner usa strings "Unicode" em todo o processamento.
O VARCHAR é compatível com um comprimento máximo de 65.535 bytes, enquanto o Cloud Spanner é compatível com até 2.621.440 caracteres.
BINARY, VARBINARY, BLOB, TINYBLOB BYTES Objetos pequenos (menos de 10 MiB) podem ser armazenados como BYTES. Pense em usar ofertas alternativas do GCP, como o Cloud Storage, para armazenar objetos maiores.
TEXT, TINYTEXT, ENUM STRING Valores pequenos de TEXT (menos de 10 MiB) podem ser armazenados como STRING. Pense em usar ofertas alternativas do GCP, como o Cloud Storage, para conseguir compatibilidade com valores de TEXT maiores.
ENUM STRING A validação dos valores ENUM precisa ser executada no aplicativo.
SET ARRAY<STRING> A validação dos valores do elemento SET precisa ser executada no aplicativo.
LONGBLOB, MEDIUMBLOB BYTES ou STRING contendo o URI para o objeto. Objetos pequenos (menos de 10 MiB) podem ser armazenados como BYTES. Pense em usar ofertas alternativas do GCP, como o Cloud Storage, para armazenar objetos maiores.
LONGTEXT, MEDIUMTEXT STRING (contendo dados ou URI para o objeto externo) Objetos pequenos (menos de 2.621.440 caracteres) podem ser armazenados como STRING. Pense em usar ofertas alternativas do GCP, como o Cloud Storage, para armazenar objetos maiores.
JSON STRING (contendo dados ou URI para o objeto externo) Strings JSON pequenas (menos de 2.621.440 caracteres) podem ser armazenadas como STRING. Pense em usar ofertas alternativas do GCP, como o Cloud Storage, para armazenar objetos maiores.
GEOMETRY, POINT, LINESTRING, POLYGON, MULTIPOINT, MULTIPOLYGON, GEOMETRYCOLLECTION O Cloud Spanner não é compatível com tipos de dados geoespaciais. É preciso armazenar esses dados usando tipos de dados padrão e implementar alguma lógica de pesquisa/filtragem na camada do aplicativo.

Processo de migração

Um cronograma geral do seu processo de migração seria:

  • Converter seu esquema e modelo de dados.
  • Traduzir qualquer consulta SQL.
  • Migrar seu aplicativo para usar o Cloud Spanner, além do MySQL.
  • Exportar em massa seus dados do MySQL e importar seus dados para o Cloud Spanner usando o Cloud Dataflow.
  • Manter a consistência entre os dois bancos de dados durante a migração.
  • Migrar seu aplicativo para fora do MySQL.

Como converter seu esquema e o banco de dados

Converta seu esquema atual para um esquema do Cloud Spanner para armazenar seus dados. Simplifique as modificações na aplicação. Verifique se o esquema convertido corresponde, da maneira mais próxima possível, ao esquema atual do MySQL. No entanto, devido às diferenças nos recursos, algumas alterações podem ser necessárias.

O uso das práticas recomendadas na criação de esquemas pode ajudar você a aumentar o rendimento e a reduzir os pontos de acesso no banco de dados do Cloud Spanner.

Chaves primárias

Cada tabela que precise armazenar mais de uma linha precisa ter uma chave primária que consista em uma ou mais colunas da tabela. A chave primária da tabela identifica exclusivamente cada linha de uma tabela e, como as linhas da tabela são classificadas por chave primária, a própria tabela atua como um índice primário.

É melhor evitar a designação de colunas que aumentem ou diminuam monotonicamente como a primeira parte da chave primária (exemplos incluem sequências ou carimbos de data/hora), porque isso pode levar a pontos de acesso causados pela ocorrência de inserções no final do seu keyspace. Um ponto de acesso é uma concentração de operações em um único nó, o que reduz a capacidade de gravação para a capacidade do nó, em vez de se beneficiar do balanceamento de carga de todas as gravações entre os nós da chave.

Use as técnicas a seguir para gerar valores de chave primária exclusivos e reduzir o risco da ocorrência de pontos de acesso:

Depois de ter designado sua chave primária para a tabela, não será possível alterá-la sem excluir e recriar a tabela. Para mais informações sobre como designar sua chave primária, consulte Esquema e modelo de dados – chaves primárias.

Aqui está um exemplo de instrução DDL, em que é criada uma tabela para um banco de dados de faixas de música:

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
  BirthDate  DATE,
) PRIMARY KEY(SingerId);

Como intercalar suas tabelas

O Cloud Spanner tem um recurso com que é possível definir duas tabelas como tendo um relacionamento pai e filho de um para muitos. Esse recurso intercala as linhas de dados filhas com as linhas pai no armazenamento, fazendo efetivamente a pré-junção da tabela e melhorando a eficiência da recuperação de dados quando pai e filhas são consultadas em conjunto.

É preciso que a chave primária da tabela filha comece com a(s) coluna(s) de chave primária da tabela pai. Da perspectiva da linha filha, a chave primária da linha pai é chamada de chave estrangeira. É possível definir até 6 níveis de relacionamentos pai-filho.

Para tabelas filhas, é possível definir ações de exclusão para determinar o que acontece quando a linha pai é excluída: todas as linhas filhas serão excluídas ou a exclusão da linha pai será bloqueada enquanto existirem linhas filhas.

Aqui está um exemplo de criação de uma tabela "Álbuns", intercalada na tabela pai "Cantores", definida anteriormente:

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId)
INTERLEAVE IN PARENT (Singers)
ON DELETE CASCADE;

Como criar índices secundários

Também é possível criar índices secundários para indexar dados dentro da tabela externa da chave primária. O Cloud Spanner implementa índices secundários da mesma forma que as tabelas, de modo que os valores da coluna, a serem usados como chaves de índice, terão as mesmas restrições que as chaves primárias das tabelas. O significado disso é que os índices têm as mesmas garantias de consistência que as tabelas do Cloud Spanner.

Pesquisas de valor usando índices secundários são efetivamente o mesmo que uma consulta com uma junção de tabela. É possível melhorar o desempenho de consultas que usam índices por meio do armazenamento de cópias dos valores da coluna da tabela original no índice secundário, usando a cláusula STORING, tornando-a um índice de cobertura.

O otimizador de consultas do Cloud Spanner usa automaticamente um índice secundário somente quando o próprio índice armazena todas as colunas que estão sendo consultadas (uma consulta coberta). Para forçar o uso de um índice ao consultar colunas na tabela original, você precisa usar uma diretiva FORCE INDEX na instrução SQL, por exemplo:

SELECT *
FROM MyTable@{FORCE_INDEX=MyTableIndex}
WHERE IndexedColumn=@value

Os índices podem ser usados para impor valores exclusivos em uma coluna da tabela, com a definição de um índice UNIQUE nessa coluna. A adição de valores duplicados será impedida pelo índice.

Aqui está um exemplo de instrução DDL em que é criado um índice secundário para a tabela "Álbuns":

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

Se você criar outros índices depois que seus dados forem carregados, o preenchimento do índice poderá levar algum tempo. Recomendamos que você limite a taxa usada para adicionar esses índices a uma média de três por dia. Para mais orientações sobre a criação de índices secundários, consulte Índices secundários. Para mais informações sobre as limitações na criação de índice, consulte Atualizações de esquema.

Traduzir qualquer consulta SQL

O Cloud Spanner usa o dialeto de SQL do ANSI 2011 com extensões e tem muitas funções e operadores para ajudar a traduzir e agregar seus dados. Quaisquer consultas SQL que usem dialeto, funções e tipos específicos do MySQL, precisarão ser convertidas para se tornarem compatíveis com o Cloud Spanner.

O Cloud Spanner não é compatível com dados estruturados como definições de coluna, mas é possível usar dados estruturados em consultas SQL usando os tipos ARRAY<> e STRUCT<>. Por exemplo, escreva uma consulta que retorne todos os álbuns de um artista usando um ARRAY de STRUCTs (aproveitando os dados pré-mesclados). Para mais informações, consulte a seção Observações sobre subconsultas da documentação.

As consultas SQL podem ser analisadas usando a interface de consulta do Cloud Spanner no Console do GCP para executar a consulta. Em geral, as consultas que executam varreduras de tabela completas em tabelas grandes são muito caras e devem ser usadas com moderação. Para mais informações sobre otimização de consultas SQL, consulte a documentação de práticas recomendadas de SQL.

Migrar seu aplicativo para usar o Cloud Spanner

O Cloud Spanner fornece um conjunto de bibliotecas de cliente para várias linguagens e a capacidade de ler e gravar dados usando chamadas de API específicas do Cloud Spanner. Também é possível usar consultas SQL e instruções DML (Data Modification Language). O uso de chamadas de API pode ser mais rápido para algumas consultas, como leituras diretas de linhas por chave, porque a instrução SQL não precisa ser traduzida.

Você tem a opção de usar o driver Java Database Connectivity (JDBC) para se conectar ao Cloud Spanner, aproveitando as ferramentas e a infraestrutura atuais que não têm integração nativa.

Como parte do processo de migração, os recursos não disponíveis no Cloud Spanner, conforme mencionado acima, precisam ser implementados no aplicativo. Por exemplo, um acionador para verificar valores de dados e atualizar uma tabela relacionada precisaria ser implementado no aplicativo usando uma transação de leitura/gravação para ler a linha atual, verificar a restrição e gravar as linhas atualizadas em ambas as tabelas.

O Cloud Spanner oferece transações de leitura/gravação e somente leitura para garantir a consistência externa dos seus dados. Além disso, as transações de leitura podem ter os limites de carimbo de data/hora aplicados quando você está lendo uma versão consistente dos dados:

  • em um momento exato no passado (até 1 hora atrás);
  • no futuro (em que a leitura será bloqueada até que chegue a hora);
  • com uma quantidade aceitável de inatividade definida, que retornará uma visualização consistente com até algum tempo no passado, sem precisar verificar se os dados posteriores estão disponíveis em outra réplica. Talvez isso traga benefícios de desempenho às custas de dados possivelmente obsoletos.

Como transferir seus dados do MySQL para o Cloud Spanner

Para transferir seus dados do MySQL para o Cloud Spanner, você precisa exportar seu banco de dados MySQL para um formato de arquivo portátil, por exemplo, XML e depois importar esses dados para o Cloud Spanner usando o Cloud Dataflow.

como transferir dados do MySQL para o Cloud Spanner

Como fazer exportação em massa do MySQL

A ferramenta mysqldump, incluída no MySQL, é capaz de exportar o banco de dados inteiro para arquivos XML bem formados. Você tem a opção de usar a instrução SQL SELECT ... INTO OUTFILE na criação de arquivos CSV para cada tabela. No entanto, essa abordagem tem a desvantagem de que apenas uma tabela pode ser exportada por vez. O significado disso é que você precisa pausar seu aplicativo ou desativar seu banco de dados para que o banco de dados permaneça em um estado consistente para exportação.

Depois de exportar esses arquivos de dados, recomendamos que você os envie para um intervalo do Cloud Storage para que possam ser importados.

Como fazer a importação em massa para o Cloud Spanner

Como os esquemas de banco de dados provavelmente diferem entre o MySQL e o Cloud Spanner, talvez seja necessário tornar algumas conversões de dados parte do processo de importação. A maneira mais fácil de realizar essas conversões de dados e importar os dados para o Cloud Spanner é usar o Cloud Dataflow. O Cloud Dataflow é o serviço distribuído de extração, transformação e carregamento (ETL na sigla em inglês) do GCP. Ele tem uma plataforma para execução de canais de dados gravados com o SDK do Apache Beam para ler e processar grandes quantidades de dados, em paralelo, em várias máquinas.

No SDK do Apache Beam é necessário que você escreva um programa Java simples para definir a leitura, a transformação e a gravação dos dados. Existem conectores do Beam para Cloud Storage e Cloud Spanner, portanto, o único código que você precisa escrever é o da própria transformação de dados.

Para ver um exemplo de um canal simples, que lê arquivos CSV e grava no Cloud Spanner, consulte o repositório de códigos de amostra.

Se você usar tabelas intercaladas pai-filho no seu esquema do Cloud Spanner, tome cuidado no processo de importação em que a linha pai é criada antes da linha filha. O código de canal de importação do Cloud Spanner gerencia isso importando primeiro todos os dados para as tabelas do nível raiz, depois todas as tabelas filhas do nível 1, depois todas as tabelas filhas do nível 2 e assim por diante.

Use o canal de importação do Cloud Spanner diretamente para importar os dados em massa, mas saiba que essa abordagem exige que seus dados estejam presentes em arquivos Avro usando o esquema correto.

Como preservar a consistência entre os dois bancos de dados

Muitos aplicativos têm requisitos de disponibilidade que impossibilitam a manutenção do aplicativo off-line pelo tempo necessário à exportação e importação dos seus dados. Portanto, enquanto você está transferindo seus dados para o Cloud Spanner, seu aplicativo continua a modificar o banco de dados atual. Por isso, é necessário duplicar as atualizações no banco de dados do Cloud Spanner enquanto o aplicativo estiver em execução.

Existem vários métodos para manter seus dois bancos de dados sincronizados, incluindo a captura de dados de alterações e a implementação de atualizações simultâneas no aplicativo.

Captura de dados de alterações

O MySQL não tem um utilitário nativo de captura de dados de alterações (CDC, na sigla em inglês). No entanto, há vários projetos de código aberto que podem receber binlogs do MySQL e convertê-los em um fluxo de CDC. Por exemplo, é possível conseguir um fluxo de CDC para seu banco de dados usando o daemon Maxwell.

Escreva um aplicativo que assine esse fluxo e aplique as mesmas modificações (após a conversão de dados, é claro) ao banco de dados do Cloud Spanner.

Atualizações simultâneas para os dois bancos de dados do aplicativo

Um método alternativo é a modificação do seu aplicativo para executar gravações em ambos os bancos de dados. Um banco de dados (inicialmente o MySQL) é considerado a fonte da verdade e, após cada gravação do banco de dados, a linha inteira é lida, convertida e gravada no banco de dados do Cloud Spanner. Dessa forma, o aplicativo substitui constantemente as linhas do Cloud Spanner com os dados mais recentes.

Quando tiver certeza de que todos os seus dados foram transferidos corretamente, será possível mudar a fonte da verdade para o banco de dados do Cloud Spanner. Com esse mecanismo, você tem um caminho de reversão se forem encontrados problemas ao mudar para o Cloud Spanner.

Como verificar a consistência dos dados

À medida que os dados são transferidos para o banco de dados do Cloud Spanner, é possível executar periodicamente uma comparação entre os dados do Cloud Spanner e os dados do MySQL, para garantir que os dados estejam consistentes. Você pode validar a consistência consultando as duas fontes de dados e comparando os resultados.

Use a transformação Join do Cloud Dataflow para realizar uma comparação detalhada em grandes conjuntos de dados. Nessa transformação, são comparados dois conjuntos de dados com chave e feita a correspondência com os valores por chave. Os valores correspondentes podem ser comparados por igualdade. É possível executar essa verificação regularmente, até que o nível de consistência corresponda aos requisitos do seu negócio.

Mudar para o Cloud Spanner como a fonte da verdade do seu aplicativo

Quando você estiver confiante na migração de dados, poderá alternar seu aplicativo para usar o Cloud Spanner como a fonte da verdade. Se você continuar gravando alterações no banco de dados MySQL, isso manterá o banco de dados MySQL atualizado e oferecerá um caminho para reversão, caso surjam problemas.

Finalmente, é possível desativar e remover o código de atualização do banco de dados MySQL e encerrar o banco de dados MySQL, agora obsoleto.

Como exportar e importar bancos de dados do Cloud Spanner

Como opção, é possível exportar suas tabelas do Cloud Spanner para um intervalo do Cloud Storage usando um modelo do Cloud Dataflow para realizar a exportação. A pasta resultante contém um conjunto de arquivos Avro e arquivos de manifesto JSON com suas tabelas exportadas. Esses arquivos podem servir a vários propósitos, incluindo:

  • Fazer o backup do banco de dados para conformidade com a política de retenção de dados ou recuperação de desastres.
  • Importar o arquivo Avro para outras ofertas do GCP, como o BigQuery.

Para mais informações sobre o processo de exportação e importação, consulte Como exportar bancos de dados e Como importar bancos de dados.

A seguir