Electric 同步引擎的 PostgreSQL 权限配置全指南:三种模式、核心权限清单与手动发布配置
【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric
本指南基于开源仓库electric(Agent 平台的内置同步引擎,核心实现位于 packages/sync-service)官方文档与源码,系统讲解如何为 Electric 创建和配置具备必要权限的 PostgreSQL 用户。读完本文,你将掌握超级用户、Electric 托管发布(自动模式)与手动模式(最小权限)三种权限方案的适用场景与完整 SQL 配置,理解ELECTRIC_MANUAL_TABLE_PUBLISHING、ELECTRIC_REPLICATION_STREAM_ID等关键配置项背后的源码实现,并能够独立完成发布(Publication)与REPLICA IDENTITY FULL的手动配置与验证。
你应该选择哪种权限方案?
Electric 需要通过 逻辑复制 读取 Postgres 的变更流,并管理发布对象(Publication)。根据不同场景,官方文档给出了三种由高到低的权限方案:
| 方案 | 适用场景 | 优点 | 缺点 | 连接配置 |
|---|---|---|---|---|
| 🟢 超级用户(推荐用于开发) | 本地开发、测试或简单的生产部署 | 设置最简单,Electric 全自动管理一切 | 权限级别最高 | DATABASE_URL=postgresql://postgres:... |
| 🔵 Electric 托管发布(自动模式,生产推荐) | 生产环境,Electric 可以拥有数据库表 | Electric 自动管理发布与REPLICA IDENTITY | Electric 必须拥有表(应用失去表所有权) | 创建专用用户并转移表所有权 |
| 🔴 手动模式(最小权限) | 高安全环境、应用必须拥有表、严格权限分离 | 应用保留表所有权,Electric 权限最小 | DBA 必须预配置发布,新增表需手动加入 | 仅REPLICATION+SELECT,DBA 配置发布 |
三种方案的详细配置步骤分别见下文 开发环境配置、Electric 托管发布配置 与 手动模式配置。
自动 vs 手动发布管理
Electric 在两种模式下运行,其行为差异由配置项ELECTRIC_MANUAL_TABLE_PUBLISHING控制(默认值为false)。
1. Electric 托管发布(自动模式,推荐)
当客户端请求某个表的 shape 时,Electric 会在 Postgres 内自动创建发布(publication)并把表加入其中,同时自动设置REPLICA IDENTITY FULL。这要求 Electric 的数据库用户具备数据库上的CREATE权限和表的所有权——PostgreSQL 规定:只有表的所有者才能把表加入发布,也只有表的所有者才能设置REPLICA IDENTITY FULL。
从源码看,该逻辑由 configurator.ex 中的PublicationManager.Configurator(一个 GenServer)实现。它维护一个"目标关系集合",收到 shape 订阅请求后去比对当前发布的实际状态,并生成to_add(加入发布)、to_configure_replica_identity(配置 replica identity)、to_drop(移除)等动作清单,最终通过 configuration.ex 中的configure_table_for_replication/4在一个事务内依次执行ALTER PUBLICATION ... ADD TABLE与ALTER TABLE ... REPLICA IDENTITY FULL:
defp do_publication_update(:add_and_configure, filter, state) do with :ok <- Configuration.configure_table_for_replication( state.db_pool, state.publication_name, filter ) do {:ok, :configured} end end值得注意的实现细节:源码注释明确指出,ALTER PUBLICATION ... ADD TABLE只持有表的SHARE UPDATE EXCLUSIVE锁,与写入者不冲突,因此在该事务内还会额外执行LOCK TABLE ... IN SHARE MODE作为屏障,等待所有在途写入者结束,从而保证"加入发布之前的写入要么通过初始快照可见、要么通过复制流可见",不会出现变更丢失。详见 configuration.ex。
2. 手动模式
手动模式下,发布由 DBA 提前创建和维护,Electric 只负责校验现有配置是否满足要求,而不会自动增删表。启用方式:
ELECTRIC_MANUAL_TABLE_PUBLISHING=true该模式只需要REPLICATION和SELECT权限,但你必须在请求 shape 之前,预先创建发布、把表加入发布,并为每张表设置REPLICA IDENTITY FULL。
从源码看,configurator.ex 中的can_update_publication?/1函数同时检查"能否修改发布"和"是否手动模式"两个条件:
defp can_update_publication?(%__MODULE__{ can_alter_publication?: can_alter, manual_table_publishing?: manual }) do can_alter and not manual end当手动模式开启时,Electric 对缺失的配置会返回明确的错误而不是自行修复。例如表未加入发布时,configurator.ex 会生成如下错误信息:
Database table "public.items" is missing from the publication "..." and the ELECTRIC_MANUAL_TABLE_PUBLISHING setting prevents Electric from adding it这一行为有完整的测试与集成测试覆盖:单元测试见 publication_manager_manual_test.exs(分别验证"表不在发布中报错"与"replica identity 非 FULL 报错"两个场景);端到端集成测试见 manual-table-publishing.lux,它用一个low_privilege角色实际启动 Postgres 与 Electric,逐级演示了"缺表 → 加表 → 仍缺 replica identity → 设置 FULL → 缺 SELECT 权限"的完整报错链路。
核心权限要求一览
根据模式不同,Electric 所需的 PostgreSQL 权限如下:
| 权限 | 用途 | Electric 托管 | 手动模式 |
|---|---|---|---|
REPLICATION | 启用逻辑复制流 | ✅ 必需 | ✅ 必需 |
表上的SELECT | 读取表数据以生成初始 shape 快照 | ✅ 必需 | ✅ 必需 |
数据库上的CREATE | 创建发布 | ✅ 必需 | ❌ 不需要 |
| 表所有权 | 设置REPLICA IDENTITY FULL并把表加入发布 | ✅ 必需 | ❌ 由 DBA 配置 |
| 发布所有权 | 修改发布(增删表) | ✅ 必需 | ❌ 由 DBA 配置 |
另外,DATABASE_URL中的用户必须具有REPLICATION角色。可参考 配置参考 中关于DATABASE_URL的说明:连接串的userspec部分指定的就是 Electric 连接 Postgres 所用的用户。
设置示例
开发环境配置(For Development)
开发环境直接使用默认的postgres超级用户(或其他超级用户角色):
DATABASE_URL=postgresql://postgres:your_password@localhost:5432/your_databaseElectric 会自动创建发布、配置REPLICA IDENTITY FULL并管理一切。对于追求简便、安全性要求不高的简单生产部署,同样适用。
Electric 托管发布配置(Electric-managed publications Setup)
创建一个专用 Electric 用户,并授予自动表配置所需权限。Electric 会在 shape 被请求时自动创建发布、加入表:
-- 创建带 REPLICATION 的 Electric 用户 CREATE ROLE electric_user WITH LOGIN PASSWORD 'secure_password' REPLICATION; -- 授予数据库级权限 GRANT CONNECT ON DATABASE mydb TO electric_user; GRANT USAGE ON SCHEMA public TO electric_user; GRANT CREATE ON DATABASE mydb TO electric_user; -- 创建发布所需 -- 授予表上的 SELECT(Electric 只读,仅需读数据) -- 所有表: GRANT SELECT ON ALL TABLES IN SCHEMA public TO electric_user; -- 未来新建的表自动获得 SELECT(ALTER DEFAULT PRIVILEGES) ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO electric_user; -- 只授权特定表: -- GRANT SELECT ON public.users, public.posts TO electric_user;将表所有权转移给 Electric:
PostgreSQL 要求表所有者才能把表加入发布并设置REPLICA IDENTITY FULL,因此必须把表所有权转移给electric_user。
针对特定表(推荐做法):
ALTER TABLE public.users OWNER TO electric_user; ALTER TABLE public.posts OWNER TO electric_user; ALTER TABLE public.comments OWNER TO electric_user;或者将该 schema 下的所有表一次转移:
DO $$ DECLARE r RECORD; BEGIN FOR r IN SELECT tablename FROM pg_tables WHERE schemaname = 'public' LOOP EXECUTE 'ALTER TABLE public.' || quote_ident(r.tablename) || ' OWNER TO electric_user'; END LOOP; END$$;[!Warning] 所有权转移警告 转移表所有权会让原所有者失去所有权。如果应用必须保留表所有权,请改用 手动模式,由 DBA 预先配置发布与
REPLICA IDENTITY FULL。
配置完成后连接 Electric:
DATABASE_URL=postgresql://electric_user:secure_password@localhost:5432/mydb手动模式配置(Manual Mode Setup)
对于有严格安全要求的环境,可使用手动发布管理来最小化 Electric 的权限:
-- 创建带 REPLICATION(但其他权限最小化)的 Electric 用户 CREATE ROLE electric_user WITH LOGIN PASSWORD 'secure_password' REPLICATION; -- 只授予连接与 usage 权限 GRANT CONNECT ON DATABASE mydb TO electric_user; GRANT USAGE ON SCHEMA public TO electric_user; -- 只对特定表授予 SELECT GRANT SELECT ON public.users TO electric_user; GRANT SELECT ON public.posts TO electric_user;然后以超级用户或数据库所有者身份,按照下文 手动配置步骤 创建发布、加入表并配置 replica identity。
配置 Electric:
DATABASE_URL=postgresql://electric_user:secure_password@localhost:5432/mydb ELECTRIC_MANUAL_TABLE_PUBLISHING=trueAWS RDS 和 Aurora
AWS RDS 与 Aurora 在复制权限方面需要特殊处理。参考 AWS 集成指南:
- 在自定义参数组中将
rds.logical_replication=1(这会设置wal_level=logical),然后重启实例; - 默认的
postgres用户已具备REPLICATION角色;若需给其他用户授予复制权限,通过rds_replication角色实现:
GRANT rds_replication TO someuser;手动配置步骤(Manual Configuration Steps)
当你需要为ELECTRIC_MANUAL_TABLE_PUBLISHING=true手动配置发布与 replica identity 时,按以下 5 步执行。
1. 创建发布(Create the Publication)
-- 创建空发布 CREATE PUBLICATION electric_publication_default; -- 或使用自定义名称(需同时配置 ELECTRIC_REPLICATION_STREAM_ID 保持一致) CREATE PUBLICATION my_custom_publication;发布名称默认形如electric_publication_<stream_id>。默认的ELECTRIC_REPLICATION_STREAM_ID为default(见 config.ex 中的replication_stream_id: "default"),该配置项作为逻辑复制发布与 slot 名称的后缀,详见 配置参考。
2. 将表加入发布(Add Tables to the Publication)
ALTER PUBLICATION electric_publication_default ADD TABLE public.users; ALTER PUBLICATION electric_publication_default ADD TABLE public.posts; ALTER PUBLICATION electric_publication_default ADD TABLE public.comments;[!Tip] 更精简的等价操作 配置参考 中给出了每次新增 shape 前的等价最小步骤,可将两步合并到同一事务:
BEGIN; ALTER PUBLICATION electric_publication_default ADD TABLE <my table>; ALTER TABLE <my table> REPLICA IDENTITY FULL; COMMIT;
3. 配置 Replica Identity
每张要同步的表都必须把 replica identity 设置为FULL:
ALTER TABLE public.users REPLICA IDENTITY FULL; ALTER TABLE public.posts REPLICA IDENTITY FULL; ALTER TABLE public.comments REPLICA IDENTITY FULL;这会让 Postgres 在复制流中输出所有列的值,是 Electric 实现精确变更跟踪的前提。
4. 设置发布所有权
让 Electric 用户成为发布的所有者(或确保发布由 Electric 连接所用的同一用户创建):
ALTER PUBLICATION electric_publication_default OWNER TO electric_user;5. 验证配置
用下面的 SQL 检查发布是否配置正确:
-- 验证 Electric 角色具有 REPLICATION 权限 SELECT rolname, rolreplication FROM pg_roles WHERE rolname = 'electric_user'; -- 列出所有发布 SELECT * FROM pg_publication; -- 检查发布设置 SELECT pubname, pubinsert, pubupdate, pubdelete, pubtruncate FROM pg_publication WHERE pubname = 'electric_publication_default'; -- 列出发布中的表 SELECT schemaname, tablename FROM pg_publication_tables WHERE pubname = 'electric_publication_default'; -- 检查表的 replica identity SELECT schemaname, tablename, relreplident FROM pg_class JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid WHERE relreplident = 'f'; -- 'f' 表示 FULL从源码看,Electric 启动时正是通过类似的 SQL 来"体检"发布状态的。configuration.ex 中的check_publication_status!/2会查询:
pg_get_userbyid(p.pubowner) = current_role—— 当前角色能否修改发布(can_alter_publication);pubinsert AND pubupdate AND pubdelete AND pubtruncate—— 发布是否覆盖全部操作类型(publishes_all_operations);- PostgreSQL 18+ 上还会检查
pubgencols是否发布生成列(publishes_generated_columns)。
如果发布不存在或未发布全部操作,configurator.ex 会判定为致命配置错误;在自动模式下会尝试重启连接子系统自愈,而在手动模式下则只记录警告,提示你手动修正配置。
常见权限错误排查
以下内容摘录自 故障排查指南 的 "Database permissions" 一节:
"insufficient privilege to create publication"
- 原因:用户没有数据库上的
CREATE权限。 - 解决:执行
GRANT CREATE ON DATABASE mydb TO electric_user;,或者改用手动发布管理(由超级用户创建发布并设置ELECTRIC_MANUAL_TABLE_PUBLISHING=true)。
"publication not owned by the provided user"
- 原因:发布已存在,但所有者是其他用户。
- 解决:转移发布所有权:
ALTER PUBLICATION electric_publication_default OWNER TO electric_user;
"table does not have its replica identity set to FULL"
- 原因:表未配置
REPLICA IDENTITY FULL。 - 解决:手动设置:
ALTER TABLE schema.tablename REPLICA IDENTITY FULL;
"permission denied for table"
- 原因:Electric 用户没有该表的
SELECT权限。 - 解决:授权:
GRANT SELECT ON schema.tablename TO electric_user;
"must be owner of table"
- 原因:执行了需要所有权的操作(如
ALTER TABLE ... REPLICA IDENTITY FULL或把表加入发布)。 - 解决:以表所有者(或超级用户)身份执行,或转移所有权:
ALTER TABLE schema.tablename OWNER TO electric_user;
从源码理解权限校验链路
最后,把上面提到的实现串成一条完整的调用链,便于你深入阅读源码:
- shape 订阅请求到达后,
PublicationManager向 Configurator(Electric.Replication.PublicationManager.Configurator)发出更新请求; - Configurator 通过 Configuration(
Electric.Postgres.Configuration)执行check_publication_status!/2检查发布存在性与操作覆盖度,再执行determine_publication_relation_actions!/3计算需要的动作; - 若
can_update_publication?/1返回true(可修改发布且非手动模式),按排序后的动作清单依次执行add_table_to_publication/4、set_table_replica_identity_full/4、drop_table_from_publication/4;否则对每个缺失的表返回relation_missing_from_publication或misconfigured_replica_identity错误; - 上述校验逻辑由 publication_manager_manual_test.exs 与 manual-table-publishing.lux 双重验证。
下一步
- 查看 部署指南 了解生产环境部署方案;
- 阅读 安全最佳实践;
- 遇到问题参考 故障排查指南;
- 查看 配置参考 了解全部可用配置项(如
DATABASE_URL、ELECTRIC_POOLED_DATABASE_URL、ELECTRIC_REPLICATION_STREAM_ID等)。
【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考