Nginx 使用100%cpu的php fpm和fwrite问题

Nginx 使用100%cpu的php fpm和fwrite问题,nginx,php,Nginx,Php,我有一个不寻常的问题,我设法找到了问题的根源。 我目前在 CentOS Linux 6.3 nginx/1.0.15 PHP版本5.3.18 PHP-FPM 5.3.18-1 我有一个refresh.txt文件,每当有人发布消息更新新的时间戳时都会写入该文件。我们还让JS每1秒检查一次这个时间戳的值。现在的问题是。。假设有5个或更多的人同时向refresh.txt文件写入数据,这将使用100%的cpu。只是为了写一个时间戳 我不知道它为什么这么做 这是我的php代码 if(!empty($rf_

我有一个不寻常的问题,我设法找到了问题的根源。 我目前在 CentOS Linux 6.3 nginx/1.0.15 PHP版本5.3.18 PHP-FPM 5.3.18-1

我有一个refresh.txt文件,每当有人发布消息更新新的时间戳时都会写入该文件。我们还让JS每1秒检查一次这个时间戳的值。现在的问题是。。假设有5个或更多的人同时向refresh.txt文件写入数据,这将使用100%的cpu。只是为了写一个时间戳

我不知道它为什么这么做

这是我的php代码

if(!empty($rf_clear))
    $tb_send = "clear";
else
    $tb_send = time();

// Add flatfile check
$tbcheck = "refresh.txt";
    $tbsend = fopen($tbcheck, 'w');
    $tbtime = $tb_send;
fwrite($tbsend, $tbtime);
fclose($tbsend);
JS

我如何解决这个问题,或者如何解决这个问题? 任何帮助我都将不胜感激

谢谢

编辑: 仍然没有解决这个问题的办法。有没有办法限制这些请求? 还是有更好的方法一起做这件事

我尝试过APC缓存,问题是它没有足够快地提供php文件 所以叫喊声真的很慢,除非我做错了什么

apc_store("refresh", time());
JS

我也尝试过使用数据库。提供php文件的速度同样太慢。

最好的选择是使用flock来锁定文件以供写入--使用循环以实现Windows兼容性,因为flock没有阻止选项在CentOS中无效,但不会造成伤害

$max_tries = 5; // don't loop forever
$tbcheck = "refresh.txt";
$tbsend = fopen($tbcheck, 'w');
for ($try=0; $try<$max_tries, $try++){
    if (flock($tbsend, LOCK_EX, true)) {  // acquire an exclusive blocking lock
        fwrite($tbsend, $tb_send);  // write to file
        fflush($tbsend);            // flush output before releasing the lock
        flock($tbsend, LOCK_UN);    // release the lock
        break;                      // exit the loop
    }
    usleep(100);                    // sleep for 100ms if we couldn't get a lock
}
fclose($tbsend);
最好的选择是使用flock来锁定您的文件以供写入--使用循环以实现Windows兼容性,因为flock没有阻止选项在CentOS中无效,但不会造成伤害

$max_tries = 5; // don't loop forever
$tbcheck = "refresh.txt";
$tbsend = fopen($tbcheck, 'w');
for ($try=0; $try<$max_tries, $try++){
    if (flock($tbsend, LOCK_EX, true)) {  // acquire an exclusive blocking lock
        fwrite($tbsend, $tb_send);  // write to file
        fflush($tbsend);            // flush output before releasing the lock
        flock($tbsend, LOCK_UN);    // release the lock
        break;                      // exit the loop
    }
    usleep(100);                    // sleep for 100ms if we couldn't get a lock
}
fclose($tbsend);

考虑改用Apc。 apc_存储“刷新”,时间;储存 apc_获得“刷新”;检索

yum安装php-apc

此外,你甚至不必把时间储存在里面。 你可以只储存一个柜台 apc_公司“进修者”;储存 每一次变化都会增加
如果新值高于上一个值,请检入js。

考虑改用Apc。 apc_存储“刷新”,时间;储存 apc_获得“刷新”;检索

yum安装php-apc

此外,你甚至不必把时间储存在里面。 你可以只储存一个柜台 apc_公司“进修者”;储存 每一次变化都会增加
如果新值高于之前的值,请在js中进行检查。

您是否有一个可以用来代替平面文件的数据库?是的,我有一个数据库,但我的问题是,我使用js来检查refresh.txt的内容,我认为这不适合db?它每1秒检查一次内容。这可能是罪魁祸首的一部分-如果您试图获得独占写入锁,这可能与读取文件冲突。我建议将其移动到数据库,然后通过AJAX请求读取。如果您担心使用APC缓存数据库结果的性能,那么在javascript中调用php脚本来检查输出的时间戳将是一个巨大的性能问题,如果您说有50人在线,那么每秒有50个php请求。目前正在使用talk_jax.openGET,boardurl+/talkbox/refresh.txt?nocache=+nocache;在jsp中,您可以丢弃该文件,只使用APC。用apc\u storerefresh替换您的写代码!空的$rf\u清除了吗?明确:时间;以及您对静态文件的AJAX请求,其中一个请求指向一个只有echo apc_fetchrefresh的PHP页面;它会做与读/写文件相同的事情,但不用担心锁。你有一个可以用来代替平面文件的数据库吗?是的,我有一个数据库,但我的问题是我用js检查refresh.txt的内容,我认为这对db不起作用?它每1秒检查一次内容。这可能是罪魁祸首的一部分-如果您试图获得独占写入锁,这可能与读取文件冲突。我建议将其移动到数据库,然后通过AJAX请求读取。如果您担心使用APC缓存数据库结果的性能,那么在javascript中调用php脚本来检查输出的时间戳将是一个巨大的性能问题,如果您说有50人在线,那么每秒有50个php请求。目前正在使用talk_jax.openGET,boardurl+/talkbox/refresh.txt?nocache=+nocache;在jsp中,您可以丢弃该文件,只使用APC。用apc\u storerefresh替换您的写代码!空的$rf\u清除了吗?明确:时间;以及您对静态文件的AJAX请求,其中一个请求指向一个只有echo apc_fetchrefresh的PHP页面;它将做与读/写文件相同的事情,但不必担心锁。嘿,非常感谢你的回复。。我有APC而不是memcached。。我不知道你是否可以同时使用memcached和apc,但你的答案肯定是总结了这一点。在APC中我将如何做到这一点?@rambocoder很好,我获取了一些实际上与文件句柄无关的代码,将使用flock更新答案。我尝试了flock解决方案,但它似乎不起作用。如果您有一个执行fwrite的php脚本;比如说2秒钟内5次,它会最大限度地耗尽你的CPU吗?它的前
真奇怪。只有当人们按enter键发送shout时,才会写入该文件,但如果我连续发送5个,则会超时,cpu将达到100%,这不太可能导致100%的cpu使用率,更可能是其他原因造成的。如果你想尝试用APC锁定,你可以用APC_fetch替换Memcached::get,用APC_store替换Memcached::set,用APC_delete替换Memcached::delete。每个人的论点都是一样的。嘿,非常感谢你的回答。。我有APC而不是memcached。。我不知道你是否可以同时使用memcached和apc,但你的答案肯定是总结了这一点。在APC中我将如何做到这一点?@rambocoder很好,我获取了一些实际上与文件句柄无关的代码,将使用flock更新答案。我尝试了flock解决方案,但它似乎不起作用。如果您有一个执行fwrite的php脚本;比如说2秒钟内5次,它会最大限度地耗尽你的CPU吗?真奇怪。只有当人们按enter键发送shout时,才会写入该文件,但如果我连续发送5个,则会超时,cpu将达到100%,这不太可能导致100%的cpu使用率,更可能是其他原因造成的。如果你想尝试用APC锁定,你可以用APC_fetch替换Memcached::get,用APC_store替换Memcached::set,用APC_delete替换Memcached::delete。每个的参数都是一样的。嘿,我实际上已经开始使用APC商店了,虽然没有那么快,但已经足够好了。从javascript获取它的最佳方法是什么?我认为这个问题需要解决。即使使用apc,我认为当你说垃圾邮件时,它也会不断地写一个新的值,因此无法从JS脚本中正确读取。有没有办法限制这一点?或者让它在1秒内把一些邮票排成一列,然后只写最后一张?如果我能做到这一点,我知道这将是解决问题的办法。我会尽力更好地解释。基本上,每次按enter键都会不断地写下新的时间,但js无法读取,因为它总是在变化,只是不断地写,在TB中没有显示任何叫喊,直到你停止。。现在有了垃圾邮件保护,但问题是如果有5个人几乎同时写,那么它在完成之前是不会被读取的,如果有一些对话在进行,那么可能需要很长时间,所以在它停止写之前什么都不会被打印出来。你为什么不检查输入是否为空,然后更新时间呢?js的问题是它不是平行的;当您按住“发送”按钮,JS发送数据时,它无法接收,而当它接收时,它无法发送。如果要对每个用户进行垃圾邮件保护,请存储每个用户上次发送邮件的时间。在会话中或作为另一个apc_键。嘿,我实际上开始使用apc存储,它没有那么快,但已经足够好了。从javascript获取它的最佳方法是什么?我认为这个问题需要解决。即使使用apc,我认为当你说垃圾邮件时,它也会不断地写一个新的值,因此无法从JS脚本中正确读取。有没有办法限制这一点?或者让它在1秒内把一些邮票排成一列,然后只写最后一张?如果我能做到这一点,我知道这将是解决问题的办法。我会尽力更好地解释。基本上,每次按enter键都会不断地写下新的时间,但js无法读取,因为它总是在变化,只是不断地写,在TB中没有显示任何叫喊,直到你停止。。现在有了垃圾邮件保护,但问题是如果有5个人几乎同时写,那么它在完成之前是不会被读取的,如果有一些对话在进行,那么可能需要很长时间,所以在它停止写之前什么都不会被打印出来。你为什么不检查输入是否为空,然后更新时间呢?js的问题是它不是平行的;当您按住“发送”按钮,JS发送数据时,它无法接收,而当它接收时,它无法发送。如果要对每个用户进行垃圾邮件保护,请存储每个用户上次发送邮件的时间。在会话中或作为另一个apc_键。
$max_tries = 5; // don't loop forever
$tbcheck = "refresh.txt";
$tbsend = fopen($tbcheck, 'w');
for ($try=0; $try<$max_tries, $try++){
    if (flock($tbsend, LOCK_EX, true)) {  // acquire an exclusive blocking lock
        fwrite($tbsend, $tb_send);  // write to file
        fflush($tbsend);            // flush output before releasing the lock
        flock($tbsend, LOCK_UN);    // release the lock
        break;                      // exit the loop
    }
    usleep(100);                    // sleep for 100ms if we couldn't get a lock
}
fclose($tbsend);
$timeout = 5; // set a cache expiration so a broken process doesn't lock forever
$key = "file_locked";
$max_tries = 5; // don't loop forever
for ($try=0; $try<$max_tries, $try++){
    // check to see if there is a lock
    if (!Memcached::get($key)){
        // not locked, so set a lock before processing
        Memcached::set($key, true, $timeout);

        // write to the file
        $tbcheck = "refresh.txt";
        $tbsend = fopen($tbcheck, 'w');
        $tbtime = $tb_send;
        fwrite($tbsend, $tbtime);
        fclose($tbsend);

        // delete the lock
        Memcached::delete($key);

        // exit the loop
        break;
    }
    // locked, pause for 100ms
    usleep(100);
}