【问题标题】:Why does this code cause high load average on the server?为什么此代码会导致服务器上的平均负载较高?
【发布时间】:2014-06-23 05:25:02
【问题描述】:

当从不太稳定的 API 获得的值在一定范围内时,下面的代码会发送一条消息。

此代码导致平均负载上升,而不是 CPU 使用率上升,可能是由于高 I/O 等待。

CentOS 6.5
Kernel 2.6.32-431.11.2.el6.x86_64
Apache 2.2.15
PHP 5.3.3 (mod_fcgid/2.3.7)

> cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]

代码对专用硬件和云(这两种情况都作为 KVM/Virtio 上的 VM)具有相同的问题影响。

可以做些什么来防止此代码*导致处理器在处理新指令之前等待指令完成**?我知道降低超时并不能真正解决问题,只会减少其影响。

*这是我理解为什么这段代码会导致load average 上升。

<?php

$min = '1';
$last_min = '1';

if (!empty($_GET['min'])) {
    $min = $_GET['min'];
} else {
    $min = false;
}

$ctx=stream_context_create(array('http'=>
    array(
        'timeout' => 10 // seconds timeout
    )
));

$json = file_get_contents('https://www.domain.com/api/ticker/',false,$ctx);

if (!empty($json )) {
    echo($json);
    if (@file_get_contents('log.txt')) {
        if (quote_changed($json)) {
            file_put_contents('log.txt', $json, FILE_APPEND);
        }
    } else {
            file_put_contents('log.txt', $json);
        }

    $obj = json_decode($json,true);
    $last = $obj['ticker']['last'];
    if (is_numeric($last)) {
        $last = (int)$last;
        $last_min = @file_get_contents('last_min.txt');
        $notified = @file_get_contents('notified.txt');
        if ($notified === false) {
            $notified = 'false';
            #echo "no notify file\n";
        }
        if (($last_min === false) || (($min) && ($last_min <> $min))) {
            $last_min = 1;
            $notified = 'false';
            file_put_contents('last_min.txt', $min);
            #echo "no min file or diff min\n";
        }
        #echo ('notified='.$notified.'\n');

        if (($last >= $min) && ($notified=='false')) {
            #$url = ('http://otherdomain.com/nexmo/sendmsg.php' . '?name=blah' . $last);
            #file_get_contents($url);
            #switch to SMS when going abroad and plugin new number when available
            mail("8885551212@mail.net","Blah at".$last,"","From: gaia@domain.com\n");
            file_put_contents('notified.txt', 'true');
            #echo "msg sent\n";
            } elseif (($last < $min) && ($notified=='true')) {
                    file_put_contents('notified.txt', 'false');
                    #echo "not sent\n";
        }           
    }
}

function quote_changed($current) {
    $previous = tailCustom('log.txt');
    #echo ('previous='.$previous);
    if ($previous === (trim($current))) {
        return 0;
    } else {
        return 1; 
    }
}

function tailCustom($filepath, $lines = 1, $adaptive = true) {

        // Open file
        $f = @fopen($filepath, "rb");
        if ($f === false) return false;

        // Sets buffer size
        if (!$adaptive) $buffer = 4096;
        else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));

        // Jump to last character
        fseek($f, -1, SEEK_END);

        // Read it and adjust line number if necessary
        // (Otherwise the result would be wrong if file doesn't end with a blank line)
        if (fread($f, 1) != "\n") $lines -= 1;

        // Start reading
        $output = '';
        $chunk = '';

        // While we would like more
        while (ftell($f) > 0 && $lines >= 0) {

            // Figure out how far back we should jump
            $seek = min(ftell($f), $buffer);

            // Do the jump (backwards, relative to where we are)
            fseek($f, -$seek, SEEK_CUR);

            // Read a chunk and prepend it to our output
            $output = ($chunk = fread($f, $seek)) . $output;

            // Jump back to where we started reading
            fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);

            // Decrease our line counter
            $lines -= substr_count($chunk, "\n");

        }

        // While we have too many lines
        // (Because of buffer size we might have read too many)
        while ($lines++ < 0) {

            // Find first newline and remove all text before that
            $output = substr($output, strpos($output, "\n") + 1);

        }

        // Close file and return
        fclose($f);
        return trim($output);

}

?>

【问题讨论】:

  • 您是否考虑过将代码分成多个部分来自己定位问题,而不是把整个代码文件扔在这里?
  • 因为它会停止生产服务器,所以不会。
  • 在while循环条件下。行来自哪里,一个数据库?
  • 在每个循环的开头放置一些时间戳日志,然后在某个函数之前放置时间戳以更好地定位问题

标签: php linux io scheduler disk


【解决方案1】:

将数据移动到数据库中,或者如果这不是一个选项,请将不稳定的文件缓存到本地服务器中,这样您就不必每次都访问外部提供程序。

如果这两个都不是一个选项,在我看来,提供 API 的人需要提高他们的性能,您可以通过对 Firebug 每次命中花费多少毫秒进行基准测试来验证这一点。

【讨论】:

  • 谢谢。但我确实需要每分钟更新一次。它变化非常快。我想在 PHP 中有一种方法可以处理不可靠的数据源 - 它是否必须在没有接收到数据时让每条指令等待?
猜你喜欢
  • 2010-12-29
  • 2013-03-14
  • 2023-04-02
  • 2019-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-20
  • 1970-01-01
相关资源
最近更新 更多