pgxpool — его пул соединений. В этом руководстве вы подключите сервис на Go к ClickHouse Managed Postgres по TLS с проверкой сертификата, создадите таблицу todos с помощью миграции golang-migrate и научите сервер на базе net/http обрабатывать запросы на создание, чтение, обновление и удаление.
Предварительные требования
- Go версии 1.25 или новее. Это руководство протестировано с Go 1.27.1, pgx 5.11.0 и golang-migrate 4.20.1.
- Аккаунт ClickHouse Cloud
psqlдля создания базы данных. Вместо этого можно выполнить операторCREATE DATABASEв консоли SQL.
Создание сервиса ClickHouse Managed Postgres
В консоли ClickHouse Cloud нажмите New service и выберите Postgres. Инстанс будет готов через несколько минут. Пошаговая инструкция приведена в кратком руководстве по началу работы.Получение сведений о подключении
Нажмите Подключение на левой боковой панели вашего сервиса. Оставьте выбранным вариант Directly и включите Use SSL. Теперь URL подключения на вкладке url использует порт5432 и заканчивается на sslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem. Нажмите Download CA certificate. Скачать его можно и позже в разделе Settings → CA Certificate. Сертификат уникален для вашего инстанса, поэтому pgx может с его помощью убедиться, что подключается именно к вашему серверу.
В этом руководстве и миграции, и приложение подключаются к Postgres напрямую через порт 5432. Сервис на Go — это долгоживущий процесс, а pgxpool уже поддерживает в нём пул соединений, поэтому второй пулер не нужен. Если вы запускаете много инстансов сервиса и вам требуется больше клиентских соединений, чем допускает Postgres, используйте для приложения встроенный PgBouncer (via PgBouncer, порт 6432). Подробнее см. в разделе Использование PgBouncer: в этом случае потребуется одна дополнительная настройка соединения.
Настройка проекта
Создайте модуль Go, добавьте pgx и установите CLI-утилитуmigrate с драйвером pgx:
-tags 'pgx5' собирает CLI migrate с драйвером pgx v5, который использует схему URL pgx5://. go install помещает бинарный файл в $GOBIN, а если GOBIN не задан — в $(go env GOPATH)/bin, поэтому убедитесь, что этот каталог указан в вашем PATH.
Настройка соединения
Переместите загруженный CA‑сертификат в каталог проекта и переименуйте его вca-certificate.pem.
Создайте базу данных для приложения. Замените <PASSWORD> и хост на значения из модального окна Подключение:
guide_go и различаются только схемой URL: приложение считывает DATABASE_URL, а CLI-утилита migrate — MIGRATE_URL:
libpq. При sslmode=verify-full он загружает файл CA из sslrootcert и проверяет как цепочку сертификатов, так и имя хоста, поэтому писать собственный код для TLS не нужно. Путь sslrootcert вычисляется относительно каталога, из которого вы запускаете команды. Если пароль содержит специальные символы, например @, / или #, закодируйте их с помощью URL-кодирования.
Создание схемы с помощью миграции
Создайте файлы миграции:up:
migrations/000001_create_todos.up.sql
down, которая её откатывает:
migrations/000001_create_todos.down.sql
migrate записывает текущую версию в таблицу schema_migrations и при последующих запусках применяет только более новые миграции. Закоммитьте каталог migrations вместе с кодом.
Всегда запускайте
migrate через прямое соединение (порт 5432). На время работы он захватывает рекомендательную блокировку (advisory lock) уровня сеанса, чтобы два развертывания не могли выполнять миграции одновременно. При работе через PgBouncer захват и освобождение блокировки могут произойти в разных соединениях Postgres. В этом случае блокировка так и остаётся захваченной, а последующие запуски migrate зависают или завершаются ошибкой timeout: can't acquire database lock.Выполнение запросов к базе данных
Создайте файлdb.go. Он создаёт пул из DATABASE_URL и при запуске проверяет соединение, запрашивая у Postgres версию TLS, используемую в текущем сеансе:
db.go
todos.go с HTTP-обработчиками. Каждый обработчик выполняет один параметризованный запрос через пул, а pgx.CollectRows и pgx.CollectExactlyOneRow считывают строки в структуру Todo, сопоставляя поля по именам столбцов:
todos.go
$1) вместо их подстановки в строку SQL защищает от SQL-инъекций: pgx отправляет их отдельно от текста запроса. Отдельно проверять ошибку, возвращаемую pool.Query, не нужно: её вернут pgx.CollectRows и pgx.CollectExactlyOneRow.
Создайте файл main.go. Он создаёт один пул на весь процесс, обслуживает маршруты на порту 3114 и закрывает пул по нажатию Ctrl+C. В существующем приложении вместо этого вызовите newPool один раз при запуске, а registerTodoRoutes — для вашего http.ServeMux:
main.go
Запуск и проверка
Добавьте оставшиеся зависимостиpgxpool в go.mod и go.sum, после чего запустите сервер:
TLSv1.3 берётся из pg_stat_ssl на сервере, а значит, сеанс действительно зашифрован. Если указать в sslrootcert любой другой сертификат, сервер не запустится и запишет в журнал x509: certificate signed by unknown authority — это доказывает, что сертификат действительно проверяется.
Во втором терминале создайте две задачи, отметьте первую как выполненную и удалите вторую:
PATCH возвращает обновлённую строку:
http://localhost:3114/todos в браузере, чтобы просмотреть список оставшихся задач. pgx возвращает значения timestamptz в вашем локальном часовом поясе. Ответ будет выглядеть так:
Shutting down, после чего сервер закроет пул.
Чтобы просмотреть данные в консоли, откройте консоль SQL на левой боковой панели вашего сервиса, разверните guide_go, затем public и выберите таблицу todos. В соседней таблице schema_migrations хранится версия миграции. В таблице todos осталась одна строка:
Использование PgBouncer
Чтобы направлять запросы приложения через встроенный PgBouncer, выберите via PgBouncer в модальном окне Подключение, измените порт вDATABASE_URL на 6432 и добавьте default_query_exec_mode=cache_describe. Для MIGRATE_URL оставьте порт 5432:
default_query_exec_mode из URL и не передаёт его на сервер. Изменять код не требуется, подходит и тот же CA‑сертификат. Теперь в журнале запуска отображается TLS: none, поскольку pg_stat_ssl сообщает о собственном соединении PgBouncer с Postgres. Соединение вашего приложения с PgBouncer по-прежнему проверяется: с неверным CA‑сертификатом подключение точно так же завершится ошибкой.
PgBouncer работает в режиме пулинга транзакций, поэтому каждая транзакция может выполняться в отдельном соединении с Postgres:
- Транзакции через
pool.Beginилиpgx.BeginFuncработают как обычно. - Настройки сеанса, заданные с помощью
SET, не сохраняются за вашим соединением и могут повлиять на других клиентов. Вместо этого используйтеSET LOCALвнутри транзакции. Кроме того, PgBouncer отклоняетsearch_pathв URL подключения с ошибкойunsupported startup parameter: search_path, поэтому указывайте имена таблиц вместе со схемой. PREPAREиEXECUTEна уровне SQL,LISTENи сеансовые рекомендательные блокировки не работают.
Дальнейшие шаги
- Подключение: строки подключения, PgBouncer и TLS
- Настройки: параметры Postgres и PgBouncer, например
max_connections - Реплики для чтения: направление запросов только на чтение в реплику с помощью второго
pgxpool.Pool - Безопасность: IP Access List и частное сетевое подключение