Jquery中文网 www.jquerycn.cn
Jquery中文网 >  脚本编程  >  php  >  正文 高性能web站点分布式处理系统gearman应用实例

高性能web站点分布式处理系统gearman应用实例

发布时间:2018-09-05   编辑:www.jquerycn.cn
jquery中文网为您提供高性能web站点分布式处理系统gearman应用实例等资源,欢迎您收藏本站,我们将为您提供最新的高性能web站点分布式处理系统gearman应用实例资源
Gearman是一个用来把工作委派给其他机器、分布式的调用更适合做某项工作的机器、并发的做某项工作在多个调用间做负载均衡、或用来在调用其它语言的函数的系统。

一. 场景分析

业务服务压力比较大,想把一些占用资源的功能异步到远程处理,比如记录业务日志,文件加密,文件分发到其他文件服务器节点上,检查文件服务器是否已同步,对用户上传的图片进行剪裁生成多份缩略图,视频转换,静态内容生成,清除缓存等等,这些请求耗时长,占用系统资源大,影响业务正常访问。这些问题会经常遇到的,如果这些任务都在用户请求过程中完成,服务器撑不撑得住暂不考虑,单凭用户体验角度考虑来说,那是难以忍受的。

二. 解决之道

对于这种需求,我们可以通过分布式计算,对任务进行拆分,转移到多台服务器上进行异步或同步处理。分布式消息队列有多种实现方式如rabbitmq、gearman等。 在这里主要说gearman—分布式处理系统。gearman由三部分组成:Job server,worker server,client server。 任务服务器job server运行这gearmand进程,来负责处理应用的远程调用请求,并且维护计算任务;工作服务器worker server负责向job server注册函数等待领取任务并执行实际的计算,然后将结果返回给job server;客户端client server提供gearman client API给应用程序调用,API支持多种语言如C、php、perl、python、mysql udf、java、ruby、go等等,主要是向job server添加任务,

流程图如下:

web架构

客户端client server向gearman添加任务时,有三种模式:

1. 同步顺序处理 相当于消息队列,先进先出。
2. 同步并行处理 这种模式会阻塞后面的运行,将互不依赖的任务并行处理,大大缩短整体处理时间。
3. 异步后台处理 将耗时任务交给后台处理,不阻塞当前进程。

三. 应用实例

需要安装的模块有Mail::SendEasy、Gearman::Worker、Gearman::Client、JSON。

# perl -MCPAN -e 'install Mail::SendEasy Gearman::Worker Gearman::Client JSON'

或通过cpanm来安装

在使用异步处理之前,当我们要发送邮件时,会直接这么写,代码如下:

<table width="620" align="center" border="0" cellpadding="1" cellspacing="1" style="background:#FB7"> <tr> <td width="464" height="27" bgcolor="#FFE7CE"> 代码如下</td> <td width="109" align="center" bgcolor="#FFE7CE" style="cursor:pointer;" onclick="doCopy('copy8193')">复制代码</td> </tr> <tr> <td height="auto" colspan="2" valign="top" bgcolor="#FFFFFF" style="padding:10px;" class="copyclass" id=copy8193>use strict;
use Mail::SendEasy ;
my $mail = new Mail::SendEasy(
    smtp => 'smtp.ttlsa.com' ,
    user => 'service@ttlsa.com' ,
    pass => 'QQ_qun:39514058',
);
 
my $status = $mail->send(
    from    => 'service@ttlsa.com' ,
    from_title => $mail_title ,
    to      => $mail_to ,
    subject => $mail_subject ,
    msg     => $mail_msg ,
    html    => "<b>$mail_msg</b>" ,
);
if (!$status) { print $mail->error ;}</td></tr></table>



这存在一个问题, 会长期阻塞在send函数,而无限制等待下去, 直到超时,很可能会拖垮服务器的。我们可以使用gearman,来改变这种发送邮件的方式。第一步,创建一个worker实例SENDMAIL,并向job server注册,等待接收任务并执行发送邮件的操作。第二步,客户端只需要将发送邮件的任务丢给job server便退出,没你什么事了。上代码:

<table width="620" align="center" border="0" cellpadding="1" cellspacing="1" style="background:#FB7"> <tr> <td width="464" height="27" bgcolor="#FFE7CE"> 代码如下</td> <td width="109" align="center" bgcolor="#FFE7CE" style="cursor:pointer;" onclick="doCopy('copy9136')">复制代码</td> </tr> <tr> <td height="auto" colspan="2" valign="top" bgcolor="#FFFFFF" style="padding:10px;" class="copyclass" id=copy9136># vim work_SENDMAIL.pl
 
use strict;
use Mail::SendEasy ;
use Gearman::Worker;
use JSON;
use Data::Dumper;
 
my $gearman_server='127.0.0.1:4730';
 
my $worker=new Gearman::Worker;
$worker->job_servers($gearman_server);
$worker->register_function(SENDMAIL=>\&sendmail);
$worker->work while 1;
 
sub sendmail{
    my $job=shift;
    my $param=$job->arg;
    my $json = JSON->new->allow_nonref;
    my $hash_ref=$json->decode($param);
    my $addr=$hash_ref->{'email'};
    my $subject=$hash_ref->{'subject'};
    my $msg=$hash_ref->{'msg'};
 
    my $mail = new Mail::SendEasy(
        smtp => 'smtp.ttlsa.com' ,
        user => 'service@ttlsa.com' ,
        pass => 'QQ_qun:39514058',
    );
 
    my $status = $mail->send(
        from    => 'service@ttlsa.com' ,
        from_title => $subject ,
        to      => $addr ,
        subject => $subject ,
        msg     => $msg ,
        html    => "<b>$msg</b>" ,
    );
    if (!$status) { print $mail->error ;}
}

# vim gearman_client.pl
use strict;
use Gearman::Client;
use JSON;
 
my $gearman_server="127.0.0.1:4730";
my $worker='SENDMAIL';
 
my $data={};
$data->{'subject'} = "www.ttlsa.com --- Operation & Maintenance of Time To Live";
$data->{'msg'} = "Date: gettime()
$data->{'email'} = '710117291@qq.com';
my $json = JSON->new->allow_nonref;
my $param=$json->encode($data);
gearman_add_job($gearman_server,$worker,$param,2);
 
sub gearman_add_job {
    my $server=shift;
    my $function_name=shift;
    my $function_param=shift;
    my $level=shift or 1;
 
    my $gearman_client = Gearman::Client->new;
    $gearman_client->job_servers($server);
    if($level == 1){
        my $result = $gearman_client->do_task($function_name,\$function_param,{});
    }
    elsif($level == 2){
        my $result = $gearman_client->dispatch_background($function_name, \$function_param,{});
    }
}
 
sub gettime {
    my @time=(localtime)[5,4,3,2,1,0];
    $time[0] =1900;
    $time[1] =1;
    return sprintf("u-u-u u:u:u",@time);
}</td></tr></table>



完成上面的改造不要认为解决了发送邮件会长期阻塞在send函数,而无限制等待下去的问题了。这其实只是解决了一部分,还有一个问题需要考虑进去,既然采用了异步方式,那么应用程序是不知道邮件是否发送成功的,因此需要记录任务执行的结果,可以将结果写入数据库,定期的对发送失败的邮件进行再次发送,或写个异常处理的worker,捕获发送邮件异常,进行多次尝试发送。

这种方案是我在捕获数据库备份过程中失败时,发邮件报警的应用。

通过这样的异步任务处理,可以很好的解决前面场景提到的问题,完全取决于如何应用gearman了。如有更好的应用可以相互交流。

您可能感兴趣的文章:
高性能web站点分布式处理系统gearman应用实例
建站用php还是java
基于.Net Framework的N层分布式应用开发
python使用哪种数据库
php和java是什么?
php除了网站能做什么
畅谈HTML5 到底是什么?
php高并发网站是什么意思
Django是什么?一文读懂Django框架
django怎么处理高并发

[关闭]