1. 程式人生 > >線上頻寬跑滿分析

線上頻寬跑滿分析

介紹下背景,公司辦公室到 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.3GBIP 特徵數為 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 個小時),這樣就基本上可以忽略不計了。

至此,這次頻寬跑滿的案例就分析完畢了,一條線下來,發現還是日誌起了至關重要的作用,所以,平時除了寫程式碼,日誌記錄也不能少,當然了,還是業務也需要嚴謹,否則一個不起眼的疏忽就造成堤壩奔潰的源頭,古語就叫“千里之堤,毀於蟻穴”。