PHP造日誌輪子的經驗

最近準備升級PHP7,發現同時使用yaf和seaslog擴展時會致使流量上升時php-fpm子進程的crash,在php-fpm.log中能夠看到如下warning記錄,最終引發請求中斷。php

WARNING: [pool www] child 15148 exited on signal 6 (SIGABRT) after 337.885989 seconds from start

通過動手實驗,發現只要加載了seaslog.so,即便不調用它的方法,仍然存在上述問題,推測是seaslog擴展的RINIT和RSHUTDOWN裏面的處理有問題,可是檢查不出來是什麼問題。對於PHP的擴展開發是愛莫能助,因此只能放棄心愛的seaslog,本身來造個簡單的日誌輪子了。併發

以上是故事背景,下面開始講造輪子的收穫。app

第一步,簡單地實現功能,對文件進行寫操做。less

$fp = fopen($file, 'a');
fwrite($fp, $log);
fclose($fp);

第二步,考慮文件鎖,高併發場景下有可能會把日誌寫亂。高併發

$fp = fopen($file, 'a');
if (flock($fp, LOCK_EX)) {
    fwrite($fp, $log);
    flock($fp, LOCK_UN);
}
fclose($fp);

第三步,考慮到寫日誌只是一個很簡單的應用場景,不須要考慮讀文件時的數據一致性,爲了提升效率咱們能夠改良一下這個文件鎖。假設程序所在的文件系統的塊的空間大小是4096字節,小於這個這個長度的日誌能夠直接寫文件,不然要先搶佔文件鎖再寫文件。php-fpm

$fp = fopen($file, 'a');
if (strlen($log) <= 4096) {
    fwrite($fp, $log);
} else if (flock($fp, LOCK_EX)) {
    fwrite($fp, $log);
    flock($fp, LOCK_UN);
}
fclose($fp);

If handle was fopen()ed in append mode, fwrite()s are atomic (unless the size of string exceeds the filesystem's block size, on some platforms, and as long as the file is on a local filesystem). That is, there is no need to flock() a resource before calling fwrite(); all of the data will be written without interruption.學習

第四步,若是咱們的日誌長度幾乎全是小於4096字節,能夠退回到第一步的代碼,並且還有一個選擇,和依次調用 fopen(),fwrite() 以及 fclose() 功能同樣。atom

file_put_contents($file, $log, FILE_APPEND);

以上四步看似走了一圈冤枉路,可是學習到的經驗仍是很值得分享的。日誌

相關文章
相關標籤/搜索