Зачем?
На многих сайтах, в том числе и на наших, используется собственная система сбора статистики. Почему собственная а не Яндекс.Метрика или Google Analytics? Причин может быть много, рассмотрим три основные, наиболее популярные причины такого выбора:
- Метрика и Analytics не распознают пользователя в привязке к сессии: а нам важно знать, Вася Пупкин или же Иван Иванов посещал страницу.
- На сайте используются хитрые механизмы отображения контента в зависимости от критериев посещаемости, например нужно ограничить доступ к определенному разделу после того, как количество прочтений отдельных страниц превысит некий лимит (например выдать лайтбокс – «Нравится читать наши новости? Зарегистрируйтесь»).
- «Большой брат следит за мной» — никаких сторонних JavaScript на моем сайте!
Так или иначе, не важно в силу каких обстоятельств, у вас появилась собственная система сбора статистики. Сама система может собирать различные данные, вешать куки первом заходе, — в зависимости от бизнес-логики и фантазии разработчика, эти нюансы мы опустим, поскольку создание самой системы не входит в тему нашей сегодняшней статьи. Но в любом случае, будет нехватать очень важного и полезного компонента, который есть у Google и Yandex, — а именно подсчета количества человек на сайте онлайн.
Как?
В интернете можно встретить массу туториалов на тему создания таких счетчиков с использованием базы данных MySQL или же файлов, и такие решения, безусловно, подойдут для небольших проектов. Но такое решение отнюдь не самое эффективное, если посещаемость сайта серьезная — зачем создавать постоянную нагрузку на MySQL сотнями или тысячами инсертов в секунду, нагружая тем самым дисковую подсистему и расходую драгоценные иопсы.
Какие есть альтернативы? Для хранения данных, на вскидку приходят два варианта:
- Использование не-реляционных хранилищ, таких как Memcached или Redis. Memcached выглядит более предпочтительно, так как в данном случае нет необходимости сохранять состояние, когда сервер выключен.
- Использование монолитного серверного приложения (демона), который хранит данные в памяти, скажем в виде переменной, массива, коллекции, хэш-мапа. Будет аналогично memcached по скорости и типу используемого хранилища (оперативная память). Это же приложение будет принимать запросы по HTTP/HTTPS/WS и скорее всего будет написано на NodeJS или Java
Второй очевидный вопрос, который встает при реализации такого счетчика – это минимальный промежуток времени (тик), по которому счетчик будет каким-то образом опрашивать клиента на предмет того, находится ли клиент до сих пор онлайн (или наоборот, клиент будет сообщать серверу).
Идеальным решением выглядят вебсокеты – используем единый демон, написанный, скажем на NodeJS, отлавливаем события connect и disconnect, храним внутри в памяти одну переменную — и вуаля, наш счетчик готов. Но это в теории.
На практике – это потребует открытия отдельного порта на сервере, развертывания соответствующего серверного приложения, а также наличие клиентского JavaScript или Flash, взаимодействующего с сервером по WS. А в случае использования HTTPS задача еще усложняется в виду развертывания дополнительного слоя на серверном приложении.
Нам же нужно простое решение, которое можно было бы развернуть за 10 минут в полевых условиях, что называется «на коленке», и которое при этом решало бы поставленную задачу.
Реализация
Было решено построить следующую архитектуру:
- Где храним – Memcached;
- Что храним – IP-адреса или хеши IP-адресов подключенных пользователей;
- Как складываем данные в Memcached? – через PHP-скрипт;
- Как запрашиваем 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/
Добавить комментарий