2016-09-28 48 views
0

我正在研究一个模块,需要按照计划从第三方系统收集数据,例如每5分钟说一次。redis pub sub和/或列表来实现数据收集器

启动数据收集的触发器来自多租户用户界面。因此,10个租户可以告诉这个模块同时开始收集数据。

我通过使用简单的redis队列开始,所有来自UI的启动请求都发布到队列中,模块充当工作者,提取作业并贯穿它们。

问题是我们需要完成一个周期的数据收集,比如说1分钟,如果有100个工作,如果我们连续进行,我们将花费一分多钟。数据收集需要按照时间表进行。所以UI说每5分钟运行一次数据收集,直到我说停止!

因此,我们添加了另一个可以开始卸载一些负载的工人。

我的问题是:如何在不保持状态(预定线程执行程序)的情况下实现常规计划?

我是不是在想这个问题,可以用更简单的方法来完成?

我的设计现在有一种cron工作,每隔1分钟从数据库读取数据收集请求,然后将它们放在工作人员从中选择它的队列中。

回答

1

在这种情况下,使用beanstalkd可能是比使用Redis更好的选择。

Beanstalkd与Redis有许多共同点:默认情况下,内存容易部署,简单,轻便,快速,通过简单的文本协议完成通信,很多clients in various languages ......但它专用于任务管理,它不是数据库。您可以动态地添加或删除工作人员,而无需在beanstalkd方面进行任何配置。

您将作业放入“管”(beanstalkd名称为队列),然后工人可以一次保留一个。一旦它保留了一份工作,工人就有最大的时间来完成它(称为TTR-运行时间),否则工作由beanstalkd释放,再次放入管中,并且可能由另一个工作人员处理。

工作只是一个字符串;例如它可能是一个序列化的Json,描述要执行的任务。

如果我对您的问题的理解是正确的,那么UI租户可以创建具有正常优先级的作业来开始数据收集,并将它们放入唯一的管中。一个或几个工人会从这个管子里“保留”(取得)一份工作,处理它,删除它以通知它已完成,然后保留另一份工作,等等。

put reserve delete -----> [READY] ---------> [RESERVED] --------> *poof*

(源出于此模式:beanstalkd的协议文档)

对于一个要处理的作业上每隔5分钟内没有任何计划,可以说每一个工人耗费的工作时间,它会创建一个新的,并且使用豆柄放入管时的“延迟放置”功能。因此,只有在延迟时间到期时(工作5分钟),工作才会呈现给工作人员。

当用户界面想要取消剩余的工作时,只需从管中选取并删除所有工作。或者,如果您希望工作人员删除它们,用户界面可以将优先级高于数据收集作业的取消作业(将其视为消息)放入管中。假设您在专门收集数据的另一个线程中收听,您也可以使用另一个管道。

我的知识和对你的问题的理解显然是有限的,但你当然可以改进这些想法来解决你的确切问题。

+0

Beenstalkd是我可以使用的工作队列,但据我所知,它在2014年最后更新。我会去看看更近的事情。只有坚持使用redis的理由是我们已经在使用它,并且我不想添加其他组件。 – darkstar

+0

它不会演变,因为它不需要它。它很稳定,简单,并且打算保持那样。我是Redis的忠实粉丝,Beanstalk是我与Redis相比的产品。但我明白你的顾虑。 –

0

您的任务可以使用Redisson完成。它提供由Redis支持的SchedulerService。它也支持cron表达式。用例:

public class RunnableTask implements Runnable { 

    @RInject 
    private RedissonClient redissonClient; 

    private Object param; 

    public RunnableTask() { 
    } 

    public RunnableTask(Object param) { 
     this.param = param; 
    } 

    @Override 
    public void run() { 
     // ... 
    } 

} 

RScheduledExecutorService executorService = redisson.getExecutorService("myExecutor"); 
schedule(new RunnableTask(), CronSchedule.of("10 0/5 * * * ?")); 

你可以在你的应用程序中运行工人的权利或独立Redisson Node运行它。