Java MQ以异步方式处理、聚合和发布数据

Java MQ以异步方式处理、聚合和发布数据,java,notifications,redis,message-queue,dataflow,Java,Notifications,Redis,Message Queue,Dataflow,在讨论真正的问题之前,先了解一些背景: 我正在开发一个由几个不同模块组成的后端应用程序。目前,每个模块都是一个“按需”运行的命令行java应用程序(稍后将提供更多详细信息) 每个模块都是一个“步骤”,是一个更大流程的一部分,您可以将其视为一个数据流;第一步从外部源收集数据文件并将其推/加载到一些SQL数据库表中;然后,根据不同的条件和事件(计时、数据库中数据的存在、通过web服务/web界面完成的消息和详细说明),执行以下步骤,从(1个或多个)数据库表中获取数据,对其进行处理,并将其写在不同的表

在讨论真正的问题之前,先了解一些背景:

我正在开发一个由几个不同模块组成的后端应用程序。目前,每个模块都是一个“按需”运行的命令行java应用程序(稍后将提供更多详细信息)

每个模块都是一个“步骤”,是一个更大流程的一部分,您可以将其视为一个数据流;第一步从外部源收集数据文件并将其推/加载到一些SQL数据库表中;然后,根据不同的条件和事件(计时、数据库中数据的存在、通过web服务/web界面完成的消息和详细说明),执行以下步骤,从(1个或多个)数据库表中获取数据,对其进行处理,并将其写在不同的表中。步骤在三个不同的服务器上运行,从三个不同的数据库读取数据,但只在一个数据库中写入数据。其目的是聚合数据、计算指标和统计数据

目前,使用cronjob定期执行每个模块(从第一个模块的几分钟/小时到链中最后一个模块的几天,这需要聚合更多数据,因此需要等待更长的时间才能使用)。 运行一个模块(目前是一个java控制台应用程序),它在给定的日期时间窗口中检查数据库中新的、未处理的信息,并完成其工作

问题是:它是有效的,但是。。我需要扩展和维护它,这种方法开始显示出它的局限性

  • 我不喜欢依赖“投票”;这是一种浪费,因为以前模块的信息可能足以“告诉”链下游的其他模块他们需要的信息何时可用,并且他们可以继续
  • 这是“缓慢的”:由于我们必须确保数据已到达并由之前的模块处理,因此链下游的模块会延迟几天。因此,我们“停止”这些模块,直到我们确定我们拥有所有的数据。新的增加要求实时(不难,但“尽快”)计算某些指标。一个很好的例子就是这里发生的事情,所以,带着徽章!:)我需要得到一些真正相似的东西
  • 为了解决第二个问题,我将引入“部分”或“增量”计算:只要我有一组相关信息,我就处理它。然后,当一些其他链接信息到达时,我计算差异并相应地更新数据,但随后我还需要通知其他(依赖)模块

    问题 -1)哪种方法最好? -2)相关:哪种方式是“通知”其他模块(在我的例子中是java可执行文件)相关数据可用的最佳方式

    我可以看到三种方式:

    • 将其他“非数据”表添加到数据库中,每个模块在其中写入“嘿,我已经这样做了,它是可用的”。当cronjob启动另一个模块时,它读取表,决定他可以计算子集xxx,并执行该操作。等等
    • 使用消息队列,如ZeroMQ(或apachecamel,如@mjn建议的),而不是DB表
    • 使用键值存储,如Redis,而不是DB表
    编辑:我确信基于队列的方法是可行的,为了完整性,我添加了“表+轮询”选项,但现在我明白这只是一种干扰(显然,每个人都会回答“是的,使用队列,轮询是邪恶的”——这是正确的!)。因此,让我将问题的措辞改为: 使用MQ而不是像Redis这样的发布/订阅的键值存储有哪些优点/缺点?

    • 3) 有没有什么办法可以帮我彻底摆脱这些工作
    编辑:特别是,在可能的情况下,这意味着:在某些MQ和/或键值存储中是否有机制,允许我以“时间”发布消息?如“在1天内交付”?很明显,它具有持久性和“几乎一次”的交付保证

    • 4) 我是否应该将这个基于消息(事件?)的解决方案构建为一个集中式服务,在其中一个服务器上作为守护进程/服务运行它
    • 5) 我是否应该放弃按需启动订阅服务器的想法,让每个模块作为守护进程/服务连续运行
    • 6) 哪些是优点和缺点(可靠性、单点故障与资源使用和复杂性…)
    编辑:这是我最关心的一点:我想“队列”本身根据队列中的消息激活“模块”,类似于MSMQ激活这是个好主意吗?Java世界中有什么东西可以做到这一点吗?我是应该自己实现它(通过MQ还是通过Redis),还是应该将每个模块作为守护进程运行?(即使某些计算通常以突发方式进行,两个小时的处理后是两天的空闲?)

    注意:我不能使用重型容器/EJB(没有Glassfish或类似产品)

    编辑:骆驼对我来说似乎有点太重了。我在这里寻找一些真正轻松的东西,无论是在资源方面还是在开发的复杂性方面


    队列任务描述部分听起来像是基于“”的系统所做的事情

    A可以用常数表示

    from("seda:b").delay(1000).to("mock:result");
    
    或变量,例如消息头值

    from("seda:a").delay().header("MyDelay").to("mock:result");
    

    1> 我建议使用消息队列,根据您的需求选择队列,但对于大多数情况,我建议您选择基于协议JMS(活动mq)或AMQP(兔子mq)的队列,并在其上编写一个简单的包装器,或者使用spring->spring JMS或spring AMQP提供的包装器

    2> 您可以编写队列使用者,以便它们通知您的系统新消息到达,例如,在rabbit中,您可以实现MessageListener接口

     public class MyListener implements MessageListener {
         @Override
    public void onMessage(Message message) {
         /* Handle the message */        
    
        }
    }
    
    3> 如果像中一样使用异步使用者,则可以摆脱所有轮询和cron作业

    4> 取决于您的需求->如果有数百万事件/消息通过队列,则在集中服务上运行队列中间件