2011-04-28 57 views
3

我有一个收集会话数据的系统。会话由许多不同的事件组成,例如“会话开始”和“执行的操作X”。没有办法确定会话何时结束,所以相反,心跳事件会定期发送。你如何对分布式系统中没有事件做出反应?

这是主要的并发症:没有确定的方式,如果一个会话已经结束,唯一的办法就是尽量不存在的事件,即没有更多的心跳反应。我如何在分布式系统中有效且正确地完成这项工作?

下面是一些背景的问题:

事件必须被组装成表示会话中的对象。会话对象稍后会使用来自其他系统的附加数据进行更新,并最终用于计算会话数量,平均会话长度等。

系统必须水平缩放,因此有多个服务器可以接收事件以及处理它们的多个服务器。属于同一会话的事件可以发送到不同的服务器并由其处理。这意味着我们无法保证它们将按顺序处理,并且还有其他复杂情况,意味着事件可能会重复(并且总会有一些丢失的风险,无论是在它们到达我们的服务器之前,还是在处理完成之前)。

大部分情况已经存在,但我没有很好的解决方案来有效地和正确地确定会话何时结束。我现在的做法是定期搜索“不完整”会话对象的集合,查找任何未等待两次心跳的时间的更新,然后将这些对象移至另一个具有“完成”会话的集合。此操作既耗时又低效,并且水平伸缩效果不佳。基本上,它包括对代表最后一个时间戳的列进行排序,并过滤掉任何不够长的行。听起来很简单,但很难并行化,如果你经常这样做,你就不会做其他任何事情,数据库会忙于过滤数据,如果你不经常做足够的话,每次运行都会很慢,因为有处理太多。

我想反应过来的时候会话尚未一会儿更新,不轮询每个会话,看它是否也已更新。

更新:只是为了给你的感觉;在任何时候都有数十万个会话活动,最终会有数百万个会话。浮现在脑海

+0

多久你需要知道,如果一个会话已经完成? – 2011-04-28 12:28:26

+0

大约在几分钟内。 – Theo 2011-04-28 18:23:50

回答

2

一种可能性:

在你的数据库表中记录了最近一次会议是跟踪会话,添加时间戳字段(如果你没有的话),“活跃” 。每当你有心跳时更新时间戳。

当你创建一个会话,安排“计时器事件”后,一些适当的延时消防检查会话是否过期。当计时器事件触发时,请检查会话的时间戳,以查看在计时器等待的时间间隔内是否有更多的活动。如果是这样,会话仍处于活动状态,因此安排另一个计时器事件以便稍后再次检查。如果没有,会话超时,所以删除它。

如果你使用这种方法,每一届总会有负责检查是否它是过期的,但不同的服务器可以负责不同的会话,所以工作量可以左右均匀地分布在一台服务器。当心跳进入时,哪个服务器处理它并不重要,因为它只是更新数据库中的一个时间戳(大概)在所有服务器之间共享。

由于您将获得定期计时器事件,使您可以检查会话是否已过期,即使尚未过期也仍然存在一些轮询。如果每次检测信号到达时您可以取消挂起的定时器事件,但可以避免使用多个棘手的服务器:处理心跳的服务器可能与预定定时器的服务器不同。无论如何,所涉及的数据库查询是轻量级的:只需通过主键查找一行(会话记录),而无需进行排序或不等式比较。

+0

在理论上使用计时器可以工作,但我不确定如何在实践中做到这一点。当会话更新时,如何确保定时器延迟(即取消并设置为新时间)?如果你没有把握好,你最终会被虚假检查所淹没。在任何时候都有数十万(并最终有望达到数百万)会话。 – Theo 2011-04-28 07:20:34

0

所以你正在收集心跳;我想知道是否可以有一个批处理过程(或者其他东西)在收集的心跳中寻找表示会话结束的模式。

准确度的高低取决于心跳的频率和收集心跳的频率。

好处是你正在通过一个机制处理所有的心跳(在一个地方 - 你不必轮询每个心跳),所以应该能够扩展 - 如果它是一个以数据库为中心的解决方案那应该能够处理大量的数据,对吧?

有可能是一个更优雅的解决方案,但我的脑子有点满刚才:)

+0

我知道心跳之间的时间间隔,因此找出一个会话已经结束是没有问题的(虽然不完美,但是两个错过的心跳足以说明会话已结束)。但这就是我在我的问题中描述的(寻找“我现在​​这样做的方式”,它位于最后一段的第三段)。问题是这种机制成为瓶颈。 – Theo 2011-04-29 11:12:56