写程序这个事情,其实规划最麻烦。比方我其实并没留意过一个完整的同步分发系统都有哪些功能。权做练手,想到哪些写哪些好了。
最基础的部分:一个提交文件列表的页面,自动分析文件列表然后从源下载文件,中心下载完成后通知边缘节点开始;
其次:文件完整性的校验,同步和分发的进度报表页面,失败报表的重试选择和报警;
再次:系统分用户,不同用户可选节点指定分发,只查看当前用户的报表。
以上。
今天先完成最基础的部分。还是用dancer -a websync创建应用。然后创建views/websync.tt如下:
```html
</head><body>

<% message %><% FOREACH url IN errurls %><% url %>
<% END %>

</body></html> 一如既往的难看……考虑是不是学下用dreamweaver画个稍微好看点的页面出来做layout啊…… 然后是lib/websync.pm,如下: perlpackage websync;
use Dancer ‘:syntax’;
use Gearman::Client;

our $VERSION = ‘0.1’;
#Don’t change index because there are so many otherthings to do!
get ‘/’ => sub {
template ‘index’;
};

any [‘get’, ‘post’] => ‘/websync’ => sub {
my @errurls;
my $message = ‘Write urllist under here.
Attention: The url format must like “http://img.domain.com/path/to/example.flv”’;
if ( request->method() eq ‘POST’ ) {
my $url_pattern = qr(^http://[^/]+?.\w+/);
my @urllists = split ‘ ‘, params->{urllist};
foreach ( @urllists ) {
push @errurls, $_ and next unless m/$url_pattern/;
peer_query($_);
};
$message = ‘Sync begin, waiting please.
And there are some error urls. Please check them:
’;
};
template ‘websync’, { ‘message’ => $message,
‘errurls’ => \@errurls,
};
};

sub peer_query {
my $url = shift;
my @job_servers = qw(127.0.0.1:7003 192.168.0.2:7004);
my $client = Gearman::Client->new;
$client->job_servers(@job_servers);
$client->dispatch_background(‘websync’, $url);
};

true; 嗯,这里试着用了gearman而不是fork,一个是考虑到可能web系统跟中心存储不在一起;另一个是考虑之后需要用mysql存储分发状态,可以把gearman::client改成mysql的trigger形式。 然后是worker.pl,运行在中心存储上,接受job,完成下载,然后通知其他节点继续: perl#!/usr/bin/perl -w
use Gearman::Worker;
use LWP::Simple;
use Net::SSH::Perl;
use POSIX ‘:WNOHANG’;
$SIG{CHLD} = sub {waitpid(-1,WNOHANG)};

my @job_servers = qw(127.0.0.1:7003 192.168.0.2);
my $worker = Gearman::Worker->new;
$worker->job_servers(@job_servers);
$worker->register_function( websync => \&websync );
$worker->work while 1;

sub websync {
my $job = shift;
my @path = split(‘/’, $job->arg);
my $filepath = ‘/var/www/’;
foreach ( 2 .. $#path - 1 ) {
$filepath .= $path[$_].’/’;
mkdir $filepath unless -d $filepath;
};
sync_get($job->arg, $filepath . $path[-1]);
};

sub sync_get {
my ( $url, $file ) = @;
my $http_code = getstore($url, $file);
dist($file) if $http_code =~ m/^2/;
};
#I will rewrite this function to use gearman too~
sub dist {
my $file = shift;
my @remote = qw(1.1.1.1 2.2.2.2);
foreach(@remote){
unless(fork){
my $ssh = Net::SSH::Perl->new($
);
$ssh->login(root, passwd);
$ssh->cmd(“rsync 192.168.0.2:$file $file”);
};
};
};```
不过想到,其实可以在remote上设定每15分钟一次rsync。这样节省掉中心的dist功能,改成remote上的rsync后,主动通过mysql汇报更新的list和md5。
明天开始改这种方式。


晚饭回来,增加dancer在nginx上的部署方式。之前写过apache上用mod_perl的方式,这回因为正好电脑上有nginx,就改用nginx反代了:
首先安装一个perl的server,命令如下:
bash# cpanm Plack Starman
Starman是一个提供prefork方式运行的HTTP服务器。另外还有基于AnyEvent的Twiggy和基于Coro的Corona,不够因为我是在本机的colinux上做实验,装的是UBUNTU9.04系统,已经没有apt源装openssl了,所以Net::SSLeay模块无法安装,AnyEvent类型的也就不能用了。
启动命令如下:
bashsudo -u www-data plackup -E production -s Starman --workers=2 -l /tmp/plack.sock -a /var/www/websync/bin/app.pl &
该命令指定了运行用户,运行server核心,读取的配置文件,启动的worker进程,提供的socket接口。
然后就可以利用nginx的upstream功能,pass到这个socket接口上了。nginx.conf相关部分如下:
```nginx upstream backendurl {
server unix:/tmp/plack.sock;
}

server {
  listen       80;
  server_name  dancer.test.com;
  access_log logs/dancer_access.log;
  error_log  logs/dancer_err.log info;
  root /var/www/websync/public;
  location / {
    try_files $uri @proxy;
    access_log off;
    expires max;
  }
  location @proxy {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass       http://backendurl;
  }
}```