todos mediante una migración de sqlx-cli y atenderá consultas de creación, lectura, actualización y eliminación desde un pequeño servidor axum. Todas las conexiones utilizan TLS con verificación completa de certificados.
Requisitos previos
- Rust 1.94 o posterior. Esta guía se ha probado con Rust 1.98.1,
sqlx0.9.0,sqlx-cli0.9.0 yaxum0.8.9. - Una cuenta de ClickHouse Cloud
psql, para crear la base de datos. También puede ejecutar la sentenciaCREATE DATABASEen la consola SQL.
Crear un servicio de ClickHouse Managed Postgres
En la consola de ClickHouse Cloud, haga clic en New service y seleccione Postgres. La instancia estará lista en unos minutos. Consulte la guía de inicio rápido para ver las instrucciones paso a paso.Obtén los detalles de conexión
Haz clic en Conectar en la barra lateral izquierda de tu servicio. Deja seleccionada la opción Directly y activa Use SSL. La URL de conexión de la pestaña url termina ahora ensslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem y el puerto es 5432.
Haz clic en Download CA certificate. También puedes descargarlo más adelante desde Settings → CA Certificate. El certificado es exclusivo de tu instancia, por lo que el controlador puede usarlo para verificar que se está comunicando con tu servidor.
Esta guía se conecta directamente a Postgres en el puerto 5432, tanto desde la aplicación como desde sqlx-cli. Un servidor axum es un proceso de larga duración y PgPool mantiene su propio grupo de conexiones, por lo que no hace falta un segundo pooler delante de Postgres. Las migraciones deben usar siempre la conexión directa. Si ejecutas muchas instancias de la aplicación, consulta Usar PgBouncer.
Configurar el proyecto
Cree un proyecto y agreguesqlx con el controlador de Postgres, el tiempo de ejecución de Tokio y el backend TLS rustls, además de axum y algunos crates auxiliares:
sqlx-cli con el mismo backend de TLS:
Configurar la conexión
Mueva el certificado de CA que descargó al directorio del proyecto y cámbiele el nombre aca-certificate.pem.
Cree una base de datos para la aplicación. Sustituya <PASSWORD> y el host por los valores que aparecen en el cuadro modal Conectar:
.env en la raíz del proyecto, o actualice DATABASE_URL en el que ya tenga, para que apunte a la base de datos guide_rust. Tanto la aplicación como sqlx-cli leen DATABASE_URL de este archivo:
.env
sslmode y sslrootcert de la URL. Con verify-full, comprueba que el certificado del servidor esté firmado por la CA de su instancia y que coincida con el nombre del host. La ruta de sslrootcert se resuelve en relación con el directorio desde el que ejecuta los comandos. Mantenga .env fuera del control de versiones y, si su contraseña contiene caracteres como @, / o #, aplíqueles codificación porcentual.
Crear la tabla mediante una migración
Cree un archivo de migración:migrations y añada la definición de la tabla:
migrations/<timestamp>_create_todos.sql
sqlx migrate run registra las migraciones aplicadas en la tabla _sqlx_migrations y, en llamadas posteriores, solo ejecuta las nuevas. Haga commit del directorio migrations junto con su código. Si prefiere aplicar las migraciones al iniciar la aplicación, llame a sqlx::migrate!().run(&pool).await? en main, siempre que el grupo de conexiones utilice la conexión directa.
Crear la API
Sustituyasrc/main.rs por un pequeño servidor axum que ejecute una consulta por ruta. En una aplicación existente, cree el grupo de la misma forma que en main y añada el struct Todo, los handlers y las rutas a su propio enrutador:
src/main.rs
.bind como parámetros ($1) y nunca se formatean dentro de la cadena SQL. Cada cadena SQL distinta se prepara una sola vez por conexión y se guarda en una caché de sentencias con capacidad para 100, que sqlx cierra al desalojarlas.
Ejecutar y verificar
Inicie el servidor:pg_stat_ssl y confirma que la sesión está cifrada. En otra terminal, cree dos tareas, marque la primera como completada y elimine la segunda:
-w '\n' simplemente añade un salto de línea después de cada respuesta:
http://localhost:3117/todos en su navegador para ver la lista de tareas pendientes:
guide_rust y luego public, y haga clic en la tabla todos. La tabla _sqlx_migrations, situada a su lado, almacena el historial de migraciones. La tabla todos contiene la fila restante:
Usar PgBouncer
Para conectar la aplicación a través del PgBouncer incluido, seleccione via PgBouncer en el cuadro de diálogo Conectar y use el puerto6432 en la DATABASE_URL de la aplicación. El mismo certificado de CA sigue siendo válido. Por ejemplo, mantenga .env con la conexión directa para sqlx-cli y defina la variable al iniciar la aplicación:
pg_stat_ssl informa sobre la propia conexión de PgBouncer con Postgres, por lo que la comprobación muestra none. La conexión de su aplicación con PgBouncer se sigue verificando: un certificado de CA incorrecto falla igualmente con UnknownIssuer.
PgBouncer se ejecuta en modo de agrupación por transacción, por lo que cada transacción puede ejecutarse en una conexión de Postgres distinta. Con sqlx:
- Para conectarse se requiere
.extra_float_digits(None), como enmain.rs. De forma predeterminada, sqlx envíaextra_float_digitscomo parámetro de inicio, y PgBouncer rechaza la conexión conunsupported startup parameter: extra_float_digits. Por el mismo motivo,PgConnectOptions::optionsfalla conunsupported startup parameter in options. - Las sentencias preparadas funcionan con la configuración predeterminada. sqlx libera las sentencias que desaloja de su caché mediante un mensaje
Closea nivel de protocolo, que PgBouncer gestiona incluso dentro de transacciones. No establezcastatement_cache_capacity(0): no es necesario y, con la caché desactivada, sqlx sigue preparando sentencias con nombre, pero nunca las cierra. - No utilice
.persistent(false)en consultas que se ejecuten fuera de una transacción. En ese caso, sqlx prepara una sentencia sin nombre y la ejecuta en un segundo viaje de ida y vuelta, que PgBouncer puede enviar a otra conexión de Postgres. La consulta puede fallar conunnamed prepared statement does not exist, o bien ejecutar sin avisar la sentencia de otro cliente y devolver resultados incorrectos. - La configuración de sesión establecida con
SET, incluso en el hookafter_connectde un grupo, no se mantiene en su conexión y puede filtrarse a otros clientes. Utilice en su lugarSET LOCALdentro de una transacción. - Las migraciones deben usar la conexión directa.
sqlx-cliy las macrosquery!no pueden conectarse a través de PgBouncer, porque siempre envíanextra_float_digits.sqlx::migrate!adquiere un bloqueo consultivo a nivel de sesión (pg_advisory_lock) y, a través de PgBouncer, la liberación puede llegar a otra conexión de Postgres. En ese caso, el bloqueo sigue retenido en una conexión del grupo, y las migraciones posteriores, incluso las que usan la conexión directa, se quedan colgadas hasta que PgBouncer cierra esa conexión.
Próximos pasos
- Conexión: cadenas de conexión, PgBouncer y TLS
- Configuración: parámetros de Postgres y PgBouncer, como
max_connections - Réplicas de lectura: envíe consultas de solo lectura a una réplica mediante un segundo
PgPool - Seguridad: listas de acceso por IP y redes privadas