線上頻寬跑滿分析
介紹下背景,公司辦公室到 IDC
走的 200M
的專用頻寬,最近運維監控圖上,一到上班時間就跑滿了,而且客服部也經常反饋,網速特別慢。之前客服走的是和其他部門的 40M
專線的,自從客服量上來後,也經常打滿,於是接入辦公網了,但是沒多久,就出現一開始的情況。
接下來就是分析,哪個環節大量佔用頻寬。運維通過監測,發現客服 IP
出口頻寬一天頻寬平均 2G
多,接下來就是更加細化的分析了,是哪個業務佔了頻寬。客服一般就是接電話、打電話,但是語音伺服器都在 IDC
那兒,聽錄音,也就是幾個主管可以做的,而且也不是經常聽,同時一通電話大概也就是佔不到 1M
的大小,基本忽略,於是就得沉下去日誌的資料了。
分析日誌,首先生產環境的 WEB
Apache
,看了下是否有日誌記錄
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog logs/access_log combined
發現有,於是把日誌下載到本地,開始切割,選擇 0903
號週一工作日
<?php $file = fopen("access_log","r"); $new_file = 'access_log_20180903'; $count = 0; while(!feof($file)) { $content = fgets($file, 4096); if (strpos($content, '03/Sep/2018') !== false) { file_put_contents($new_file, $content.PHP_EOL, FILE_APPEND); } } fclose($file);
開啟日誌後,發現一共 869152
行,同時依據 apache
日誌記錄格式
10.255.140.8 - - [03/Sep/2018:23:59:18 +0800] "GET /project/web/strip/monitor/data?_=1535940421926 HTTP/1.1" 302 388 "http://10.255.140.92/project/web/agent/monitor" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134"
簡單分析了下流量
ini_set('memory_limit', '-1');
$file = fopen("access_log_20180903","r");
$arr = [];
$ipArr = [];
$count = 0;
while(!feof($file))
{
$str = fgets($file, 4096);
$arr = explode(' ', $str);
$count += intval(isset($arr[9]) ? $arr[9] : 0);
if (!isset($ipArr[$arr[0]])) {
$ipArr[$arr[0]] = $arr[0];
}
}
$arr = [];
echo getSize($count);
foreach ($ipArr as $k => $v) {
if (strpos($v, '10.255') !== false) {
$arr[] = $v;
}
}
print_r($arr);
fclose($file);
function getSize($filesize) {
if($filesize >= 1073741824) {
$filesize = round($filesize / 1073741824 * 100) / 100 . ' GB';
} elseif($filesize >= 1048576) {
$filesize = round($filesize / 1048576 * 100) / 100 . ' MB';
} elseif($filesize >= 1024) {
$filesize = round($filesize / 1024 * 100) / 100 . ' KB';
} else {
$filesize = $filesize . ' 位元組';
}
return $filesize;
}
發現一天 153.3GB
,IP
特徵數為 67
,二者相除為 2.283582089552239
和上面運維的統計資料一致。為了簡單直觀統計,接著建立張表
CREATE TABLE `log_stat` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`host` varchar(25) NOT NULL DEFAULT '' COMMENT '主機',
`identd` varchar(32) NOT NULL DEFAULT '' COMMENT '遠端登入名',
`remote_username` varchar(32) NOT NULL DEFAULT '' COMMENT '遠端使用者名稱',
`time` datetime DEFAULT NULL COMMENT '時間',
`method` varchar(32) NOT NULL DEFAULT '' COMMENT 'get/post',
`api` varchar(500) NOT NULL DEFAULT '' COMMENT 'api 介面',
`status` varchar(3) NOT NULL DEFAULT '' COMMENT '狀態',
`len` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '返回值大小',
`referer` varchar(500) NOT NULL DEFAULT '' COMMENT '引用',
`agent` varchar(500) NOT NULL DEFAULT '' COMMENT '代理頭',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='統計表';
同時,為了方便寫入 MySQL
表,進一步把切割的日誌表優化了下
ini_set('memory_limit', '-1');
$file = fopen("access_log_20180903","r");
$newFile = 'access_log_20180903_load';
$count = 0;
while(!feof($file))
{
$str = fgets($file, 4096);
if (strlen(trim($str)) < 5)
continue;
preg_match('/(\S+)\s+(-)\s+(-)\s+\[(\S+\s\S+)\]\s+("[^"]+")\s+(\S+)\s+(\S+)\s+"(\S+)"\s+("[^"]+")/', $str, $matches);
$_tmp = [];
if (isset($matches[5])) {
$_tmp = explode(' ', trim($matches[5], '""'));
file_put_contents($newFile, (++$count) ."\t{$matches[1]}\t{$matches[2]}\t{$matches[3]}\t" . (date('Y-m-d H:i:s', strtotime($matches[4]))) . "\t" . (isset($_tmp[0]) ? $_tmp[0] : '') . "\t" . (isset($_tmp[1]) ? $_tmp[1] : '') . "\t{$matches[6]}\t{$matches[7]}\t{$matches[8]}\t" . (trim($matches[9], '"')) . PHP_EOL, FILE_APPEND);
}
}
執行後,大體資料為
1 10.255.251.83 - - 2018-09-03 00:00:01 POST /sync_service/sservice/rpcserv.php 200 317 - PHPRPC Client 3.0 for PHP
然後 LOAD DATA LOCAL INFILE 'access_log_20180903_load' INTO TABLE log_stat;
入庫,接下來便統計下各個呼叫連結佔用的頻寬
SELECT sum(len) as size,api FROM `log_stat` GROUP BY api ORDER BY size desc;
一查,嚯,便發現了端倪
size api
163355547042 /project/index.php?d=project&c=knowledge_base&m=get_horse_race_lamp
163355547042
這個資料不直觀,轉換下為 152.14GB
,佔了總頻寬的 99%
。於是找到對應的專案,發現這是個跑馬燈請求,每 5
秒請求一次,看了下一次請求頻寬佔 450K
,這樣再算一下 12 * 0.45 * 60 * 9 = 2.916GB
,大致和上面的每臺機子佔用頻寬相等(注,上面的為均值,具體到每臺機子不同)。同時查看了下後臺程式碼,發現每次請求都會把整張表的資料拿出來。既然查到了源頭,優化也就簡單了,問了下相關產品,把請求頻率由 5
秒改為 1
分鐘,同時只拿出符合條件指定的資料。這樣一下來,看了下,每次請求大小為 11KB
,再算一下 1 * 0.011 * 60 * 9 = 5.94MB
(注,1
分鐘佔用頻寬 0.011
乘以 1
個小時再乘以上班的 9
個小時),這樣就基本上可以忽略不計了。
至此,這次頻寬跑滿的案例就分析完畢了,一條線下來,發現還是日誌起了至關重要的作用,所以,平時除了寫程式碼,日誌記錄也不能少,當然了,還是業務也需要嚴謹,否則一個不起眼的疏忽就造成堤壩奔潰的源頭,古語就叫“千里之堤,毀於蟻穴”。