Java异步处理

Java异步处理,java,architecture,asynchronous,hazelcast,Java,Architecture,Asynchronous,Hazelcast,我目前正在开发一个使用异步处理分配的系统。信息的传输是使用队列完成的。因此,一个进程将把信息放入队列(并终止),另一个进程将接收并处理它。我的实现让我面临许多挑战,我对每个人解决这些问题的方法(从架构和库的角度)都很感兴趣 让我来画这幅画。假设您有三个过程: Process A -----> Process B | Process C <-----------| 流程A----->流程B | processc在我看来,您所问的问题类型是“

我目前正在开发一个使用异步处理分配的系统。信息的传输是使用队列完成的。因此,一个进程将把信息放入队列(并终止),另一个进程将接收并处理它。我的实现让我面临许多挑战,我对每个人解决这些问题的方法(从架构和库的角度)都很感兴趣

让我来画这幅画。假设您有三个过程:

Process A -----> Process B
                      |
Process C <-----------|
流程A----->流程B
|

processc在我看来,您所问的问题类型是“气味”,队列和异步处理可能不是适合您情况的最佳工具

1) 这违背了排队的目的。听起来你需要一个同步的请求-响应过程


2) 一般来说,进程C没有得到答复。它正在从队列中获取消息。如果队列中有一条消息,并且进程C已准备就绪,那么它将获取该消息。例如,进程C可以在收到消息后判断消息是否过时。

好的,队列的目的是使事情保持相当隔离

如果您没有被任何特定的技术所困扰,您可以使用数据库来处理队列

但首先,确保两个进程协调的一个简单机制是使用套接字。如果可行,只需让进程B在某个众所周知的端口上创建一个开放的套接字侦听器,进程A将连接到该套接字并监视它。如果进程B离开,进程A会知道,因为它们的套接字关闭了,它可以用它作为进程B出现问题的警报

对于B->C问题,有一个db表:

create table queue (
    id integer,
    payload varchar(100), // or whatever you can use to indicate a payload
    status varchar(1),
    updated timestamp
)
然后,进程A将其条目放入队列,当前时间和状态为“B”。B、 在队列上侦听:

select * from queue where status = 'B' order by updated
完成B后,它更新队列以将状态设置为“C”

同时,“C”正在使用以下命令轮询DB:

select * from queue where status = 'C' 
    or (status = 'B' and updated < (now - threshold) order by updated 
从状态为'C'的队列中选择*
或(状态='B'和更新<(现在-阈值)按更新的顺序
(阈值是您希望队列中的东西腐烂的时间长度)

最后,C将队列行更新为“D”表示已完成,或者删除它,或者您喜欢的任何内容

黑暗的一面是这里有一点竞争条件,C可能会在B刚启动时尝试抓住一个入口。你可能可以通过严格的隔离级别和一些锁定来度过这一关。简单地说:

select * from queue where status = 'C' 
    or (status = 'B' and updated < (now - threshold) order by updated 
FOR UPDATE
从状态为'C'的队列中选择*
或(状态='B'和更新<(现在-阈值)按更新的顺序
更新
还用于更新B的选择。这样,无论谁赢得选择比赛,都将获得排他锁


这将使您在实际功能方面走得相当远。

您期望异步(消息传递)设置的同步处理语义是不可能的。我在WebSphere MQ上工作过,通常当消费者死亡时,消息将永远保留在队列中(除非您设置了过期时间)。一旦队列到达其深度,后续消息将移动到死信队列。

我已使用类似的方法为视频转码作业创建排队和处理系统。其工作方式基本上是:

  • 进程A
    仲裁器Q
    发布“调度”消息,该消息将作业添加到其“等待”队列中
  • 进程B
    仲裁器Q
    请求下一个作业,该仲裁器将删除其“等待”队列中的下一个项目(受一些自定义调度逻辑的约束,以确保单个用户不能淹没转码请求并防止其他用户能够转码视频),并将其插入其“处理”中在将作业返回到
    进程B
    之前设置。当作业进入“处理”集中时,会加上时间戳
  • 过程B
    完成作业并将“完成”消息发布到
    仲裁器Q
    ,该消息将作业从“处理”集中删除,然后修改某些状态,以便
    过程C
    知道作业已完成
  • 仲裁器Q
    定期检查其“处理”集中的作业,并对任何已运行异常长时间的作业进行超时。
    进程A
    可以根据需要再次尝试将同一作业排队
  • 这是使用JMX实现的(JMS可能更合适,但我离题了)。
    进程A
    只是响应用户发起的代码转换请求的servlet线程。
    仲裁器Q
    是一个MBean单例(在服务器集群中的所有节点上持久化/复制),它接收“调度”和“完整”消息。其内部管理的“队列”"是简单的
    列表
    实例,当作业完成时,它会修改应用程序数据库中的一个值,以引用转码视频文件的URL。
    进程B
    是转码线程。它的任务只是请求一个作业,对其进行转码,然后在完成后报告。一次又一次,直到t结束ime.
    Process C
    是另一个用户/servlet线程。它将看到URL可用,并向用户提供下载链接


    在这种情况下,如果
    进程B
    死亡,那么作业将处于“等待”状态永远排队。然而,在实践中,这从未发生过。如果您的
    进程B
    没有运行/做它应该做的事情,那么我认为这表明
    进程B
    的部署/配置/实现中存在问题,而不是整个方法中的问题。

    我认为您的第一个问题已经解决了其他的海报对此做出了充分的回答

    关于第二个问题,根据应用程序使用的消息传递引擎,您可能会尝试执行什么操作。我知道这适用于IBM MQ。我已经看到使用网站执行此操作