【问题标题】:Is Monolog safe for logging to same file from multiple scripts? [closed]Monolog 是否可以安全地从多个脚本记录到同一个文件? [关闭]
【发布时间】:2021-02-09 11:20:30
【问题描述】:

与使用file_put_contentsLOCK_EX 标志进行日志记录相比,使用Monolog 会消除潜在的瓶颈吗?

我有以下面向公众的 PHP 脚本,平均执行速度约为 10x/s,峰值时间为 100x/s。这导致了瓶颈,因为由于LOCK_EX,脚本必须相互等待。

<?php
    // ... do some things
    // then log the result:
    file_put_contents("/home/logs/public.log", "\n" . date("d.m. G:i:s") . " (some log) $httpcode $retry_count", FILE_APPEND | LOCK_EX);
?>

我正在考虑重写它以使用这样的 Monolog:

<?php
    require_once(DIR.'/vendor/autoload.php');
    use MonologLogger;
    use MonologHandlerStreamHandler;
    
    $logger = new Logger('public-script');
    $logger->pushHandler(new StreamHandler('/home/logs/public.log', Logger::INFO));

    // ... do some things
    // then log the result:
    $logger->info("(some log) $httpcode $retry_count");
?>

--

根据 Koala Yeung 的回答,使用 Monolog 不会帮助解决瓶颈问题。我需要找到其他能够写入文件而不阻塞脚本执行的东西。

【问题讨论】:

    标签: php monolog


    【解决方案1】:

    您可以简单地编写一个脚本来测试自己:

    main.php:

    <?php
    
    use Monolog\Logger;
    use Monolog\Handler\StreamHandler;
    
    require __DIR__ . '/vendor/autoload.php';
    
    $logger = new Logger('public-script');
    $logger->pushHandler(new StreamHandler(__DIR__ . '/public.log', Logger::INFO));
    
    $options = getopt("n:l:s:");
    
    $name = $options['n'] ?? 'pid:' . getmypid();
    $limit = (int) ($options['l'] ?? 1000);
    $sleep = (int) ($options['s'] ?? 1000);
    
    // ... do some things
    // then log the result:
    for ($i=1; $i<=$limit; $i++) {
            $logger->info("workering", [
                    'worker' => $name,
                    'count' => $i,
            ]);
            usleep($sleep);
    }
    

    运行它:

    php main.php -n 'worker 1' &; php main.php -n 'worker 2' &
    

    或者以更小的间隔运行它(每个日志 10 微秒):

    php main.php -s 10 -n 'worker 1' &; php main.php -s 10 -n 'worker 2' &
    

    结果:

    [2021-02-09T19:37:51.649015+08:00] public-script.INFO: workering {"worker":"worker 1","count":1} []
    [2021-02-09T19:37:51.650283+08:00] public-script.INFO: workering {"worker":"worker 1","count":2} []
    [2021-02-09T19:37:51.650370+08:00] public-script.INFO: workering {"worker":"worker 1","count":3} []
    [2021-02-09T19:37:51.650447+08:00] public-script.INFO: workering {"worker":"worker 1","count":4} []
    [2021-02-09T19:37:51.649321+08:00] public-script.INFO: workering {"worker":"worker 2","count":1} []
    [2021-02-09T19:37:51.650522+08:00] public-script.INFO: workering {"worker":"worker 1","count":5} []
    [2021-02-09T19:37:51.650555+08:00] public-script.INFO: workering {"worker":"worker 2","count":2} []
    [2021-02-09T19:37:51.650596+08:00] public-script.INFO: workering {"worker":"worker 1","count":6} []
    [2021-02-09T19:37:51.650640+08:00] public-script.INFO: workering {"worker":"worker 2","count":3} []
    [2021-02-09T19:37:51.650670+08:00] public-script.INFO: workering {"worker":"worker 1","count":7} []
    [2021-02-09T19:37:51.650716+08:00] public-script.INFO: workering {"worker":"worker 2","count":4} []
    [2021-02-09T19:37:51.650743+08:00] public-script.INFO: workering {"worker":"worker 1","count":8} []
    [2021-02-09T19:37:51.650789+08:00] public-script.INFO: workering {"worker":"worker 2","count":5} []
    [2021-02-09T19:37:51.650815+08:00] public-script.INFO: workering {"worker":"worker 1","count":9} []
    [2021-02-09T19:37:51.650861+08:00] public-script.INFO: workering {"worker":"worker 2","count":6} []
    [2021-02-09T19:37:51.650886+08:00] public-script.INFO: workering {"worker":"worker 1","count":10} []
    [2021-02-09T19:37:51.650911+08:00] public-script.INFO: workering {"worker":"worker 2","count":7} []
    [2021-02-09T19:37:51.650958+08:00] public-script.INFO: workering {"worker":"worker 1","count":11} []
    [2021-02-09T19:37:51.650985+08:00] public-script.INFO: workering {"worker":"worker 2","count":8} []
    [2021-02-09T19:37:51.651031+08:00] public-script.INFO: workering {"worker":"worker 1","count":12} []
    [2021-02-09T19:37:51.651057+08:00] public-script.INFO: workering {"worker":"worker 2","count":9} []
    [2021-02-09T19:37:51.651103+08:00] public-script.INFO: workering {"worker":"worker 1","count":13} []
    ...
    

    原木交织得很好。

    如果你阅读StreamHandler::write()的源代码,你可以看到它使用了与file_put_contents相同的排他锁(LOCK_EX)机制。

    【讨论】:

    • 所以基本上,如果我开始使用 Monolog 而不是简单的 file_put_contentsLOCK_EX 标志,将不会有性能提升;对吗?
    • 拥有 Monolog 提供的所有抽象和功能,我相信只有性能损失。但是对日志有更好的抽象可以在未来为您提供灵活性和功能(例如,从文件日志切换到数据库日志,轻松切换日志级别)。如果性能损失对您的使用不重要,则最好使用更高级别的库而不是直接使用file_put_contents()
    • 感谢您的意见。看来我需要继续寻找能够异步写入同一个文件而不阻塞脚本执行的东西。
    • @PrimožKralj:为什么不登录到其他一些非阻塞数据存储?如果您选择登录到文件,总会有一些锁定机制来确保事情通过而不会相互覆盖。使用 Monolog,您可以为您的源代码实现自己的处理程序。
    • 您可以将其发送到 RabbitMQ 并让工作人员编写日志。队列服务是非阻塞的。我能想到的另一个选择是像Apache Cassandra 这样的非阻塞数据库。
    猜你喜欢
    • 2021-07-07
    • 2019-07-04
    • 2017-07-15
    • 2011-05-21
    • 2022-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    相关资源
    最近更新 更多