Migrar do MySQL para o Spanner

Neste artigo, explicamos como migrar seu banco de dados de processamento de transações on-line (OLTP) do MySQL para o Spanner.

Restrições de migração

O Spanner usa determinados conceitos de forma diferente de outras ferramentas corporativas de gerenciamento de banco de dados. Portanto, talvez seja necessário ajustar a arquitetura do aplicativo para aproveitar ao máximo os recursos. Talvez seja necessário complementar o Spanner com outros serviços do Google Cloud para atender às suas necessidades.

Acionadores e procedimentos armazenados

O Spanner não é compatível com a execução de código de usuário no nível do banco de dados. Portanto, como parte da migração, a lógica de negócios implementada por acionadores e procedimentos armazenados no nível do banco de dados precisa ser movida para o aplicativo.

Sequências

O Spanner recomenda usar o UUID versão 4 como método padrão para gerar chaves-valor primárias. A função GENERATE_UUID() (GoogleSQL, PostgreSQL) retorna valores de UUID versão 4 representados como tipo STRING.

Se você precisar gerar valores inteiros, o Spanner oferece suporte a sequências positivas com bits invertidos (GoogleSQL, PostgreSQL), que produzem valores distribuídos uniformemente no espaço de números positivos de 64 bits. Você pode use esses números para evitar problemas de ponto de acesso.

Para mais informações, consulte estratégias de valor padrão da chave primária.

Controles de acesso

O Spanner oferece suporte a um controle de acesso refinado na tabela e na coluna nível Não há suporte para o controle de acesso granular para visualizações. Para mais informações, consulte Sobre o controle de acesso detalhado.

Restrições de validação de dados

O 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.

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

Restrição Implementação com o Spanner
Não nulo Restrição de coluna NOT NULL
Único Índice secundário com restrição UNIQUE.
Foreign key (para tabelas normais) Consulte Criar e gerenciar relacionamentos de chave estrangeira.
Ações ON DELETE/ON UPDATE de chaves estrangeiras Possível somente para tabelas intercaladas. Caso contrário, implementada na camada do aplicativo
Verificações de valor e validação por meio de restrições CHECK Consulte Como criar e gerenciar restrições de verificação.
Verificações de valor e validação por meio de acionadores Implementada na camada do aplicativo

Colunas geradas

O Spanner é compatível com colunas geradas, onde o valor da coluna sempre será gerado por uma função fornecida como parte da definição da tabela. Como no MySQL, as colunas geradas não podem ser expressamente definidas como um valor fornecido em uma instrução DML.

As colunas geradas são definidas como parte da definição da coluna durante uma instrução de linguagem de definição de dados (DDL, na sigla em inglês) CREATE TABLE ou ALTER TABLE. A palavra-chave AS é seguida por uma função SQL válida e pela palavra-chave de sufixo STORED obrigatória. A palavra-chave STORED faz parte da especificação ANSI SQL e indica que os resultados da função serão armazenados junto com outras colunas da tabela.

A função SQL, a expressão de geração, pode incluir qualquer expressão, função e operador determinística. Ela pode ser usada em índices secundários ou como uma chave externa.

Para saber mais sobre como gerenciar esse tipo de coluna, consulte Como criar e gerenciar colunas geradas.

Tipos de dados compatíveis

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

Talvez seja necessário transformar ainda mais os dados conforme descrito na coluna "Observações" para que os dados do MySQL se ajustem ao banco de dados do Spanner. Por exemplo, é possível armazenar um BLOB grande, como um objeto, em um bucket 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 Spanner Notas
INTEGER, INT, BIGINT MEDIUMINT, SMALLINT INT64
TINYINT, BOOL, BOOLEAN BOOL, INT64 Os valores TINYINT(1) são usados para representar valores booleanos de "true" (diferente de zero) ou "false" (0).
FLOAT, DOUBLE FLOAT64
DECIMAL, NUMERIC NUMERIC, STRING No MySQL, os tipos de dados NUMERIC e DECIMAL aceitam até um total de 65 dígitos de precisão e escala, conforme definido na declaração da coluna. O tipo de dados NUMERIC do Spanner aceita até 38 dígitos de precisão e 9 dígitos decimais de escala.
Se você precisar de mais precisão, consulte Como armazenar dados numéricos de precisão arbitrária para mecanismos alternativos.
BIT BYTES
DATE DATE Tanto o 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 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 Spanner usa apenas strings Unicode.
O VARCHAR é compatível com um comprimento máximo de 65.535 bytes, enquanto o 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 Google Cloud, 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 Google Cloud, 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 Google Cloud, como o Cloud Storage, para armazenar objetos maiores.
LONGTEXT, MEDIUMTEXT STRING (contendo dados ou o URI do objeto externo) Objetos pequenos (menos de 2.621.440 caracteres) podem ser armazenados como STRING. Pense em usar ofertas alternativas do Google Cloud, como o Cloud Storage, para armazenar objetos maiores.
JSON JSON Strings JSON pequenas (menos de 2.621.440 caracteres) podem ser armazenadas como JSON. Pense em usar ofertas alternativas do Google Cloud, como o Cloud Storage, para armazenar objetos maiores.
GEOMETRY, POINT, LINESTRING, POLYGON, MULTIPOINT, MULTIPOLYGON, GEOMETRYCOLLECTION O 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

Este é um exemplo do cronograma geral do processo de migração:

  1. Conversão do esquema e do modelo de dados
  2. Conversão de consultas SQL.
  3. Migrar seu aplicativo para usar o Spanner além do MySQL.
  4. Exportar seus dados em massa do MySQL e importe-os para o Spanner usando o Dataflow.
  5. Manter a consistência entre os dois bancos de dados durante a migração.
  6. Migrar seu aplicativo para fora do MySQL.

Etapa 1: converter o banco de dados e o esquema

Converta seu esquema atual em um Spanner esquema 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.

Usar as práticas recomendadas do design de esquemas ajuda a aumentar a capacidade e reduzir os gargalos no banco de dados do Spanner.

Chaves primárias

No Spanner, cada tabela que precisa armazenar mais de uma linha precisa ter uma chave primária que consiste em uma ou mais colunas da tabela. O valor da sua tabela a chave primária identifica exclusivamente cada linha em uma tabela, e o Spanner usa a chave primária para classificar as linhas da tabela. Como o Spanner é é altamente distribuída, é importante escolher uma técnica que escalona bem de acordo com o crescimento dos dados. Para mais informações, consulte as estratégias de migração de chave primária que recomendamos.

Após designar sua chave primária, não será possível adicionar ou remover um coluna de chave primária ou alterar o valor de uma chave primária posteriormente sem excluir e de recriar a tabela. Para mais informações sobre como designar a chave primária, consulte Esquema e modelo de dados – primário chaves.

Intercalar as tabelas

O 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 mãe é chamada de chave estrangeira. Você pode definir até seis níveis de relacionamentos pai-filho.

Você pode definir ações acionadas na exclusão para tabelas filhas, determinando o que acontece quando a linha mãe é excluída: todas as linhas filhas são excluídas ou a exclusão da linha mãe é bloqueada enquanto existem linhas filhas.

Veja um exemplo da criação de uma tabela de álbuns intercalada com a tabela mãe de intérpretes 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;

Criar índices secundários

Também é possível criar índices secundários para indexar dados da tabela fora da chave primária. O 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 das chaves primárias das tabelas. Isso também significa que os índices têm as mesmas garantias de consistência das tabelas do Spanner.

Pesquisas de valor por índices secundários são, na prática, iguais a consultas com uma mesclagem de tabela. Para melhorar o desempenho das consultas que usam índices, armazene cópias dos valores de coluna da tabela original no índice secundário usando a cláusula STORING, o que as transforma em índice abrangente.

O otimizador de consultas do 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 no original use uma string 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, definindo a Índice UNIQUE na coluna. O índice impedirá a inclusão de valores duplicados.

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.

Etapa 2: traduzir consultas SQL

O Spanner usa o dialeto ANSI 2011 do SQL com extensões; e tem muitos Funções e operadores para traduzir e agregar seus dados. Todas as consultas SQL que usam o dialeto, as funções e os tipos específicos do MySQL precisarão ser convertidas para serem compatíveis com o Spanner.

Embora o Spanner não seja compatível com dados estruturados como definições de coluna, é 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 Subconsultas da documentação.

É possível criar perfis de consultas SQL usando a página do Spanner Studio na console do Google Cloud 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 a otimização de consultas SQL, consulte a Práticas recomendadas de SQL na documentação do Google Cloud.

Etapa 3: migrar o aplicativo para usar o Spanner

O Spanner oferece 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 Spanner, além de usar consultas SQL e instruções da linguagem de modificação de dados (DML). 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.

O Spanner fornece um driver JDBC para aplicativos Java.

Como parte do processo de migração, os recursos não disponíveis no Spanner, conforme mencionado acima, precisam ser implementados no aplicativo. Por exemplo, um gatilho 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 Spanner oferece transações de leitura/gravação e somente leitura para garantir a consistência externa dos seus dados. Além disso, leia as transações pode ter Limites de carimbo de data/hora aplicada, 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. Isso pode aumentar o desempenho, mas pode retornar dados obsoletos.

Etapa 4: transferir os dados do MySQL para o Spanner

Para transferir seus dados do MySQL para o 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 Spanner usando o Dataflow.

transferência de dados do MySQL para o Spanner

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. Como alternativa, use o SELECT ... INTO OUTFILE instrução SQL para criar 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 bucket do Cloud Storage para que possam ser importados.

Importação em massa para o Spanner

Como os esquemas de banco de dados provavelmente diferem entre o MySQL e o Spanner, talvez seja necessário tornar algumas conversões de dados parte do processo de importação. A maneira mais fácil de realizá-las e importar os dados para o Spanner é por meio do Dataflow. O Dataflow é o serviço distribuído do Google Cloud para extração, transformação e carregamento (ETL, na sigla em inglês). Ele fornece uma plataforma para executar pipelines de dados escritos usando as SDK do Apache Beam (em inglês) para ler e processar grandes quantidades de dados em paralelo em máquinas.

O SDK do Apache Beam exige a criação de 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 Spanner, o único código que precisa ser escrito é a própria transformação dos dados.

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

Se usar as tabelas mães-filhas intercaladas forem usadas no esquema do Spanner, você deverá tomar cuidado durante o processo de importação para que a linha mãe seja criada antes da linha filha. O código do canal de importação do Spanner lida com isso importando primeiro todos os dados para as tabelas de nível superior, depois todas as tabela filhas de nível 1, depois todas as tabelas filhas de nível 2 e assim por diante.

Você pode usar o canal de importação do Spanner diretamente para importar seus dados em massa, mas essa abordagem exige que seus dados existam em arquivos Avro usando o esquema correto.

Etapa 5: manter a consistência entre os dois bancos de dados

Muitos aplicativos têm requisitos de disponibilidade que impossibilitam que fiquem off-line pelo tempo necessário para exportar e importar os dados. Portanto, enquanto você está transferindo seus dados para o Spanner, seu aplicativo continua a modificar o banco de dados atual. Por isso, é necessário duplicar as atualizações no banco de dados do 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 alterados

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, o daemon Maxwell pode fornecer um fluxo de CDC para seu banco de dados.

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 Spanner.

Atualizações simultâneas no aplicativo em ambos os bancos de dados

Um método alternativo seria o de modificar o 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 Spanner. Dessa forma, o aplicativo substitui constantemente as linhas do Spanner com os dados mais recentes.

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

Verificar a consistência dos dados

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

Use o Dataflow para realizar uma comparação detalhada de grandes conjuntos de dados usando a transformação de mesclagem. Essa transformação usa dois conjuntos de dados com chaves e corresponde os valores pelas chaves. 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.

Etapa 6: mudar para o Spanner como a fonte da verdade do aplicativo

Quando você confiar na migração de dados, poderá mudar seu aplicativo para usar o Spanner como lugar confiável. 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.

Exportar e importar bancos de dados do Spanner

Como opção, é possível exportar as tabelas do Spanner para um bucket do Cloud Storage usando um modelo do 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 Google Cloud, 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