Минимальная установка и стресс тестирование производительности веб-сервера Apache

THE HOLY BIBLE - King James Version - БИБЛИЯ в Синодальном переводе
"Нас Атакуют!" Изобличи козни лукавого, запрети диаволу

Минимальная установка и стресс тестирование производительности веб-сервера Apache

Установка собственного веб-сервера Apache - дело несложное, но требующее некоторой практики. Веб-сервер необходимо сконфигурировать в соответствии с требованиями веб-приложения и в пределах возможностей имеющегося аппаратного обеспечения. Гонка за числом запросов в секунду приносит больше вреда, чем пользы и заканчивается крахом "сверхпроизводительного" сервера под реальной повседневной нагрузкой.

Данная заметка предлагает читателю способ минимальной установки веб-сервера Апачи на базе Oracle Enterprise Linux 6.1, его начального стресс-тестирования, последующей проверки правильности работы веб-приложения и выявления утечек памяти. Для тестов будут использоваться поставляемый с Апачи "ab" и программа "siege", входящая в состав большинства дистрибутивов Linux.

Прежде чем мы продолжим, я хотел бы привести строки из Евангелия:



............. == Послание к Ефесянам святого апостола Павла == .................
=== Глава 2, Стих 1 ===
1 И вас, мертвых по преступлениям и грехам вашим,
2 в которых вы некогда жили, по обычаю мира сего, по воле князя,
 господствующего в воздухе, духа, действующего ныне в сынах противления,
3 между которыми и мы все жили некогда по нашим плотским похотям, исполняя
 желания плоти и помыслов, и были по природе чадами гнева, как и прочие,
4 Бог, богатый милостью, по Своей великой любви, которою возлюбил нас,
5 и нас, мертвых по преступлениям, оживотворил со Христом, -- благодатью вы
 спасены, --
6 и воскресил с Ним, и посадил на небесах во Христе Иисусе,
7 дабы явить в грядущих веках преизобильное богатство благодати Своей в
 благости к нам во Христе Иисусе.
8 Ибо благодатью вы спасены через веру, и сие не от вас, Божий дар:
9 не от дел, чтобы никто не хвалился.

Лично для вас благая весть - Единородный Сын Божий Иисус Христос любит вас, Он взошел на крест за ваши грехи, был распят и на третий день воскрес, сел одесную Бога и открыл нам дорогу в Царствие Небесное.

"благодатью вы спасены через веру" - какие простые слова и как много откровенного смысла вместили они! Вся наша жизнь, предшествующая Покаянию - одна сплошная цепь грехов и преступлений. И как бы ни старался кто-либо неверующий делать, как ему кажется, добро - выходит только хуже. Потому что неспасённый человек не имеет понятия о добре, все извращено в его уме диаволом. И спастись делами невозможно - только вера в Иисуса Христа спасает нас, грешников, по милости Господа и Его любви к нам. И только тогда, уверовавший и спасшийся через веру может понять что же есть истинное добро и как делать его, возлюбив ближнего своего "как самого себя". И только тогда приходит великое и "преизобильное богатство благодати" Божией к оживотворённым со Христом - воистину Божий дар, который каждый из нас должен заслужить.

Покайтесь, примите Иисуса как вашего Спасителя, ибо наступают последние времена и время близко - стоит Судья у ворот.

Пожалуйста, в своих каждодневных трудах, какими бы занятыми вы себе ни казались - находите время для Бога, Его заповедей и Библии.

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


Вернемся к нашим техническим деталям.

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

Я предполагаю, что уважаемый читатель уже устанавливал Linux самостоятельно и имеет представление о базовых действиях - это позволит мне избежать массы ненужных копий экрана и быть предельно кратким, сосредотачиваясь на сути. В моей статье я использую Oracle Unbreakable Linux 6.1 с ядром Oracle Unbreakable Enterprise Kernel как операционную систему.

Помимо начальной установки, мы рассмотрим два варианта тестирования Апачи:

  • Стресс-тест - определение максимального для нашего сервера числа "простых" http запросов.
  • Тест функциональности - проверка правильности работы и масштабируемости всей системы в комплексе.
  • Я хотел бы подчеркнуть ещё раз - по моему глубокому убеждению, веб сервер должен "строиться" под определенное приложение с уже известными функциональными особенностями. Если вам необходимо просто выдавать как можно больше статических страниц в секунду - Апачи должен быть собран соответственно, делая основной упор на модули кэширования и сжатия. (Этот вариант очень похож на наш первый стресс-тест). Если же ваша цель - обработка данных и вывод динамических страниц, ваш Апачи должен собираться и тестироваться совершенно по-другому.

    Более того, я отдаю предпочтение разработке веб приложений как можно "ближе" к самому "ядру" веб сервера. Именно поэтому мой проект "Нас Атакуют!" Изобличи козни лукавого, запрети диаволу разработан как модуль вебсервера и не использует никаких frameworks типа php, cgi, RoR и прочих. Это позволяет мне максимально упростить сервер и избежать всех недостатков "скриптования", связанных с безопасностью.

    Тем не менее, описываемый здесь процесс установки и тестирования пригодится и пользователям frameworks - вам только понадобятся дополнительные действия по установке и конфигурированию соответствующих модулей Апачи.

    Установка минимальной операционной системы

    Я выбрал OUL 6.1 по ряду причин, основными из которых стали его масштабируемость, производительность и бесплатность. Все написанное ниже почти буквально подойдет и для Red Hat 6.

    Прежде чем вставлять диск, зайдите в BIOS машины и установите время в GMT. Также проверьте настройки биоса и устраните досадные недоразумения, типа выключенной поддержки много-ядерности, слишком консервативных установок контроллера SATA и прочих.

    Загрузите компьютер с OUL 6.1 64-бит dvd диска

    Естественно, это предполагает наличие современного 64-битного процессора. Я активно использую вызовы "mmap" в своих проектах и 32 битная архитектура накладывает нежелательные ограничения на максимальный размер "отображаемого" в память файла.

    Выберите тип установки "Install with basic video driver". Oracle Enterprise Kernel (2.6.32-100.34.1.el6uek.x86_64) будет автоматически выбран как опция загрузки по умолчанию.

    Я предпочитаю создавать файловую систему ext4 на обычных разделах (partitions), не используя Logical Volume Managers. Создайте отдельный раздел для своппинга, размером в два раза превышающим объём оперативной памяти. Иногда бывает полезно создать отдельный раздел для файловой системы "/boot" с "консервативной" файловой системой типа ext2. Если на вебсервере будут храниться какие-либо секреты, файловую систему надо шифровать - в этом случае придется использовать и LVM и LUKS. Это крайне нежелательно, так как надо будет вводить пароль файловой системы при каждой перегрузке, а следовательно находиться рядом с сервером.

    Выберите конфигурацию "minimal configuration" и добавьте вручную compilers, make и binutils пакеты - они понадобятся для компиляции и сборки Апача. Впоследствии средства разработки (gcc) рекомендуется удалить из соображений безопасности.

    Установите систему как обычно, следуя инструкциям на экране. Пароль "root" выберите получше, но это не будет играть особой роли - весь доступ к нашей машине будет осуществляться исключительно с использованием public/private keys infrastructure. Сетевые параметры я обычно выбираю как DHCP и потом уже на сетевом роутере резервирую нужный IP адрес и привязываю его к MAC адресу моего сервера. Время машины у нас установлено в GMT - не забудьте сообщить об этом программе установки.

    По окончании установки перегрузите машину, установите пароль на BIOS вашей системы и запретите загрузку со всего, кроме встроенного жесткого диска. Если машина будет находиться во внешнем помещении, выберите корпус типа "full tower" и заприте его на ключ. С лаптопами я поступаю проще - заклеиваю корпус по периметру на стыке старой доброй эпоксидкой (или супер клеем, по вкусу). Не забываем, что лаптоп - это одноразовое вычислительное средство.

    Ну, достаточно шуток. Теперь самое время защитить паролем однопользовательский режим работы линукса. Последние версии этой системы отказались от классических безотказно работавших "System V init scripts" и перешли на новые экзотические продукты (которые продолжают изменяться от релиза к релизу). В OUL6 мы редактируем файл "/etc/sysconfig/init" и устанавливаем "SINGLE=/sbin/sulogin". Также измените в "PROMPT=no" чтобы отключить "interactive startup".

    Запустите сетевой интерфейс

    По доброй традиции, OUL и RedHat игнорируют настройки сетевого интерфейса при минимальной установке. Как "root" изменим последующие файлы:

    Файл: /etc/sysconfig/network-scripts/ifcfg-eth0
    Должен содержать:
    
    DEVICE="eth0"
    HWADDR=xxxxxxxxxx
    NM_CONTROLLED="no"
    ONBOOT="yes"
    BOOTPROTO="dhcp"
    
    Перезапустите сеть:
    service network restart
    
    Проверьте сервис:
    
    Last login: Mon Oct  3 15:50:31 2011 from myhost.read-and-think.org
    ..................... == Первая книга Паралипоменон == .........................
    === Глава 28, Стих 9 ===
    8 И теперь пред очами всего Израиля, собрания Господня, и  во  уши  Бога  нашего
    _говорю:_ соблюдайте и держитесь всех заповедей  Господа  Бога  вашего,  чтобы
    владеть вам сею доброю землею и оставить ее  после  себя  в  наследство  детям
    своим на век;
    9 и ты, Соломон, сын мой, знай Бога отца твоего и служи Ему от  всего  сердца  и
    от всей души, ибо Господь испытует все сердца и  знает  все  движения  мыслей.
    Если будешь искать Его, то найдешь Его, а если оставишь Его, Он  оставит  тебя
    навсегда.
    
    [root@attack ~]#
    [root@attack ~]# service network status
    Configured devices:
    lo eth0
    Currently active devices:
    lo eth0
    [root@attack ~]#
    [root@attack ~]# ifconfig
    eth0      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
    inet addr:192.168.1.11  Bcast:192.168.1.255  Mask:255.255.255.0
    inet6 addr: fe80::218:8bff:feaa:afdd/64 Scope:Link
    UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
    RX packets:365 errors:0 dropped:0 overruns:0 frame:0
    TX packets:258 errors:0 dropped:0 overruns:0 carrier:0
    collisions:0 txqueuelen:1000
    RX bytes:39993 (39.0 KiB)  TX bytes:36271 (35.4 KiB)
    Interrupt:18
    
    lo        Link encap:Local Loopback
    inet addr:127.0.0.1  Mask:255.0.0.0
    inet6 addr: ::1/128 Scope:Host
    UP LOOPBACK RUNNING  MTU:16436  Metric:1
    RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
    collisions:0 txqueuelen:0
    RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
    
    [root@attack ~]#  -- Проверим работу сети, пингуем мой сетевой шлюз:
    [root@attack ~]# ping 192.168.1.1
    PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
    64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.02 ms
    64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.573 ms
    ^C
    --- 192.168.1.1 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1723ms
    rtt min/avg/max/mdev = 0.573/0.796/1.020/0.225 ms
    [root@attack ~]#
    

    Я устанавливаю "Библию для людей, работающих с командной строкой" на все мои сервера, и этот не исключение - как видно, при каждом открытии терминальной сессии меня встречает стих из Библии.

    Добавьте работающий yum-репозиторий в вашу систему

    Этот шаг значительно упрощает админситрирование системы и просто необходим. Oracle поддерживает "общественный" репозиторий - добавим его и будем использовать при каждом добавлении программных пакетов. Как root, поместим в каталог
    "/etc/yum.repos.d" файл загруженный из "http://public-yum.oracle.com/public-yum-ovm2.repo". Откроем в текстовом редакторе файл "/etc/yum.repos.d/public-yum-ovm2.repo" и изменим "enabled=0" на "enabled=1" только для последней записи "ol6_u1_base". Теперь выдадим команду "yum repolist" - вы должны увидеть репозиторий с именем "Oracle Linux 6 U1 - x86_64 - base".

    Добавим необходимые пакеты в систему:

  • yum install man sysstat file mlocate lynx wget openssh-clients-5.3p1-52.el6.x86_64
  • yum install vim-common.x86_64 vim-enhanced.x86_64 elinks bind-utils
  • Установите правильное время и его синхронизацию

    Правильный часовой пояс выставляется на линуксе созданием symbolic link из "/etc/localtime" на соответствующий файл в "/usr/share/zoneinfo" каталоге. Используйте "hwclock" чтобы проверить правильность времени в BIOS. Установите правильное текущее время командой "date". Наконец, установите ntpd ("yum install ntp*") и запустите службу времени ("chkconfig ntpd on", "service ntpd start"). Подождите минут 10-20 и проверьте как синхронизируется время:

    ..................... == Книга Премудрости Соломона == .........................
    === Глава 3, Стих 19 ===
    18 А  если  скоро  умрут,  не  будут  иметь  надежды  и  утешения  в  день суда;
    19 ибо ужасен конец неправедного рода.
    
    [root@attack ~]#
    [root@attack ~]# yum list installed ntp*
    Installed Packages
    ntp.x86_64                                4.2.4p8-2.el6           @ol6_u1_base
    ntp-doc.noarch                            4.2.4p8-2.el6           @ol6_u1_base
    ntpdate.x86_64                            4.2.4p8-2.el6           @ol6_u1_base
    [root@attack ~]# service ntpd status
    ntpd (pid  1278) is running...
    [root@attack ~]# chkconfig --list ntpd
    ntpd           	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    [root@attack ~]# grep -i "synchronized" /var/log/messages
    Oct  3 16:03:10 attack ntpd[1278]: synchronized to xxxxx, stratum 2
    [root@attack ~]#
    

    Отключите ненужные службы

    Чем меньше процессов занимает процессор нашей машины, тем лучше. Кроме того, соображения безопасности требуют ограничивать число работающих служб до самого минимума.

  • chkconfig netfs off
  • chkconfig postfix off
  • chkconfig rhnsd off
  • chkconfig rsyslog on
  • chkconfig sshd on
  • chkconfig sysstat on
  • В результате получается что-то подобное приведенному ниже. Как видно, я использую LVM на этом сервере.

    ..................... == Первая книга Паралипоменон == .........................
    === Глава 16, Стих 23 ===
    23 Пойте Господу,  вся  земля,  благовествуйте  изо  дня  в  день  спасение Его.
    
    [root@attack ~]# chkconfig --list | grep 3:on
    auditd         	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    crond          	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    ip6tables      	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    iptables       	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    lvm2-monitor   	0:off	1:on	2:on	3:on	4:on	5:on	6:off
    network        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    ntpd           	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    rsyslog        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    sshd           	0:off	1:off	2:on	3:on	4:on	5:on	6:off
    sysstat        	0:off	1:on	2:on	3:on	4:on	5:on	6:off
    udev-post      	0:off	1:on	2:on	3:on	4:on	5:on	6:off
    [root@attack ~]#
    

    Настройте брандмауэр (или как мы там называем сегодня firewall?)

    Про настройки iptables можно писать много и долго. В нашем случае разрешим только ssh и http, а все остальное запретим.

    ............ == Послание к Филиппийцам святого апостола Павла == ...............
    === Глава 2, Стих 7 ===
    6 Он,  будучи  образом  Божиим,  не  почитал   хищением   быть   равным    Богу;
    7 но уничижил Себя Самого, приняв образ раба, сделавшись  подобным  человекам  и
    по виду став как человек;
    8 смирил  Себя,  быв   послушным   даже   до   смерти,   и   смерти    крестной.
    
    [root@attack ~]# cat /etc/sysconfig/iptables
    # Это просто образец, не рассчитывайте найти именно это на моем сайте :-)
    *filter
    :INPUT DROP [0:0]
    :FORWARD DROP [0:0]
    :OUTPUT ACCEPT [0:0]
    -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    -A INPUT -m state --state NEW -m tcp -p tcp --dport ssh -j ACCEPT
    -A INPUT -m state --state NEW -m tcp -p tcp --dport http -j ACCEPT
    -A INPUT -j DROP
    -A FORWARD -j DROP
    COMMIT
    [root@attack ~]# iptables -L
    Chain INPUT (policy DROP)
    target     prot opt source               destination
    ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
    ACCEPT     all  --  anywhere             anywhere
    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:http
    DROP       all  --  anywhere             anywhere
    
    Chain FORWARD (policy DROP)
    target     prot opt source               destination
    DROP       all  --  anywhere             anywhere
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    [root@attack ~]# ip6tables -L
    Chain INPUT (policy DROP)
    target     prot opt source               destination
    ACCEPT     all      anywhere             anywhere            state RELATED,ESTABLISHED
    ACCEPT     all      anywhere             anywhere
    DROP       all      anywhere             anywhere
    
    Chain FORWARD (policy DROP)
    target     prot opt source               destination
    DROP       all      anywhere             anywhere
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    [root@attack ~]#
    

    Настройте удалённый доступ к серверу

    Как я уже говорил, доступ к нашему серверу возможен только через ssh и с использованием индивидуальных "ключей". После 2-3 дней в интернете проверьте логи вашего sshd и вы убедитесь, что это было правильным решением - наши друзья из Китая, Индии и обеих Корей проявляют завидное упорство в деле подбора паролей.

    Нам требуется создать обычных пользователей, перегенерировать ключи сервера и настроить ssh сервер правильно:

    -- as root, use "useradd -m myuser"
    Также, создайте пользователя с именем "apache":
    -- as root, use "useradd -r -m apache"
    
    -- as root, (re)generate host keys
    ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
    ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
    
    .............. == Послание к Евреям святого апостола Павла == ..................
    === Глава 8, Стих 13 ===
    13 Говоря "новый", показал ветхость первого;  а  ветшающее  и  стареющее  близко
    к уничтожению.
    
    [root@attack ~]# cat /etc/ssh/sshd_config  | grep -v "^#" | grep -v "^$"
    Protocol 2
    SyslogFacility AUTHPRIV
    LoginGraceTime 2m
    PermitRootLogin no
    StrictModes yes
    MaxAuthTries 3
    MaxSessions 10
    HostbasedAuthentication no
    IgnoreRhosts yes
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    GSSAPIAuthentication no
    UsePAM yes
    AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
    AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
    AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
    AcceptEnv XMODIFIERS
    X11Forwarding no
    Subsystem	sftp	/usr/libexec/openssh/sftp-server
    

    Теперь используйте "ssh-keygen" чтобы сгенерировать свой уникальный ключ на вашей рабочей станции и поместите его "public" часть в файл "/home/myuser/.ssh/authorized_keys" в вашей домашней директории на вебсервере. После этого перезапустите ssh (service sshd restart) - строка "PermitRootLogin no" (см. выше) запрещает доступ к серверу как root, а строка "PasswordAuthentication no" не позволяет использовать пароли для входа на сервер.

    Установка Веб Сервера Apache

    С установкой минимальной ОС покончено. Теперь нам необходимо установить вебсервер. Делается это только из исходного кода и никак по-другому. Не используйте пакет Апачи из вашего дистрибутива линукс.

    Подготовьте исходный код

    Загрузите последнюю стабильную версию кода с сайта apache и поместите "tar.gz" файл в директорию "/root" на вебсервере. Как root распакуйте архив. Создайте в новой директории файл "apache_config.sh" и сделайте его исполняемым:

    == Первое послание к Фессалоникийцам (Солунянам) святого апостола Павла == ....
    === Глава 3, Стих 13 ===
    12 А вас Господь да исполнит и преисполнит любовью  друг  к  другу  и  ко  всем,
    какою мы исполнены к вам,
    13 чтобы утвердить сердца  ваши  непорочными  во  святыне  пред  Богом  и  Отцем
    нашим в пришествие  Господа  нашего  Иисуса  Христа  со  всеми  святыми  Его.
    Аминь.
    
    [root@attack httpd-2.2.21]# pwd
    /root/httpd-2.2.21
    [root@attack httpd-2.2.21]# cat apache_config.sh
    #!/bin/bash
    # Check http://httpd.apache.org/docs/2.2/install.html
    ./configure --disable-authz-host --disable-authz-groupfile --enable-auth-digest --disable-include --disable-filter \
    --disable-auth-basic --disable-authn-default --disable-authz-default --disable-expires --disable-headers \
    --disable-deflate --disable-env --disable-autoindex --disable-asis --enable-info --disable-cgi --disable-actions \
    --disable-imagemap --enable-mime-magic --disable-version --disable-negotiation \
    --disable-userdir --enable-dir --disable-alias --with-included-apr --with-mpm=prefork \
    --disable-cache --disable-disk-cache --disable-mem-cache --disable-file-cache
    
    # Сия галиматья компилит в сервер только эти статические модули:
    # Compiled in modules:
    #   core.c
    #   mod_authn_file.c
    #   mod_authz_user.c
    #   mod_auth_digest.c
    #   mod_log_config.c
    #   mod_mime_magic.c
    #   mod_setenvif.c
    #   prefork.c
    #   http_core.c
    #   mod_mime.c
    #   mod_status.c
    #   mod_info.c
    #   mod_dir.c
    #   mod_so.c
    [root@attack httpd-2.2.21]#
    

    Как вы понимаете, содержимое файла "apache_config.sh" я подогнал под свои нужды. Тем не менее, для нашей цели построения минимального самого быстрого и безопасного вебсервера именно эта конфигурация является оптимальной. Впрочем, для действительно самого быстрого сервера вам понадобятся все модули с "cache" в последней строке. Я ими не пользуюсь, так как мой проект написан сам по себе в виде модуля и мой код, исполняемый внутри Апача, имеет непосредственный контроль над внутренним механизмом кэширования вебсервера, который я контролирую и изменяю напрямую, без всяких модулей.

    Скомпилируйте и установите сервер

    Теперь приступим к самому процессу конфигурации, компиляции и установки Апача. Как root:

  • ./apache_config.sh
  • make
  • make install
  • make distclean
  • Сервер будет установлен в "/usr/local/apache2", где ему и место.

    Следите чтобы в последних строках вывода каждого скрипта не было сообщений об ошибках. Если они есть на этапе "config" - наверняка вы пропустили какую-то библиотеку или добавили к моему списку (выше) какую-либо опцию. Найдите нужную библиотеку и установите ее. Самый лучший помощник в этом нелегком деле - "yum", используйте его так: "yum provides */glibc*" - в этом примере я ищу стандартную библиотеку C, что весьма странно :-)

    Как видно, я выполняю все шаги как "root", что обычно умиляет специалистов по безопасности. На самом деле, именно в этом случае никакой разницы нет. Еще один "тонкий" момент - я использую самый старый Multi-Processing Module (MPM) с именем prefork, что обычно вызывает насмешки :-) Тем не менее, я рекомендую именно этот MPM по многим причинам, одна из которых - мое убеждение в том, что "threads are evil". Если у читателя есть желание использовать что-либо поновее - пожалуйста, все что требуется это заменить "--with-mpm=prefork" на "--with-mpm=event" (и запастись терпением и адресом листа рассылки разработчиков апачи :-))

    Еще одна деталь - если вы планируете использовать базу данных для хранения записей на вашем сервере, наилучший выбор - использовать модуль "mod_dbd" и библиотеку APR. Блестящие результаты показывает SQLite.

    Сконфигурируйте ваш новый вебсервер

    Мы почти у цели - нам надо создать конфигурационный файл, несколько директорий и наконец запустить сервер. Ниже я привожу краткий список всего, что надо сделать.

    Подготовим конфигурационный файл "httpd.conf" и поместим его в "/usr/local/apache2/conf/"

    .............. == Послание к Галатам святого апостола Павла == .................
    === Глава 3, Стих 20 ===
    20 Но    посредник    при     одном     не     бывает,     а     Бог       один.
    
    [root@attack httpd-2.2.21]# cd /usr/local/apache2/
    [root@attack apache2]# cd conf
    [root@attack conf]# cat httpd.conf | grep -v "^#" | grep -v "^$"
    ServerTokens OS
    ServerRoot "/usr/local/apache2"
    PidFile run/httpd.pid
    Timeout 60
    KeepAlive Off
    MaxKeepAliveRequests 100
    KeepAliveTimeout 15
    <IfModule prefork.c>
    StartServers      10
    MinSpareServers    5
    MaxSpareServers   20
    ServerLimit      300
    MaxClients       300
    MaxRequestsPerChild  8000
    </IfModule>
    Listen 80
    Include conf.d/*.conf
    ExtendedStatus On
    User apache
    Group apache
    ServerAdmin nospam@read-and-think.org
    ServerName attack.read-and-think.org:80
    UseCanonicalName On
    DocumentRoot "/usr/local/apache2/htdocs"
    <Directory />
    Options FollowSymLinks
    AllowOverride None
    </Directory>
    <Directory "/usr/local/apache2/htdocs">
    Options FollowSymLinks
    AllowOverride None
    </Directory>
    DirectoryIndex index.html index.html.var
    TypesConfig /etc/mime.types
    DefaultType text/plain
    <IfModule mod_mime_magic.c>
    MIMEMagicFile conf/magic
    </IfModule>
    HostnameLookups Off
    ErrorLog logs/error_log
    LogLevel warn
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    LogFormat "%{Referer}i -> %U" referer
    LogFormat "%{User-agent}i" agent
    CustomLog logs/access_log combined
    ServerSignature Off
    <Directory "/var/www/icons">
    Options FollowSymLinks
    AllowOverride None
    </Directory>
    AddLanguage en .en
    AddLanguage ru .ru
    AddDefaultCharset UTF-8
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddType application/x-x509-ca-cert .crt
    AddType application/x-pkcs7-crl    .crl
    AddHandler type-map var
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
    <IfModule mod_negotiation.c>
    <IfModule mod_include.c>
    <Directory "/var/www/error">
    AllowOverride None
    Options IncludesNoExec
    AddOutputFilter Includes html
    AddHandler type-map var
    #Order allow,deny
    #Allow from all
    LanguagePriority en es de fr
    ForceLanguagePriority Prefer Fallback
    </Directory>
    </IfModule>
    </IfModule>
    BrowserMatch "Mozilla/2" nokeepalive
    BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
    BrowserMatch "RealPlayer 4\.0" force-response-1.0
    BrowserMatch "Java/1\.0" force-response-1.0
    BrowserMatch "JDK/1\.0" force-response-1.0
    BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
    BrowserMatch "MS FrontPage" redirect-carefully
    BrowserMatch "^WebDrive" redirect-carefully
    BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully
    BrowserMatch "^gnome-vfs/1.0" redirect-carefully
    BrowserMatch "^XML Spy" redirect-carefully
    BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
    <Location /server-status>
    SetHandler server-status
    AuthType Digest
    AuthName "Сюда нельзя!"
    AuthDigestDomain /server-status
    AuthDigestProvider file
    AuthUserFile /somedir/somefile
    Require valid-user
    </Location>
    <Location /server-info>
    SetHandler server-info
    AuthType Digest
    AuthName "Сюда нельзя!"
    AuthDigestDomain /server-status
    AuthDigestProvider file
    AuthUserFile /somedir/somefile
    Require valid-user
    </Location>
    [root@attack conf]#
    

    Тема конфигурации апача заслуживает отдельного сайта - и их достаточно в интернете. Не забывайте, что лучший источник информации - вебсайт разработчиков Апачи. Ознакомление с материалом займет некоторое время, но результат превзойдет все ваши ожидания - сделайте себе подарок, прочтите документацию!

    Из моего конфигурационного файла видно, что я использую digest authentication. Причины, по которым я это делаю, изложены на моем вебсайте "Нас Атакуют!" Изобличи козни лукавого, запрети диаволу - добро пожаловать увидеть и проверить Апачи модуль в действии. Если вы все-таки зайдете на мой сайт - большое спасибо, и всегда смотрите в source code сгенерированной страницы. Обратите внимание - рисование диаграмм с использованием Cairo занимает неприлично много времени, но мне очень нравится эта библиотека (и я категорически против HTML 5 с его "canvas"). Также заметьте что время подготовки страницы указывается в микросекундах (а не миллисекундах) - это к разговору на тему "какой медленный сервер Апачи" :-)

    Проверьте конфигурационный файл командой "/usr/local/apache2/bin/httpd -t" - ответ должен быть "Syntax OK", если это не так - найдите и устраните ошибку прежде чем продолжить.

    Создадим недостающие директории

    Несколько мелких доделок:

    -- mkdir /usr/local/apache2/conf.d
    [root@attack ~]# ls -latrh /usr/local/apache2/ | grep conf.d
    drwxr-xr-x.  2 root root 4.0K Jul 24 11:18 conf.d
    [root@attack ~]#
    
    -- mkdir /usr/local/apache2/run
    [root@attack ~]# ls -la /usr/local/apache2/| grep run
    drwxr-xr-x.  2 root root  4096 Oct  1 18:42 run
    [root@attack ~]#
    
    Если еще не сделано:
    -- create user apache
    [root@attack ~]# useradd -r -m apache
    [root@attack ~]# id -a apache
    uid=xx(apache) gid=xx(apache) groups=xx(apache)
    [root@attack ~]#
    
    -- copy file "mime.types" from directory
    "/usr/local/apache2/conf/mime.types"
    into "/etc":
    [root@attack ~]# ls -la /etc/mime.types
    -rw-r--r--. 1 root root 48509 Oct  1 18:38 /etc/mime.types
    

    Проверим наличие открытых уязвимостей Apache на вебсайте seclists.org и последуем приведенным там рекомендациям.

    Проверьте чтобы в стартовом скрипте Апачи (ниже) переменная среды LANG для Apache была бы установлена в UTF.

    ................. == Откровение святого Иоанна Богослова == ....................
    === Глава 2, Стих 9 ===
    9 Знаю твои дела, и скорбь, и нищету (впрочем ты богат),  и  злословие  от  тех,
    которые  говорят  о  себе,  что  они  Иудеи,  а  они  не  таковы,  но  сборище
    сатанинское.
    
    [root@attack ~]#
    [root@attack ~]# cat /etc/init.d/httpd
    #!/bin/bash
    #
    # httpd        Startup script for the Apache HTTP Server
    . /etc/rc.d/init.d/functions
    
    if [ -f /etc/sysconfig/httpd ]; then
    . /etc/sysconfig/httpd
    fi
    
    HTTPD_LANG="en_US.UTF-8"
    INITLOG_ARGS=""
    
    apachectl=/usr/local/apache2/bin/apachectl
    httpd=${HTTPD-/usr/local/apache2/bin/httpd}
    prog=httpd
    pidfile=${PIDFILE-/usr/local/apache2/run/httpd.pid}
    lockfile=${LOCKFILE-/var/lock/subsys/httpd}
    RETVAL=0
    
    start() {
    echo -n $"Starting $prog: "
    LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && touch ${lockfile}
    return $RETVAL
    }
    
    stop() {
    echo -n $"Stopping $prog: "
    killproc -p ${pidfile} -d 10 $httpd
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
    }
    reload() {
    echo -n $"Reloading $prog: "
    if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then
    RETVAL=6
    echo $"not reloading due to configuration syntax error"
    failure $"not reloading $httpd due to configuration syntax error"
    else
    # Force LSB behaviour from killproc
    LSB=1 killproc -p ${pidfile} $httpd -HUP
    RETVAL=$?
    if [ $RETVAL -eq 7 ]; then
    failure $"httpd shutdown"
    fi
    fi
    echo
    }
    
    case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    status)
    status -p ${pidfile} $httpd
    RETVAL=$?
    ;;
    restart)
    stop
    start
    ;;
    condrestart|try-restart)
    if status -p ${pidfile} $httpd >&/dev/null; then
    stop
    start
    fi
    ;;
    force-reload|reload)
    reload
    ;;
    graceful|help|configtest|fullstatus)
    $apachectl $@
    RETVAL=$?
    ;;
    *)
    echo $"Usage: $prog {start|stop|restart|condrestart|try-restart| \
    force-reload|reload|status|fullstatus|graceful|help|configtest}"
    RETVAL=2
    esac
    
    exit $RETVAL
    [root@attack ~]#
    

    Добавьте путь к Апачи (/usr/local/apache2/bin) в переменную PATH, в скрипте "/etc/profile". Как root запустите "chkconfig httpd on" чтобы зарегистрировать службу. Теперь "service httpd status" будет работать правильно. Запустите Апачи (service httpd start) и проверьте лог файл.

    Создайте файл для digest authentication командой "htdigest -c /somedir/somefile 'Сюда нельзя!' user1" - вы увидите приглашение "Adding password for user1 in realm Сюда нельзя!", введите пароль дважды - именно этот пароль будет использован для доступа к "server-status" и "server-info".

    ........................ == Книга пророка Захарии == ...........................
    === Глава 13, Стих 2 ===
    2 И будет в тот день, говорит Господь Саваоф, Я истреблю  имена  идолов  с  этой
    земли, и они не будут более упоминаемы,  равно  как  лжепророков  и  нечистого
    духа удалю с земли.
    
    root@attack ~]# tail -f /usr/local/apache2/logs/error_log
    ...
    [Sat Oct 01 18:43:45 2011] [notice] Digest: generating secret for digest authentication ...
    [Sat Oct 01 18:43:45 2011] [notice] Digest: done
    [Sat Oct 01 18:43:45 2011] [notice] Apache/2.2.21 (Unix) configured -- resuming normal operations
    

    Для облегчения своей участи администратора веб сервера установите два дополнительных пакета - "yum install logrotate" и "yum install logwatch". Эти два пакета должны поместить вызовы своих скриптов в директорию "/etc/cron.daily/".

    -- Добавьте эти строки в файл "/etc/logrotate.conf":
    # Apache
    "/usr/local/apache2/logs/access_log" /usr/local/apache2/logs/error_log {
    rotate 5
    size 200k
    sharedscripts
    postrotate
    /usr/bin/killall -HUP httpd
    endscript
    }
    
    -- Создайте символическую ссылку для logwatch:
    ln -s /usr/local/apache2/logs/ /var/log/httpd
    

    Проверим страницы диагностики вебсервера

    Поместите значок вашего сайта в файл "/usr/local/apache2/htdocs/favicon.ico", чтобы избежать предупреждений в лог файле. Зайдите веб броузером с вашей рабочей станции по адресу "http://192.168.1.11/" (или какой IP у вашего веб сервера) - вы должны увидеть оптимистичное сообщение "It works!". Поздравляем, это действительно "works" - ваш вебсервер готов к тестированию.

    В заключение проверьте страницу "http://192.168.1.11/server-status", введите "user1" и пароль, выбранный вами выше - вы должны увидеть старницу статуса вебсервера. На странице "http://192.168.1.11/server-info/" перейдите по ссылке "Module List" - должен появиться такой список:

    Apache Server Information
    Server Module List
    mod_so.c
    mod_dir.c
    mod_info.c
    mod_status.c
    mod_mime.c
    http_core.c
    prefork.c
    mod_setenvif.c
    mod_mime_magic.c
    mod_log_config.c
    mod_auth_digest.c
    mod_authz_user.c
    mod_authn_file.c
    core.c
    

    Как видно, наш сервер имеет минимальную, но рабочую конфигурацию, как и планировалось. Приступим к тестам.

    Стресс-тест производительности Веб Сервера Apache

    Мы начнем тестирование с определения максимального количества статических страниц, выдаваемых нашим вновь построенным сервером. В качестве тестовой страницы будет использоваться заглавная страница сайта "attack.read-and-think.org" размером 28 килобайт. Очень важно производить тестирование именно на реальном содержимом - тестирование странички "It works!" не будет отражать реальных возможностей вашей системы.

    В течение теста файл "index.html" заменяется каждую минуту, таким образом этот тест нельзя считать исключительно "статическим". Для тестирования мы будем использовать стандартное средство из поставки Апача - "ApacheBench". Цель моей проверки - определение максимального числа страниц, генерируемых вебсервером. Обычно это число ограничено возможностями процессора, но в реальной жизни сдерживающим фактором становится сеть. Например, наш сервер подключен к 100 Mbps порту, а во время стресс-теста web траффик составляет около 750 Mbps, что значительно превышает существующую пропускную способность. Именно поэтому я исключаю сеть из стресс-тестирования, направляя все запросы на "localhost". С другой стороны, функциональное тестирование будет проводиться через реальное сетевое подключение.

    Мы сделаем два теста, имитирующих 350 и 500 одновременно работающих пользователей. Как видно из конфигурации нашего сервера (MaxClients 300), он может использовать только 300 рабочих процессов одновременно. Таким образом, где-то в середине теста на 350 пользователей мы ожидаем активный рост очереди "socket connections". А тест на 500 клиентов наверняка превысит возможности системы. Очевидно, наибольшее число запросов в секунду будет показано первым тестом. Проверим наши предположения.

    Стресс-тест - 350 concurrent users

    Запустить тест просто. Ниже приведена командная строка для запуска теста на 350 одновременно работающих пользователей и результаты первого теста.

    .......... == Первое соборное послание святого апостола Петра == .............
    === Глава 3, Стих 12 ===
    10 Ибо, кто любит жизнь и хочет видеть добрые дни,  тот  удерживай  язык  свой
    от зла и уста свои от лукавых речей;
    11 уклоняйся  от  зла  и  делай  добро;  ищи   мира   и   стремись   к   нему,
    12 потому что очи Господа _обращены_ к праведным  и  уши  Его  к  молитве  их,
    но лице Господне против делающих зло, (чтобы истребить их с земли).
    
    [root@attack ~]# cat test350.sh
    
    ab -c 350 -e ab.csv -r -n 1000000 http://localhost/
    
    [root@attack ~]# cat test350.log
    This is ApacheBench, Version 2.3
    
    Benchmarking localhost (be patient)
    Completed 100000 requests
    Completed 200000 requests
    Completed 300000 requests
    Completed 400000 requests
    Completed 500000 requests
    Completed 600000 requests
    Completed 700000 requests
    Completed 800000 requests
    Completed 900000 requests
    Completed 1000000 requests
    Finished 1000000 requests
    
    
    Server Software:        Apache/2.2.21
    Server Hostname:        localhost
    Server Port:            80
    
    Document Path:          /
    Document Length:        28423 bytes
    
    Concurrency Level:      350
    Time taken for tests:   328.983 seconds
    Complete requests:      1000000
    Failed requests:        0
    Write errors:           0
    Total transferred:      28696298561 bytes
    HTML transferred:       28426265081 bytes
    Requests per second:    3039.67 [#/sec] (mean)
    Time per request:       115.144 [ms] (mean)
    Time per request:       0.329 [ms] (mean, across all concurrent requests)
    Transfer rate:          85182.81 [Kbytes/sec] received
    
    Connection Times (ms)
    min  mean[+/-sd] median   max
    Connect:        0   28  31.4     28    9028
    Processing:     7   87 104.1     84   14302
    Waiting:        3   29 104.2     26   14247
    Total:         22  115 108.9    115   14320
    
    Percentage of the requests served within a certain time (ms)
    50%    115
    66%    115
    75%    116
    80%    120
    90%    126
    95%    128
    98%    130
    99%    133
    100%  14320 (longest request)
    [root@attack ~]#
    

    Во время тестирования всегда держите открытым "top" и проверяйте использование виртуальной памяти и "runtime" очередь процессора. В моем случае оба ядра процессора использовались почти на 100%. Также держите открытой и периодически обновляйте страничку статуса (/server-status) вебсервера - данные о числе "requests currently being processed" и "requests/sec" должны коррелировать с результатами "ab" - "Concurrency Level" и "Requests per second" соответственно.

    Стресс-тест - 500 concurrent users

    Увеличим число пользователей, работающих одновременно до 500 и посмотрим как это отразится на работе веб сервера.

    .......................... == Книга Екклезиаста == .............................
    === Глава 4, Стих 4 ===
    4 Видел я также, что всякий труд и всякий  успех  в  делах  производят  взаимную
    между людьми зависть. И это - суета и томление духа!
    5 Глупый   _сидит,_   сложив   свои    руки,    и    съедает    плоть      свою.
    
    [root@attack ~]# cat test500.sh
    
    ab -c 500 -e ab.csv -r -n 1000000 http://localhost/
    
    [root@attack ~]# cat test500.log
    This is ApacheBench, Version 2.3
    
    Benchmarking localhost (be patient)
    Completed 100000 requests
    Completed 200000 requests
    Completed 300000 requests
    Completed 400000 requests
    Completed 500000 requests
    Completed 600000 requests
    Completed 700000 requests
    Completed 800000 requests
    Completed 900000 requests
    Completed 1000000 requests
    Finished 1000000 requests
    
    
    Server Software:        Apache/2.2.21
    Server Hostname:        localhost
    Server Port:            80
    
    Document Path:          /
    Document Length:        28423 bytes
    
    Concurrency Level:      500
    Time taken for tests:   333.716 seconds
    Complete requests:      1000000
    Failed requests:        18			       	! Видны потерянные запросы
    (Connect: 0, Receive: 6, Length: 6, Exceptions: 6)
    Write errors:           0
    Total transferred:      28693665559 bytes
    HTML transferred:       28423652541 bytes
    Requests per second:    2996.56 [#/sec] (mean)		! Снизилось незначительно
    Time per request:       166.858 [ms] (mean)		! Возросло заметно - около 30%
    Time per request:       0.334 [ms] (mean, across all concurrent requests)
    Transfer rate:          83967.01 [Kbytes/sec] received 	! Веб траффик уменьшился.
    
    Connection Times (ms)
    min  mean[+/-sd] median   max
    Connect:        0   30  84.0     28    9031
    Processing:     6  136 346.8    115   15858
    Waiting:        0   72 344.6     46   13288
    Total:         27  166 363.1    142   18864
    
    Percentage of the requests served within a certain time (ms)
    50%    142
    66%    145
    75%    147
    80%    149
    90%    154
    95%    159
    98%    165
    99%    171
    100%  18864 (longest request)
    [root@attack ~]#
    
    Заметьте это сообщение в логе Апача, все доступные рабочие процессы были использованы:
    
    [Sun Oct 02 12:22:32 2011] [notice] Apache/2.2.21 (Unix) configured -- resuming normal operations
    [Sun Oct 02 12:38:44 2011] [error] server reached MaxClients setting, consider raising the MaxClients setting
    

    Как мы видим, практика подтвердила наши предположения - второй тест показал заниженные результаты и очевидно, что наш сервер не выдержит такое число concurrent users.

    Результаты стресс-теста

    Наиболее важные цифры из результатов - "Time per request", "Requests per second", "Failed requests" и "Transfer rate". В нашем тесте на 350 пользователей сервер обслуживал более трёх тысяч запросов в секунду от 350 одновременно работающих клиентов со средним временем отклика 115 миллисекунд для одной страницы размером 28 килобайт. При этом ни один запрос не был утерян.

    Вероятно, мы никогда не увидим 259 миллионов дневных хитов на нашем вебсайте :-), но сам по себе стресс-тест дает неплохую приблизительную оценку возможностей нашей системы. На мой взгляд, технически вебсайт работает отлично. Проверим, как он будет обслуживать пользователей в реальных условиях.

    Тест функциональности Веб Сервера Apache

    Для проверки правильности работы вебсайта нам понадобится более сложная и "умная" программа. Я выбрал бесплатный "siege", но если у вас есть возможность использовать коммерческий LoadRunner - я настоятельно рекомендую именно его.

    В этом тесте я буду имитировать реальную активность моих пользователей. Я выключу digest authentication на время теста (комментируем строку "Require valid-user" в конфигурационном файле Апача и перезапускаем веб сервер), ввиду несовершенства программы "siege".

    Как я уже говорил, мой проект "Нас Атакуют!" Изобличи козни лукавого, запрети диаволу разработан как модуль Апачи. В этом случае в своем коде я могу преобразовывать приходящие GET запросы "на лету", делая из них POST с нужными мне параметрами, включая новое имя аутентифицированного пользователя. В результате мне не понадобится сложный коммерческий пакет типа LoadRunner - мои "virtual users" будут созданы моим кодом, внутри моего модуля. Таким образом, только на время тестирования каждый GET запрос, приходящий на мой сайт становится POST запросом ввода данных, каждый раз от имени очередного пользователя.

    Всё, что мне надо сделать для тестирования - поместить мой вебсервер под стабильную длительную нагрузку и проверять результаты работы моего приложения, использование виртуальной памяти (выявление утечек) и логи Апача (обнаружение ошибок в конфигурации). Обычно для своих тестов я делаю начальный часовой тест, исправляю замеченные недостатки и помещаю вебсервер под нагрузку на 8-12 часов. В этом случае, даже если я не обнаружил утечки памяти заранее, перерасход памяти будет очевиден и легко заметен. Одна тонкость - на время теста нам необходимо установить параметр Апача "MaxRequestsPerChild" равным нулю - это значительно увеличит "время жизни" рабочих процессов и проявит утечки памяти в моем коде.

    Тест функциональности - 1 час

    Запустим "siege" на один час, с задержкой времени реакции пользователя в одну секунду. В программе имеется параметр "--benchmark", но мы хотим иметь некую задержку между запросами, иначе наш тест правильности работы превратится в еще один стресс-тест. Тем не менее, мы запускаем 100 одновременно работающих пользователей, на мой взгляд такой уровень concurrency позволяет достаточно нагрузить систему и в то же время не создаёт беспорядка в результатах. Подключение клиентов "siege" к вебсерверу происходит по реальной сети.

    Команда для запуска теста:
    
    siege -d1 -c100 -t1H -l ./siege.log http://attack/ua
    
    

    Обратите внимаие, программа "siege" требует адрес страницы-обработчка запросов, но не старницы с HTML формой. Как я сказал, я не посылаю никаких параметров через GET или POST - их формирует непосредственно мой код.

    По мере продвижения нашего теста, проверяем периодически использование виртуальной памяти, командами "sar" и "top".

    sar -RrBW 30 50
    ...
    Average:     pswpin/s pswpout/s
    Average:         0.00      0.00
    
    Average:     pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
    Average:         0.00    712.25    601.43      0.00    719.66      0.00      0.00      0.00      0.00
    
    Average:      frmpg/s   bufpg/s   campg/s
    Average:       -10.03      0.40      9.50
    
    Average:    kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit %commit
    Average:       917866   1123254     55.03     38449    841931    187739    3.06
    

    Заметьте: значения "%commit", "%memused", "kbbuffers" и "kbcached" будут изменяться, но они должны оставаться вблизи какого-то определённого стабильного значения в течение всего времени теста. Если эти значения монотонно возрастают - память где-то "течёт". В этом случае нам поможет "top", показывающий использование памяти по "секциям" каждого процесса:

    В моём тесте значения в колонке "RES" оставались стабильно в пределах 4380-4450 KB для каждого "httpd" процесса. Никаких сообщений в лог ошибок Апача в течение теста не выводилось. Оценим результаты первого часового теста.

    .......... == Первое послание к Тимофею святого апостола Павла == ..............
    === Глава 6, Стих 15 ===
    13 Пред   Богом,   все   животворящим,   и   пред   Христом   Иисусом,   Который
    засвидетельствовал пред Понтием Пилатом доброе исповедание, завещеваю тебе
    14 соблюсти заповедь чисто и  неукоризненно,  даже  до  явления  Господа  нашего
    Иисуса Христа,
    15 которое в свое время откроет блаженный  и  единый  сильный  Царь  царствующих
    и Господь господствующих,
    16 единый имеющий бессмертие, Который обитает  в  неприступном  свете,  Которого
    никто из человеков не видел и видеть не может. Ему честь  и  держава  вечная!
    Аминь.
    
    [root@attack ~]# cat siege.log
    Lifting the server siege...      done.
    
    Transactions:		      399810 hits
    Availability:		       99.99 %
    Elapsed time:		     3599.24 secs
    Data transferred:	     2395.27 MB
    Response time:		        0.40 secs
    Transaction rate:	      111.08 trans/sec
    Throughput:		        0.67 MB/sec
    Concurrency:		       44.26
    Successful transactions:      399810
    Failed transactions:	          29
    Longest transaction:	       16.13
    Shortest transaction:	        0.02
    [root@attack ~]#
    

    Эти результаты кажутся лично мне более "вменяемыми" - около 110 "сложных" запросов в секунду, при реальном уровне concurrency 44. Время отклика в 400 миллисекунд явно велико, что свидетельствует о необходимости более мощного процессора для вебсервера под такой нагрузкой. На это же указывает и разница в запрошенном количестве одновременно работающих пользователей (100) и их реальным числом (44).

    Надо отметить, что нагрузка на процессор может быть снижена переходом на многопоточный MPM для Апача ("worker" вместо "prefork"). Тем не менее, документация по Апачу говорит чётко: "... sites that need a great deal of scalability can choose to use a threaded MPM like worker, while sites requiring stability or compatibility with older software can use a prefork." Я не вижу необходимости использования многопоточных MPM ма моём вебсайте и полученные результаты тестов меня вполне устраивают.

    Тест функциональности - 4 часa

    Закрепим победу :-) - проведём длительный тест "на выживание" вебсервера. Для этой заметки я отвёл на тестирование всего 4 часа и увеличил concurrency до 150. Также я перевёл процесс обновления главной страницы сайта в его нормальный режим - раз в 10 минут (а не каждую минуту, как было до этого). Вызов программы остаётся таким же, просто замените "-c100 -t1H" на "-c150 -t4H". По-прежнему будем проверять использование памяти и сообщения в логах.

    ............. == Послание к Римлянам святого апостола Павла == .................
    === Глава 6, Стих 15 ===
    15 Что  же?  станем  ли  грешить,  потому  что  мы  не  под   законом,   а   под
    благодатью? Никак.
    
    [root@attack ~]# cat sar.log
    -- В начале тестирования:
    Average:     pswpin/s pswpout/s
    Average:         0.00      0.00
    
    Average:     pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
    Average:         0.02    583.37    827.39      0.00    769.02      0.00      0.00      0.00      0.00
    
    Average:      frmpg/s   bufpg/s   campg/s
    Average:        -7.54      0.40      7.17
    
    Average:    kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit %commit
    Average:       800605   1240515     60.78     43898    854631    365185    5.95
    
    -- В середине теста:
    05:43:17 PM  pswpin/s pswpout/s
    05:43:47 PM      0.00      0.00
    
    05:43:17 PM  pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
    05:43:47 PM      0.00    627.68   1178.66      0.00    847.08      0.00      0.00      0.00      0.00
    
    05:43:17 PM   frmpg/s   bufpg/s   campg/s
    05:43:47 PM   -148.12      0.40      7.30
    
    05:43:17 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit %commit
    05:43:47 PM    706380   1334740     65.39     48908    942692    363940    5.93
    
    -- В конце теста:
    Average:     pswpin/s pswpout/s
    Average:         0.00      0.00
    
    Average:     pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
    Average:         0.00    550.13    913.32      0.00    773.52      0.00      0.00      0.00      0.00
    
    Average:      frmpg/s   bufpg/s   campg/s
    Average:        -5.80      0.40      7.01
    
    Average:    kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit %commit
    Average:       730691   1310429     64.20     47721    922088    360354    5.87
    [root@attack ~]#
    

    Как видно, использование памяти не изменялось значительно за время теста и оставалось в пределах 60-66%. Сообщений об ошибках не наблюдалось. "top" показывал стабильное истощение всех ресурсов процессора в течение всего теста, около 110 процессов постоянно находились в "run queue" ("load average" в "top", в предыдущем часовом тесте это значение было существенно ниже - около 30). Естественно, мы предполагаем что время отклика при таких условиях должно возрасти, проверим это:

    .......... == Первое соборное послание святого апостола Иоанна == ..............
    === Глава 4, Стих 20 ===
    20 Кто говорит: "я люблю Бога", а брата  своего  ненавидит,  тот  лжец:  ибо  не
    любящий брата своего, которого видит, как  может  любить  Бога,  Которого  не
    видит?
    21 И мы имеем  от  Него  такую  заповедь,  чтобы  любящий  Бога  любил  и  брата
    своего.
    
    [root@attack ~]# cat siege4.log
    Lifting the server siege...      done.
    
    Transactions:		     1223688 hits
    Availability:		       99.92 %
    Elapsed time:		    14725.43 secs
    Data transferred:	     7856.35 MB
    Response time:		        1.29 secs 	!!! Возросло на 70%
    Transaction rate:	       83.10 trans/sec 	!!! Снизилось на 25%
    Throughput:		        0.53 MB/sec
    Concurrency:		      107.32
    Successful transactions:     1223688
    Failed transactions:	        1033 !!!
    Longest transaction:	       17.00
    Shortest transaction:	        0.02
    [root@attack ~]#
    

    Очевидно, что такая нагрузка была просто непосильна для нашего компьютера - и тем не менее, утечек памяти и ошибок не наблюдалось. "Failed transactions" объясняются превышением времени ожидания на TCP сокете, ввиду "занятости" процессора нашей машины. В заключение напомню - даже "жалкие" 80 запросов в секунду соответствуют семи миллионам хостов в сутки.

    Результаты тестирования функциональности

    Наиболее важный результат - отсутствие ошибок в работе программ и утечек памяти под реальной нагрузкой на вебсервер. Цель наших тестов достигнута - поздравим себя с появлением нового вебсайта в интернете! :-)

    Спасибо что зашли,

    Будьте благословенны!
    Денис