Проблемы быстродействая в системах мониторинга Интернет-Ресурсов.
- Принцип работы систем мониторинга интернет-ресурсов;
- Мощность уходящая в бесконечность;
- Inner Loop (внутренний цикл);
- SQL - это вам не это;
- Заключение.
Принцип работы систем мониторинга интернет-ресурсов
"Реклама - двигатель прогресса" - это выражение как ни есть лучше отражает сущность современного рунета (.ru), так как большая его часть живет именно на деньги полученные от нее. Главная задача владельца сайта - сделать его популярным, так как именно популярный сайт (сайт с наиболее большой и специфичной аудиторией) наиболее интересен потенциальному рекламодателю.
Создать популярный сайт - задача не из простых. Система мониторинга помогает владельцу сайта следить за его популярностью, изменением аудитории и изменением ee интересов.
Самая популярная часть интернета (та часть которую принято по старинке называть WWW) работает по HTTP протоколу. Подробности этого протокола мы рассматривать не будем, более подробное описание вы можете почитать в RFC2068. Сейчас мы его рассмотрим на пальцах.
Связь между двумя компьютерами осуществляется следующим образом: сервер слушает сеть - ждет обращения. А клиент (броузер), в свою очередь, посылает серверу HTTP запрос похожий на этот:
Host: space.novgorod.ru
Referer: http://www.yandex.ru
Accept-Language: ru
- В первой строке всегда указывается метод запроса (GET) ,протокол (HTTP/1.0) , путь (/) и имя запрашиваемого файла (index.htm).
- Во второй строке указано имя сервера (это надо в том случае, если сервер виртуальный - большая часть интернет серверов виртуальные)
- В третей строке указана страница реферер - страница с которой осуществляется переход (http://www.yandex.ru).
- В четвертой строке указан поддерживаемый системой клиента язык (RU).
На такой запрос сервер должен вернуть ответ, походящий на один из двух описанных ниже - в первом сервер не возвращает документ, т.к. произошла ошибка, а во втором сразу после заголовка идет содержимое документа, не зависимо от того, что документ содержит (HTML, картинка, видео, звук и т.д.)
Пример 1:
Connection:Close
- В первой строке возвращается код операции и его описание (404 - Документ на сервере не найден)
- Во второй строке указано, что сервер разорвал соединение.
Пример 2:
Content-type:text/html
- В первой строке возвращается код операции и его описание (200 - все в порядке)
- Во второй строке указан тип возвращаемого документа - HTML.
Кроме того обычно указывается кодировка, размер и дата обновления файла.
Именно используя этот протокол работает большая часть интернет и все системы мониторинга как его неотъемлемая часть. Владелец на свой сайт устанавливает небольшую картинку - которая запрашивается с сервера в момент загрузки страницы. Сервер обрабатывает этот запрос - добавляет информацию о нем в базу данных и возвращает клиенту картинку, содержащую, обычно, информацию о количестве посетителей.
В зависимости от типа счетчика сервер может получить совершено разнообразную информацию, такую как IP адрес пользователя, адрес страницы на которой установлен счетчик, ОС, тип броузера и многое другое. Эту информацию сервер хранит у себя и выдает владельцу сайта (по его запросу) статистку сформированную на ее основе.
Мощность уходящая в бесконечность
Представим следующую ситуацию - наша система обслуживает не очень популярный ресурс, на который поступает около 200 000 обращений в день. За год происходит 365*200000 = 73 000 000 запросов. Информация о каждом запросе может занимать от 200 байт до 4Kb, в зависимости от типа статистики. Возьмем в среднем - 1,5 Kb. В итоге получаем ~103 Гб - объем не очень внушительный для наших дней.
Позже, отчеты могут быть запрошены в любом количестве, любым количеством владельцев сайтов - и они должны формироваться налету из ~103Гб данных.
Пример из реальной жизни: система статистики SpyLog™ обслуживает 14791 сайт (на 3 мая 2001 года), и обрабатывает более 50 млн. запросов в день. Объем базы данных SpyLog™ исчисляется Терабайтами.
И еще один факт - рост рунета (по данным Яндекс™) в период с 07 апреля по 14 апреля (1 неделя) составил 8.08% Таким образом становится все больше и больше пользователей, все больше и больше сайтов и данные которые должны будут обрабатывать системы мониторинга через несколько лет сейчас нам кажутся бесконечностью.
Inner Loop (внутренний цикл)
Система мониторинга состоит из двух основных частей:
- Система протоколирование запросов.
- Система генерации отчетов
Система протоколирования запросов
Система протоколирования в свою очередь состоит из трех не первый взгляд не очень сложных операций:
- Получение информации о клиенте и его системах (ОС, броузер, IP-адрес, уникальность запроса и т.д.).
- Сохранение информации о клиенте и его системах.
- Возвращение клиенту выбранного графического изображения (обычно в формате GIF) содержащего краткую статистическую информацию (Количество хитов или хостов всего, количество хитов и хостов за сегодня)
Конечно наиболее эффективный способ написания такой системы - это закодировать все операции в машинном коде (или на ассемблере). Такой шаг может увеличить скорость выполнения программы в 2-3 раза. Но все-же, такой выигрыш несоизмерим с тем, который можно получить используя специализированное ПО (SQL сервера, которые специально заточены для обработки больших объемов данных) и разделение задач между сервером и клиентами.
Получение информации о клиенте и его системах не представляет из себя ни какой сложности, так как большая часть такой информации передается в готовом виде в HTTP запросе (Тип броузера, ссылающаяся страница, ОС и т.д.) и самом IP пакете (IP адрес). Единственная информация которая должна быть получена программой протоколирования запроса - это уникальность обращения - цифра дающая представление о количестве пользователей посетившем ресурс (Один и тот-же ресурс может быть несколько раз запрошен одним пользователем). Для получения такой информации необходимо заносить все уникальные хосты в специальную таблицу, и проверять существование хоста в ней при любом следующем обращении.
Пример программы протоколирующей все запросы на специальном Web-адаптированном языке PHP (Hypertext Preprocessor) приведен ниже.
Header( "Content-type: image/gif");
header("Cache-Control: no-cache");
// Соединяемся с SQL сервером и выбираем базу данных, проверяем ID (уникальный
// номер) пользователя.
mysql_pconnect($sqlhost,$sqluser,$sqlpassword)
or fatal_error("Ошибка соединения с SQL сервером");
mysql_select_db("rating")
or fatal_error("Ошибка выбора базы данных");
if (!empty($id)) $login=$id;
// Проверяем на ошибки данные полученные от клиента.
$agent=htmlspecialchars($HTTP_USER_AGENT); // Тип броузера
$ip=$REMOTE_ADDR; // IP адрес
$proxy=""; // IP адрес прокси сервера.
if (!empty($HTTP_X_FORWARDED_FOR)) {
$proxy=$ip;
$ip=$HTTP_X_FORWARDED_FOR;
}
$page=urlencode(htmlspecialchars($HTTP_REFERER));
$date=date("Y-m-d H:i:s"); // Дату соединения
$curdate=date("Y-m-d");
$referer=htmlspecialchars($r); // URL загружаемой страницы.
$language=htmlspecialchars($HTTP_ACCEPT_LANGUAGE);
$flag=0;
$login=intval($login); // ID пользователя
// Теперь получим информацию о уникальности данного хоста, для этого проверим
// занесен ли он в таблицу "today", и если хост туда занесен, значит он не
// уникален и flag=0, иначе занесем его туда и flag=1
$r=mysql_query("SELECT count(*) FROM today WHERE login='$login' AND ip='$ip'");
$is=mysql_result($r,0,0);
if ($is==0) {
mysql_query("INSERT INTO today (login,ip) VALUES ('$login','$ip')");
$flag=1;
}
// Занесем информацию о запросе в таблицу "log".
mysql_query("INSERT INTO log (login,date,ip,type,proxy,
page,agent,referer,language)
VALUES ('$login', '$date', '$ip' ,$flag, '$proxy',
'$page', '$agent', '$referer', '$language')");
// Далее изменим общую статистическую информацию, хранящуюся в таблице
// "counter" , и отобразим ее на графическом счетчике, который будет построен
// внешней программой make_gif1
$r=mysql_query("SELECT hits,hosts,t_hits,t_hosts
FROM counter
WHERE id='$login'");
if (mysql_num_rows($r)!=1) {
mysql_query("INSERT INTO counter
SET hits='1', hosts='1',
t_hits='1', t_hosts='1', id='$login'");
$hits=1;
$hosts=1;
$t_hits=1;
$t_hosts=1;
}
else {
$hits=mysql_result($r,0,0)+1;
$t_hits=mysql_result($r,0,2)+1;
$hosts=mysql_result($r,0,1);
$t_hosts=mysql_result($r,0,3);
if ($flag==1) {
$hosts++;
$t_hosts++;
}
mysql_query("UPDATE counter
SET hits='$hits', hosts='$hosts', t_hits='$t_hits',
t_hosts='$t_hosts', last='$date' WHERE id='$login'");
}
passthru($path."binary/make_gif1");
?>
SQL - это вам не это
Вторая - наиболее объемная часть системы мониторинга это Система генерации отчетов. Основная сложность в генерации отчетов - это разнородность самих отчетов. Большинство из них приходится кодировать отдельно, что требует времени. (На рисунке 1 приведен скриншот из системы статистики Top Novgorod On-Line)
Рисунок 1 - меню отчетов системы статистики Top Novgorod On-Line
Все отчеты могут быть построены с помощью SQL запросов, что на первый взгляд кажется несложным, но при более подробном изучении это оказывается не совсем так. При грамотном построении SQL запроса система работает (как и должна) в режиме реального времени. Я не буду подробно рассматривать принципы работы SQL серверов, и способы эффективного построения SQL запросов, я лишь приведу два примера из реальной жизни:
Задача.Необходимо получит список языков, установленных в системах пользователей посетивших Web-ресурс. При этом мы имеем таблицу содержащую код страны, и список "код страны" - "ее название".
Вариант первый.Из списка на стадии разработки создать таблицу (countries), содержащую поля - "код страны" и "название страны", и результат выполнять простым SQL запросом.
FROM log, countries
WHERE log.country_code= countries.country_code
Вариант простой, и даже наверное более правильный, н к сожалению очень медленный (из-за того что результат получается путем выборки информации из двух таблиц, во время которой производится умножение двух таблиц, а что может увеличить объемы обрабатываемых данных в сотни, и даже тысячи раз)
Вариант второй: Мы можем разработать более сложный SQL запрос, но скорость его работы будет на порядок превышать скорость работы предыдущего.
IF(country_cod='ru','Россия',
..............................
IF(country_cod='lv','Латвия',
IF(country_cod='ua','Украина',
'Неизвестный язык'))...)),
COUNT(referer)
FROM log
WHERE login='305'
AND date>'2001-05-06 00:00:00'
AND DATE
Теперь остановимся более подробно на некоторых отчетах.
Отчет о посещаемости Web-ресурса за некоторый период времени
SQL запрос:
WHERE date>'2001-05-06 00:00:00'
AND DATE
Так пользователь видит результат запроса:
Отчет о поисковых системах
SQL запрос:
IF(LOCATE('ttp://www.yandex.ru',referer)!=0,'Яndex',
.....................................................
IF(LOCATE('ttp://search.rambler.ru',referer)!=0,'Rambler',
IF(LOCATE('ttp://sm.aport.ru',referer)!=0,'Апорт',
'Остальные ссылки'))...)),COUNT(referer)
FROM log
WHERE TYPE=1
AND login='305'
AND date>'2001-05-06 00:00:00'
AND DATE
Так пользователь видит результат запроса:
Отчет о языках
SQL запрос:
WHERE date>'2001-05-06 00:00:00'
AND DATE
Так пользователь видит результат запроса:
Заключение
В заключение хотел бы дать один совет, который я не использовал (по неграмотности) в своих системах: как можно больше операций старайтесь выполнить на машинах клиентов, они этого даже не заметят, а вы смажете здорово разгрузить ваш сервер. Например определить уникальность хоста можно используя Cookies - вы избавитесь от заведения дополнительных таблиц, и нескольких SQL запросов во внутреннем цикле системы мониторинга.