todos com uma migration do sqlx-cli e atende a consultas de criação, leitura, atualização e exclusão a partir de um pequeno servidor axum. Todas as conexões usam TLS com verificação de certificados completa.
Pré-requisitos
- Rust 1.94 ou superior. Este guia foi testado com Rust 1.98.1,
sqlx0.9.0,sqlx-cli0.9.0 eaxum0.8.9. - Uma conta no ClickHouse Cloud
psql, para criar o banco de dados. Você também pode executar a instruçãoCREATE DATABASEno SQL Console.
Crie um serviço ClickHouse Managed Postgres
No console do ClickHouse Cloud, clique em New service e selecione Postgres. A instância estará pronta em poucos minutos. Para um passo a passo completo, consulte o guia de início rápido.Obtenha os detalhes de conexão
Clique em Connect na barra lateral esquerda do seu serviço. Mantenha Directly selecionado e ative Use SSL. A URL de conexão na aba url passa a terminar comsslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem, e a porta é 5432.
Clique em Download CA certificate. Você também pode baixá-lo depois em Settings → CA Certificate. O certificado é exclusivo da sua instância, o que permite ao driver usá-lo para confirmar que está se comunicando com o seu servidor.
Este guia se conecta diretamente ao Postgres na porta 5432, tanto na aplicação quanto no sqlx-cli. Um servidor axum é um processo de longa duração, e o PgPool mantém seu próprio pool de conexões; portanto, não é necessário um segundo pooler à frente do Postgres. As migrations devem sempre usar a conexão direta. Se você executa muitas instâncias da aplicação, consulte Usar o PgBouncer.
Configure o projeto
Crie um projeto e adicione osqlx com o driver do Postgres, o tempo de execução do Tokio e o backend TLS rustls, além do axum e de alguns crates auxiliares:
sqlx-cli com o mesmo backend TLS:
Configure a conexão
Mova o certificado da CA que você baixou para o diretório do projeto e renomeie-o paraca-certificate.pem.
Crie um banco de dados para a aplicação. Substitua <PASSWORD> e o host pelos valores exibidos no modal Connect:
.env na raiz do projeto, ou atualize a DATABASE_URL no seu arquivo existente, para que ela aponte para o banco de dados guide_rust. Tanto a aplicação quanto o sqlx-cli leem a DATABASE_URL desse arquivo:
.env
sslmode e sslrootcert da URL. Com verify-full, ele verifica se o certificado do servidor foi assinado pela CA da sua instância e se corresponde ao hostname. O caminho de sslrootcert é resolvido em relação ao diretório a partir do qual você executa os comandos. Mantenha o .env fora do controle de versão e, se a sua senha contiver caracteres como @, / ou #, codifique-os com percent-encoding.
Crie a tabela com uma migration
Crie um arquivo de migration:migrations e adicione a definição da tabela:
migrations/<timestamp>_create_todos.sql
sqlx migrate run registra as migrations aplicadas na tabela _sqlx_migrations e, nas chamadas seguintes, executa apenas as novas. Faça commit do diretório migrations junto com o seu código. Se preferir aplicar as migrations na inicialização da aplicação, chame sqlx::migrate!().run(&pool).await? em main, desde que o pool use a conexão direta.
Crie a API
Substitua osrc/main.rs por um pequeno servidor axum que executa uma consulta por rota. Em uma aplicação existente, crie o pool da mesma forma que em main e adicione a struct Todo, os handlers e as rotas ao seu próprio router:
src/main.rs
.bind como parâmetros ($1) e nunca formatados diretamente na string SQL. Cada string SQL distinta é preparada uma única vez por conexão e mantida em um cache de instruções com capacidade para 100 instruções, que o sqlx fecha ao removê-las do cache.
Executar e verificar
Inicie o servidor:pg_stat_ssl e confirma que a sessão está criptografada. Em um segundo terminal, crie dois todos, marque o primeiro como concluído e exclua o segundo:
-w '\n' serve apenas para adicionar uma quebra de linha após cada resposta:
http://localhost:3117/todos no navegador para listar as tarefas restantes:
guide_rust e, em seguida, public, e clique na tabela todos. A tabela _sqlx_migrations, logo ao lado, armazena o histórico de migrations. A tabela todos contém a linha restante:
Usar o PgBouncer
Para conectar a aplicação por meio do PgBouncer incluído, selecione via PgBouncer no modal Connect e use a porta6432 na DATABASE_URL da aplicação. O mesmo certificado de CA continua válido. Por exemplo, mantenha o .env apontando para a conexão direta, usada pelo sqlx-cli, e defina a variável ao iniciar a aplicação:
pg_stat_ssl informa a conexão do próprio PgBouncer com o Postgres, por isso a verificação exibe none. A conexão da sua aplicação com o PgBouncer continua sendo verificada: um certificado de CA incorreto falha com UnknownIssuer da mesma forma.
O PgBouncer é executado no modo de pooling de transações, portanto cada transação pode ser executada em uma conexão diferente com o Postgres. Com o sqlx:
- Conectar exige
.extra_float_digits(None), como emmain.rs. Por padrão, o sqlx enviaextra_float_digitscomo parâmetro de inicialização, e o PgBouncer rejeita a conexão comunsupported startup parameter: extra_float_digits. Pelo mesmo motivo,PgConnectOptions::optionsfalha comunsupported startup parameter in options. - Prepared statements funcionam com as configurações padrão. O sqlx libera as instruções que remove do cache por meio de uma mensagem
Closeno nível do protocolo, que o PgBouncer processa, inclusive dentro de transações. Não definastatement_cache_capacity(0): isso não é necessário e, com o cache desativado, o sqlx continua preparando instruções nomeadas, mas nunca as fecha. - Não use
.persistent(false)em consultas executadas fora de uma transação. Nesse caso, o sqlx prepara uma instrução sem nome e a executa em uma segunda ida e volta (round trip), que o PgBouncer pode encaminhar para uma conexão diferente com o Postgres. A consulta pode falhar comunnamed prepared statement does not existou executar silenciosamente a instrução de outro cliente e retornar resultados incorretos. - Configurações de sessão definidas com
SET, inclusive no hookafter_connectde um pool, não permanecem na sua conexão e podem vazar para outros clientes. Em vez disso, useSET LOCALdentro de uma transação. - Migrations devem usar a conexão direta. O
sqlx-clie as macrosquery!não conseguem se conectar por meio do PgBouncer, pois sempre enviamextra_float_digits. Osqlx::migrate!adquire um advisory lock no nível da sessão (pg_advisory_lock) e, por meio do PgBouncer, a liberação pode chegar a outra conexão com o Postgres. Com isso, o bloqueio continua retido em uma conexão do pool, e as migrations seguintes, inclusive pela conexão direta, ficam travadas até que o PgBouncer feche essa conexão.
Próximos passos
- Conexão: strings de conexão, PgBouncer e TLS
- Configurações: parâmetros do Postgres e do PgBouncer, como
max_connections - Réplicas de leitura: envie consultas read-only para uma réplica usando um segundo
PgPool - Segurança: listas de acesso por IP e rede privada