Сколько человек онлайн на сайте? – пишем счетчик на PHP с использованием Memcached

от автора


Зачем?

На многих сайтах, в том числе и на наших, используется собственная система сбора статистики. Почему собственная а не Яндекс.Метрика или Google Analytics? Причин может быть много, рассмотрим три основные, наиболее популярные причины такого выбора:

  1. Метрика и Analytics не распознают пользователя в привязке к сессии: а нам важно знать, Вася Пупкин или же Иван Иванов посещал страницу.
  2. На сайте используются хитрые механизмы отображения контента в зависимости от критериев посещаемости, например нужно ограничить доступ к определенному разделу после того, как количество прочтений отдельных страниц превысит некий лимит (например выдать лайтбокс – «Нравится читать наши новости? Зарегистрируйтесь»).
  3. «Большой брат следит за мной» — никаких сторонних JavaScript на моем сайте!

Так или иначе, не важно в силу каких обстоятельств, у вас появилась собственная система сбора статистики. Сама система может собирать различные данные, вешать куки первом заходе, — в зависимости от бизнес-логики и фантазии разработчика, эти нюансы мы опустим, поскольку создание самой системы не входит в тему нашей сегодняшней статьи. Но в любом случае, будет нехватать очень важного и полезного компонента, который есть у Google и Yandex, — а именно подсчета количества человек на сайте онлайн.

Как?

В интернете можно встретить массу туториалов на тему создания таких счетчиков с использованием базы данных MySQL или же файлов, и такие решения, безусловно, подойдут для небольших проектов. Но такое решение отнюдь не самое эффективное, если посещаемость сайта серьезная — зачем создавать постоянную нагрузку на MySQL сотнями или тысячами инсертов в секунду, нагружая тем самым дисковую подсистему и расходую драгоценные иопсы.

Какие есть альтернативы? Для хранения данных, на вскидку приходят два варианта:

  • Использование не-реляционных хранилищ, таких как Memcached или Redis. Memcached выглядит более предпочтительно, так как в данном случае нет необходимости сохранять состояние, когда сервер выключен.
  • Использование монолитного серверного приложения (демона), который хранит данные в памяти, скажем в виде переменной, массива, коллекции, хэш-мапа. Будет аналогично memcached по скорости и типу используемого хранилища (оперативная память). Это же приложение будет принимать запросы по HTTP/HTTPS/WS и скорее всего будет написано на NodeJS или Java

Второй очевидный вопрос, который встает при реализации такого счетчика – это минимальный промежуток времени (тик), по которому счетчик будет каким-то образом опрашивать клиента на предмет того, находится ли клиент до сих пор онлайн (или наоборот, клиент будет сообщать серверу).

Идеальным решением выглядят вебсокеты – используем единый демон, написанный, скажем на NodeJS, отлавливаем события connect и disconnect, храним внутри в памяти одну переменную — и вуаля, наш счетчик готов. Но это в теории.

На практике – это потребует открытия отдельного порта на сервере, развертывания соответствующего серверного приложения, а также наличие клиентского JavaScript или Flash, взаимодействующего с сервером по WS. А в случае использования HTTPS задача еще усложняется в виду развертывания дополнительного слоя на серверном приложении.

Нам же нужно простое решение, которое можно было бы развернуть за 10 минут в полевых условиях, что называется «на коленке», и которое при этом решало бы поставленную задачу.

Реализация

Было решено построить следующую архитектуру:

  1. Где храним – Memcached;
  2. Что храним – IP-адреса или хеши IP-адресов подключенных пользователей;
  3. Как складываем данные в Memcached? – через PHP-скрипт;
  4. Как запрашиваем PHP-скрипт? Через AJAX с заданным интервалом (раз в секунду/полминуты/минуту/и т.д.).

Memcached предполагает установку определенного срока годности (жизни) данных, то есть, когда мы кладем данные в Memcached, мы обязательно указываем, сколько секунд будут храниться данные. Этим свойством мы и воспользуемся – устанавливаем срок годности равный интервалу обращений к счетчику, и в случае если клиент уйдет в офлайн, запись о его IP-адресе автоматически удалится из Memcached по истечении срока жизни переменной в Memcached.

Установку самого Memcached оставим за кадром, благо в интернете есть сотни мануалов и туториалов на тему установки Memcached из пакетов для всех популярных систем, или же компиляции из исходников.

Перейдем непосредственно к части программной реализации.

Сам PHP-скрипт получился до безобразия простым и лаконичным:

$mem  = new Memcached();      $mem->addServer('192.168.2.20',11211); 	 $hashname = md5($_SERVER['REMOTE_ADDR']);  if($_GET['set']){     $mem->add($hashname, 1 ,10);	// срок жизни - 10 секунд	 }  if($_GET['count']){     $data = $mem->getAllKeys();     echo count($data); } 

Скрипт будет принимать GET-параметр — set/get для добавления записи об IP-адресе или получения количества пользователей онлайн соответственно. Разумеется, для определения IP-адреса клиента, $_SERVER[‘REMOTE_ADDR’] можно заменить на значение X_FORWARDED_FOR или другого заголовка, в зависимости от конфигурации вашего сервера.

IP-адреса по желанию можно и не хешировать, мы всегда хешируем все, что не нужно хранить в открытом виде исходя из бизнес-логики. Нам ведь важно понять количество уникальных пользователей, и совершенно не нужно хранить в Memcached сами IP-адреса.

Остается написать клиентский JavaScript-код, который будет запрашивать наш счетчик с интервалом в 10 секунд. С использованием jQuery это также всего лишь несколько строчек:

setInterval(function(){	    $.get("/counter.php?set"); }, 10000); 

Запускаем – работает. Проверить работу счетчика и получить количество пользователей, которые находятся на сайте можно будет запросив URI:

 	/counter.php?get 

Просто, быстро, надежно, практично.

Вместо заключения

Рассмотренный подход можно дополнять и видоизменять по вкусу в зависимости от конкретных задач и применяемых серверных технологий. Этот подход, безусловно, не нов и основан на самых простых и элементарных принципах и функциональных особенностях используемого ПО (Memcached). Но мы надеемся, что он пригодится как новичкам, так и возможно опытным разработчикам, и позволит сэкономить как свое, так и серверное время.

Если будет интересно, как реализовать счетчик посещаемости в виде NodeJS-приложения с взаимодействием через WebSocket, мы можем рассказать об этом в отдельной статье – вам нужно будет обозначить интерес к тематике комментариях.

ссылка на оригинал статьи http://habrahabr.ru/post/262939/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *