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