实时

实时架构


Realtime 是一个全球分布式部署的 Elixir 集群。客户端可以通过 WebSocket 连接到集群中的任意节点,并向连接到该集群的任何其他客户端发送消息。

Realtime 使用 Elixir 编写,编译为 Erlang 字节码,并充分利用了 Phoenix 框架 提供的开箱即用工具。

全球架构

Elixir 与 Phoenix

Phoenix 框架性能卓越,能够处理数百万并发连接。

Phoenix 之所以能处理大量并发连接,是因为 Elixir 提供了轻量级进程(非操作系统进程)机制。

面向客户端的 WebSocket 服务器需要处理大量并发连接。Elixir 和 Phoenix 使得 Supabase Realtime 集群能够轻松实现这一目标。

通道

通道功能通过 Phoenix Channels 实现,其底层使用 Phoenix.PubSub 并默认采用 Phoenix.PubSub.PG2 适配器。

PG2 适配器利用 Erlang 的进程组机制来实现发布/订阅模型,使得发布者可以向众多订阅者广播消息。

全局集群

Presence 是一个基于 CRDT 的内存键值存储。当用户连接到集群时,该用户的状态会被发送到所有连接的 Realtime 节点。

Broadcast 允许您从任何连接的客户端向频道发送消息。连接到同一频道的其他客户端都将收到该消息。

这是全局生效的。连接到美国 Realtime 节点的客户端可以向连接到新加坡节点的另一个客户端发送消息。将两个客户端连接到同一个 Realtime 频道,它们都将收到相同的消息。

Broadcast 非常适合需要快速将消息传递给同一地理位置用户的场景。如果一组客户端连接到新加坡的节点,消息只需传输到新加坡的 Realtime 节点再返回。如果用户靠近 Realtime 节点,他们将在集群 ping 时间内收到 Broadcast 消息。

得益于 Realtime 集群,您(一位出色的 Supabase 用户)无需考虑客户端连接的具体区域。

无论您使用 Broadcast、Presence 还是数据库变更流,消息始终会通过最短路径到达您的用户。

连接数据库

Realtime 允许您监听 Postgres 数据库的变更。当新客户端连接到 Realtime 并初始化 postgres_changes Realtime 扩展时,集群将连接到您的 Postgres 数据库,并开始从复制槽流式传输变更。

Realtime 知道您的数据库所在区域,并会从最近的区域进行连接。

每个 Realtime 区域至少有两个节点,因此如果一个节点离线,另一个节点会重新连接并继续流式传输变更。

从Postgres广播

Realtime Broadcast(实时广播)会在数据库发生变化时发送消息。在底层实现上,Realtime会在realtime.messages表上创建一个发布。然后读取该表的预写日志(WAL)文件,每当有插入操作时就会发送消息。这些消息会通过WebSocket以JSON格式包发送。

realtime.messages表按天进行分区。这种设计可以通过删除旧分区来高效清理历史消息。分区会保留3天后被自动删除。

广播功能默认使用Realtime授权机制来保护您的数据安全。

流式传输预写日志

当连接到数据库时,Realtime会获取一个Postgres逻辑复制槽。

Realtime通过轮询复制槽并将频道订阅ID附加到每个WAL记录上来传递变更。

订阅ID是代表集群中底层socket的Erlang进程。这些ID具有全局唯一性,Erlang虚拟机会自动路由到这些进程的消息。

轮询查询返回结果后,Realtime会将附加了订阅ID的记录分发给对应的客户端。