
Electric 同步引擎基准测试详解:从 CDN 扇出到优化 where 子句的写吞吐【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric本文以 Electric 官方文档 benchmarks.md 为主体,系统讲解 Electric 团队如何对同步引擎做性能基准测试:三类基准(Cloud、核心 Electric、PGlite)各自回答什么问题,8 组核心图表分别测量初始同步、实时更新扇出与写吞吐,并结合仓库内的实际基准数据文件与源码,说明优化 where 子句如何把写处理时间压到亚毫秒级、以及 CDN 请求折叠如何让单台同步服务承载百万级并发客户端。基准测试的总体目标与阅读前提Electric 的设计目标是简单、可扩展、低成本运行:单个 Electric 实例应能承受大量并发用户、高读写负载,即把数据从 Postgres 以各种 shape 拓扑高吞吐地推送到海量客户端。文档中给出的量化目标是:支持数百万并发用户、数十万个 shape,以及单实例上的高读/写吞吐;对源 Postgres 的影响降到最低;计算与内存占用低、稳定、可预测。基准测试是团队内部用来度量并指导性能优化的手段,官方页面公开的只是其中一部分,用于让读者了解:Electric 团队都在跑哪些类型的基准;内部基准运行中看到的性能水平。重要警告(原文档强调):基准结果强烈依赖工作负载、版本与硬件。这些数字绝不保证能代表你在自己硬件上运行 Electric 时的表现。必须用有代表性的负载、在自己的基础设施上实测。如何自行运行基准与持续集成文档还交代了两个运行渠道的现状:自行运行:团队正在将electric-sql/benchmarking-fleet仓库开源(文档写作时仍在开放过程中)。公开后即可按其说明在自己的环境中复现这些基准。持续集成:团队正在搭建每次发布(patch / minor / major)都自动跑基准的流程,完成后会在文档中说明如何查看各版本的基准结果、如何跟踪性能改进与回归。Cloud 基准:CDN 请求折叠支撑百万并发Electric 被设计为运行在 CDN 之后,利用 CDN 的 request collapsing(请求折叠) 能力,把数据分发横向扩展到大量并发用户。请求折叠的机制在 HTTP API 文档 中有完整描述:客户端完成 shape 初始数据拉取后进入 live 模式,用长轮询等待新数据;CDN 识别出针对同一资源的并发请求,将其挂入等待队列,只向源站发送一个请求,响应再分发给所有等待者。因此 Electric 不需要为每个客户端保持一条连接,连接扇出在 CDN 层完成,同步服务与源 Postgres 的负载被压到极低——这正是支撑数百万并发客户端的实现路径。Cloud 基准图展示的正是这一技术的效果:在写负载为 960 事务/分钟(即 16 写/秒)的条件下,单台 Electric 服务器通过请求折叠处理10 万到 100 万并发用户时的延迟与计算资源占用。这份图的原始数据就存放在仓库中:website/static/data/benchmarks/cdn_perf_benchmark_2024-12-09.json,由 website/src/components/ScalabilityChart.vue 渲染(页面中该组件默认取16这一系列,即 16 writes/sec / 960 事务每分钟)。从该 JSON 数据文件可以读到几个关键事实:横轴为 100k、200k、…、1M 共 10 档并发客户端数;在 16 写/秒负载档(16系列)下,平均延迟(latencyMean)在 10 万客户端时约 169ms,之后基本平稳在100~110ms区间,直到 100 万客户端仍约 108ms;P99 延迟稳定在 300~420ms 量级;同步服务内存(syncServiceMemory)从 10 万客户端的约 183MB 缓慢上升到 100 万客户端的约 213MB,整体保持在130~220MB的量级,没有随并发数线性膨胀。这些统计由官方的 client load benchmarking 套件生成,该套件可以测量任意并发连接客户端数 × 数据库负载组合下的 (a) 客户端延迟与 (b) 同步服务资源占用。Electric 核心引擎基准:8 组测试的完整清单对核心 Electric 的基准分为三组,共 8 项:组测量目标基准初始同步客户端首次同步耗时1. 大量并发客户端同步一个小 shape;2. 单个客户端同步一个大 shape实时更新写入后客户端收到更新的耗时3. 多个互相独立的 shape;4. 一个 shape 多个客户端;5. 多个重叠 shape 各带一个客户端;6. 多个重叠 shape 共享一个客户端写吞吐Electric 处理一次写入的耗时7. 优化 where 子句下的写吞吐;8. 非优化 where 子句下的写吞吐初始同步基准 1:大量并发客户端同步一个小 shape测量并发客户端数量逐渐增加时,对同一个500 行的单 shape 做初始同步,所有数据同步到所有客户端所需的时间与内存占用。结果显示:内存占用保持稳定,全部数据同步完成的时间随并发客户端数近似线性上升,直到 2,000 个并发客户端为止。基准 2:单个客户端同步一个大 shape单个客户端同步单个 shape,数据量最大到100 万行。结论:同步耗时随行数线性增长,内存占用稳定——说明初始同步是流式的,不会因为 shape 变大而在服务端堆积内存。实时更新(写扇出延迟)基准 3:多个互相独立的 shape测量一次写操作到达订阅了相关 shape 的客户端所需的延迟,横轴是活跃 shape 数;每个 shape 互相独立,一次写只影响其中一个 shape。图中两条曲线对应两种 where 子句类型:上图:field constant,每个 shape 分配唯一常量。这类子句属于 优化 where 子句,无论 shape 数量多少都以高性能方式求值,效果类似字段上有索引。延迟始终平稳在 6ms:其中 3ms 是 PostgreSQL 处理写入本身的时间,3ms 是 Electric 的传播时间。下图:field ILIKE constant,典型的非优化子句。此时 Electric 必须逐个评估每个 shape 是否受该写入影响,延迟随 shape 数线性增长——但即便如此,10,000 个 shape 时的响应时间仍在 0.1 秒量级。基准 4:一个 shape、多个客户端测量写延迟(客户端看到写入的时间):一个事务以逐渐增大的大小写入同一个 shape log,并流转到逐渐增多的客户端。同组还有一张对应的内存占用图(见 write-fanout-memory.png),用于观察扇出规模扩大时内存的行为。基准 5:多个重叠 shape,每个 shape 一个客户端shape 数量变化,每个 shape 各有一个客户端订阅;统计一次影响所有 shape的写到达各客户端的平均耗时。结论:延迟与内存占用均线性上升。基准 6:多个重叠 shape,只共享一个客户端shape 数量变化,但只有一个客户端(它订阅其中一个 shape);统计一次影响所有 shape 的写到达该客户端的耗时。结论:延迟与峰值内存线性上升,平均内存保持平稳。写吞吐:优化 vs 非优化 where 子句基准 7:优化 where 子句下的写吞吐该基准测量不同 shape 数量下每次写的处理时间,所有 shape 使用优化子句field constant。优化 where 子句的工作原理(原文档 Tip 完整继承):创建 shape 时可以指定 where 子句,过滤 shape 关心的行。Electric 会对从 Postgres 收到的变更做过滤,让每个 shape 只收到自己关心的行变更。shape 很多时,每次写入可能要评估大量 where 子句——Electric 对此做了优化:只要子句符合若干模式(称为优化 where 子句),就能一次性评估数百万条where 子句。field constant是被优化的模式之一:Electric 内部按每个 shape 的常量值建立索引,一次查表即可取出该常量的全部 shape。这个索引完全是 Electric 内部的实现,与 Postgres 索引无关,本质上就是一个 hashmap。field const AND another_condition也是被优化的模式,一些可索引的OR组合同样已经支持优化。本基准仍只测field constant这一具体情形。有了优化 where 子句,无论有多少 shape,处理一次写只需要四分之一毫秒(0.25ms)级别。图中上幅为 Postgres 14,下幅为 Postgres 15。两条线的含义:绿线(影响 shape 的写):两图中吞吐都平稳在 0.17~0.27ms/变更,即4000~6000 行变更/秒,与 shape 数量无关。紫线(不影响任何 shape 的写):Postgres 14 上平稳在0.02ms/变更(50,000 行变更/秒);Postgres 15 上则随 shape 数线性增长。原因在于 Postgres 15 支持基于 where 子句过滤复制流,Electric 用它来过滤掉不影响任何 shape 的写——但如图所示,在这个场景下这个优化反而不理想。团队正在改进;目前保留该行为是因为它对非优化 where 子句(见基准 8)有益。基准 8:非优化 where 子句下的写吞吐同样测量不同 shape 数量下每次写的处理时间,但所有 shape 使用非优化子句field ILIKE constant。由于必须逐个 shape 评估,吞吐随 shape 数线性下降。上幅(Postgres 14):无论写是否影响 shape(绿/紫线),吞吐大致相同,140k 行变更/秒/shape。下幅(Postgres 15):由于能用复制流 where 过滤掉不影响任何 shape 的写,影响 shape 的写仍得到与 Postgres 14 相同的 140k 行变更/秒/shape,而不影响 shape 的写可达1400k 行变更/秒/shape——即过滤让无效写的处理快了一个数量级。这组对比给出的工程结论很清晰:shape 规模增长时,优先把 where 子句写成可优化的形式,是保持写处理延迟平稳的关键。完整的优化子句模式清单(如array_field array_constant、field IN list_constant、IN (subquery)、优化条件与AND/OR的组合等)见 shapes 文档的 Throughput 章节;该文档同时给出直观对照:10 个 shape 时非优化子句约 1,400 变更/秒,100 个 shape 时降到 140 变更/秒,而优化子句下 10 个或 1,000 个 shape 都稳定在约 5,000 行变更/秒。PGlite 基准PGlite 方向的基准数据不维护在本仓库,而是记录在 PGlite 官方的基准页面(pglite.dev/benchmarks 的 /benchmarks 路径)。本文档仅作为指引,将 PGlite 的测量口径与 Electric 核心/Cloud 基准区分开。小结:如何正确使用这份基准数据把 8 组图表当作能力轮廓而非承诺:初始同步是流式的(大 shape 内存平稳),写扇出延迟在独立 shape 优化子句下可稳定在约 6ms,写吞吐在优化子句下与 shape 数量解耦;非优化子句下,吞吐随 shape 数线性下降是结构性行为(逐 shape 求值),Postgres 15 的复制流过滤只能缓解无效写一侧;Cloud 场景的百万并发能力来自CDN 请求折叠 长轮询,而非单机多连接,单机同步服务的内存与延迟曲线在 10 万~100 万客户端间基本平稳(见上文 基准数据 JSON 的实测数字);任何容量规划都应以自己的负载、自己的硬件实测为准,官方明确声明页面数字不构成性能保证。【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考