我正在使用 OTP Genserver 在 Elixir 中开发一个聊天室 [all to all] 应用程序,并在用户注册其姓名作为第一阶段时从 js 客户端获取消息。现在,只是有点不确定以某种方式将这些名称存储在我的 elixir 服务器上并通过在线用户列表或数据库存储向客户端发送定期更新的最佳方法是什么。请建议最好的方法。
2 回答
我同意 bitwalker 的观点,即 ETS 非常适合。
这是我在生产中所做的简短摘要。它不是聊天服务器,而是通过长轮询连接数千名用户的服务器推送。推送的数据分为大约 50 个类别,用户可以选择他们想要的类别。在高峰时间,服务器每 2 秒推送一次新消息,并处理 > 2000 个请求/秒。
本质上,我gen_server
为每个用户保留了一个,其中保存了待处理的消息和用户的配置(基本上是所选频道的列表)。这对于长轮询是有益的,因为用户的数据与用户的请求是分离的,所以当请求是瞬态的时数据仍然存在。但是,我认为这种方法也适用于永久连接,例如 websockets,因为可能仍然会偶尔断开连接,并且保持更稳定的用户数据可以让您在重新连接后有机会恢复。
显然,当请求到达时,您需要找到用户特定的进程,而对于这一点,ETS 非常适合,因为您没有单个进程的瓶颈。我建议将gproc与via
元组结合使用,而不是手动使用 ETS。基本上,在启动用户的 gen_server 时,您可以根据内部用户的 id(并在本地节点上指示唯一名称)提供您name: {:via, :gproc, {:n, :l, key}}
在哪里创建的一些自定义键(任意术语)。然后,您可以在发出调用/强制转换时使用相同的元组,并将用于查找相应的进程。key
:n
:l
via
gen_server
gproc
最后,您需要有一些超时/断开逻辑来清理用户进程。在我的例子中,如果 web 层没有任何活动,我只是终止了用户的进程(一段时间内没有最终用户来获取数据)。Gproc 将自动从其内部 ETS 表中删除已终止进程的条目。最好在temporary
策略下监督用户进程。
我意识到所有这些仍然有点模糊,但我希望它是有道理的。请记住,这不是最终模式(当然没有这样的事情),但我认为这是一个合理的第一次尝试。
您可能还想看看Phoenix Web 框架,它有一个有趣的发布-订阅工具,格式为Topics
. 我自己还没有尝试过,但它看起来很有趣,甚至可以简化我上面讨论的一些内容,或者至少有助于将通知从聊天室推送给所有用户。
听起来像是ETS的一个很好的用例。
一种更简单的方法可能是使用代理来存储在线用户信息,但这在很大程度上取决于您选择的存储机制需要什么。