我的日常工作有很大一部分比重是处理各种网络问题。很多时候,面对突发故障,完全搞不清楚缘由,此时,一个完善的监控系统能起到事半功倍的效果。
一个好消息是「netstat -s」里的各种计数器包含了很多有用的信息;一个坏消息是计数器记录的通常都是一些硕大无比的绝对值,不够直观。以前,我写过一篇的文章来介绍如何监控相关数据,但写得并不完善;最近,浏览 文章 时偶然发现一个 工具 ,可以很方便的实时查询计数器相对值的变化情况,可惜不能方便的对接到监控系统里。既然现有的轮子都不太合适我的需求,那么我便有了充足的理由去重新造一个。
解决问题前需要摸摸底,如下可见命令「netstat -s」的结果是一个层次化的结构:
netstat -s
我们需要把它转换成更利于使用的规范化结构。翠花,上代码:
<?php function one_dimensional_array($values, $prefix = 'netstat') { $result = array(); foreach ($values as $key => $value) { $key = $prefix . '.' . $key; if (is_string($value)) { $result[$key] = $value; } else { $result += one_dimensional_array($value, $key); } } return $result; } function multi_dimensional_array($values, $indent = 0) { $result = array(); for (reset($values); $v = current($values); next($values)) { $space = space($v); $last = substr($v, -1); if ($space == $indent && $last == ':') { $title = title($v); continue; } if ($last == ':') { $_values = array($v); while ($_value = next($values)) { if (space($_value) > $space) { $_values[] = $_value; } else { prev($values); break; } } $v = multi_dimensional_array($_values, $space); } if (is_string($v)) { if (preg_match('//s(/d+)/', $v, $matches)) { $v = preg_replace("/{$matches[1]}/s?/", '', $v); $result[$title][title($v)] = $matches[1]; } } else { $result[$title] += $v; } } return $result; } function space($string) { return strlen($string) - strlen(ltrim($string)); } function title($string) { return str_replace(' ', '_', rtrim(trim($string), '/.:')); } ?>
利用递归把数据先整理成一个层次化数组,再转换成一个扁平化的数组,调用如下:
<?php exec('netstat -s', $values); $values = multi_dimensional_array($values); $values = one_dimensional_array($values); print_r($values); ?>
最终能生成一百多项网络情况相关数据,很容易就能对接到 Graphite 等监控系统:
Graphite
不过需要说明的是,监控的是相对值,不是绝对值!你可以通过 cron 每分钟生成一份当前的绝对值快照,然后对比前一分钟的情况,把相对值发送到监控系统里,例子:
netstat.TcpExt.fast_retransmits
图例监控的是 TcpExt 里的 fast_retransmits 数据,可以明显看到在某一时刻,一部分服务器的 fast_retransmits 变化量明显超过其它服务器,猜测对应的网络可能存在类似丢包等不稳定的情况,有了这些监控,我们就不用再盲人摸象了。