V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
star7th
V2EX  ›  程序员

开源的任务队列服务 HTQ

  •  
  •   star7th · 2016-09-05 22:32:06 +08:00 · 3060 次点击
    这是一个创建于 3001 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一、什么是 HTQ

    先介绍下基本概念。

    我们在编写程序时,偶尔会遇到需要用到异步队列的情况。比如说,我发送一万封邮件,如果单纯使用一个 for 循环来发送,则执行时间要很长,要等很久才能发完,同时很容易导致阻塞、超时等问题。当邮件更多,比如一百万封的时候,问题会更加明显。这时最好的解决方案就是把这十万封邮件排队,一一发出去。这就是任务队列的概念。

    并且,我们并不需要等到十万封邮件都发送完毕后才在网站前台通知用户。我们可以把邮件一入队列,就通知用户。这样,用户等待的时间就不是漫长的“发十万封邮件”的时间,而是“把十万封邮件排队”的时间。因此能明显地缩短了用户等待时间。这就是异步的概念。

    HTQ ,全称 Http Task Queue ,是一个以 Http 方式执行异步任务的队列服务。你可以推送若干 url 进 HTQ 队列,HTQ 会以 Http GET 的方式访问这些 url 。如果 url 所在的脚本写上各种具体的任务操作,如发送邮件等,便可以实现异步操作了。 HTQ 使用 node.js 编写,可跟各种后台语言如 PHP 、 java 配合使用以增强异步处理能力。目前支持的队列类型有实时异步队列、定时异步队列、可变异步队列。

    如果你依然对 HTQ 陌生,则可往下看详细的应用场景以加深了解。

    二、应用场景

    1 、实时异步队列

    所谓实时,指的是把任务一推进队列就马上执行。一个典型的应用场景就是我们上面所说的发送邮件。邮件推送进任务队列,队列马上把它发出去。如果它推进队列后有其他邮件正在发送中,它则等待当前邮件发送完毕后才发送。

    除了发邮件,我们在发文章、发微博、发评论的时候都可以用得上 HTQ 的实时任务队列,尤其是数量非常大的时候。比如评论用户太多,如果一瞬间让服务器处理,服务器可能因为支撑不了太高的并发从而造成阻塞。这个时候就可以让评论们进入队列再一一处理。

    2 、定时异步队列

    定时,顾名思义,就是在特定的时间执行任务队列。这种队列服务可用于定时邮件、定时短信。需要说明的是,这里的定时,不一定是精准的定时。假如你设置了明天 12 点执行某个任务,那么,它在明天 12 点的时候将进入队列。假如队列中已经有任务在执行,那么它会等待到前面的任务完毕才执行。此时可能是 12 点 01 分钟才执行。

    3 、可变队列

    我们推送 10 个任务进队列,这 10 个队列会反复循环地执行,并且它们的执行快慢能够根据返回情况进行调整,这就是可变队列。比如,我们做扫描监控,会反复地执行“扫描”这个任务。我们希望,在有异常情况的时候,能加快扫描的速度以便更快速地发现问题;而在没有长期异常的情况能减慢一下扫描速度以节省机器资源。

    再举一个场景例子,通过 API 拉取微博新动态。我们网站上有 10 万绑定了新浪微博的用户,我们需要时常获取他们的最新动态以展示在我们的网站的用户主页上。 如果是采用定时获取动态的方式,那么,假设 1 分钟能获取 1 千个用户的动态(因为受 API 使用频率和网络等原因限制,我们获取不了太快。这里先假设一个数字),那么,获取完所有用户状态需要 100 分钟。对用户来说,他在微博更新动态后, 100 分钟后才显示到我们网站。这明显滞后太多。有没有办法加快点呢?此时可以使用 HTQ 的可变队列。可变队列会对长期没有更新动态的那部分不活跃用户进行减缓速度,减缓对他们微博的获取频率,同时加大对活跃用户的获取频率。这样,一个活跃用户更新微博后,可能 10 分钟就能同步到我们网站了。对于不活跃用户,可能获取时间会变长了些,但不要紧,我们愿意分配更多的资源去满足活跃用户的需求。

    使用可变队列,能让我们有所侧重地使用我们的资源,以减少浪费、增加利用率。

    三、安装和使用

    1 、安装

    首先安装好 node 环境和 redis 服务,请参考:http://nodejs.cn/download/http://redis.io/download

    clone 或下载代码:https://github.com/star7th/htq

    下载到你想要放置的目录,命令行进入该目录,执行命令:

    npm install 
    

    安装完毕后,执行以下命令启动:

    node htq.js 
    

    上面这种启动方式是临时运行的,关闭命令行窗口就会停止了。如果想一直在后台运行,则可:

    nohup node htq.js > ~/htq.log 2>&1 &
    

    如果想关闭退出,可运行:

    killall -9 node 
    

    2 、如何使用

    启动后, HTQ 默认监听本机的 5999 端口。你可以通过此端口访问 HTQ 的 APi ,以添加队列和任务。详细的 API 文档可看:http://www.showdoc.cc/htq?page_id=37198

    你可以根据 API 文档来在你的项目中调用 API 以新建任务。官方提供了一个 PHP 调用的 SDK (在 /PHPSDK 目录)。欢迎其他语言的开发者也将 HTQ 的 API 封装成其他语言的 SDK

    如果要修改默认端口以及默认的 redis 地址,可修改配置文件 config.json 。修改完毕需重启 HTQ 才能生效

    四、安全与容错

    1 、程序安全

    访问 HTQ 的 API 时需要填写简单的 token 认证,认证信息在配置文件 config.json 里定义。为了安全起见,你可以在下载代码将 token 设置为其他随机数。如果你已经启动了 HTQ ,则需要关闭后再重启才能让新配置生效。

    如果你担心直接执行 url 会带来安全隐患,怕自己暴露的 url 被外部访问,那你可以在推送进 HTQ 的 url 上带参数签名校验。然后在 url 触发的任务脚步里检验签名即可。

    2 、数据安全

    HTQ 使用 redis 来储存队列。 Redis 自身带有持久化功能。如另外需要对数据进行备份,则备份 redis 即可,不用在业务中实现数据备份。

    3 、正确性

    HTQ 能执行 url ,但不能保证业务上的正确。比如说 HTQ 确实是触发了发文章的脚本,然而这个脚步可能自身因为网络原因发布文章失败。此时应该在业务层做好相应的容错处理,比如让该 url 重新入队列。

    14 条回复    2016-09-07 15:52:46 +08:00
    cxbig
        1
    cxbig  
       2016-09-05 22:48:12 +08:00
    和 AWS 的 SQS 相比有何优势?
    majinjing3
        2
    majinjing3  
       2016-09-05 22:54:12 +08:00 via Android
    关注下~改天试试效果如何
    wph95
        3
    wph95  
       2016-09-06 00:14:29 +08:00 via iPhone
    1. 有 long pull 吗
    2. 容错依赖 redis …… 那还是很有概率丢数据
    ………
    66CCFF
        4
    66CCFF  
       2016-09-06 04:33:13 +08:00
    这轮子是方的系列
    ecloud
        5
    ecloud  
       2016-09-06 07:50:22 +08:00 via iPhone
    为什么不用现成的 MQ ?
    ixinshang
        6
    ixinshang  
       2016-09-06 08:09:16 +08:00 via Android
    博主好第七星尘
    breeswish
        7
    breeswish  
       2016-09-06 09:06:53 +08:00
    和 RabbitMQ 相比有优势吗
    star7th
        8
    star7th  
    OP
       2016-09-06 14:38:51 +08:00
    @cxbig 其实消息队列和任务队列的应用场景有些区别的。 HTQ 解决的是 http 的方式执行任务这种场景,它并不是为消息队列而生。更具体点的话,它还支持定时队列和可变队列,这是普通的消息队列里没有的。详细在文中的应用场景有介绍到。
    star7th
        9
    star7th  
    OP
       2016-09-06 14:39:27 +08:00
    @ecloud @breeswish 其实消息队列和任务队列的应用场景有些区别的。 HTQ 解决的是 http 的方式执行任务这种场景,它并不是为消息队列而生。更具体点的话,它还支持定时队列和可变队列,这是普通的消息队列里没有的。详细在文中的应用场景有介绍到。
    star7th
        10
    star7th  
    OP
       2016-09-06 14:43:45 +08:00
    @wph95 不支持 long pull 呢。 HTQ 并不是用于消息队列的场景的,解决的是 http 的方式执行任务这种场景。至于容错,是有可为空间,可以完善些。鉴于当前 HTQ 刚出来,而 redis 的持久化能力其实不错了,所以还没有做到这种更细微的容错。
    keller
        11
    keller  
       2016-09-06 15:28:02 +08:00
    lz 支持周期性定时任务吗?
    star7th
        12
    star7th  
    OP
       2016-09-06 15:33:58 +08:00
    @keller 当初不做周期性定时任务是因为觉得它跟 crontab 没有区别,做出来没意思。所以不做。但如果你要用也可以的。先推送一个定时任务进队列。在脚本每次执行完的时候把下一次执行的定时任务又再推进队列。
    breeswish
        13
    breeswish  
       2016-09-07 09:39:05 +08:00
    @star7th 谢谢解释,仔细看了下应用场景,确实挺有用的, mark :P 加油
    star7th
        14
    star7th  
    OP
       2016-09-07 15:52:46 +08:00
    @breeswish 我突然想到,会不会是文章写得太详细了导致显得太长。也许我应该首先把可变队列当作亮点在前文写,这样就能明显看出与消息队列的区别了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2821 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 09:27 · PVG 17:27 · LAX 01:27 · JFK 04:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.