hitcounter — несколько клиентов PHP, обращающихся к одному и тому же файлу

Я начал играть с PHP и увидел этот фрагмент кода, который должен действовать как счетчик посещений для веб-страницы:

/* counter */

//opens countlog.txt to read the number of hits
$datei = fopen("/countlog.txt","r");
$count = fgets($datei,1000);
fclose($datei);
$count=$count + 1 ;
echo "$count" ;
echo " hits" ;
echo "\n" ;

// opens countlog.txt to change new hit number
$datei = fopen("/countlog.txt","w");
fwrite($datei, $count);
fclose($datei);

Исходя из того, что я прочитал, несколько запросов могут выполняться одновременно на сервере. Так что есть шанс, что они получат доступ к этому файлу countlog.txt в то же время (правильно?). Если это так, этот код не работает для загруженного веб-сайта (правильно?). Как изменить этот код, чтобы он работал на загруженном веб-сайте? Можете ли вы использовать блокировки в PHP, которые совместно используются несколькими запросами?

PS: вопрос НЕ о счетчиках. Пожалуйста, избегайте использования SQL в ответе, если это возможно.

2

Решение

Вы можете использовать flock (), чтобы получить эксклюзивную блокировку файла, см. http://php.net/manual/en/function.flock.php

$fp = fopen("/tmp/lock.txt", "r+");

if (flock($fp, LOCK_EX)) {
$datei = fopen("/countlog.txt","r");
$count = fgets($datei,1000);

$count=$count + 1 ;
echo "$count" ;
echo " hits" ;
echo "\n" ;

ftruncate($fp, 0);
fwrite($fp, $count);
fflush($fp);
flock($fp, LOCK_UN);
} else {
echo "Could not lock file!";
}

fclose($fp);

Возможно, вам следует создать цикл, который ожидает успешной блокировки, используя usleep (), чтобы избежать активного ожидания: http://php.net/manual/en/function.usleep.php

0

Другие решения

Я думаю, что ваше требование должно быть выполнено с учетом вашего трафика.

Если ваш трафик низкий, внедрение счетчика на основе блокировки не может быть проблемой. Поскольку вероятность одновременного доступа к одному и тому же файлу очень мала, и для открытия, записи и закрытия файла требуется несколько миллисекунд.

Другим решением может быть использование механизма кэширования memcached, redis или APC и сохранение единого счетчика в хранилище ключей.

Если вы рассматриваете несколько миллионов обращений в секунду, его нельзя разместить на одном сервере. Скорее всего, он масштабируется с помощью балансировщика нагрузки и размещается в разных регионах / серверах. Затем должен быть реализован счетчик обращений неблокированной службы, такой как очередь сообщений. Если вы заинтересованы в очереди вашего счетчика посещений, вы можете прочитать больше на RabbitMQ, или же ActiveMQ

RabbitMQ и ActiveMQ поддерживают следующие протоколы и многие другие протоколы, и вы можете найти множество клиентских библиотек php для подключения по этим протоколам.

Несколько примеров кода

Использование APC в качестве счетчика

<?php
apc_add('counter', 0);
echo apc_inc('counter')
?>

Использование Memcached

<?php
$m = new Memcached();
$m->addServer('localhost', 11211);

$m->add('counter', 0);
$m->increment('counter');
?>

RabbitMQ и php-amqplib

composer.json

{
"require": {
"videlalvaro/php-amqplib": "2.5.*"}
}

$ composer.phar install

<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('counter', false, false, false, false);

$callback = function($msg) {
// $msg->body has the content of the message
// counter update implementation goes here
};

$channel->basic_consume('counter', '', false, true, false, false, $callback);

while(count($channel->callbacks)) {
$channel->wait();
}
?>
3

По вопросам рекламы [email protected]