Erlang:会话管理和超时

7

我正在编写一个基于gen_server的http会话管理器。该服务器创建并从内存存储中删除会话。我需要在超时时删除过期的会话。我有两个解决方案:

  1. 创建一个计时器来从管理器中删除过期的会话
  2. 为每个会话创建一个计时器

第一个解决方案在所有会话未处理完之前锁定服务器(锁问题)。第二个解决方案对于每个会话都需要一个进程(内存问题)。

问题是哪种解决方案是正确的?

谢谢!

4个回答

5

使用 timer:send_aftertimer:exit_after 或者 timer:kill_aftertimer 模块使用 ets 存储定时器,整个 VM 中只有一个 gen_server。在每个会话记录中存储定时器引用以便重新启动定时器等操作。这是一个简单而干净的解决方案。


你是对的,但每个计时器处理程序都将在新进程中调用。如果同时调用多个处理程序,则会创建许多进程。 - Kirill Trofimov
为什么要用机枪打死一只苍蝇? - jldupont
抱歉,send_after 函数不会创建进程。我是指 timer:apply_after 函数。 - Kirill Trofimov

2

我认为低频事件应该由低频进程处理。您不希望在不“生成”价值的事情上“花费”太多资源。

“清理”活动似乎不需要“锁定”服务器。也许您需要详细阐述这一点。

为什么您在解决方案#1中需要“锁定”某些内容?您在这里有哪些顾虑?请详细说明您的顾虑,以便我能提供更多建议。


你想说第一个解决方案是有道理的。对吗? - Kirill Trofimov
是的,我的意思是,#1的整体策略更符合清理活动的价值观。我不明白的是“锁定服务器”的含义。 - jldupont
gen_server有一个状态(State),其中包含可以通过回调函数创建或删除的会话(sessions)。为了实现策略#1,我将创建一个新的回调函数,例如:handle_call({remove_expired_session} ...)。当计时器(timer)调用该函数时,其他调用将等待,直到remove_expired_session完成。它看起来像是锁定(lock)。 - Kirill Trofimov
看起来更像是延迟。某个时候你必须进行一些清理处理,不是吗?如果你担心在这个特定的过程中活动的持续时间,你可以随时使用其他进程并分割工作,不是吗? - jldupont
没错,如果清理程序需要很长时间,我可以将任务分割。 - Kirill Trofimov

1

这是我在我的“Web框架”中处理会话的方式。

工作进程直接查找现有会话并将新会话创建到ets表中(无需任何服务器干预)。此外,工作进程在成功查找后检查会话是否已过期。如果是,则创建一个新会话并删除旧会话。由于ets表不需要排序,因此可以启用写并发。

“会话服务器”的角色是拥有会话表,并定期生成清理进程。这是一个低优先级进程,通过ets:next()调用遍历ets表并删除过期会话。

请注意,没有涉及计时器。


工作进程为什么要创建会话?在Web应用程序中,HTTP请求会创建会话。 - Kirill Trofimov
我所说的工作进程是指实际处理HTTP请求本身的进程。例如,在mochiweb中,执行注册循环函数的进程。 - Zed
无论如何,我的观点是根本没有理由使用计时器。死会话不会导致额外的系统负载或内存使用量;那么为什么要为每个会话精确地使用计时器来杀死它们呢? - Zed
你使用的会话超时值是多少? - Zed
@Zed:这是可配置参数。默认值为5分钟。 - Kirill Trofimov
显示剩余3条评论

0

只要你没有大量的会话,任何建议的解决方案都不会出错。我的意思是你应该进行基准测试。

定时器模块作为有序ETS表实现,可以有效地找到应该过期的第一个定时器并休眠直到发生。因此,通过定时器模块添加许多计时器没有问题。每个会话一个计时器。

如果您有很多会话,则具有故障安全设计的问题可能更大。您需要分发会话数据库以便可以负载平衡请求,并且您不容易受到任何一个Web服务器机器失效的影响。

这就是我在没有功能要求的情况下能够做出的具体建议。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接