接下来进入我不擅长的页面部分了。规划页面分为side和main,side中提供时间选择框/类型下拉选择框和提交按钮;main中展示最后形成的chart。 时间选择框是用js和css完成的,这个网上有很多,不过要同时支持多浏览器和分钟级别的选项的,目前就发现一个好用的。下载地址如下:http://chenlinux.com/images/uploads/Calendar.zip 然后创建cachemoni/public/cdn.html如下: ```html 继续阅读……
02 Aug 2011 Posted in monitor
接下来进入我不擅长的页面部分了。规划页面分为side和main,side中提供时间选择框/类型下拉选择框和提交按钮;main中展示最后形成的chart。 时间选择框是用js和css完成的,这个网上有很多,不过要同时支持多浏览器和分钟级别的选项的,目前就发现一个好用的。下载地址如下:http://chenlinux.com/images/uploads/Calendar.zip 然后创建cachemoni/public/cdn.html如下: ```html 继续阅读……
01 Aug 2011 Posted in monitor
上篇完成了xml的输出,这篇开始说charts图像的生成。我们采用fusioncharts的免费版,之前博客有提到另一个amcharts,不过amcharts的免费版会在图像左上角加上自己amcharts.com的广告标识……
从fusioncharts官网下载free版的压缩包,有20MB大,不过其中对我们这个小项目有用的只有MSLine.swf/MSBar2D.swf/fusioncharts.js等。
说明:
1、官网介绍上写了支持perl,不过下载包里只有php/asp/jsp/rails的class,没有perl的。所以还是得采用js的方式;
2、js下有setDataURL和setDataXML两个方法,不过官方强烈建议使用setDataURL方法,这种方法可接受的数据量比setDataXML大很多。
页面html很简单,加如下js代码即可:
javascript</script>
<script type="text/javascript">
var myChart = new FusionCharts("/Charts/MSBar2D.swf", "myChartId", "600", "500");
myChart.setDataURL(escape("/xml?begin=***&end=***&type=area"));
myChart.render("chartdiv");
</script>
要点在这个escape(),如果URL里带参数的话,必须用escape()转码,不然的话第一个&之后的所有参数都会丢失掉!
在调试中注意到,为了忽略缓存,setDataURL()会在url最后跟上一个随机1-4位数字参数&curr=1234然后再发起请求。
现在就可以访问页面看看了~嗯,可以看到图像中的中文字有问题。这是因为fusioncharts不认utf8的中文,必须输出gbk或者gb2312的xml数据才行。所以需要修改一些dancer的charset配置,把config.yml里的charset: UTF-8改成charset: GBK。然后重新请求,中文就正确显示了。
如下图:
继续阅读……
28 Jul 2011 Posted in monitor
准备使用funsioncharts绘图,其采用xml数据,在绘制line图的时候,就要从mysql里读取数据,并输出成xml格式,相关配置如下: ```perl package cachemoni; use Dancer ‘:syntax’; use Dancer::Plugin::Database; use POSIX qw(strftime); 继续阅读……
27 Jul 2011 Posted in monitor
准备两个表,一个存储原始数据,另一个存储每5分钟归总一次的数据。之后根据时间段绘制省份运营商性能图的时候,就直接从汇总表里获取数据;原始表留给详细查询。 数据库准备脚本如下: ```mysqlUSE myops; CREATE TABLE IF NOT EXISTS cdn_ori_record ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, ip INT(10) NOT NULL DEFAULT ‘0000000000’, isp ENUM(‘0’,’1’,’2’,’3’,’4’), area INT(4) NOT NULL DEFAULT ‘0000’, cur_date TIMESTAMP DEFAULT NOW(), cdn_time INT(10) NOT NULL DEFAULT ‘0’, cdn ENUM(‘CHINACACHE’,’DNION’,’FASTWEB’) NOT NULL, KEY time_key (cur_date) ); 继续阅读……
26 Jul 2011 Posted in monitor
话接上篇,ip整理出来,然后就是接一个ip地址,快速定位查找到它属于哪个ip段,然后返回具体的省份和运营商。因为之前的ip已经转换成数字,而且是顺序排列的,所以可以采用折半算法(二分法)。perl脚本如下:
```perl#!/usr/bin/perl -w
#my $ip = inet_aton(“$ARGV[0]”);
my $ip = inet_aton(get_test_ip());
my $file = $ARGV[1] || ‘iplist.txt’;
my $length = cat $file | wc -l
;
继续阅读……
25 Jul 2011 Posted in monitor
为了跟第三方监控做对比和作为备用,准备自己通过页面js返回数据做个监控。首先第一步,整理一个足够自己用的ip库。 首先,考虑调用会比较频繁,打算把内容尽可能归并,到省级运营商即可; 其次,未知归并完会有多大的情况下,考虑到qqwry的地区都是中文,打算统一使用电话区号代替地区,运营商也有一位数字代替,ip采用inet-aton网络值代替;这样每条记录的字节数固定,可以方便采用seek和sysread提高读取某条记录的速度。 继续阅读……
21 Jul 2011 Posted in perl
原贴地址:http://bbs.chinaunix.net/thread-3563215-1-1.html flw回帖里有翻译,我试答如下: 继续阅读……
08 Jul 2011 Posted in monitor
上篇加了bash_history的监控,这篇说mysql_history的监控。不像bash4,mysql自始至终没有提供过syslog的代码,只能自己通过守护进程去实时获取~/.mysql_history的记录了。一个小脚本如下: ```perl#!/usr/bin/perl -w use POE qw(Wheel::FollowTail); use Log::Syslog::Fast qw(:all); 继续阅读……
08 Jul 2011 Posted in monitor
@钚钉钬影 童鞋要试验系统日志收集处理,采用rsyslog+loganalyzer做界面,因为需求有把bash_history也带上,所以采用修改bash源码的方式。最先采用了bash4.2(bash4.2已经带了这个功能,但是默认不开启,删掉哪个/**/就行了),不过因为这个bash4.+跟redhat的network-functions脚本有点小矛盾,重启的时候报个错——虽然改起来也很简单,就是加一个./的事情——不过本着尽量改动少的原则,换回bash3.1。 bash3.1里默认没有记录syslog的代码,所以从bash4.2/bashhist.c里复制有关bash_syslog_history代码段到bash3.1中——注意不是原样复制到bashhist.c,那样不顶用——需要复制到lib/readline/history.c中,如下: 继续阅读……
28 Jun 2011 Posted in dancer
squid监控之前有一篇关于snmp的内容,不过这次是真要用上了,所以细细挑出来几个做监控。碰巧凯哥更新了一把modern perl的东西,我亦步亦趋,也试试dancer。不过花了两天时间,DBIx::Class::Schema还是没搞出来,最终还是简单的用DBI跳过了…… 用的database就是之前nmap试验时生成的数据,有application/channel/intranet等column。 首先安装: ```perlcpanm Dancer DBI DBD:mysql Template Dancer::Session::YAML dancer -a cachemoni 继续阅读……
23 Jun 2011 Posted in linux
做运维几年没用过patch,说来也怪了~~趁着上一篇自己的小改动,熟悉一下这个命令的简单用法。
首先是patch的制作,用diff命令。
bashtar zxvf squid-2.7.STABLE9.tar.gz
cp squid-2.7.STABLE9 squid-2.7.STABLE9-old && mv squid-2.7.STABLE9 squid-2.7.STABLE9-new
#然后按照上篇的内容修改squid-2.7.STABLE9-new/里的文件
diff -uNr squid-2.7.STABLE9-old squid-2.7.STABLE9-new > squid-snmp.patch
这就完成了,好简单啊~来看看patch文件的内容吧:
```cdiff -uNr squid-2.7.STABLE9-old/include/cache_snmp.h squid-2.7.STABLE9-new/include/cache_snmp.h
— squid-2.7.STABLE9-old/include/cache_snmp.h 2006-09-22 10:49:24.000000000 +0800
+++ squid-2.7.STABLE9-new/include/cache_snmp.h 2011-06-23 13:25:04.000000000 +0800
@@ -125,6 +125,7 @@
MESH_PTBL_KEEPAL_S,
MESH_PTBL_KEEPAL_R,
MESH_PTBL_INDEX,
继续阅读……
22 Jun 2011 Posted in monitor
做反向代理的squid集群监控,在单机维护时,squidclient mgr:server_list里的OPEN CONNS是经常看的一项数据,不过在开启snmp支持后,在mib里却没有找到相关的数据。还一度怀疑是不是cachePeerKeepAlRecv或者cachePeerKeepSent。今天想起来去src里grep了一把源码,顺利的在squid/src/neighbors.c里看到了OPEN CONNS等数据的来源,如下:
cstatic void
dump_peers(StoreEntry * sentry, peer * peers)
{
peer *e = NULL;
……
for (e = peers; e; e = e->next) {
……
storeAppendPrintf(sentry, "OPEN CONNS : %d\n", e->stats.conn_open);
……
storeAppendPrintf(sentry, "keep-alive ratio: %d%%\n",
percent(e->stats.n_keepalives_recv, e->stats.n_keepalives_sent));
然后在squid/src/snmp_agent.c里看到了这些数据的snmp输出,如下:
cvariable_list *
snmp_meshPtblFn(variable_list * Var, snint * ErrP)
{
variable_list *Answer = NULL;
struct in_addr *laddr;
int loop, index = 0;
char *cp = NULL;
peer *p = NULL;
int cnt = 0;
……
switch (Var->name[LEN_SQ_MESH + 2]) {
case MESH_PTBL_NAME:
cp = p->name;
Answer = snmp_var_new(Var->name, Var->name_length);
……
case MESH_PTBL_KEEPAL_R:
Answer = snmp_var_new_integer(Var->name, Var->name_length,
p->stats.n_keepalives_recv,
SMI_COUNTER32);
break;
case MESH_PTBL_INDEX:
Answer = snmp_var_new_integer(Var->name, Var->name_length,
index,
ASN_INTEGER);
break;
default:
*ErrP = SNMP_ERR_NOSUCHNAME;
break;
}
return Answer;
}
一对比,发现确实没有stats.conn_open输出……
好在这个比较简单,稍微改一下,就能搞出来:
1、修改squid/include/cache_snmp.h如下:
cenum { /* cachePeerTable */
……
MESH_PTBL_CONN_OPEN, /*新增这个*/
MESH_PTBL_HOST,
MESH_PTBL_END
};
2、修改squid/src/snmp_core.c如下:
继续阅读……
14 Jun 2011 Posted in testing
小型的mysql测试工具,主要有自带的mysqlslap、super-smack和mybench。嗯,我这里的小型的意思是指工具安装过程简单。
mysqlslap的使用方法遍地都是,就不先详细写了。根据个人偏好写写mybench吧,毕竟是perl的。
安装很简单,如下:
bashcpanm DBI DBD::mysql Time::HiRes
wget http://jeremy.zawodny.com/mysql/mybench/mybench-1.0.tar.gz
tar zxvf mybench-1.0.tar.gz
cd mybench-1.0
perl MakeFile.PL && make && make install
但是使用就不是太简单了——mysqlslap会自己生成(-a选项)sql,super-smack则带了一个gen-data程序生成数据然后自动导入,但是mybench没有,所以只能自己搞定数据。
不过mybench还是自己生成了一个测试模版的脚本在/usr/bin/bench_example,很简单的就知道怎么做了。
example如下:
```perl#!/usr/bin/perl -w
继续阅读……
09 Jun 2011 Posted in perl
今天写基调测试报告,需要从原始的ping延时和丢包率数据中自己计算标准方差以评估波动性(直接运行ping命令可见,不过基调报告里没有)。
方差是各个数据与其平均数的差的平方的平均数。标准差(均方差)则是方差的算术平方根。
这个时候可以打开excel……不过作为excel只会填文字的人,只好打开CPAN来解决问题了~
perl#!/usr/bin/perl -w
use Statistics::Descriptive;
use strict;
open FH,'<','data';
my $data={};
while(<FH>){
my @F = split;
push @{$data->{"快网延时"}}, $F[3];
push @{$data->{"快网丢包"}}, $F[4];
push @{$data->{"森华延时"}}, $F[6];
push @{$data->{"森华丢包"}}, $F[7];
push @{$data->{"帝联延时"}}, $F[9];
push @{$data->{"帝联丢包"}}, $F[10];
}
close FH;
my $stat = Statistics::Descriptive::Full->new();
foreach my $key (sort keys %{$data}) {
$stat->add_data(@{$data->{"$key"}});
print $key."\t".$stat->standard_deviation(),"\n";
$stat->clear();
}
记住一定要clear,不然的话add_data会接着上一次的加,然后数据就错了。
继续阅读……
09 Jun 2011 Posted in perl
spread还是半年前的时候偶然看到的,一直没有试过。前段时间用gearman收集集群日志时,发现gearman的方式,worker不会知道client来自哪里,一条job只会一个worker来做,比较适合做分布式计算,但相比我最初设想的实时系统管理需求,还是有一定距离。于是重新翻出来spread,感觉可以根据应用系统设置不同的group,然后统一再由一个回收结果的group即可。于是有了如下试验: 继续阅读……
09 Jun 2011 Posted in linux
一些squid服务器为了强调加速效果,使用tmpfs来做cache_dir。刚开始运行的时候也嗖嗖的,不过没过一两天,mgr:info就看到缓存命中率急剧下降,字节命中率甚至只剩下10%左右!检查了多次配置,绝对没有问题,但同样的url,曾经一分钟几百次的HIT,现在一分钟几百次MISS…… df看,不管是tmpfs,还是logs所在的目录,都才用了不到30%。最后想起来df -i看了下,果然,tmpfs的inode使用率100%了! 赶紧remount了一次,解决了问题。但不是根本出路。还是得想办法搞定这个inode。 在linux代码说明里找到了关于tmpfs的文档(/usr/src/linux/Documentation/filesystems/tmpfs.txt): tmpfs has three mount options for sizing: …… nr_inodes: The maximum number of inodes for this instance. The default is half of the number of your physical RAM pages, or (on a machine with highmem) the number of lowmem RAM pages, whichever is the lower. These parameters accept a suffix k, m or g for kilo, mega and giga and can be changed on remount. The size parameter also accepts a suffix % to limit this tmpfs instance to that percentage of your physical RAM: the default, when neither size nor nr_blocks is specified, is size=50% 继续阅读……
03 Jun 2011 Posted in monitor
gearman其实不是重点,因为我就是抄了一遍perldoc的样例而已。关键在服务器上的log4j日志是回滚的,所以需要配合回滚(猜测log4j的DailyRollingFile回滚方式类似mv resin.log resin.log-ymd && reload,这样在回滚后,FH还在resin.log-ymd上,就读不到新日志了)重启FH。 另:tail命令有个参数-F/–follow=name,可以锁定文件名而不是文件描述符,不知道这个功能是怎么做到的? 一步一步来: 继续阅读……
01 Jun 2011 Posted in perl
给我自己的学习计划做个开头,从html::template开始试用。
首先利用上上篇的nmap.pl脚本,提取一些数据,然后展示在页面上。
cgi脚本如下:
perl#!/usr/bin/perl -w
use HTML::Template;
use XML::Simple;
use Net::MySQL;
#定期执行这个
#system("nmap -n -p 22,5666 10.168.168.0/23 10.168.170.0/24 -oX output.xml");
my $text = XMLin("output.xml");
#读取html模版
my $temp = HTML::Template->new(filename => '../template/html/server.tmpl');
my $localhost = '127.0.0.1';
my @array = ();
my $i = 0;
my $hash = {};
while ( $text->{host}->[$i] ) {
#因为新增了ssh端口扫描,所以xml解析和前例稍有不同
my $ssh_state = $text->{host}->[$i]->{ports}->{port}->[0]->{state}->{state};
my $nrpe_state = $text->{host}->[$i]->{ports}->{port}->[1]->{state}->{state};
my $ip = ref($text->{host}->[$i]->{address}) eq 'ARRAY' ? $text->{host}->[$i]->{address}->[0]->{addr} : $text->{host}->[$i]->{address}->{addr};
my $mac = ref($text->{host}->[$i]->{address}) eq 'ARRAY' ? $text->{host}->[$i]->{address}->[1]->{addr} : '00:1E:C9:E6:E1:7C';
$i++;
my $channel = &mysql_query($mac);
#将ip按照频道排成列表,每个ip存有ssh和nrpe状态
if ( exists $hash->{$channel} ) {
push @{$hash->{$channel}}, { 'IP' => $ip, 'SSH' => $ssh_state, 'NRPE' => $nrpe_state, };
} else {
$hash->{$channel}->[0] = { 'IP' => $ip, 'SSH' => $ssh_state, 'NRPE' => $nrpe_state, };
}
}
#将上面while生成的hash转成HTML::Template认可的array,不过array的单个元素可以是hash
foreach my $key( keys %{$hash} ) {
my $onechannel = {};
$onechannel->{"CHANNEL"} = $key;
my $j = 0;
foreach my $ip( @{$hash->{$key}} ) {
$onechannel->{"IP_LOOP"}->[$j] = $ip;
$j++;
}
push @array, $onechannel;
}
#将array传递给之前定义的html模版
#注意:不管是param还是@array里,所有的key必须都在tmpl里使用,冗余也会报错
$temp->param(CHANNEL_LOOP => \@array);
#输出成html格式
print "Content-Type: text/html\n\n", $temp->output;
#这段没什么说的,根据mac获取频道
sub mysql_query {
my $mac = shift;
my $mysql = Net::MySQL->new( hostname => $localhost,
database => 'myops',
user => 'myops',
password => 'myops',
);
$mysql->query("select channel from myhost where mac='$mac'");
&alert("New server") unless $mysql->has_selected_record;
my $a_record_iterator = $mysql->create_record_iterator();
while (my $record = $a_record_iterator->each) {
return $record->[0];
};
}
#留着后续继续处理
sub alert {
print @_,"\n";
}
然后是template文件server.tmpl:
继续阅读……
30 May 2011 Posted in nginx
第一个测试,关于http_perl_module。之前写过一篇关于nginx忽略大小写的博文,今天被朋友问上门来,url是类似/Upload/Dir/2011/123_D.jpg的形式。如果单纯的lc($r->uri),得到的url会变成/upload/dir/2011/123_d.jpg,目录是不存在的。所以要稍微改进一下。如下:
perl perl_set $url '
sub {
my $r = shift;
return $1.lc($2) if ($r->uri =~ m/^(.+\/)([^\/]+)$/);
return $r->uri;
}
';
这样就行了。
继续阅读……
27 May 2011 Posted in monitor
perl#!/usr/bin/perl -w
use XML::Simple;
use Net::MySQL;
system("nmap -n -p 5666 10.1.1.0/23 10.1.3.0/24 -oX output.xml");
my $text = XMLin("output.xml");
my $i = 0;
while ( $text->{host}->[$i] ) {
my $nrpe = $text->{host}->[$i]->{ports}->{port}->{state}->{state};
#因为在扫描到本机的时候,是没有mac的,所以到本机时不是ARRAY而是HASH
my $ip = ref($text->{host}->[$i]->{address}) eq 'ARRAY' ? $text->{host}->[$i]->{address}->[0]->{addr} : $text->{host}->[$i]->{address}->{addr};
my $mac = ref($text->{host}->[$i]->{address}) eq 'ARRAY' ? $text->{host}->[$i]->{address}->[1]->{addr} : '00:1E:C9:E6:E1:7C';
&mysql_query($ip, $mac, $nrpe);
$i++;
}
sub mysql_query {
my ($ip, $mac, $nrpe) = @_;
my $mysql = Net::MySQL->new( hostname => '10.1.1.25',
database => 'myops',
user => 'myops',
password => 'myops',
);
$mysql->query(
"insert into myhost (intranet, mac, monitorstatus) values ('$ip', '$mac', '$nrpe')"
);
}
小脚本一个,扫描内网网段内存活的机器,获取其MAC地址,以及nrpe端口情况。后期再配合myhost里的system,如果是linux(其实用nmap -O也可以获取system,但是结果不准,耗时还特别长,200台机器花10分钟),但monitorstatus还是closed的,就expect上去安装nrpe,嗯~~
继续阅读……
20 May 2011 Posted in monitor
上篇提到纯真ip库有很多行是浪费的,比如下面这种:yaml
223.214.0.0 223.215.255.255 安徽省 电信
223.216.0.0 223.219.255.255 日本
223.220.0.0 223.220.162.1 青海省 电信
223.220.162.2 223.220.162.2 青海省海东地区 平安县九歌网吧
223.220.162.3 223.221.255.255 青海省 电信
很简单的223.220.0.0-223.221.255.255段,却被拆成了三行。于是在通过起始ip结束ip计算子网之前,还需要合并一下这些ip段。
因为涉及ip比对,所以第一反应想到了mysql里有的inet_aton函数,去CPAN上搜了一下,发现有NetAddr::IP::Util模块有inet_aton函数,结果一用,发现居然生成的不是数字……于是从网上找到了pack的办法,如下:
```perl#!/usr/bin/perl -w
while(<>){
next unless $_ =~ /^(\S+)\s+(\S+)\s+(\S+)/;
my $low = unpack(‘N’,(pack(‘C4’,(split( /./,$1)))));
#下面这行是IP::QQWry模块里的写法
继续阅读……
19 May 2011 Posted in monitor
首先申明只是一个简单的方式,因为打算的是提取总列表成bind9使用的acl格式,所以不在乎性能问题。 第一步、从CZ88.NET下载QQWry数据库,然后运行IP.exe,选择“解压”,然后会在桌面生成一个qqwry.txt,这里就有四十多万行的ip记录。格式如下: 起始ip 结束ip 大区域 小区域 但是这个大区域也不是想像中的那么整齐,比如清华大学宿舍楼也是大区域的…… 好在我们DNS只需要一个大概的南北指向,根据电信占主流的现实,只要取出来联通的,其他都算电信就行了~ 第二步、把起始ip-结束ip改成acl需要的子网掩码格式,这一步用perl完成,全文如下: 继续阅读……
12 May 2011 Posted in monitor
话接上篇,继续完成这个perl脚本。花了今天一天的时间,基本定稿如下: ```perl#!/usr/bin/perl -w use Net::Ping::External qw(ping); use Tie::File; use Getopt::Long; 继续阅读……
12 May 2011 Posted in perl
考虑到公司环境必须先rsa_auth再su的问题,一般的pssh啊mussh啊sshbatch啊,都不能直接用,决定把上篇脚本里的相关部分抽出来成为一个模块,借机学习一下package和bless的简单概念: ```perl #包名,如果做pm的话,必须和(.*).pm的名字一样 package raocl; use Parallel::ForkManager; use Expect; #Exporter模块是perl提供的导入模块方法的工具 use base ‘Exporter’; #Exporter有两个数组,@EXPORT里存的是模块的sub,@EXPORT_OK里存的是模块的var; #使用模块时只能调用这些数组里有定义的东西 our @EXPORT = qw/new cluster/; #一般模块都有一个new方法来进行初始化定义 sub new { #所有sub传入的第一个参数都是本身,所以要先shift出来,然后才是脚本显式传入的参数 my $class = shift; #将参数转成哈希方式,并返回一个引用; #正规做法应该在这里指定一些必须要有的参数,比如passwd => %args{‘passwd’} || ‘123456’ my $self = {@_}; #bless上面返回的哈希引用到自己,再传递出去;以后在这之外的地方,使用被bless过的$self时自动就关联上new里的数据了。 #这里我写的极简单,看比较正式的模块写发,这里对$class还要用ref();判断是不是引用等 return bless $self,$class; } 继续阅读……