使用 Fly.io 部署 Electric 同步服务:Postgres、同步引擎与客户端应用的全栈实战
2026/9/16 18:20:41 网站建设 项目流程

使用 Fly.io 部署 Electric 同步服务:Postgres、同步引擎与客户端应用的全栈实战

【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric

Electric 是一个构建在 Postgres 逻辑复制之上的实时同步平台,其核心是发布为 Docker 镜像electricsql/electric的 Elixir 同步引擎(sync service)。本文基于仓库中 Fly.io 集成文档 展开,完整讲解如何在 Fly.io 上分别部署 Postgres 数据库、Electric 同步服务与客户端应用:从fly.toml配置、flyctl启动命令,到健康检查验证与 IPv6 连接踩坑,并辅以 同步服务配置参考、部署指南 和同步服务源码中的实现细节,让你读完即可在 Fly.io 上跑通一整套可用的实时同步栈。

Fly.io 与 Electric:为什么是天然组合

Fly.io 是一个面向"需要快速交付的开发者"构建的公共云平台。它的一个突出强项是部署 Elixir 应用,而 Electric 的同步引擎正是一个 Elixir 应用(源码位于 packages/sync-service),因此 Fly.io 尤其适合用于:

  • 部署Electric 同步服务(见下文"部署 Electric");
  • 部署基于 Electric 的Phoenix 应用(参见 Phoenix 集成文档)。

按照 Fly.io 集成文档 的划分,你可以使用 Fly.io 部署 Electric 技术栈中的任意或全部组件

组件说明部署章节
Postgres 数据库存放业务数据,是同步的变更来源部署 Postgres
Electric 同步服务连接 Postgres,通过 HTTP 对外提供 shape 同步部署 Electric
客户端应用通过 HTTP 订阅 shape,接收实时变更部署你的应用

[!TIP] 需要更多背景? 完整的部署架构与原则请参阅 部署指南。下文每个步骤都会给出与该指南、配置参考 和 故障排查指南 对应的交叉引用。

部署前准备:理解一次成功部署的三个要素

在开始 Fly.io 配置之前,先明确 部署指南 定义的三个要素:

  1. 运行一个 Postgres 数据库:Electric 通过DATABASE_URL连接 Postgres;你的应用则通过 HTTP 连接 Electric,通常借助官方 TypeScript 客户端库。
  2. 运行并连接 Electric 同步服务:它负责从 Postgres 捕获变更并组织成 shape 同步流。
  3. 让应用/客户端通过 HTTP 连接 Electric:客户端从/v1/shape等 HTTP 端点拉取数据。

关于 Postgres 侧,需要注意两个硬性前提(详见部署指南):

  • 必须启用逻辑复制(logical replication);
  • 连接使用的数据库角色必须具备REPLICATION属性

此外,配置参考 明确说明DATABASE_URL是 Electric 的两个必需配置项之一(另一个是ELECTRIC_SECRET)。连接字符串需符合 libpg Connection URI 格式:postgresql://[userspec@][hostspec][/dbname][?sslmode=<sslmode>],生产环境建议将sslmode设为require

第一步:在 Fly 上部署 Postgres

在 Fly 上部署 Postgres 有两种途径,Fly.io 集成文档 给出了清晰的取舍:

  • Fly Postgres:它不是托管 Postgres 服务。需要参照部署指南中 Running Postgres 一节的通用建议,自行完成逻辑复制启用、REPLICATION角色配置等步骤。
  • Fly 的 Supabase Postgres:这是由 Supabase 提供底层能力的托管 Postgres 服务。Supabase Postgres 默认已启用逻辑复制且具备 Electric 所需的权限,是开箱即用的选择。

如果选择 Supabase Postgres,集成文档 有一条关键提醒

连接时必须使用 IPv6 的DATABASE_URL,而不是DATABASE_POOLER_URL

原因在 Supabase 集成文档 中有详细解释:连接池(pooler)URL 不支持逻辑复制,必须使用直连 URL;而该直连 URL 目前只支持 IPv6。因此,需要在 Electric 侧开启 IPv6 连接:

ELECTRIC_DATABASE_USE_IPV6=true

该变量的行为在 配置参考 中有明确说明:默认值为false;设为true后,Electric 会优先通过 IPv6 连接数据库,若 IPv6 解析失败则回退到 IPv4 DNS 查找。从 runtime.exs 源码可以看到,该开关最终被并入复制连接与查询连接的连接选项中:

extra_conn_opts = Enum.reject( [ipv6: database_ipv6_config, cacertfile: database_cacertfile], fn {_, val} -> is_nil(val) end )

关于 IPv6 的更多排障细节(例如 Docker 守护进程的 IPv6 网络配置),见 故障排查指南的 IPv6 支持一节。

第二步:部署 Electric 同步服务

这是本文的核心操作。整个流程只有三个动作:写fly.toml、运行flyctl launch、curl 健康检查。

编写 fly.toml 配置

将以下配置复制到名为fly.toml的文件中,替换应用名称和DATABASE_URL

app = "YOUR_UNIQUE_APP_NAME" [build] image = "electricsql/electric:latest" [env] DATABASE_URL = "postgresql://..." ELECTRIC_DATABASE_USE_IPV6 = true [http_service] internal_port = 3000 force_https = true [[http_service.checks]] interval = "10s" timeout = "2s" grace_period = "20s" method = "GET" path = "/v1/health"

逐项解读这份配置背后的设计依据:

  • [build] image = "electricsql/electric:latest":直接使用官方 Docker 镜像。同步引擎是一个用 Docker 打包的 Elixir Web 服务(见 部署指南),镜像发布在 Docker Hub 的electricsql/electric仓库。
  • DATABASE_URL:Postgres 连接字符串,是必需配置项(配置参考)。注意要填直连地址而不是连接池地址——Electric 依赖逻辑复制,而大多数连接池不支持它(pgBouncer 自 1.23 起才支持)。如果还想为复制之外的其他查询单独走一个连接池,可以额外设置ELECTRIC_POOLED_DATABASE_URL
  • ELECTRIC_DATABASE_USE_IPV6 = true:对应上文 Fly 上 Supabase Postgres 的 IPv6 直连要求。若你的数据库同时支持 IPv6/IPv4,也可以省略此变量,让 Electric 走默认的 IPv4 解析。
  • internal_port = 3000:Fly 平台把公网流量转发到容器的 3000 端口,这正是 Electric HTTP API 的默认端口ELECTRIC_PORT(默认值3000,见 配置参考)。
  • force_https = true:强制 HTTPS 访问,符合生产环境对传输安全的要求。
  • [[http_service.checks]]:Fly 平台健康检查,指向/v1/health端点。该端点不需要认证,即使设置了ELECTRIC_SECRET也能正常响应(部署指南)。检查参数含义:interval(检查间隔 10 秒)、timeout(单次超时 2 秒)、grace_period(启动宽限期 20 秒,避免服务冷启动时被误判为不健康)。

使用 flyctl 启动

在包含fly.toml的同一目录下,使用flyctl客户端 执行:

flyctl launch --copy-config --ha=false

参数说明:

  • --copy-config:沿用当前目录下已编写好的fly.toml,而不是让 flyctl 重新生成;
  • --ha=false:关闭高可用冗余,只启动单实例。这一点对 Electric 尤其重要——在 状态监控源码 中可以看到,实例启动需要先获取 Postgres 侧的 advisory lock(pg_lock_acquired条件),同一数据库上同时存在多个写实例会互相等待锁,这也是滚动升级时需要特殊处理的原因。单实例部署是 Fly.io 上最简单可靠的形态。

验证健康检查

启动后,请求健康检查端点确认一切正常:

$ curl https://YOUR_UNIQUE_APP_NAME.fly.dev/v1/health {"status":"active"}

返回{"status":"active"}表示服务已完全就绪。这个端点的行为可以在源码中找到完整实现:health_check_plug.ex 将 status_monitor.ex 的内部状态映射为 HTTP 状态码与状态文本:

HTTP 状态响应含义
200{"status": "active"}完全可用,可以处理 shape 请求
202{"status": "waiting"}正在等待获取复制锁(advisory lock),已可只读服务已有 shape
202{"status": "starting"}正在启动、建立数据库连接
200{"status": "active"}连接已缩放至零(scale-to-zero)的休眠态,收到请求会透明恢复(源码中:sleeping映射为200 active

实际状态由StatusMonitor综合 8 个就绪条件(pg_lock_acquiredreplication_client_readyadmin_connection_pool_readysnapshot_connection_pool_readyshape_log_collector_readysupervisor_processes_readyintegrety_checks_passedshape_metadata_ready)推导而来。若长期停留在starting,可参考 故障排查指南 检查是否存在未提交的挂起事务、数据库连接池误用或权限问题。

此外,健康检查响应带有Cache-Control: no-cache, no-store, must-revalidate头(见 health_check_plug.ex),避免被 CDN 或浏览器缓存导致探活结果失真。

第三步:部署你的客户端应用

Fly.io 可以运行大多数类型的应用,包括静态站点。客户端应用与 Electric 的对接方式非常简单:通过 HTTP 请求/v1/shape端点订阅 shape。部署指南给出了典型写法:

const stream = new ShapeStream({ url: `https://your-electric-service.example.com/v1/shape`, params: { table: `foo`, }, }) const shape = new Shape(stream)

在 Fly 场景下,把url换成你上一步部署的 Electric 服务地址即可,例如https://YOUR_UNIQUE_APP_NAME.fly.dev/v1/shape。任何能发起 HTTP 请求的语言/环境都可以接入,完整的协议细节见 HTTP API 文档 与 TypeScript 客户端文档。

生产环境强化建议

部署指南与配置参考还给出了几个在 Fly.io 上跑生产环境必须关注的点,建议按需补充到fly.toml[env]中:

1. 持久化存储:ELECTRIC_STORAGE_DIR

Electric 会把 Shape 日志(shape logs)与元数据缓存在文件系统上(部署指南 的"Optimizing for disk"一节)。存储路径通过ELECTRIC_STORAGE_DIR配置,默认值为./persistent(见 配置参考)。部署指南强调:该目录中的数据必须能在服务重启后存活

从这一点可以推断:在 Fly 上生产部署时,应当为应用挂载 Fly Volume 等持久化磁盘,并把ELECTRIC_STORAGE_DIR指向挂载路径(例如/var/electric)。若使用 Fly 默认的临时文件系统,每次机器重建都会丢失已缓存的 shape 数据,触发全量重同步。磁盘性能的优先级从高到低依次是:磁盘速度 > 内存 > CPU。

2. 安全:ELECTRIC_SECRET与访问控制

配置参考明确指出,默认情况下 Electric API 是公开的,会以ELECTRIC_SECRET校验所有 shape 请求,因此生产环境必须设置ELECTRIC_SECRET(除非设置ELECTRIC_INSECURE=true的显式不安全模式)。同时建议参照 部署指南的 Securing data access 一节 对 Electric 的 HTTP API 做网络级访问控制,或在其前面加一层带认证/授权的代理。

3. 代理与缓存

Electric 被设计为运行在缓存代理之后(Nginx、Caddy、Varnish 或 Cloudflare 等 CDN)。虽然不强制,但加上缓存代理可以利用 Electric 的缓存头做请求合并(request collapsing),显著降低并发连接数、提升大规模客户端订阅时的性能。注意:代理必须保留响应中的electric-...头,否则客户端会因缺少必要响应头而报错(故障排查指南)。

4. 可观测性

同步服务支持通过ELECTRIC_OTLP_ENDPOINT导出 OpenTelemetry 追踪,也支持ELECTRIC_PROMETHEUS_PORT暴露 Prometheus 指标(配置参考)。部署指南有一条重要警告:如果启用了 Prometheus 端口,就必须定期抓取,否则指标会在内存中无限累积导致服务崩溃;只使用 OpenTelemetry 时应保持ELECTRIC_PROMETHEUS_PORT不设置。

5. 监控 WAL 增长

Electric 会在 Postgres 中创建逻辑复制槽(默认名为electric_slot_default)来跟踪 WAL 位置。若槽位长期不推进,Postgres 会持续保留 WAL 文件导致存储膨胀。建议在数据库侧设置max_slot_wal_keep_size(如10GB)作为上限,并定期用pg_replication_slots查询槽位状态(故障排查指南)。如果决定停止使用某个数据库,记得同时清理复制槽和electric_publication_default发布,保持 Postgres 内持久状态与磁盘上 shape 缓存的一致性。

小结与相关资源

至此,你已经在 Fly.io 上完成了 Electric 技术栈的三层部署:用 Supabase Postgres(IPv6 直连)或自管 Fly Postgres 作为数据源,用fly.toml+flyctl launch --copy-config --ha=false拉起同步服务并以/v1/health验证可用性,最后让任意 HTTP 客户端订阅/v1/shape获得实时同步。Fly.io 对 Elixir 应用的天然支持,让它成为自托管 Electric 同步服务的理想平台之一。

若想深入了解各环节,建议继续阅读仓库中的以下文档:

  • Fly.io 集成文档:本文的原始依据;
  • 部署指南:三层部署架构、Postgres 要求、存储与健康检查细节;
  • 同步服务配置参考:全部环境变量及默认值;
  • Supabase 集成文档:托管 Postgres 的 IPv6 直连细节;
  • 故障排查指南:IPv6 支持、WAL 增长、权限问题等常见坑。

【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询