问题是:
安装在许多不同服务器上的"代理"每5秒向中央服务器发送一次"心跳"信号。我怎样才能找到主动错过心跳超过10秒的人并发出警报?
如果不考虑可扩展性,问题很简单。最简单的形式是,您可以在数据库表中记录从每个代理接收到的最新心跳的时间戳,并运行常规查询以查找比阈值更早的心跳。
然而,这个解决方案不能扩展到数百万个代理。
我正在寻找算法或技术,使这成为可能。
- 使用map: AgentId -> LastHearbeatTime
- 使用11个集合(假设1秒的分辨率足够),每个集合保存在1秒窗口中报告的代理id。
每次agent报告心跳时:1. 在地图上找2. 将其从相关集合中删除3.在地图中更新它4. 将其添加到相关集合
定义一个线程:每秒钟一次,最老的一组过期。它应该是空的。如果没有,它包含没有报告的代理的id。一旦集合过期,您可以重用它(集合的循环数组)。
我相信它可以实现没有锁(也许你需要12组)。
在不了解语言和平台的情况下,很难给您提供详细的实现建议,但是我的建议与Lior Kogan的建议有些类似。然而,在我看来,您只需要两个集合,而不涉及映射:
假设你有两个变量表示集合A和b。
每次心跳都从集合A中移除代理id。每隔5秒,一个不同的线程为B中的每个代理id发出警报,然后设置B = a,最后创建一个包含所有代理id的集合,并将a设置为等于这个集合(如果代理id的数量非常大,您可以在一次检查和另一次检查之间准备新的集合,剩下的时间只休眠)。只有在更改指向每个集合的变量时才需要锁,前提是使用无锁集合集合。性能在很大程度上取决于所述实现的算法复杂性,如果采用这种方法,则应该将性能最好的(不一定是最好的大0,例如,如果最坏情况下延迟对您很重要)用于删除。
边注,如果内存不是问题或故障相对较少,当你检查是否需要提高警报,这样做,你可以在自己的线程和有趣的性能加速(平台和运行时,在erlang中这将是一个微风但在窗口创建一个全面的新线程的成本可能超过性能优势如果失败很少)的成本保持旧的B组在内存中。
MongoDB非常适合这种类型的使用。虽然不完全是一种算法,但它确实符合创建此服务所需的基本技术的要求。我们在CopperEgg的RevealCloud产品中使用它,它完全按照你说的去做——当系统离开一段时间后,我们会发送一个警报——每5秒采样一次。我很想听到更多关于您的想法和用例的信息。你能否提供更多细节?