【问题标题】:redis pub sub and/or lists to implement a data collectorredis pub sub 和/或列表来实现数据收集器
【发布时间】:2016-09-28 13:13:36
【问题描述】:

我正在开发一个模块,该模块需要按计划从第三方系统收集数据,比如每 5 分钟一次。

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

我从使用一个简单的 redis 队列开始,所有来自 UI 的启动请求都发布到队列中,模块充当工作人员,拿起作业并运行它们。

问题是我们需要在 1 分钟内完成一个数据收集周期,如果有 100 个作业,如果我们连续进行,我们将花费一分钟以上。数据收集需要按计划进行。所以 UI 说每 5 分钟运行一次数据收集,直到我说停止!

因此,我们添加了另一个可以开始减轻负载的工作人员。

我的问题是:如何在不保持状态(调度线程执行器)的情况下实现常规调度?

我是不是想得太多了,能不能用更简单的方式来完成?

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

【问题讨论】:

    标签: java redis queue


    【解决方案1】:

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

    Beanstalkd 与 Redis 有很多共同点:易于部署、简单、轻便、快速、默认在内存中、通过简单的文本协议完成通信、很多 clients in various languages...一个数据库。您可以动态添加或删除工作人员,无需在 beanstalkd 方面进行任何配置。

    您将作业放入“管”(队列的 beanstalkd 名称)中,然后工作人员可以保留它们——一次一个。一旦它保留了一个工作,一个工作人员就有一个最大的时间来完成它(称为 TTR —Time To Run),否则工作会被 beanstalkd 释放,再次放入管中,因此可能由另一个工作人员处理。

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

    如果我对您的问题的理解是正确的,UI 租户可以创建具有正常优先级的作业来开始数据收集,并将它们放入一个独特的管中。一个或多个工人将从该管中“保留”(接受)一项工作,对其进行处理,删除它以通知 beanstalkd 它已完成,然后保留另一个工作,等等。

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

    (此架构的来源:beantalkd 的协议文档)

    对于一个每 5 分钟重复处理一次的作业,没有任何调度器,你可以说每次工作人员消费一个作业时,它都会创建一个新作业,并在将其放入时使用 beanstalkd 的“延迟放置”功能管子。因此,只有在延迟到期(在您的情况下为 5 分钟)时,才会将作业呈现给工作人员。

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

    我对您的问题的了解和理解显然有限,但您当然可以提炼这些想法来解决您的确切问题。

    【讨论】:

    • Beenstalkd 是一个我可以使用的作业队列,但据我所知,它最后一次更新是在 2014 年。我去看看最近的东西。坚持使用 redis 的唯一原因是我们已经在使用它,我不想添加另一个组件。
    • 它不会进化,因为它不需要它。它稳定、简单,并打算保持这种状态。我是 Redis 的忠实粉丝,Beanstalk 是我比较 Redis 的产品。但我理解你的担忧。
    【解决方案2】:

    您的任务可以通过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 * * * ?"));
    

    您可以直接在您的应用程序中运行 worker 或在独立的 Redisson Node 中运行它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 2011-10-17
      • 1970-01-01
      • 2012-04-27
      • 1970-01-01
      • 2015-11-09
      相关资源
      最近更新 更多