Подсчет трафика в nginx
О большой практической пользе awk
Постановка задачи: есть Linux-сервер, на котором живёт сотня-другая виртуальных хостов. Сервер работает под управлением nginx. Нужно реализовать подсчет трафика с отображением «живой» статистики.
Вариант решения:
Таблица для хранения данных:
`in` INTEGER UNSIGNED NOT NULL, /* если качаются файлы размером более 4 ГБ, нужно использовать BIGINT */
`out` INTEGER UNSIGNED NOT NULL,
`sum` INTEGER UNSIGNED NOT NULL,
`host` VARCHAR(64) NOT NULL,
`dt` DATETIME NOT NULL,
`ym` MEDIUMINT NOT NULL,
KEY `host_ym`(`host`, `ym`)
);
Фрагменты конфигурационного файла nginx:
log_format trafctr '$request_length $bytes_sent $server_name $time_local';
}
Каждый виртуальный хост должен содержать подобную строку:
access_log /var/log/nginx/traffic_vhost trafctr;
}
В логе будут записи вида
А теперь собственно чёрная магия с использованием awk:
AWK=/usr/bin/awk
TAIL=/usr/bin/tail
MYSQL=/usr/bin/mysql
MYSQL_USER=mysql
MYSQL_PASS=pass
MYSQL_DB=traffic
LOG_PATH=/var/log/nginx
$TAIL -F $LOG_PATH/* | $AWK '
/^[[:digit:]]+ [[:digit:]]+ / {
m["Jan"]="01";
m["Feb"]="02";
m["Mar"]="03";
m["Apr"]="04";
m["May"]="05";
m["Jun"]="06";
m["Jul"]="07";
m["Aug"]="08";
m["Sep"]="09";
m["Oct"]="10";
m["Nov"]="11";
m["Dec"]="12";
year=substr($4, 8, 4);
month=m[substr($4, 4, 3)];
day=substr($4, 1, 2);
print "INSERT INTO traf_stats VALUES (" $1 ", " $2 ", " $1+$2 ", \"" $3 "\", \"" year "-" month "-" substr($4, 1, 2) " "substr($4, 13, 8) "\", " year month ");"; }
' | $MYSQL -u$MYSQL_USER -p$MYSQL_PASS -D$MYSQL_DB
Удалось обойтись тремя лишними процессами: mysql, awk и tail (вместо пяти: mysql, awk, tail, egrep и sed).
Подсчёт трафика в nginx: часть 2.
Автор: Vladimir; опубликовано в: Linux, MySQL, nginx, Администрирование; метки: Linux, MySQL, nginx, лог, трафикЯнв
2009
Комментарии к статье «Подсчет трафика в nginx» (9) »
Пожалуйста, не используйте эту форму для комментирования! Данная форма предназначена исключительно для ботов.
Оставить комментарий к записи «Подсчет трафика в nginx»
गते गते पारगते पारसंगते बोधि स्वाहा
Меня зовут Владимир, я программист-фрилансер, специализирующийся на Web-программировании и програмировании под Linux.
По совместительству занимаюсь администрированием LAMP/LNMP-серверов и техническим переводом.


Изящное решение.
К сожалению недостаточно знаю mysql, посему возник вопрос:
Если по каким либо причинам будет на некоторое время нарушена связь с сервером MySQL, то что произойдет с описываемой связкой? Она обвалится или просто будут пропущены логи за промежуток с нарушенной связью?
Если честно, я не проверял — копаю сейчас в сторону написания своего модуля для nginx.
Но по идее, в логах просто появится промежуток за время с нарушенной связью.
Кстати, можно обойтись без awk, ведь можно задать log_format таким образом, чтобы сразу создать нужный SQL-запрос.
А если потребуется какая-то сложная логика, можно воспользоваться хранимыми процедурами MySQL.
С одной стороны, да. А с другой стороны — при большой посещаемости такой лог займет очень много места.
И еще. Я проверил, утилита mysql не вываливается в случае обрыва соединения с сервером, а культурно пытается подконнектится при каждом запросе. Так что действительно, будут просто промежутки в БД.
Что касаемо модуля для nginx, то у меня тоже возникла идея создать модуль на базе ngx_http_log_module. Добавить туда возможность записи лога в БД. Правда сразу появились вопросы. Дело в том, что при работе с БД могут возникнуть задержки, которые (вследствие архитектуры nginx) будут блокировать обработку ВСЕХ текущих запросов. Неприятно, однако. Правда, вероятно, есть возможность работать с MySQL в «неблокируещем» режиме, в частности, применять INSERT DELAYED. В итоге я рещил, что проще скрестить tail и mysql, написать маленький демон, который будет, скажем, раз в секунду читать лог nginx и писать его в БД.
Тем не менее, даже просто ради приобретения опыта, я с удовольствием посодействую вам в создании этого модуля, начиная от тестирования и может быть каких-то идей, заканчивая собственно программированием (неплохо владею C и C++).
INSERT DELAYED работает только с MyISAM,я не уверен, целесообразно ли использовать MyISAM при большой посещаемости ресурса.
Просто уже неоднократно видел, как от большого числа вставок падают майисамовские таблицыю
У меня была идея заставить модуль писать в сокет, на другом конце которого будет висеть демон и передавать запросы непосредственно MySQL (возможно, даже с некоторой обработкой данных).
Ну если именно так подходить к вопросу, то зачем вообще заморачиваться? Читать прямо из файла, без всяких сокетов.
Можно еще отдельный поток (thread) создать, который и будет писать в MySQL. А чтобы сервер поменьше мучать, запросы накапливать в буфере и отправлять одним большим INSERTом. А в случае обрыва связи временно буферизовать логи в файле, как это делает mod_log_sql для апача.
Потоки не особо кросс-платформенные. Плюс к тому, при сборке добавляется лишняя зависимость — libmysql15.
Надо в коде nginx основательно покопаться…
[...] статье «Подсчёт трафика в nginx» я приводил один из возможных вариантов живого [...]