mod_proctitle — модуль Apache для отображения запросов и краткой статистики в имени программы (вывод top и ps)

    Часто возникает ситуация, когда надо быстро оценить, чем занимается ваш веб-сервер. Иногда для успокоения «вроде не он». Когда на сервере один апач, один сайт, нагрузка небольшая — проблем нет. Зашел, top посмотрел. /server-status посмотрел, tail -f на логи сделал, помедитировал — и обычно всё понятно. Однако бывает ситуация, когда сайтов много, много самих apache (почти все ОС сейчас из коробки умеют подымать несколько веб-серверов apache, но этим редко пользуются почему-то). Бывает ситуация, когда apache уже и ответить не может. Как было бы хорошо, хотя бы примерно прикинуть, что делают (или уже делали) воркеры апача. Представьте — делаете вы ps -aux, а у вас там — кто какие URL запрашивает, какой ширины канал занят, какова скорость работы — ня!

    Я достаточно давно использую патч для apache, который после разбора строки запроса пишет в имя программы IP, откуда был запрос, то, что пришло в заголовке Host и саму строку запроса. Но этот двухстрочный патч был написан 12 лет назад для Apache версии 1.3. А потом руки не доходили. Тем более, с того времени появилось множество (я за пять минут нашел как минимум два) разновидностей модулей для тех целей, для более новых версий Apache. Однако, со временем мне стало маловато просто строк запросов. И… я написал свой модуль.

    Доктор, откуда у Вас такие картинки?


    Вначале я намучился с отсутствием документации для разработчиков у Apache. Нужные hook'и пришлось искать методом перечитывания всего исходного кода. Не, когда вы уже 10-ой модуль пишете, оно может и отлично, а когда первый и может быть последний — проблема.

    Когда мне удалось найти хук ap_hook_monitor(), который вызывается из рутового процесса apache каждые 20 запросов или каждую 1 секунду, мною овладела жажда запихать в строку как можно больше крутой статистики. Я пробовал всякие статусы, количества, загрузку за 10 секунд, 1 минуту, 5 минут, аптайм… Но посмотрев на результат, я понял, что эта мишура только мешает и оставил только битрейт и запросы в секунду.

    Самым главным новшеством модуля являются значения Complete и Incomplete Listen Queue Lenght. Это когда в httpd.conf пишем BackLog чтототам, то запросы, которые сервер не успевает принять, копятся в этой очереди. А когда очередь заполняется — начинают отбрасываться. Обычно такое происходит при хабраэффекте например, или если сайт обращается к стороннему ресурсу, а тот «лежит» или заблокирован (как например недавно github). И вот тут нашему глазу очень поможе цифра в listen queue и цифра qps.

    Как всё плохо в этих ваших линуксах


    Внезапно оказалось, что малыми жертвами модуль можно написать только под FreeBSD. Для изменения имени программы там есть функция setproctitle(), а посмотреть Complete и Incomplete Listen Queue Lenght можно через вызов getsockopt() с параметром SO_LISTENQLEN и SO_LISTENINCQLEN.

    Для Linux всё сложнее. Требуется взять имя исполняемого файла и отдельно всегда его дописывать (FreeBSD делает это автоматически). Это нужно помому, что подавляющее большинство rc-скриптов используют имя, которое светится в ps в целях запуска/перезапуска.

    Для Linux оказалось непросто и значения Listen Queue найти. Пока что мне видится вариант работы с netlink(7). Но детали ускользают.

    Вливайся


    Для FreeBSD + Apache 2.4 модуль абсолютно работоспособен. Можно попробовать его на других версиях Apache. Можно и нужно помочь портировать его на Linux.

    Модуль распространяется в исходных кодах и вы можете сделать с ним всё, что захотите:
    github.com/schors/mod_proctitle

    P.S. Некстати, хочу дополнить его функцией периодического сброса статистики по UDP куда-нибудь. Чуть более полной.
    Поделиться публикацией
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 25
    • +2
      Насчет udp рекомендую посмотреть pinba.
      Изначально pinba делалась для php, но уже есть nginx модуль для pinba.
      Я думаю, модуль apache для pinba сделать будет не так сложно.
      • 0
        Спасибо кстати за pinba. Написать UDP не сложно. На самом деле даже для Linux setproctitle передрать не сложно. Устал на поиске listen queue :))) Основная сложность оказалась на вот этом Listen Queue — очень нестандартная вещь в смысле информации, хотя в ядрах имеется с BSD4.4.
        • +1
          Да setproctitle и передирать не надо, есть минимум одна готовая либа: git.altlinux.org/people/ldv/packages/setproctitle.git
          • 0
            Ну например. Ну один фиг посмотреть внутрь надо. А то как посмотришь, так волосы шевелиться начинают.
            • 0
              А вот точно ли rx_queue это оно? Я вот гуглением не понял. Такое впечатление, что там наполненность буферов. Во всяком случае netstat и ss показывают совершенно разные значения Recv-Q и Sent-Q для одного и того же на одной машине в один момент времени. А вот ss лезет в netlink(7) в нормальной ситуации.
              • 0
                Хм… по исходникам вообще похоже на «оно». Собственно в netlink попадает inet_diag_msg.rqueue который явно в /usr/src/linux/net/ipv4/tcp_diag.c:

                if (sk->sk_state == TCP_LISTEN) {
                                r->idiag_rqueue = sk->sk_ack_backlog;
                                r->idiag_wqueue = sk->sk_max_ack_backlog;
                        } else {
                                r->idiag_rqueue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
                                r->idiag_wqueue = tp->write_seq - tp->snd_una;
                        }
                
          • 0
            P.S. Некстати, хочу дополнить его функцией периодического сброса статистики по UDP куда-нибудь. Чуть более полной.
            — добавь в collectd
            • 0
              Ну вот как вариант.

              P.S. Вот кстати следующий шаг — заправить gstat в collectd
            • 0
              А с каким mpm дружит? peruser?
              • 0
                И вспомнили же труп…
                Судя по коду он будет работать без проблем с prefork и основанным на нем, такими как itk.
                • 0
                  peruser получше будет, чем itk. Itk chroot не умеет
                  • +1
                    Тем не менее проект труп.
                    • 0
                      peruser не мертв, пилят его потихоньку, в Freebsd листах патчи проявляются периодически.
                • 0
                  Проверял и на prefork и на worker. На worker по очевидным причинам запросы не показывает. На event тоже запросы не показывает, а статистику не проверял на нем.
                  • 0
                    peruser/itk не проверял. Должен показывать статистику… запросы… а фиг знает. Это в зависимости где он форк делает. И да, будут врать со статусом.

                    Не надо использовать ни itk, ни peruser. Запускайте каждому свой апач. Там перерасход памяти под буфера, да под конфиг смехотворный. А и FreeBSD и вроде даже Linux уже 100 лет умеют mmap´ить и .so, и запускаемые файлы, там вообще перерасхода 0. Под FreeBSD «каждому свой апач» вообще штатно из кородки идёт — взгляните внутрь /usr/local/etc/rc.d/apache24. С Linux сложнее, они такие затейники с конфигурациями…
                    • 0
                      Это смехотворно, когда надо штук 10 запустить, когда 500 уже другой результат.
                      Разница 2.5 гб под только запущенное и 500мб под только запущенное.
                      Как разкочегарится все вырастает в два раза.
                      • 0
                        Это откуда такие цифры? Нет там такого. Любой php скрипт сожрёт больше в сумме, чем apache.
                        • 0
                          mod_perl + mod_php вот в такое и вырастает.
                          • 0
                            А в peruser _не_ вырастает? За счёт простите чего?
                  • 0
                    Для Linux давно уже использую модифицированный модуль mod_proctitle(не этот, а старый).
                    К нему собрал библиотеку с одной функцией setproctitle.
                    Есть в Linux проблема с длиной тайтла, но я ее решаю в Apache правкой скрипта инициализации.
                    Работает как часы уже 3-4 года.
                    • 0
                      Ну вот мне надо просто взять и туда же воткнуть тоже такую функцию :) У всех есть проблема с длиной тайтла :) FreeBSD просто не устанавливает его, если длина превышена. Я вот думаю, не внедрить ли враппер-функцию, которая резать будет.
                      • +1
                        Я как-то кроссплатформенный setproctitle из исходников proftpd выдирал, там оно вполне компактно и не пугающе.
                        • 0
                          А вот кстати. А кто-нибудь в курсе, что там ещё за способы в proftpd? Там есть ifdef´ы, которые я не совсем понимаю. Документации и комментариев конечно 0, поэтому только гадать.
                        • +1
                          Вам бы документацию по этому механизму в Linux почитать.
                          Проблемы ведь в том что длина тайтла должна быть такой же как длина argv массива.
                          По докам можно дописать еще в env массив, но по факту не работает.
                          Т.е. нужно сделать длинным argv массив.
                          А ограничивать длину все равно нужно, иначе переполнение будет.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое