相信apache的mod_rewrite模块都很熟悉了,今天这儿换个思路,利用mod_perl来实现下,发现竟然是如此的简单!
首先得保证apache已经安装了mod_perl模块,具体安装配置可以看上一篇文章哦。
修改下http.conf配置,添加一下内容:
PerlTransHandler MyTrans # MyTrans 这个是自己添加的处理模块名
具体MyTrans.pm脚本如下:
package MyTrans;
use strict;
use Apache2::Const qw(DECLINED);
sub handler {
my $r = shift;
my $uri = $r->uri;
my ($id) = ($url =~ m|^/news/(.*)\.html|);
$r->uri("/news.php");
$r->args("id=$id");
return Apache2::Const::DECLINED;
}
1;
实现就是:/news/12345.html => /news.php?id=12345
大体思路是这样的,比如有 一个地址:http://www.aa.com/down/1.mp3,不幸搜索引擎或者迅雷扒到了,就无偿为他们奉献流量了。 但是假如在http://www.aa.com/down/1.mp3?key=123,key参数每天变化或者几分钟变化一次,在apache服务端校 验下这个参数,不正确则显示拒绝访问或者找不到的话,那样防盗链的效果就算达到了把。
modperl强大到可以任意应用apache内部API,官方地址是:http://perl.apache.org 。根据apache版本选择相应的modperl版本,现在大部分都apache2了,就选择modperl2把。具体安装配置可以看官方文档。
先建立/home/httpd/modperl/startup.pl(目录请自行修改),内容如下:
use strict;
use lib qw(/home/httpd/modperl); # 把这个路径加入到perl lib路径
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Connection ();
use Apache2::RequestUtil ();
use Apache2::ServerUtil ();
use Apache2::Log ();
use Apache2::Request ();
1;
部分本机httpd.conf配置:
LoadModule perl_module modules/mod_perl.so
LoadModule apreq_module modules/mod_apreq2.so
PerlPostConfigRequire /home/httpd/modperl/startup.pl
<Location /down >
SetHandler modperl # 设置该目录交给modper处理
PerlAccessHandler Down # Down是模块名称
PerlSetVar key 123 # 设置校验参数值
</Location>
mod_apreq2.so这个模块需要安装Apache2::Request,具体安装:http://pyh7.spaces.live.com/blog/cns!47D8D44208AC51E5!128.entry
startup.pl文件一般modperl应用都有,加载一些常用库,可以在apache启动时预先载入,避免重复加载。
修改这些后可以重启下apache,看下logs/error_log里最后是否有mod_apreq和mod_perl字样,如果有就说明成功了。剩下都就是写校验的perl脚本了,/home/httpd/modperl/Down.pm,内容如下:
package Down;
use strict;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Connection ();
use Apache2::RequestUtil ();
use Apache2::ServerUtil ();
use Apache2::Log ();
use Apache2::Const -compile => qw(OK FORBIDDEN);
use Apache2::Request ();
sub handler {
my $r = shift;
my $req = Apache2::Request->new($r);
my $ip = $r->connection->remote_ip;
my $k = $req->param('key') || ''; # 判断访问时是否带key参数
my $key = $r->dir_config('key') || '123'; # 加载httpd.conf配置中的key值
if ($key eq $k) { # 相等可以正常访问
return Apache2::Const::OK;
} else { # 否则显示拒绝访问
my $s = Apache2::ServerUtil->server;
$s->log_error("[$ip--------forbidden.]");
return Apache2::Const::FORBIDDEN;
}
}
1;
提示一下,以上两个perl脚本文件末尾记得加上1;
重启下apache。现在可以通过http://www.aa.com/down/1.mp3和http://www.aa.com/down /1.mp3?key=123测试下。可以看见不加参数拒绝访问了把。这里只是简单的判断,实际上可以根据日期或者IP加密生成一个字符串来判断。
写这个帖子完全是无意中搜索modperl应用时候发现了,具体可以参见:
http://pyh7.spaces.live.com/blog/cns!47D8D44208AC51E5!140.entry
上面的文档已经写都很详细了,包括怎么安装modperl、Apache2::Request等模块以及配置apache的http.conf就不在累赘都重复了。
发现mysql slave服务器经常因为一些特殊字符或者符号产生的更新语句报错,整个同步也会因此而卡在那,最初的办法只是手动去出错的机器,执行下面三条sql语句,跳过错误即可。
slave stop;
set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
slave start;
一台slave机器用这样方法还行,多台就麻烦了,就顺手写了个简单的perl脚本,方便统一跳过错误,代码如下:
#!/usr/bin/env perl
use strict;
use warnings;
# get slave status
sub get_status {
my ($ip, $usr, $pass) = @_;
my $info = `mysql -u$usr -p$pass -h$ip -e 'show slave status\\G;'`;
if (($info =~ /Slave_IO_Running: Yes/) && ($info =~ /Slave_SQL_Running: No/)) {
return 1;
}
return 0;
}
# mysql slave skip
sub slaveskip {
my ($ip, $usr, $pass) = @_;
print "slave error **\n";
system("mysql -u$usr -p$pass -h$ip -e 'slave stop;'");
system("mysql -u$usr -p$pass -h$ip -e 'set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;'");
system("mysql -u$usr -p$pass -h$ip -e 'slave start;'");
}
my @hosts = qw/
192.168.0.101:root:tt1234
192.168.0.102:root: tt1234
192.168.0.103:root: tt1234
/;
foreach (@hosts) {
my ($ip, $usr, $pass) = split ':';
print "// ----- $ip\n";
my $count = 1;
while ($count < 100000) {
my $status = get_status($ip, $usr, $pass);
print "i: $count status: $status\n";
last if $status == 0;
slaveskip($ip, $usr, $pass);
select(undef, undef, undef, 0.1);
$count++;
}
print "\n";
}
exit;
功能简述
统计出日志里一个或多个页面总共访问的次数,比如aa.jsp, bb.jsp这样页面分别多少次。
实现简述
Apache单个日志文件800M。
最初程序使用Python编写,按行来统计,分别使用in(最慢)和index方法去查找,然后使用了正则匹配,程序运行时间从最初的1分50多秒优化到1分10秒左右,参考了qyb博客中提到的gc.disable(),有了一定的提升,最终还是需要1分左右。
然后随意用了Perl写了一个,用了最土鳖的<LOG>这样的按行分析,最后正则匹配,然后++,速度竟然在40-50秒之间,惊叹!后来经过shucho指点,在正则部分采用了预编译,效果那是相当惊人!800M文件只用了7秒左右。卧槽!
程序片段
# --------------------------------------------------------------------
use strict;
use Benchmark;
my $LOG_FILE = '/usr/local/apache/logs/access.log';
# 下面qr部分起了关键作用,预编译了表达式
my @EXT_LIST = map {qr/$_/} qw{
aaServlet
bbServlet
};
my $startime = new Benchmark;
my %result;
map {$result{$_} = 0} @EXT_LIST;
open LOG_FILE, $LOG_FILE;
while (<LOG_FILE>){
foreach my $ext (@EXT_LIST){
$result{$ext}++ if $_ =~ /$ext/;
}
}
close LOG_FILE;
while (my ($key, $value) = each(%result)){
$key =~ s/\(\?-xism:(.*?)\)/$1/g;
print "$key:\t$value\n";
}
printf "** %s\n\n", timestr(timediff(new Benchmark, $startime));