Pular para o conteúdo principal

MySQL gerenciado

O MySQL gerenciado é um banco MySQL 8.4 LTS que a plataforma cria, atualiza, monitora e copia para você. Ele é um nó do grafo do ambiente, como uma aplicação ou um volume: você o adiciona no canvas (ou no coda.yaml), liga as aplicações a ele e usa as variáveis que ele publica.

O banco usa replicação síncrona: com 3 nós, toda transação confirmada já está nos três. Isso traz algumas restrições que valem desde o primeiro nó, para que a passagem de 1 para 3 nós nunca quebre sua aplicação. Leia a seção Restrições antes de migrar uma aplicação existente.

Criar o banco​

No canvas do ambiente, adicione um MySQL e escolha:

CampoDescrição
Versão8 (MySQL 8.4 LTS). Não muda depois de aplicada.
TamanhoCPU, memória e disco padrão (db-s1 a db-l1).
Instâncias1 ou 3. Com 3, o banco tem alta disponibilidade e um endereço de leitura. Dois nós não são aceitos. O máximo depende do plano.
Disco (GiB)Só aumenta.
PITRRecuperação a um instante (ligada por padrão).
Janela de manutençãoQuando as atualizações de versão menor podem ser aplicadas.
Agenda e retenção de backupHorário do backup diário e por quantos dias guardá-lo (o teto depende do plano).

O mesmo banco no coda.yaml:

services:
db:
kind: mysql
config:
engineMajor: "8"
size: db-s2
instances: 3
storageGiB: 20
pitr: true
api:
type: web
port: 8080
connects:
- db
variables:
DATABASE_URL: ${{ db.DATABASE_URL }}

O painel do nó mostra a pegada do banco: o tamanho escolhido vezes o número de instâncias e, separados, os componentes da plataforma (proxy, coleta de métricas e de logs binários). A pegada é o que conta nas quotas de serviços de dados do plano; veja Planos, recursos e limites.

Conectar a aplicação​

Ligue a aplicação ao banco com uma aresta de rede (porta 3306) e use as variáveis do nó. O banco só é alcançável pelas aplicações ligadas a ele, dentro do ambiente.

VariávelConteúdo
DATABASE_URL, MYSQL_URLmysql://app:<senha>@<nó>:3306/app?ssl-mode=REQUIRED (segredo)
DATABASE_READONLY_URLMesmo formato, apontando para as réplicas de leitura. Só existe com 3 instâncias. (segredo)
HOST, PORTNome do nó e 3306
DATABASE, USERapp
PASSWORDSenha do usuário app (segredo)
  • TLS é obrigatório. O servidor recusa conexão sem TLS. Use ssl-mode=REQUIRED (ou o equivalente do seu driver: sslmode, ssl: true, MYSQL_ATTR_SSL_CA).
  • A senha é gerada pela plataforma e guardada no cofre da organização. Para trocá-la, use Rotacionar credencial no painel do nó: a rotação entra no rascunho, e as aplicações que usam as variáveis são reiniciadas ao aplicar.
  • O usuário app tem todos os privilégios no banco app, mas nenhum privilégio global. Crie quantas tabelas, views, procedures e triggers quiser dentro de app.

Restrições​

Valem com 1 ou 3 instâncias, porque o servidor roda em modo estrito (pxc_strict_mode=ENFORCING) desde o primeiro nó.

RestriçãoO que aconteceO que fazer
Só InnoDBTabelas MyISAM, MEMORY ou ARCHIVE não são replicadas e a escrita nelas é recusada.Crie tabelas com ENGINE=InnoDB (o padrão) e converta as antigas com ALTER TABLE t ENGINE=InnoDB.
Chave primária obrigatória para escreverINSERT, UPDATE ou DELETE numa tabela sem chave primária falha (erro 3750).Toda tabela precisa de PRIMARY KEY. Numa tabela sem chave natural, acrescente id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY.
Sem LOCK TABLES e GET_LOCK entre nósTravas explícitas valem só no nó em que foram pedidas; com 3 nós, não protegem nada.Use transações com SELECT ... FOR UPDATE ou uma coluna de versão (bloqueio otimista).
Transações grandes limitadasUma transação que altera mais dados que o limite de replicação (wsrep_max_ws_size) é recusada.Divida cargas e DELETE/UPDATE em massa em lotes (por exemplo, 1.000 a 10.000 linhas por transação).
Sem transações XAXA START/XA COMMIT não são suportados.Use transações locais ou um padrão de saga na aplicação.
Sem privilégios globaisFILE, SUPER, LOAD DATA LOCAL INFILE e SELECT ... INTO OUTFILE não estão disponíveis.Importe e exporte pela conexão normal (INSERT em lotes, mysqldump/mysql pela aplicação).

Com 3 instâncias, um conflito de escrita entre nós aparece como deadlock (erro 1213) no COMMIT. Trate-o como qualquer deadlock: repita a transação.

WordPress​

  • O núcleo do WordPress cria as tabelas wp_* em InnoDB e com chave primária; ele funciona como está.

  • Plugins antigos às vezes criam tabelas sem chave primária ou em MyISAM. O sintoma é um erro de escrita só nas telas do plugin. Para achar essas tabelas:

    SELECT t.table_name, t.engine
    FROM information_schema.tables t
    LEFT JOIN information_schema.table_constraints c
    ON c.table_schema = t.table_schema AND c.table_name = t.table_name AND c.constraint_type = 'PRIMARY KEY'
    WHERE t.table_schema = 'app' AND (c.constraint_name IS NULL OR t.engine <> 'InnoDB');

    Corrija com ALTER TABLE wp_plugin_x ENGINE=InnoDB; e ALTER TABLE wp_plugin_x ADD COLUMN id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY FIRST;, ou troque o plugin.

  • Plugins de backup que usam SELECT ... INTO OUTFILE ou LOCK TABLES não funcionam. Use os backups da plataforma.

  • Em wp-config.php, defina DB_NAME, DB_USER, DB_PASSWORD e DB_HOST a partir das variáveis do nó e ligue o TLS com define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);.

Laravel​

  • Use sempre $table->id(); (ou outra chave primária) nas migrations, inclusive nas tabelas pivô e nas tabelas de pacotes que você publica. Uma tabela pivô só com duas chaves estrangeiras precisa de $table->primary(['a_id', 'b_id']);.

  • Não defina $table->engine = 'MyISAM';. Deixe o padrão (InnoDB) ou declare 'engine' => 'InnoDB' em config/database.php.

  • Troque DB::unprepared('LOCK TABLES ...') e DB::select('SELECT GET_LOCK(...)') por transações com lockForUpdate():

    DB::transaction(function () use ($id) {
    $conta = Conta::whereKey($id)->lockForUpdate()->first();
    $conta->saldo -= 100;
    $conta->save();
    }, attempts: 3); // repete em caso de deadlock
  • Use chunkById() em atualizações em massa, para não estourar o limite de tamanho de transação.

  • Em config/database.php, passe o TLS com 'options' => [PDO::MYSQL_ATTR_SSL_CA => ...] ou use DB_URL com ssl-mode=REQUIRED.

Backups, PITR e clone​

  • Backup diário automático na agenda do nó, guardado fora do cluster, no armazenamento da sua organização (nenhuma outra organização o alcança), pelo número de dias do nó. Você também pode pedir um backup sob demanda na aba Backups.
  • PITR: com o campo PITR ligado, os logs binários são enviados a cada minuto. Você pode restaurar o banco a qualquer instante entre o backup mais antigo retido e o último envio.
  • Restaurar (de um backup ou de um instante) e clonar sempre criam um nó novo ao lado do original, pelo rascunho do ambiente; o original nunca é sobrescrito. O nó novo recebe credenciais novas. Depois de conferir os dados, aponte as aplicações para ele e remova o antigo.
  • O clone de MySQL não tem mascaramento de dados nesta versão.
  • Remover o banco exige o papel Admin e confirmação. A plataforma faz um backup final antes de apagar e o guarda pelo prazo do plano.

A plataforma também restaura uma cópia dos backups toda semana, num ambiente isolado, para verificar que eles funcionam.

O que ainda não está disponível​

  • Importar um dump (.sql) pelo portal chega com a fase 65 do roadmap. Até lá, importe pela própria aplicação (um job que roda mysql contra DATABASE_URL), respeitando as restrições.
  • Acesso ao banco de fora do ambiente (o acesso público TCP ainda não cobre o MySQL) e console de dados no portal.
  • Outras versões do MySQL (só 8.4 LTS) e upgrade de versão maior.