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);

以上四步看似走了一圈冤枉路,可是学习到的经验仍是很值得分享的。日志

相关文章
相关标签/搜索