PHP使用Redis+Gearman构建队列服务

PHP使用Redis+Gearman构建队列服务

PHP使用Redis+Gearman构建队列服务

队列的好处就不说了...

牛刀小试

  1. 创建client.php文件写入

    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    for($i=0;$i<100000;$i++){
      $id = uniqid();
      $action = ['cls' => 'TestJob', 'action' => 'handle', 'arg' => ['id' => $id]];
      $redis->lPush('queue', serialize($action));
    }

    往队列中写入10万条数据,等待服务器处理,在action变量中写入处理的类,函数,参数以便服务端进行相应处理

  2. 创建server.php文件写入

    require_once 'TestJob.php';
    
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $redis->set('i', 0);
    
    $is_start = false;
    $start_time = time();//记录开始时间
    
    //直接调用
    while (true) {
        $item = $redis->lPop('queue');//正常情况应该使用blPop没有数据,会阻塞等待(这里方便测试)
        if (!$item) {
            //没有数据时,如果已开始停止脚本,打印结果
            if ($is_start) {
                $end_time = time();
                var_dump($end_time - $start_time);
                var_dump($redis->get('i'));
                break;
            }
            continue;
        }
        $item = unserialize($item);
        $service = new $item['cls'];
        $service->$item['action']($item['arg']);
        $is_start = true;
    }

    不断循环从队列中取出一个值,反序列化数据,实例化对应类,调用对应函数

  3. 运行脚本(耗时29s)

    $ php index.php
    $ php server.php
  4. 效果 效果图

到这里,一个简单易用的redis服务就构建完成了,我们发现串行的处理大量队列,处理效率很低,下面我们使用gearman处理Job

进阶拓展

  1. 安装Gearman
    $ brew install gearman
  2. 安装php扩展
    $ brew install php56-gearman
  3. 检查Gearman是否安装成功
    $ php -r "print gearman_version();"
    1.1.12
  4. 启动Gearman服务

    $ brew services start gearman

    linux 使用gearmand -d

  5. 修改server.php

    //Gearman
    $gmClient = new \GearmanClient();
    $gmClient->addServers();
    while (true) {
        $item = $redis->lPop('queue');
        if (!$item) {
        //没有数据时,如果已开始停止脚本,打印结果
             if ($is_start) {
                 $end_time = time();
                var_dump($end_time - $start_time);
                break;
            }
             continue;
         }
        $item = unserialize($item);
        $service = new $item['cls'];
        $gmClient->doBackground('handle', serialize($item));//原来直接处理的,现在交给gearman worker
        $is_start = true;
    }
  6. 创建gearman_server.php文件,写入

    require_once 'TestJob.php';
    
    $gmWorker = new GearmanWorker();
    $gmWorker->addServers();
    $gmWorker->addFunction('handle', function (\GearmanJob $job) {
        $job->handle();
        $item = $job->workload();
        if (!empty($item)) {
            $item = unserialize($item);
            if (is_array($item)) {
                (new $item['cls']())->handle($item['arg']);
            }
        }
        $job->sendComplete('complete');
    });
    while ($gmWorker->work()) {
        if ($gmWorker->returnCode() != GEARMAN_SUCCESS) {
            echo "return_code: " . $gmWorker->returnCode() . "\n";
        }
    }
  7. 运行脚本(耗时16s)

    $ php index.php
    $ php gearman_server.php
    $ php server.php
  8. 效果 效果图

  9. 电脑配置

    电脑配置

  10. https://github.com/larry-666/redis_queue


Tags

Back to top