Electric 1.0 BETA:Postgres 同步引擎的稳定化之路——架构、规模验证与渐进式接入实战
【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric
这篇指南以 Electric 官方博客《Electric BETA release》(对应仓库内 website/blog/posts/2024-12-10-electric-beta-release.md)为骨架展开:你将了解 Electric 作为 Postgres 同步引擎(sync engine)的定位、它从 2024 年 6 月重写冲刺到 1.0.0-beta.1 的演进背景、生产环境验证与可扩展性设计,以及如何用useShape把传统的fetch数据获取渐进式替换为实时数据同步。读完后,你可以直接在现有 Postgres 技术栈上评估并落地 Electric,而不必更换数据库或自研同步引擎。
什么是 Electric
Electric 是一个Postgres 同步引擎:它对 Postgres 数据做实时部分复制(partial replication),将数据流式同步到本地应用和服务中。核心抽象是Shape——对数据集中一个子集的持续同步通道。
BETA 发布博客对它的定位可以概括为两点:
- 用数据同步(sync)取代数据获取(fetching),在即时、实时、本地化的数据之上构建应用;
- 无需自研同步引擎,也无需改变现有技术栈。
同时团队还开发了PGlite,一个可以在浏览器中运行的轻量级 WASM Postgres(对应文档入口见 website/docs/sync/pglite.md),常与 Electric 搭配实现 local-first 架构。
从当前仓库的结构看,这一产品形态由若干工作区包支撑:
| 组件 | 路径 | 说明 |
|---|---|---|
| 同步服务(Elixir) | packages/sync-service | 核心服务,运行在 Postgres 前端,管理 Shape 同步 |
| TypeScript 客户端 | packages/typescript-client | 发布为@electric-sql/client,Shape/ShapeStream原语 |
| React Hooks | packages/react-hooks | 发布为@electric-sql/react,提供useShape等 Hook |
| Elixir 客户端 | packages/elixir-client | 服务端 Elixir 集成 |
| 演示应用 | examples/linearlite | 10 万数据级 local-first 参考实现 |
通往 BETA 的路径:一次彻底重写
BETA 博客交代了时间线:
- 六个月前(2024 年 7 月)团队启动了一次干净重写(clean re-write);
- 新代码库的首个提交在 2024 年 6 月 29 日;
- 在约600 个已合并的 pull request之后,版本
1.0.0-beta.1发布,Electric 进入 BETA。
重写后的代码库就是当前仓库的主体。一个可以直接核证的细节是版本管理:packages/sync-service/mix.exs 中version/0函数优先读取ELECTRIC_VERSION环境变量,其次读取同目录package.json的version字段,这保证了 Elixir 服务与 npm 包发布版本号的一致性。而 packages/react-hooks/CHANGELOG.md 清晰记录了从1.0.0-beta.1起步、逐次迭代至今的发布轨迹——BETA 正是这条版本线的起点。
生产就绪:真实使用与规模验证
来自生产环境的反馈
BETA 发布时,Electric 与 PGlite 已被多家公司用于生产,官方博客引用了其中的代表性反馈:
We use ElectricSQL to power Trigger.dev Realtime, a core feature of our product. When we execute our users background tasks they get instant updates in their web apps. It's simple to operate since we already use Postgres, and it scales to millions of updates per day. —— Matt Aitken,Founder & CEO,Trigger.dev
At Otto, we built a spreadsheet product where every cell operates as its own AI agent. ElectricSQL enables us to reliably stream agent updates to our spreadsheet in real-time and efficiently manage large spreadsheets at scale. —— Sully Omar,Co-founder & CEO,Otto
At Doorboost we aggregate millions of rows from a dozen platforms, all of which gets distilled down to a simple dashboard. With Electric we have been able to deliver this dashboard in milliseconds and update live. —— Vache Asatryan,CTO,Doorboost
这些案例的共同点值得注意:它们都已经在使用 Postgres,Electric 作为Postgres 前端的薄同步层加入,不改变既有认证、写入或 API 结构——这直接对应后文“与现有 API 共存”的接入模式。
可扩展性:从底层设计的到基准测试
BETA 博客强调:很多实时同步系统演示效果好,但在真实负载下会崩坏;Electric 是从底层为高吞吐工作负载设计的,可以从单个普通 Postgres 向百万级并发用户流式推送实时数据,且延迟低、资源占用平坦。
博客中引用的云基准(cloud benchmarks)数据是:单个 Electric 服务在960 writes/minute 的持续写入负载下,把实时同步从10 万扩展到 100 万并发客户端,内存与延迟都基本保持平坦(flat)。
这一结论在仓库文档中有完整佐证。website/docs/sync/reference/benchmarks.md 说明了基准的目标与限定条件:
- 目标是支撑百万级并发用户、数十万个 Shape、高读写吞吐,且对源 Postgres 影响最小;
- 云侧扩展依赖 CDN 的**请求合并(request collapsing)**能力,由 CDN 把大量并发客户端的同一请求合并后打到 Electric;
- 文档中明确警告:基准强依赖工作负载、版本与硬件,必须在自己的基础设施上用代表性负载自行测试。
该页面还列出了 8 组核心基准,覆盖三类测量:初始同步时间(大量并发客户端同步小 Shape、单客户端同步大 Shape)、写入后的更新延迟(多种 Shape 拓扑)、写入处理吞吐(优化/未优化的 where 子句)。从源码结构看,同步服务的核心依赖也印证了“为吞吐而设计”的工程取向:packages/sync-service/mix.exs 的依赖中包含stream_split(按 shape 维度拆分数据流的库)、bandit(高性能 HTTP 服务器)、postgrex(Postgres 客户端)、nimble_pool(连接池)与esqlite(SQLite 持久化,用于 shape cache)。
规模化的直观参照:Linearlite 演示
博客用来展示“大规模应用用起来是什么手感”的是Linearlite——一个 Linear 克隆演示,它通过 Electric 把 **10 万个 issue 及其评论(约 150MB 数据)**加载进浏览器内的 PGlite,加载完成后完全可交互且“感觉是即时的”。
仓库中的 examples/linearlite/README.md 给出了该演示的完整架构与数据细节:
- 后端:Postgres 作为唯一事实源;Electric 同步服务在其前端产生 Shape 复制流;一个简单的 HTTP write server 负责把写入应用到 Postgres。
- 前端:PGlite 作为浏览器内数据库存储本地副本,React UI 直接查询本地库,而不是查远端 API。
- 写入路径:采用“write through the database”模式,本地变更先写入本地 PGlite 表,再由 live query 监控未同步行并 POST 到 write server。本地库的每张表带有
deleted、new、modified_columns、sent_to_server、synced、backup等状态列,配合触发器在服务端同步(electric.syncing = true)与本地写入(electric.syncing = false)两种状态下分别维护冲突解决状态。 - 性能技巧:初始同步完成前禁用触发器、延迟创建索引;全文搜索索引延迟到用户首次打开搜索功能时再建,以缩短到“可用”的时间。
这套模式展示了 BETA 版本能力的一个关键应用:同步不只给小仪表盘,也能支撑百万行级数据集的 local-first 应用。
易于采用:API 稳定性承诺与文档体系
BETA 博客明确了对 API 的承诺:团队在 API 上迭代了很多轮,力求简单而强大,并且未来的 minor 与 patch 版本中不再有破坏性变更。这与 packages/react-hooks/CHANGELOG.md 中 beta 之后持续小步迭代的版本记录是吻合的。
配套文档在仓库中完整存在,博客列出的主题一一对应:
- Quickstart:website/docs/sync/quickstart.md,从脚手架到部署的完整流程;
- 认证(auth)、本地写入(writes)、Shapes 部分复制、部署(deployment)、自行编写客户端(client development):位于 website/docs/sync/guides 目录下的各篇指南;
- 客户端库 API与React 集成:website/docs/sync/integrations/react.md;
- 性能基准:website/docs/sync/reference/benchmarks.md。
渐进式采用:把 fetch 换成 useShape
BETA 博客给出的最重要落地路径是逐组件、逐路由地增量替换。凡是现有代码里在做类似这样的数据获取:
import React, { useState, useEffect } from 'react' const MyComponent = () => { const [items, setItems] = useState([]) useEffect(() => { const fetchItems = async () => { const response = await fetch('https://api.example.com/v1/items') const data = await response.json() setItems(data) } fetchItems() }, []) return <List items={items} /> }都可以替换为基于useShape的同步版本(把useEffect里的fetch换掉):
import { useShape } from '@electric-sql/react' const MyComponent = () => { const { data: items } = useShape({ url: 'https://electric.example.com/v1/shapes', params: { table: 'items', }, }) return <List items={items} /> }差异的本质在于:fetch返回一次性的快照,而useShape绑定的是一个持续物化的 Shape——初始加载后,Postgres 端的变更会通过 HTTP 流持续推送到组件的data数组。useShape还接受where、columns等 PostgreSQL 参数用于定义 Shape 子集。
这一点与仓库中的正式集成文档 website/docs/sync/integrations/react.md 一致,且文档给出了生产环境的推荐模式:
// 推荐:通过你的后端 API 代理 Electric 请求,便于安全与授权 import { useShape } from '@electric-sql/react' const MyComponent = () => { const { isLoading, data } = useShape<{ title: string }>({ url: `http://localhost:3001/api/items`, // 你的 API 端点 }) if (isLoading) { return <div>Loading ...</div> } return ( <div> {data.map((item) => ( <div>{item.title}</div> ))} </div> ) }该文档同时说明:直连 Electric 端点(/v1/shape+table参数)仅建议用于开发,因为它会暴露数据库结构。useShape的返回结构(UseShapeResult)包含data(物化的行数组)、shape(Shape实例)、isLoading、lastSyncedAt、isError/error,可用于同步状态指示。
useShape 的源码级实现:全局缓存与外部 Store 订阅
useShape并不是每个组件各自开一条连接。查看 packages/react-hooks/src/react-hooks.tsx 可以看到其内部机制:
- 全局流缓存。模块级维护
streamCache(选项哈希 →ShapeStream)与shapeCache(ShapeStream→Shape)两个 Map。getShapeStream(options)会用sortedOptionsHash(对 options 做键排序后序列化)生成哈希:相同配置的多个组件复用同一条ShapeStream,避免对同一 shape log 消费多条流;getShape(shapeStream)同理复用物化的Shape。若流已被AbortController中止,缓存条目会被清理并重新创建。 - React 集成。
useShape内部用useMemo构造subscribe/getSnapshot,再通过use-sync-external-store的useSyncExternalStoreWithSelector把 Shape 桥接为 React 状态;parseShapeData从 Shape 上读取currentRows、isLoading()、lastSyncedAt()与error,shapeResultChanged则通过比较lastOffset、handle等字段判断是否需要触发重渲染。 - 路由级预加载。
preloadShape(options)会先getShapeStream→getShape,再await shape.rows,适合放在路由 loader 中确保数据先于页面渲染就绪。
这个“哈希 → 单例流 → 订阅”的设计正是“增量采用”能够成立的关键:页面里无论多少组件引用同一张表,网络上也只有一条同步流。
与现有 API 共存:同步只是加一层,不是替换一套
BETA 博客的另一条重要结论:因为 Electric 基于 HTTP 同步,它可以与你的现有 API 一起使用。这意味着:
- 认证(auth)与写入(writes)可以继续由现有代码与 Web 服务集成处理;
- 不需要把授权逻辑固化成数据库规则(如 RLS);
- 不需要替换既有的 API 端点与中间件栈。
仓库中的 examples/proxy-auth 就是这一模式的完整示例:Next.js 应用通过shape-proxy端点代理 Electric 的 shape 请求,认证发生在代理层而非数据库层。配合 website/docs/sync/guides 中的 auth 与 writes 指南,这套“现有 API 管鉴权与写入、Electric 管只读实时同步”的分工可以完整落地。
同时博客强调兼容性边界:这种方式适用于任意Postgres 数据模型与托管环境、任意数据类型与扩展(包括 pgvector、PostGIS、序列 ID、唯一约束等)——使用 Electric不需要修改数据模型或 migrations。
部署与托管:自托管或 Electric Cloud
BETA 时点,使用方式有两条路径:
- 自托管:按照 website/docs/sync/guides 中的部署指南,把同步服务跑在自己基础设施上,Postgres 保持原有部署不变。仓库提供了现成的运行载体,例如 packages/sync-service/Dockerfile 以及各示例自带的 Docker Compose 后端(如 examples/linearlite 的
pnpm backend:up); - Electric Cloud:托管版 Electric(website/cloud/index.md),面向不想自行运维同步服务的用户,发布博客中提供了 early access 注册入口。
自托管侧的实现事实可以从源码核证:同步服务以 Elixir 编写(packages/sync-service/mix.exs 声明elixir: "~> 1.17",应用入口为Electric.Application),基于bandit+plug提供 HTTP 端点(路由见 packages/sync-service/lib/electric/plug/router.ex,shape API 见 packages/sync-service/lib/electric/shapes/api.ex),并内置 OpenTelemetry 遥测(opentelemetry_telemetry、opentelemetry_exporter依赖,可通过MIX_TARGET=application启用 metrics 目标构建)。集成测试套件(integration-tests)则覆盖了复制槽重建、崩溃恢复、滚动部署、安全模式等运维场景。
小结:BETA 意味着什么
回到 BETA 发布的原始信息,可以提炼出对评估者最有用的四条事实:
- 这是一个重写后的 1.0 版本线的起点(
1.0.0-beta.1),版本历史可从 packages/sync-service/CHANGELOG.md 与 packages/typescript-client/CHANGELOG.md 完整追溯; - 生产就绪有具体证据:多家公司生产引用、百万并发客户端下内存/延迟平坦的云基准、以及 10 万 issue 级的 Linearlite 参考实现;
- API 稳定性有了明确承诺:minor/patch 不再破坏,配套 quickstart 与专题指南成体系;
- 接入成本被压到最低:保留 Postgres、保留现有 API 与认证,逐组件把
fetch换成useShape,同步流按配置自动去重复用。
如果你的应用已经基于 Postgres,并存在“手动刷新、轮询、WebSocket 补丁式推送”之类的数据获取代码,BETA 版本的 Electric 提供了一条不动数据模型、不换技术栈就能转向实时本地数据的路径。下一步可以直接从 website/docs/sync/quickstart.md 的 Quickstart 开始,或用 examples/linearlite 作为大规模场景的对照参考。
【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考