pg gem 支持 PostgreSQL。
在本指南中,您将创建一个新的 Rails 应用,通过经证书验证的 TLS 连接将其接入 ClickHouse Managed Postgres,运行一次迁移,并对外提供一个由脚手架生成的 Post 资源。
前置条件
- Ruby 3.2 或更高版本。本指南已在 Ruby 4.0.7、Rails 8.1.4 和
pg1.6.3 环境下测试通过。 - 一个 ClickHouse Cloud 账户。
pg gem 为 Linux、macOS 和 Windows 提供了内置 libpq 的预编译构建,因此无需在本地安装 PostgreSQL。
创建 ClickHouse Managed Postgres 服务
在 ClickHouse Cloud 控制台中,点击 New service,然后选择 Postgres。实例会在几分钟内就绪。详细操作步骤请参阅快速入门。获取连接信息
打开您的服务,在左侧边栏中点击 Connect。保持选中 Directly,并开启 Use SSL。 复制密码和服务器主机名,然后点击 Download CA certificate。 每个服务都有其专属的 CA 证书。您也可以稍后在 Settings → CA Certificate 中下载。 直连还是 PgBouncer? Rails 服务器是长期运行的进程,会自行维护连接池 (即config/database.yml 中的 max_connections,默认每个进程 5 个) ,因此本指南通过 5432 端口直连 Postgres。
如果您运行的进程较多,导致连接数达到上限,请参阅使用 PgBouncer。
创建 Rails 应用
安装 Rails,并创建一个使用 PostgreSQL 的应用:配置数据库连接
将下载的 CA 证书移动到应用的config 目录下,并重命名为 ca-certificate.pem。
下载的文件以您的服务名称命名,例如 your-service-ca-certificate.pem:
config/database.yml 中,将 development 部分替换为:
sslmode: verify-full 会让 libpq 校验服务器证书是否由您服务的 CA 签发,且与主机名匹配。Rails.root.join 返回的是绝对路径,因此无论您从哪个目录启动 Rails,该设置都能正常生效。
将 DATABASE_URL 指向您的服务,并使用一个新的数据库名称。本指南使用 guide_rails:
DATABASE_URL 中不要带查询字符串。URL 中的参数会覆盖 database.yml 中的键,因此一旦复制了 sslrootcert=your-service-ca-certificate.pem,你的设置就会被替换为相对于当前目录的路径。db:create 只会创建 DATABASE_URL 中指定的数据库。它会连接到默认的 postgres 数据库来执行 CREATE DATABASE,但不会对该数据库做任何修改。此外,如果设置了 DATABASE_URL,Rails 也不会创建本地测试数据库。
生成模型并运行迁移
为Post 资源生成脚手架并应用其迁移。对于已有应用,bin/rails db:migrate 还会在新数据库中创建应用中已有的表。这些表最初是空的,因为 SQLite 中的数据不会被复制过来:
查询数据库
创建script/posts_demo.rb,并在其中编写几个 Active Record 调用:
bin/rails runner 运行该脚本:
pg_stat_ssl,以确认该会话已加密。
运行应用
启动开发服务器:guide_rails 数据库,然后选择 posts 表。
Rails 还会创建 schema_migrations 和 ar_internal_metadata 表,用于跟踪迁移。
posts 表中包含 script/posts_demo.rb 写入的两行数据:
使用 PgBouncer
每个 Rails 进程最多会打开max_connections 个直接连接。如果多个进程的连接总数接近 Postgres 的连接上限,请改为通过内置的 PgBouncer 进行连接:在 Connect 对话框中选择 via PgBouncer,并在 DATABASE_URL 中使用端口 6432。
PgBouncer 以事务池模式运行:
-
预处理语句:只要
pggem 版本不低于 1.6,且使用的libpq版本不低于 17,即可在 Rails 默认配置下正常工作。预编译的pg1.6 gem 已内置libpq18。在这些版本中,Rails 将某条语句从缓存中淘汰时,会通过协议层的Close消息释放该语句,而内置的 PgBouncer 能够处理该消息。较旧版本的pg或libpq则会改为发送 SQLDEALLOCATE,经由 PgBouncer 执行时会失败,并报错prepared statement "a1" does not exist。如果该错误发生在事务中,事务将被中止 (PG::InFailedSqlTransaction) 。要检查当前版本,请运行:两者分别需要不低于1.6.0和170000。如果无法升级,请在development部分添加prepared_statements: false。Rails 在production中会启用预处理语句,而在development中则默认关闭,因为此时query_log_tags_enabled已开启。 -
迁移会获取会话级咨询锁 (
pg_try_advisory_lock) ,以防止并发执行。在事务池模式下,解锁请求可能会被发送到另一个 Postgres 连接,从而失败并报错Failed to release advisory lock,锁也会一直处于持有状态,导致后续运行失败并报错Cannot run migrations because another migration process is currently running。您可以使用端口为5432的直接DATABASE_URL运行bin/rails db:migrate,也可以关闭该锁:
advisory_locks: false 时,请确保同一时间只有一个部署任务在执行迁移。
故障排查
SSL error: certificate verify failed:sslrootcert未指向您服务的 CA 证书。请前往 Settings → CA Certificate 重新下载。每个服务都有各自独立的 CA,公共 CA 证书包无法使用。root certificate file "..." does not exist:sslrootcert中的路径有误。请检查config/ca-certificate.pem是否存在。
后续步骤
- 在
production配置中使用相同的sslmode和sslrootcert设置。 - 连接:连接字符串、PgBouncer 和 TLS。
- 设置:修改 Postgres 和 PgBouncer 参数,例如
max_connections。 - 只读副本:扩展读取能力,例如结合 Rails 的多数据库功能。
- Sync to ClickHouse:将 Rails 表复制到 ClickHouse,用于分析。