实时架构
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的记录分发给对应的客户端。