MemQ 实现异步任务

作者: 尽情的嘲笑我吧 | 来源:发表于2017-12-19 15:41 被阅读25次
"MemQ异步任务"

这几天在做推送相关的任务的时候发现了一段神奇的代码。

$pushmsg = new NormalPushMsg($userid, $content, $clickurl,"");
PushService::getInstance()->sendPushToMemq($pushmsg);

一开始的时候我还纳闷,为什么不直接发呢,走这么大一圈子弯路到底是为了啥,后来想了想,发送push动辄几十上百万的用户,会是一个很耗时的操作。短时间会对服务器造成不小的压力。而通过memq这样一种曲线救国的套路,倒也还是一个不错的方法。

下面就自己动手,也来实现一下这样的功能。

准备

总用量 16
-rw-r--r-- 1 root root  82 12月 19 14:15 config.ini
-rw-r--r-- 1 root root 339 12月 19 14:36 publish_tasks.php
-rw-r--r-- 1 root root 387 12月 19 14:38 runjobs_background.php
-rw-r--r-- 1 root root 176 12月 19 14:13 worker.php

config.ini

内容格式大概可以是下面的形式。

queuename = default
queueip = 192.168.1.1
queueport = 22201
classname = Worker

下面来讲讲每个参数对应的含义。

  • queuename 是我们要进行存放的队列的名称
  • queueip 即会在那台主机上执行对应的任务
  • queueport 对应主机上memcache的端口
  • classname 通过PHP的哪个类来执行对应的“异步”方法。

确切的来讲,对公司而言queueip和queueport是必须的,因为你会管理很多的主机,如果不进行限制,异步任务变多的时候,那就是一个灾难。但是对于本次试验而言,就没什么必要了。

worker.php

这个文件就是我们会具体调用的类文件,代码可以根据具体的业务需求而定。我这里只是演示一下,就随便写了。

<?php
class Worker {

    public function __construct() {
    }
    public function saveToLocal($msg="default data") {
        LiveLog("./worker.log", $msg);
    }
}

这个类的名称和上面的config.ini文件的classname保持一致就好了。否则会出现load错误的问题。

publish_tasks.php

按照一开始描述的,这个文件起到一个发布任务的作用。好比开启了一个给XXX用户群发送push召回的任务。这里还是简单的写一下。

<?php
header("Content-Type:text/html;charset=UTF-8");
require "/home/wwwroot/api.newtv.com/common/common.inc.php";

$memq = new useLiveMemQueue();
$key = "my:memq:test";
$msg = "爱过,一个人的春夏秋冬!";
$result = $memq->cache($key, "saveToLocal('$msg')");
var_dump($result);

这里面有一些公司封装好的API,比如useLiveMemQueue类以及内部对应的cache方法。涉及到公司隐私性,就不再粘贴了。但是这都是对memcache的简单的封装,你自己花一点点时间也能写得出来的。

runjobs_background.php

任务已经被发布到了memq相应的队列中了,接下来就是要去消费它,否则很有可能导致服务器内存吃紧,那你的手机报警就哐哐的响了吧。

<?php
header("Content-Type:text/html;charset=UTF-8");
require "/home/wwwroot/api.newtv.com/common/common.inc.php";
require __DIR__."/worker.php";

$executor = null;
$memq = new useLiveMemQueue();
$method = trim($memq->get("my:memq:test"));
$classname = "Worker";
$executor = new $classname();

$execstr = "\$executor->$method".";";

$result = eval($execstr);
var_dump($result);

具体的原理,看完代码应该就明白了。其中最关键的就是PHP这门动态语言的优势。否则要使用Java这种编译性语言的话,还需要一套相应的反射机制了。

定时任务

一般来说,我们会写一个crontab脚本来定期的去“消费”memq中的“异步”任务,比如针对上面的实验,我们就可以写这样的一个crontab。

*/10 * * * * cd /home/wwwroot/workspace/mars/background/ && php runjobs_background.php 2>&1

每10分钟执行一次,相应的队列就会被消费掉了。但是这个10分钟只是一个频率。因为我们要进行消费的任务量会很大,10分钟内根本跑不完,在第二个10分钟的时候cron会再次开启一个进程,来进行消费。以此类推,就有可能会出现多个进程来消费相同的任务。

这个只要在不影响服务器性能的情况下,是没什么影响的,了解这么个情况就可以了。

验证结果

简单验证

好了,crontab部署后的10分钟已经到了,下面就来看看有没有生成


底层API

对应的worker.log文件吧。


成功生成了日志文件
“异步”运行结果

大规模测试

刚才只是在memq里面存放了一条“异步”任务,下面我们可以来试试多放点任务来试试。比如我们循环1000次cache操作,相当于在队列中存放了1000个待消费的任务。经过消费后,得到的结果如下。


查看worker.log结果

总结

到此,本次试验就结束了。相比较于自己随意的写代码,公司的代码库更具有实际意义,很多工程上的思维是学校的老师教不了的。多实践下,才能明白自身的不足之处。

这里使用的是PHP,所以在runjobs_background.php中执行起来才会很方便。如果使用其他的动态(解释性)语言,也会有如此感受。当然使用Java的话,就需要再写一个反射的工具类,多了一步,但也还是很方便的。

相关文章

  • MemQ 实现异步任务

    这几天在做推送相关的任务的时候发现了一段神奇的代码。 一开始的时候我还纳闷,为什么不直接发呢,走这么大一圈子弯路到...

  • Celery+Redis实现异步任务(2)

    相关: Celery-详解Celery+Redis实现异步任务(1)Celery+Redis实现异步任务(2)Ce...

  • Celery+Redis实现异步任务(3)

    相关: Celery-详解Celery+Redis实现异步任务(1)Celery+Redis实现异步任务(2)Ce...

  • 自定义FutureTask实现

    FutureTask FutureTask是Future的实现,用来异步任务的获取结果,可以启动和取消异步任务,查...

  • PHP实现异步任务

    在实际的应用开发中经常都会碰到碰到一些相对比较耗时的任务需要处理,而用户也不能等到这些耗时的任务结束后才收到响应,...

  • flutter之---Future的正确用法

    在flutter中经常会用到异步任务,dart中异步任务异步处理是用Future来处理,那么如何实现用Future...

  • flutter Future

    在flutter中经常会用到异步任务,dart中异步任务异步处理是用Future来处理,那么如何实现用Future...

  • CompletionService 源码解析

    CompletionService的主要作用是:按照异步任务的完成顺序,逐个获取到已经完成的异步任务。主要实现是在...

  • Spring Boot中如何配置线程池拒绝策略,妥善处理好溢出的

    通过之前三篇关于Spring Boot异步任务实现的博文,我们分别学会了用@Async创建异步任务[https:/...

  • Spring Boot与任务

    异步任务、定时任务、邮件任务 一、异步任务在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是...

网友评论

    本文标题:MemQ 实现异步任务

    本文链接:https://www.haomeiwen.com/subject/pknbwxtx.html