todos с помощью миграции sqlx-cli и реализуете обработку запросов на создание, чтение, обновление и удаление в небольшом сервере на axum. Все соединения защищены TLS с полной проверкой сертификата.
Предварительные требования
- Rust версии 1.94 или выше. Это руководство проверено на Rust 1.98.1,
sqlx0.9.0,sqlx-cli0.9.0 иaxum0.8.9. - Аккаунт ClickHouse Cloud
psqlдля создания базы данных. Вместо этого можно выполнить операторCREATE DATABASEв консоли SQL.
Создание сервиса ClickHouse Managed Postgres
В консоли ClickHouse Cloud нажмите New service и выберите Postgres. Через несколько минут инстанс будет готов. Пошаговые инструкции приведены в кратком руководстве.Получение сведений о подключении
Нажмите Подключение на левой боковой панели вашего сервиса. Оставьте выбранным вариант Directly и включите Use SSL. Теперь URL подключения на вкладке url заканчивается наsslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem, а в качестве порта указан 5432.
Нажмите Download CA‑сертификат. Скачать его можно и позже — в разделе Settings → CA‑сертификат. Этот сертификат уникален для вашего инстанса, поэтому драйвер может с его помощью убедиться, что взаимодействует именно с вашим сервером.
В этом руководстве и приложение, и sqlx-cli подключаются к Postgres напрямую через порт 5432. Сервер axum — долгоживущий процесс, а PgPool поддерживает собственный пул соединений, поэтому дополнительный пулер перед Postgres не нужен. Миграции всегда следует выполнять через прямое соединение. Если вы запускаете много инстансов приложения, см. раздел Использование PgBouncer.
Настройка проекта
Создайте проект и добавьтеsqlx с драйвером Postgres, средой выполнения Tokio и TLS-бэкендом rustls, а также axum и несколько вспомогательных крейтов:
sqlx-cli с тем же TLS-бэкендом:
Настройка соединения
Переместите скачанный CA‑сертификат в каталог проекта и переименуйте его вca-certificate.pem.
Создайте базу данных для приложения. Замените <PASSWORD> и хост значениями из модального окна Подключение:
.env в корне проекта или измените DATABASE_URL в уже существующем файле так, чтобы этот параметр указывал на базу данных guide_rust. И приложение, и sqlx-cli считывают DATABASE_URL из этого файла:
.env
sslmode и sslrootcert из URL. В режиме verify-full он проверяет, что сертификат сервера подписан CA вашего инстанса и соответствует имени хоста. Путь sslrootcert разрешается относительно каталога, из которого вы запускаете команды. Не добавляйте .env в систему контроля версий, а если пароль содержит такие символы, как @, / или #, закодируйте их в percent-encoding.
Создание таблицы с помощью миграции
Создайте файл миграции:migrations и добавьте определение таблицы:
migrations/<timestamp>_create_todos.sql
sqlx migrate run записывает применённые миграции в таблицу _sqlx_migrations и при последующих вызовах выполняет только новые. Добавьте каталог migrations в репозиторий вместе с кодом. Если же нужно применять миграции при запуске приложения, вызовите sqlx::migrate!().run(&pool).await? в main — при условии, что пул использует прямое соединение.
Создание API
Замените содержимоеsrc/main.rs небольшим сервером на axum, который выполняет по одному запросу на каждый маршрут. В существующем приложении создайте пул так же, как в main, и добавьте структуру Todo, обработчики и маршруты в свой маршрутизатор:
src/main.rs
.bind как параметры ($1) и никогда не подставляются в строку SQL напрямую. Каждая уникальная строка SQL подготавливается один раз на соединение и хранится в кэше операторов ёмкостью 100 операторов; вытесняемые из кэша операторы sqlx закрывает.
Запуск и проверка
Запустите сервер:pg_stat_ssl, подтверждающий, что сеанс зашифрован. Во втором терминале создайте две задачи, отметьте первую как выполненную и удалите вторую:
-w '\n' лишь добавляет перевод строки после каждого ответа:
http://localhost:3117/todos в браузере, чтобы увидеть список оставшихся задач:
guide_rust, затем public и выберите таблицу todos. В соседней таблице _sqlx_migrations хранится история миграций. В таблице todos осталась одна строка:
Использование PgBouncer
Чтобы подключить приложение через встроенный PgBouncer, выберите via PgBouncer в модальном окне Подключение и укажите порт6432 в DATABASE_URL приложения. CA‑сертификат используется тот же. Например, оставьте в .env прямое соединение для sqlx-cli, а переменную задавайте при запуске приложения:
pg_stat_ssl показывает собственное соединение PgBouncer с Postgres, поэтому проверка выводит none. Соединение вашего приложения с PgBouncer при этом всё равно проверяется: с неверным CA‑сертификатом подключение точно так же завершится ошибкой UnknownIssuer.
PgBouncer работает в режиме пула транзакций, поэтому каждая транзакция может выполняться в отдельном соединении с Postgres. При использовании sqlx учитывайте следующее:
- Для подключения требуется
.extra_float_digits(None), как вmain.rs. По умолчанию sqlx передаётextra_float_digitsкак параметр запуска, и PgBouncer отклоняет соединение с ошибкойunsupported startup parameter: extra_float_digits. По той же причинеPgConnectOptions::optionsзавершается ошибкойunsupported startup parameter in options. - Подготовленные операторы работают с настройками по умолчанию. Операторы, вытесняемые из кэша, sqlx освобождает с помощью сообщения
Closeна уровне протокола, и PgBouncer корректно его обрабатывает, в том числе внутри транзакций. Не задавайтеstatement_cache_capacity(0): в этом нет необходимости, а при отключённом кэше sqlx по-прежнему подготавливает именованные операторы, но никогда их не закрывает. - Не используйте
.persistent(false)для запросов, выполняемых вне транзакции. В этом случае sqlx подготавливает безымянный оператор и выполняет его отдельным обращением к серверу, которое PgBouncer может направить в другое соединение с Postgres. В результате запрос может завершиться ошибкойunnamed prepared statement does not existили незаметно выполнить оператор другого клиента и вернуть неверные результаты. - Настройки сеанса, заданные через
SET, в том числе в хукеafter_connectпула, не закрепляются за вашим соединением и могут повлиять на других клиентов. Вместо этого используйтеSET LOCALвнутри транзакции. - Миграции необходимо выполнять через прямое соединение.
sqlx-cliи макросыquery!не могут подключиться через PgBouncer, поскольку всегда передаютextra_float_digits.sqlx::migrate!захватывает рекомендательную блокировку уровня сеанса (pg_advisory_lock), а при работе через PgBouncer команда её снятия может попасть в другое соединение с Postgres. Тогда блокировка так и остаётся на одном из соединений пула, и последующие миграции, в том числе через прямое соединение, зависают, пока PgBouncer не закроет это соединение.
Дальнейшие шаги
- Подключение: строки подключения, PgBouncer и TLS
- Настройки: параметры Postgres и PgBouncer, например
max_connections - Реплики для чтения: направление запросов только для чтения на реплику через второй
PgPool - Безопасность: IP Access List и частное сетевое подключение