zoukankan      html  css  js  c++  java
  • Gearman实战第一弹:异步处理结算单

    昨天梦回jm,醒来之后看着窗外万里晴空,想大声喊一句:爷青回!
    我想起之前使用gearman的岁月。不知不觉也过了快5年,想总结一篇关于gearman的技术文章算是一种对青春的祭奠,再不写的话更少有phper用过这个强大的分布式任务分发框架,毕竟这个时代已经属于swoole。

    先讲一下Gearman,它是一款用C++编写的分布式任务分发框架,通过暴露API给使用方来完任务委托,在多台机器上负载均衡且并发地执行任务。特别是密集型计算,可以使用Gearman去异步地完成任务调度。

    Gearman的结构分成三个角色:
    Client: 客户端,可以是不同的编程语言,如php,java,python等.
    Job Server: 任务服务器,负责分派任务,不负责业务逻辑。
    worker: 执行任务的节点,可以是不同的编程语言实现,不一定和clent端的语言一样,如java,php, python等。

    整个流程图如下图所示:

    下一步开始安装gearman和相关扩展,这次我们还是使用php来作为编程语言。之前我写过一篇文章讲在服务器上安装gearman,这里只讲一下在macpro上如何安装gearman和php扩展。

    比起linux上面的编译安装,mac上安装很简单,使用brew命令如下:

    brew install gearman
    
    # 为了让上一步安装的gearman能直接在终端调用,需要先创建下面这个目录
    sudo mkdir /usr/local/sbin
    # 让当前用户成为gearman安装目录下的sbin的所有者
    sudo chown -R $(whoami) $(brew --prefix)/sbin
    
    # 把link指向刚才安装的gearman
    brew link gearman
    # 这一步很关键,让终端可以直接调用gearmand命令
    ln -s /usr/local/opt/gearman/sbin/gearmand /usr/local/bin
    
    

    先介绍一下背景:
    假设我们有一个场景,很多商家通过我们的结算平台进行天结算,然后结算单需要复杂的计算,然后结算完成后异步地把计算结果以附件excel的方式发送给用户。假设有十万商家,每天订单有上万每户,那么这是比较大的数据量,且都是在某个时间段开放结算,有并发的压力。

    这个时候用户(也就是商家)非常想快速完成结算并看到结果,对于处理过程的等待是非常低容忍度的,我们需要考虑可以利用多个worker异步去处理这些结算任务。

    首先编写worker端的代码:

    <?php
    
    $worker = new GearmanWorker();
    $worker->addServer('127.0.0.1', 4730); // 可以注册多个server,server可以在不同的机器上。
    // 非阻塞方式运行
    $worker->addOptions(GEARMAN_WORKER_NON_BLOCKING);
    
    $worker->addFunction("calculate", "calculatePayment");
    
    $worker->addFunction('send', "sendEmail");
    
    while($worker->work());
    // 计算结算单
    function calculatePayment($job) {
        $data = json_decode($job->workload());
    
        // 开始复杂的计算 todo
    
        return $data;
    
    }
    
    // 发送邮件
    function sendEmail($job) {
        // todo
    
        $data = $job->workload();
        send_email_with_attachment($data->email, $data->content);
        return true;
    }
    
    

    然后是编写客户端,命名为client.php,代码如下:

    <?php
    
    $client = new GearmanClient();
    
    $client->addServer();
    echo "start the calling";
    $paymentList = [['order_id' => '110112', 'product_id' => [2323,4455,4455], 'pay_money' => '4423.00'], [['order_id' => '110113', 'product_id' => [223,45,67], 'pay_money' => '1400.00']]];
    $data = $client->addTask('calculate', json_encode($paymentList));
    // 后台方式运行,因为毕竟只是发邮件
    $client->addTaskBackground("send", $data);
    
    echo "finish
    ";
    
    

    然后可以先把gearmand跑起来,也就是job server这一块,命令很简单:

    
    

    但是因为有可能任务执行失败或者gearmand服务因为各种原因挂掉,所以建议结合mysql做持久化,也就是把执行情况记录到mysql中,一旦出现问题down掉,重新运行的时候可以根据mysql中的执行记录从失败的记录开始重跑。

    为了做持久化,先创建用于持久化的数据库和表:

    
    CREATE DATABASE gearman;
     
    CREATE TABLE `gearman_queue` (
    `unique_key` varchar(64) NOT NULL,
    `function_name` varchar(255) NOT NULL,
    `priority` int(11) NOT NULL,
    `data` longblob NOT NULL,
    `when_to_run` int(11),
    PRIMARY KEY (`unique_key`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    

    运行gearmand的时候可以使用到mysql方式作为持久化,命令如下所示:

    gearmand -q mysql 
    --mysql-host=127.0.0.1 
    --mysql-port=3306 
    --mysql-user=mine 
    --mysql-password=xxxxx 
    --mysql-db=gearman 
    --mysql-table=gearman_queue
    

    然后可以把worker运行起来,可以多开几个终端,例如跑三个worker,命令如下:

    php /path/to/folder/worker.php
    

    然后再执行client去触发任务:

    php /path/to/folder/client.php
    

    剩下就交给gearman去分发任务了,worker开始并发地高效处理任务啦!

    当然我们也要考虑监控和管理job server,可以用shell去监听,也可以自己编写一个Gearman manager工具。这是后面可以聊的,到时候另开一篇文章吧。
    除此之外,其他我们对于worker部分完全可以考虑使用一些异构语言,如java或者golang,PHP只做客户端使用,有人已经编写了grpc去实现了。

    今年gearman的作者还在不断迭代,目前最新版本是1.1.19.1, 我收回之前的话,还是很多人在为这个框架付出,听说10年前左右雅虎已经大面积使用这个gearman框架来做新闻聚合了,当然jm也有用。

    gearman=swoole+任务分发,老骥伏枥,志在千里罢了。

  • 相关阅读:
    echo和重定向
    grep命令
    重温JSP学习笔记--JSP动作标签
    重温JSP学习笔记--El表达式
    重温JSP学习笔记--El函数库
    重温JSP学习笔记--JSTL标签库
    重温JSP学习笔记
    Android 用 camera2 API 自定义相机
    从零开始用 Flask 搭建一个网站(一)
    从零开始用 Flask 搭建一个网站(二)
  • 原文地址:https://www.cnblogs.com/freephp/p/13800111.html
Copyright © 2011-2022 走看看