内容提要
RDS Supabase 的 Realtime 提供三项能力:Postgres Changes 监听表增删改并实时推送,Broadcast 支持客户端间互发瞬时消息,Presence 跟踪频道在线成员。文章以聊天室为例,讲解建表、RLS 权限、发布清单配置,以及监听、广播、在线状态与三者协同的实现,并提示连接配额、断线重连、密钥安全等边界。
延伸解读
发布清单与 RLS:两道必过的门槛
文章强调,表默认不会推送变更,必须加入 supabase_realtime 发布清单;但加入清单不等于客户端能收到,中间还有 RLS 按 JWT 角色过滤。这意味着配置时要同时检查两处:publication 是否包含目标表,以及对应角色的 SELECT 策略是否放行。若订阅后收不到事件,优先排查这两层,而非怀疑 WebSocket 连接本身。
REPLICA IDENTITY FULL 的代价与取舍
要让 UPDATE/DELETE 的 payload.old 携带整行旧值,需将表设为 REPLICA IDENTITY FULL;默认只记录主键,旧值字段为空。文章在聊天室撤回场景中依赖旧 id 移除消息,因此该设置必要。但 FULL 会让每次更新写入更多 WAL 数据,高频更新的大表应权衡:若业务只需主键定位,保持默认即可减少复制开销。
三类能力的分工决定实现方式
文章用聊天室把三项能力拆得很清楚:消息持久化走 Postgres Changes,输入提示走 Broadcast 且不落库,在线名单走 Presence 且仅在频道内同步。这个分工直接影响性能与数据一致性——高频瞬态信号若误用 Postgres Changes,会带来不必要的写库与 WAL 压力;反之需要持久化的消息若走 Broadcast,断线后无法补回。选型时应先判断数据是否需要留存。
上线前需关注的运行边界
文章提示了几条容易被忽略的边界:并发连接数与推送频率有配额,高频写入需评估推送压力和 WAL 开销;SDK 虽自动重连,业务回调仍应容错;前端只能使用 anon 密钥,service_role 必须留在服务端以免绕过 RLS。此外,订阅需等 status 为 SUBSCRIBED 后才可依赖,Presence 的 track 也须在此后调用,否则状态无法登记。
Q&A
RDS Supabase 的 Realtime 提供哪些能力?分别用在什么场景?
Realtime 提供三项能力:Postgres Changes 监听表的增删改并实时推送,适合消息持久化同步;Broadcast 在客户端之间互发瞬时消息,适合“对方正在输入”等瞬时通知;Presence 跟踪频道内在线成员,适合在线名单展示。
为什么 Supabase 默认不推送表变更?如何让某张表的变更被实时推送?
出于性能考虑,Supabase 默认不推送任何表的变更。需要将表加入名为 supabase_realtime 的 publication(发布清单),例如执行 ALTER PUBLICATION supabase_realtime ADD TABLE public.messages;,列入清单的表变更才会被发出。
使用 Postgres Changes 监听 UPDATE 或 DELETE 时,如何拿到完整的旧行数据?
需要将表的副本标识设为 FULL,例如 ALTER TABLE messages REPLICA IDENTITY FULL;。否则默认只记录主键,payload.old 中只有主键字段,无法获取完整旧值。
Broadcast 和 Presence 有什么区别?聊天室中“对方正在输入”应该用哪个?
Broadcast 用于客户端之间互发瞬时消息,不落库;Presence 用于跟踪频道内在线成员,底层采用 CRDT 保证最终一致。“对方正在输入”是瞬时状态,适合用 Broadcast 发送 typing 事件,并建议节流(如 300ms 一次)。
在聊天室中如何同时使用 Postgres Changes、Broadcast 和 Presence?
创建一个频道,在 config 中启用 broadcast(self: false)和 presence(指定 key),然后通过多个 .on() 分别监听 postgres_changes(过滤 room_id)、broadcast 的 typing 事件和 presence 的 sync 事件,最后调用一次 subscribe() 即可同时处理三类事件。
使用 Realtime 时有哪些连接或安全方面的限制需要注意?
需注意:并发连接数和推送频率有配额限制(以控制台为准);SDK 会自动重连,但业务侧应对回调异常做容错;需持久化的数据用 Postgres Changes,瞬时状态用 Broadcast;前端只用 anon 密钥订阅,service_role 密钥仅放服务端,避免绕过 RLS。