todos.
Requisitos previos
- Elixir 1.15 o posterior y Erlang/OTP. Esta guía se ha probado con Elixir 1.20.4, Erlang/OTP 29, Phoenix 1.8.15,
ecto_sql3.14.0 y Postgrex 0.22.4. - Una cuenta de ClickHouse Cloud
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 seguir el proceso paso a paso.Obtén los detalles de conexión
Abre tu servicio y haz clic en Conectar en la barra lateral izquierda. El cuadro modal muestra tu nombre de usuario, contraseña, servidor y puerto, e incluye un toggle Directly / via PgBouncer. Deja seleccionada la opción Directly y activa Use SSL. Copia la contraseña y el nombre del host del servidor y, a continuación, haz clic en Download CA certificate. El certificado de CA es exclusivo de tu servicio. También puedes descargarlo más adelante desde Settings → CA Certificate. ¿Conexión directa o PgBouncer? Una aplicación Phoenix es un proceso de larga duración, y Ecto mantiene su propio grupo de conexiones (pool_size, diez de forma predeterminada). En esta guía, la conexión a Postgres se realiza directamente en el puerto 5432. Si entre todas las instancias de la aplicación os acercáis al límite de conexiones de Postgres, consulta Uso de PgBouncer.
Crear una aplicación Phoenix
Instale el generador de proyectos de Phoenix y cree una aplicación. Postgres es la base de datos predeterminada:Configurar la conexión a la base de datos
Mueva el certificado de CA que descargó al directoriopriv de la aplicación y cámbiele el nombre a ca-certificate.pem. El archivo descargado lleva el nombre de su servicio; por ejemplo, your-service-ca-certificate.pem:
priv también se incluyen en las releases.
En config/dev.exs, sustituya las líneas username, password, hostname y database de la configuración de Hello.Repo por url y ssl:
config/dev.exs
ssl es una lista de palabras clave, Postgrex activa la verificación de certificados (verify: :verify_peer) y la comprobación del nombre del host, y envía el nombre del host de la URL como nombre de servidor TLS. Solo necesita proporcionar el certificado de la CA. ssl: true no funciona, ya que valida el certificado del servidor con el almacén de CA de su sistema operativo, que no contiene la CA de su servicio.
Configure DATABASE_URL para que apunte a su servicio, con un nombre de base de datos nuevo. En esta guía se usa guide_phoenix:
mix ecto.create se conecta a la base de datos predeterminada postgres con la misma configuración de TLS para ejecutar CREATE DATABASE.
Genera un recurso JSON y ejecuta la migración
Genera un contexto, un esquema, una migración y un controlador JSON para las tareas (todos):lib/hello_web/router.ex, descomenta el scope /api y añade el recurso:
lib/hello_web/router.ex
schema_migrations y, en ejecuciones posteriores, solo aplica las nuevas.
Ejecutar y verificar
Compruebe que la conexión está cifrada. La consulta leepg_stat_ssl de la conexión actual:
3116:
PATCH devuelve la tarea actualizada:
http://localhost:3116/api/todos en su navegador para ver la lista de tareas pendientes:
guide_phoenix y, a continuación, public, y haga clic en la tabla todos. El esquema public también contiene schema_migrations:
Configurar el entorno de producción
En producción, Phoenix lee la configuración de la base de datos desdeconfig/runtime.exs. En la configuración de Hello.Repo, dentro de if config_env() == :prod do, sustituya la línea # ssl: true, por la ruta del certificado de la CA:
config/runtime.exs
Application.app_dir resuelve la ruta dentro de su build o release, de modo que la configuración funciona sin importar el directorio desde el que se inicie la aplicación. Defina DATABASE_URL en su entorno de despliegue, de nuevo sin cadena de consulta.
Si su aplicación empezó con SQLite, config/runtime.exs lee DATABASE_PATH en su lugar. Sustituya la variable database_path y su llamada config :hello, Hello.Repo por:
config/runtime.exs
--database sqlite3 también ejecutan las migraciones pendientes al iniciarse una release, mediante el proceso hijo Ecto.Migrator definido en lib/<your_app>/application.ex. Este mecanismo sigue funcionando con Postgres.
Uso de PgBouncer
Si entre todas las instancias de tu aplicación se abren demasiadas conexiones directas, conéctate a través del PgBouncer incluido. Selecciona via PgBouncer en el cuadro de diálogo Conectar, usa el puerto6432 en DATABASE_URL y añade prepare: :unnamed a la configuración del repo, tanto en config/dev.exs como en config/runtime.exs:
config/dev.exs
-
Sentencias preparadas: de forma predeterminada, Ecto ejecuta cada consulta como una sentencia preparada con nombre, y el PgBouncer incluido admite sentencias con nombre. Postgrex libera las sentencias con un mensaje
Closea nivel de protocolo, nunca conDEALLOCATEde SQL. Aun así, con el valor predeterminadoprepare: :named, surgen dos problemas al pasar por PgBouncer:- Una consulta cuyo texto SQL ocupa unos 4 KB puede quedarse bloqueada hasta agotar el tiempo de espera. El llamador recibe
DBConnection.ConnectionErroral cabo de aproximadamente un minuto. - Después de que una migración cambie el tipo de una columna, las consultas que leen esa columna siguen fallando con
cached plan must not change result type, incluso después de reiniciar la aplicación, porque PgBouncer reutiliza su sentencia preparada en el servidor.
prepare: :unnamed, Postgrex vuelve a preparar cada consulta en cada ejecución y ambos problemas desaparecen, a cambio de un viaje de ida y vuelta adicional por la red en cada consulta. - Una consulta cuyo texto SQL ocupa unos 4 KB puede quedarse bloqueada hasta agotar el tiempo de espera. El llamador recibe
-
Migraciones:
mix ecto.migratefunciona a través de PgBouncer con el bloqueo de migración predeterminado de Ecto, que bloquea la tablaschema_migrationsdentro de una transacción. No configuremigration_lock: :pg_advisory_lockpara una conexión de PgBouncer. El bloqueo consultivo a nivel de sesión puede liberarse en una conexión de Postgres distinta, lo que falla confailed to release advisory locky deja el bloqueo retenido, de modo que las ejecuciones posteriores, incluidas las del puerto5432, se quedan esperando a que se libere. Para ejecutar las migraciones a través de la conexión directa, establezca unDATABASE_URLcon el puerto5432para el comandomix ecto.migrate. -
Estado de sesión: las sentencias
SET, como unSET search_pathen un callbackafter_connect, solo se aplican a la conexión de Postgres de la transacción actual. Unsearch_pathen la opciónparametersde Postgrex falla conunsupported startup parameter: search_path.LISTENyNOTIFY, que utilizaPostgrex.Notifications, requieren una conexión directa.
Solución de problemas
CLIENT ALERT: Fatal - Unknown CA:cacertfileno apunta al certificado de CA de su servicio, o bien establecióssl: true. Vuelva a descargar el certificado desde Settings → CA Certificate. Cada servicio tiene su propia CA.CLIENT ALERT: Fatal - Bad Certificateconhostname_check_failed: el host deDATABASE_URLno coincide con el certificado del servidor; por ejemplo, porque utilizó una dirección IP. Utilice el nombre del host que aparece en el modal Conectar.Invalid CA certificate file ... no such file or directory: la ruta decacertfilees incorrecta. Compruebe que existapriv/ca-certificate.pem.
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: dirija las lecturas a una réplica mediante los repositorios de réplicas de Ecto
- Sincronizar con ClickHouse: replique sus tablas de Phoenix en ClickHouse para tareas de analítica