Сбор статистики просмотров с использованием memcaсhed

Рассмотрим типовую ситуацию для высоконагруженных ресурсов: нам нужно организовать сбор статистики просмотров каждой страницы (например, с товарами). Обращение к БД напрямую в данном случае не является оправданным. Поэтому нам нужно реализовать следующее: помещать данные о просмотрах в memcached, после чего они периодически сбрасываются в БД специальным скриптом через cron

Сам скрипт счетчика просмотров должен только вызываться, но его исполнение самой загружаемой страницей контролироваться не должно («запустил и забыл»).

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

Вариантов реализации можно предусмотреть сразу несколько, например, реализовав работу метода в отдельном потоке за счет вызова сценария с использованием функции exec(). Также, вероятно, можно и особым образом настроить crontab, формируя очередь исполнения скриптов, и наверняка есть и другие варианты решений, все нужно пробовать. 

Я остановлюсь на решении с сокетами, потому как оно является, наверное, наиболее кроссплатформенным, не требует сторонних библиотек.

Решение разделим на три php-файла, два приведены ниже — index.php с классом, который в рамках своего конструктора вызывает файл сценария views_counter.php, а третий connect.php — это стандартное подключение к БД (его мы приводить не будем). 

Основной файл index.php:

class product_views{

 //конструктор

 function product_views($url, $params = array())

{

    $parts = parse_url($url);

    if (!$fp = fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80))

    {

        return false;

    }

    $data = http_build_query($params, '', '&');

    fwrite($fp, "POST " . (!empty($parts['path']) ? $parts['path'] : '/') . ' HTTP/1.1\r\n');

    fwrite($fp, "Host: " . $parts['host'] . "\r\n");

    fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");

    fwrite($fp, "Content-Length: " . strlen($data) . "\r\n");

    fwrite($fp, "Connection: Close\r\n\r\n");

    fwrite($fp, $data);

    fclose($fp);

    return true;

 }

}

//получаем ID продукта

$id = $_GET['productID'];

//создаем экземпляр класса product_views

$pageCount = new product_views('http://имя_сайта.ru/phpfns/views_counter.php', array('$productID'=>$id));

?>

Данные в файле сценария мы получаем через $_POST['productID']. В данном случае мы не будем предусматривать возможности добавления префиксов или суффиксов для ключей записей продуктов. Хотя в реальной ситуации они должны быть предусмотрены для удобной идентификации конкретных параметров. 

Второй файл views_counter.php может выглядеть так:

//получаем id продукта

$productID = $_GET['productID'];

$memcache_obj = new Memcache;

//коннектимся с сервером Memcached

$memcache_obj->connect('memcache_host', 11211);

//стандартный вариант, но с исключением

//коллизий на всякий случай

while(true) {

$get_result = $memcache_obj->get($productID);

if($get_result)

 {

 if($memcache_obj->increment($productID)) break;

 } 

 else 

 {

 //подключаемся к БД

 include('includes/connect.php');

 //обращаемся к БД

 $query="SELECT views FROM products_table WHERE productID='".$productID."';";

 $result = mysql_query($query);

 $row = mysql_fetch_assoc($result);

 $row['views']++;

 if($memcache_obj->add($productID, $row['views'])) break;

 }

usleep(rand(10, 1000));

}

//Закрываем соединение с сервером Memcached

$memcache_obj->close();

?>

Также тут стоит отметить, что в данном файле вы можете заметить бесконечный цикл, выход из которого конкретно не описан. Тут дело в том, что предусмотрен тот факт, что время выполнения PHP-скриптов ограничивается со стороны PHP (по умолчанию оно составляет 30 секунд, см. настройки php.ini). Если скрипт не успевает выполниться, он сбрасывается. При более аккуратном программировании рекомендуется самостоятельно продумать выход из бесконечного цикла.

Кристофер

www.igd.by

Версия для печатиВерсия для печати

Рубрики: 

  • 1
  • 2
  • 3
  • 4
  • 5
Всего голосов: 0
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!