Overview

Bastion4这个项目经过我们实验验证和安全考虑,决定舍弃kafka而转用gearman这个消息队列框架,具体分析将在后续文章中给出,这里只记录gearman相关的安装。

1.下载安装gearman

最新版的gearmangearmand-1.1.12。我们执行下面几步,先将其下载到本地主文件夹,并解压缩。

sudo apt-get update
wget https://launchpad.net/gearmand/1.2/1.1.12/+download/gearmand-1.1.12.tar.gz
tar zxvf gearmand-1.1.12.tar.gz
cd gearmand-1.1.12/

进入gearmand-1.1.12文件夹后,如果直接运行

./configure

就会报缺少如下几个依赖包错误:

configure: error: could not find boost
configure: error: Could not find a version of the library
configure: error: could not find gperf
configure: error: Unable to find libevent
configure: error: Unable to find libuuid

所以,我们先将这些依赖都安装好:

sudo apt-get install libboost-dev
sudo apt-get install libboost-all-dev
sudo apt-get install gperf
sudo apt-get install libevent-dev
sudo apt-get install uuid-dev

安装好之后,如果没有错误,仍在gearmand-1.1.12文件夹下运行下面两条命令,编译时间比较长:

sudo make
sudo make install

这个过程中如果出现了错误,就运行下面的命令清除一下之前编译产生的可执行文件以及object文件(即扩展名为o的文件):

sudo make clean

继续重新安装编译:

./configure
sudo make
sudo make install

没有错误的话,就安装gearmanjob server

sudo apt-get install gearman-job-server

安装好以后,运行一下gearman:

gearman

会提示错误:

gearman: error while loading shared libraries: libgearman.so.8: cannot open shared object file: No such file or directory

这表示找不到libgearman.so.8所在的目录。这时我们打开/etc/ld.so.conf文件:

sudo vim /etc/ld.so.conf

添加一句话:

include /usr/local/lib

保存退出,并执行下面这句:

sudo /sbin/ldconfig

这样就不会出错了。
启动一下job server

gearmand -d

报错如下:

gearmand: Could not open log file "/usr/local/var/log/gearmand.log", from "/home/young/gearmand-1.1.12", switching to stderr. (No such file or directory)

我们这样解决:在/usr/local/下面新建var子目录,进去,新建log子目录,再进去,新建文件gearmand.log。这样就没有问题了。
sudo权限运行下面的命令:

sudo gearmand -d -L 127.0.0.1 -p 4730

-d表示daemon,在后台运行;
-L表示监听的ip,默认是localhost
-p表示监听的端口号port,默认是4730

这样gearmanubuntu14.04上面就安装成功了。

2.安装perl扩展包

perl端需要3个扩展包:

Gearman::Server
Gearman::Client
Gearman::Worker

可以用之前Chris的博客BioPerl(一):安装BioPerl中介绍的方法,先安装好CPAN
之后,用sudo权限打开CPAN

sudo cpan

然后依次安装3个扩展包:

install Gearman::Server
install Gearman::Client
install Gearman::Worker

都安装后之后,可以重启一下机器。
启动之后,用如下命令观察4730端口,查看gearmanjob server是否已经启动(gearmand -d这条命令是否生效):

sudo lsof -i:4730

如果不加sudo是看不到的,所以linux命令建议都要加上sudo

可以看到:

COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand 576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)
gearmand 576 gearman   10u  IPv6  12862      0t0  TCP *:4730 (LISTEN)

服务器端可能会只显示

COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand 576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)

可见这个server是开机启动的。

3.运行测试perl脚本

client.pl将消息发送到server,相当于生产者;
worker.pl来处理这些消息,并把结果返回给client.pl
相当于消费者。我们观察输出即可。
client.pl代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use Gearman::Client;
use Storable; 
use Storable qw(freeze);
use Storable qw(thaw);
use IO::All;

# fork this process
my $pid = fork();
if ($pid == 0)
{
    # do this in the child
    print "start new client \n";
    my $client = Gearman::Client->new;
    print "finish new client \n";
    print "start job_servers \n";
    $client->job_servers('127.0.0.1',4730);
    print "finish job_servers \n";
    # 设置异步任务
    print "start new_task_set \n";
    my $tasks = $client->new_task_set; 
    print "finish new_task_set \n";
    print "start add_task \n";
    #handle database
    my @rows=('hello','byebye');
    $tasks->add_task(
        # 开始任务,多个参数
        showMessage => freeze(\@rows), 
        # 注册回调函数 
        { on_complete => \&complete },  
    );  
    print "finish add_task \n";
    print "start wait \n";
    # 等待任务结束
    $tasks->wait;
    print "finish wait \n";
    exit;
}

print "The background task will be finished shortly.\n";
 
sub complete{   
    my $ret = ${ $_[0] };
    #io("complete.txt")->print($ret);
    print $ret, "\n";
} 
 

worker.pl代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use Gearman::Worker;
use Storable qw(thaw);
use Storable qw(freeze);

 print "start new worker \n";
my $worker = Gearman::Worker->new;
print "finish new worker \n";
print "start job_servers \n";
$worker->job_servers('127.0.0.1',4730);
print "finish job_servers \n";
# Worker 注册可以使用的功能
print "start register_function \n";
$worker->register_function( showMessage => \&showMessage );  
 print "finish register_function \n";
# 等待连接的任务
print "start work \n";

$worker->work while 1;  
print "finish work \n";
sub showMessage{
    my @row=@{ thaw($_[0]->arg) };

    my $job = \@row;
    print "\n";
    print "$row[0] \n";
    print "$row[1] \n";   
    print "start sleep \n";
    my $date = &getTime();  
    print  $date->{date}," ",$date->{hour},":",$date->{minute},":",$date->{second};
    print "\n";
    sleep(10);
    print "finish sleep \n";
    $date = &getTime();  
    print  $date->{date}," ",$date->{hour},":",$date->{minute},":",$date->{second};
    print "\n";

    my $ret = "hello world";
    return $ret;
}

sub getTime
{
    my $time = shift || time();
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);

    $year += 1900;
    $mon ++;

    $min  = '0'.$min  if length($min)  < 2;
    $sec  = '0'.$sec  if length($sec)  < 2;
    $mon  = '0'.$mon  if length($mon)  < 2;
    $mday = '0'.$mday if length($mday) < 2;
    $hour = '0'.$hour if length($hour) < 2;
    
    my $weekday = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$wday];

    return { 'second' => $sec,
             'minute' => $min,
             'hour'   => $hour,
             'day'    => $mday,
             'month'  => $mon,
             'year'   => $year,
             'weekNo' => $wday,
             'wday'   => $weekday,
             'yday'   => $yday,
             'date'   => "$year-$mon-$mday"
          };
}

我们先运行worker.pl

sudo perl worker.pl

再查看4730端口:

sudo lsof -i:4730

发现多了两个占用:

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand  576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   10u  IPv6  12862      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   33u  IPv4 191760      0t0  TCP localhost:4730->localhost:37151 (ESTABLISHED)
perl     4508    root    3u  IPv4 192605      0t0  TCP localhost:37151->localhost:4730 (ESTABLISHED)

再运行多个client.pl

sudo perl client.pl

每启动一个client.pl就会多两个端口占用。

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand  576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   10u  IPv6  12862      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   33u  IPv4 191760      0t0  TCP localhost:4730->localhost:37151 (ESTABLISHED)
gearmand  576 gearman   34u  IPv4 215493      0t0  TCP localhost:4730->localhost:37189 (ESTABLISHED)
perl     4508    root    3u  IPv4 192605      0t0  TCP localhost:37151->localhost:4730 (ESTABLISHED)
perl     4709    root    3u  IPv4 214688      0t0  TCP localhost:37189->localhost:4730 (ESTABLISHED)

每运行一次worker.pl表示启动一个新的消费者。如果只启动一个消费者,而启动多个生产者,就可以很好地观察到“排队”效果了:一定是一个任务执行完成之后才会开始处理另一个任务。
这样gearmanperl扩展包的安装使用就结束了。

这篇文章主要参考了如下几篇文章:

Gearman Job Server
Gearman
使用 Gearman 实现分布式处理
Gearman 安装使用 以及 问题处理
Ubuntu下Gearman安装搭建