一些背景知识,然后才是真正的问题:
我正在开发一个后端应用程序,由几个不同模块组成。每个模块目前都是一个命令行Java应用程序,可以根据需要“按需”运行(稍后会有更多详细信息)。
每个模块是一个“步骤”,是可以视为数据流的更大过程的一部分;第一步从外部源收集数据文件并将其推送/加载到某些SQL数据库表中;然后,基于不同的条件和事件(时间、DB中的数据存在、通过Web服务/Web界面完成的消息和计算),后续步骤从(1个或多个)DB表中获取数据,处理它们,并将它们写入不同的表格。步骤在三个不同的服务器上运行,从三个不同的DB中读取数据,但只写入单个DB。目的是汇总数据,计算指标和统计信息。
目前,每个模块定期执行(从第一个模块的几分钟/几小时到链中最后几个模块的数天,需要聚合更多数据,因此需要“等待”它们可用性更长时间),使用cronjob。运行一个模块(目前是Java控制台应用程序),它检查给定时间窗口内的新的未处理信息,并执行其工作。
问题:它有效,但是…我需要扩展和维护它,而这种方法开始显示出其限制。
- 我不喜欢依赖“轮询”;考虑到以前模块的信息可能足以“告诉”链中其他模块何时可用它们所需信息,它们可以继续进行。
- 它很“慢”:链条下面的几天延迟是因为我们必须确保数据已到达并由上一个模块处理。因此,我们暂停这些模块,直到确信我们拥有所有数据。新添加的内容需要实时(不难办到,但尽快)计算某些指标。这里在 SO 上发生的事情很好地说明了这一点! :) 我需要获得非常相似的东西。
为了解决第二个问题,我将引入“部分”或“增量”计算:只要我拥有一组相关信息,我就会处理它。然后,当其他链接的信息到达时,我计算差异并相应更新数据,但然后我还需要通知其他(相关的)模块。
问题(S)
- 1)哪种方法最好?
- 2)相关:通知其他模块(在我的情况下为Java可执行文件)可用的最佳方法是什么?
我可以看到三种方法:
- 在数据库中添加其他“非数据”表,每个模块都会写入“嘿,我已经完成了这个任务并且可用”。当cronjob启动另一个模块时,它读取表格,决定它可以计算子集xxx,并进行计算。以此类推。
- 使用消息队列,如ZeroMQ(或者像@mjn建议的Apache Camel)而不是数据库表
- 使用键值存储,如Redis,而不是数据库表
编辑:我相信基于队列的方法是正确的方法,我添加了“表+轮询”选项以保证完整性,但现在我明白它只是一个干扰(显然,每个人都会回答“是的,请使用队列,轮询很糟糕” - 这是正确的!)。所以让我重述问题: 使用MQ会比使用pub / sub类Redis的键值存储有哪些优缺点?
- 3) 有没有解决方案可以帮助我完全摆脱cronjobs?
编辑:特别是在我的情况下,意味着:是否有一种机制在某些MQ和/或键值存储中,可以使我发布带有“时间”的消息?例如“在1天内交付”?当然具有持久性和“几乎一次”的交付保证
- 4) 我应该将这个基于消息(事件?)的解决方案构建为一个集中式服务,在其中一个服务器上作为守护程序/服务运行吗?
- 5) 我是否应该放弃启动订阅者的想法,并使每个模块作为守护程序/服务持续运行?
- 6) 这些都是利弊分析(可靠性,单点故障与资源使用和复杂性之间的关系...)?
编辑:这是我最关心的部分:我想要 “队列” 本身激活基于队列中的消息的“模块”,类似于MSMQ激活。 这是一个好主意吗?在Java世界中有什么可以做到这一点的东西,是我应该自己实现它(在MQ或Redis上),还是应该将每个模块作为守护线程运行? (即使某些计算通常会发生突发情况,在长达两小时的处理后跟随两天的闲置?)
注意:我不能使用重量级容器/EJB(没有Glassfish或类似产品)
编辑:像Camel这样的东西对我来说也有点重,我在这里寻找的是真正轻巧的东西,无论是资源还是开发复杂度方面。