Reputation: 438
I have an unusual problem that I managed to find the root of. I am currently set up on CentOS Linux 6.3 nginx/1.0.15 PHP Version 5.3.18 PHP-FPM 5.3.18-1
I have a refresh.txt file that is written every time someone posts a shout to update the new time stamp. We also have JS checking the value of this time stamp every 1 second. Now the problem with this is.. Say 5 or more people shout at the same time writing to the refresh.txt file it will use 100% cpu. just to write a time stamp!!
I don't know why it is doing this..
Here is my php code.
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
talk_jax.open("GET", boardurl+"/talkbox/refresh.txt?nocache="+nocache);
How can I fix this or maybe work around this? Any help would me massively appreciated.
Thanks.
Edit: still no solution to this. Is there a way to limit the requests? Or is there a better way todo this all together.
I have tried APC cache, the problem with that is its not serving the php file fast enough so shouts are really slow, unless I was doing something wrong?
apc_store("refresh", time());
JS
talk_jax.open("GET", boardurl+"/talkbox/refresh.php?nocache="+nocache);
I have also tried using a database. Its same too slow to serve the php file.
Upvotes: 1
Views: 1693
Reputation: 12019
Consider using Apc instead.
apc_store('refresh', time());
to store
apc_get('refresh');
to retreive
yum install php-apc
Besides, you don't even have to store the time in it.
You could just store a counter
apc_inc('refresher');
to store
that will increase every time there is a change
and check in js if the new value is higher than the previous one you had.
Upvotes: 1
Reputation: 27599
The best option is to use flock()
to lock your file for writing - https://www.php.net/flock - using a loop for Windows compatibility as flock
does not have a blocking option (not valid in your case for CentOS, but unharmful).
$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);
Another option would be to use APC
or memcached
to store a lock, which can then be checked from other PHP processes. Assuming that you have memcached
your code would look something like this:
$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);
}
Upvotes: 3