在 Erlang 中将消息路由到 PID

Posted

技术标签:

【中文标题】在 Erlang 中将消息路由到 PID【英文标题】:Routing messages to PIDs in Erlang 【发布时间】:2016-11-13 23:35:18 【问题描述】:

我正在用 erlang 编写一个处理大量消息(记录)的服务器。 每条消息都有一个标签(原子),就像一个用户 ID。

如果该进程不存在,“路由器”将为该用户生成一个专用的永久进程(在保存和传递消息之前累积几分钟的消息)。否则它将作为消息传递到现有进程邮箱。

问题在于路由表的簿记。

我可以考虑序列化路由器,每条消息都会导致 ETS 查找通过 userId 查找 PID,如果没有退出,则最终 Spawn 和 ETS 插入。但这在几秒钟内就变得拥挤了。

另一种方法是直接生成一个进程来路由每条消息,但如果发送给单个用户的几条消息紧随其后,并且在 ETS 中找不到它们对应的 PID 并生成了永久进程,这可能会导致竞争状况.消息将丢失,只有最后生成的进程有效(覆盖 ETS 中的其他进程),其他进程将处于空闲状态且未被跟踪。

我也可能想错了。有没有更好的方法来处理这种情况?

【问题讨论】:

【参考方案1】:

就像您建议的那样,每个用户拥有一个进程(一台服务器)是一种常见的模式。

有时,如果使用的协议允许,则不是将消息从侦听所有用户的服务器路由到“用户”进程,而是在任何连接之前产生一个新进程,侦听(等待)新的用户连接请求.当请求到达时,会产生一个新的等待进程,当前进程管理与新用户的完整会话(有关详细示例,请参阅learyousomeerlang: a bucket of socket)。

【讨论】:

没错。现在我为每条消息实现了一个流程来进行路由。然后每个用户都有一个进程来接收这些消息。 gen_server 负责用户进程的生成和簿记。根据 A. Sarid 的回答设置 Ets 选项后,该解决方案在实际流量中运行良好。 您还提到让用户进程进行侦听,因此不需要路由。在这种情况下这是不可能的,消息以记录的形式来自同一个 RPC。如果消息源每个用户都有一个套接字/pid,那就太好了。【参考方案2】:

您的第一个解决方案听起来很适合这种情况。对我来说,如果您有大量消息,则为收到的每条消息启动一个流程听起来并不正确。 ETS 速度很快,应该能够处理大量数据。

您可能需要考虑使用 erlang OTP gen_server。你可以阅读更多关于它的信息here、here和here。

此外,如果您要从多个进程访问 ETS,您可能需要考虑 read_concurrency, trueread_concurrency, true 选项。阅读更多关于它的信息here 和 here。

【讨论】:

谢谢。我正在使用 otp gen_server。正如你提到的,我将使用 read_concurrency。并将实施第一个解决方案的变体。我为每条消息生成一个进程只是为了进行 ets 查找。如果未找到,则 gen_server 将提供一个新生成的 worker 并更新 ets 表。我会回来告诉你进展如何。

以上是关于在 Erlang 中将消息路由到 PID的主要内容,如果未能解决你的问题,请参考以下文章

在 OTP/Erlang 中将 ID 映射到进程的惯用方式是啥?

消息队列选型

关于 HTTP 服务的 Erlang 设计建议

Java 到 Erlang 的消息

EMQ --集成搭建

如何在 Erlang 中将整数转换为二进制?