Определите производительность программы после внесения в ее код изменений с помощью трассировки

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

Используйте Web-сервер Apache в качестве примера, для того чтобы увидеть, как анализировать распространенные конфигурации на предмет их производительности. При трассировке отслеживаются системные вызовы, сделанные приложением во время работы. Считая вызовы и время, которое они заняли, вы можете легко увидеть влияние изменений на производительность.

Шон Волберг, старший сетевой инженер, P.Eng

В академической, корпоративной средах, среде поставщиков интернет-услуг Шон Волберг (Sean Walberg) работает с системами Linux и UNIX с 1994 года. За последнюю пару лет он очень много написал о системном администрировании. Вы можете написать ему на sean@ertw.com.



24.12.2007

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

Введение в трассирование приложений

Во время выполнения приложения оно совершает системные вызовы к лежащей в основе операционной системе, вне зависимости от того, что этому приложению нужно сделать - открыть файл, послать пакет или использовать системные ресурсы. Трассировка приложения подразумевает, что вы наблюдаете системные вызовы, как только они были совершены, что позволяет вам заглянуть в поведение приложения. Для операционных систем Solaris и IBM AIX® трассировка выполняется командой truss, для Linux® командой strace. В примере 1 показан пример трассировки команды pwd.

Пример 1. Трассировка команды pwd
-bash-3.00$ truss pwd
...
getcwd("/export/home/sean", 1025)               = 0
/export/home/sean
write(1, " / e x p o r t / h o m e".., 18)      = 18
_exit(0)

После удаления выводимой информации, относящейся к загрузке приложения, вы можете видеть, что сделаны три системных вызова:

  1. getcwd возвращает текущую рабочую директорию. В выводе видно, что строка "/export/home/sean" была записана в буфер.
  2. write отображает заданную строку. Из-за того, что системный вызов отображается после того, как он был осуществлен, вывод данных происходит в предыдущей строке. Также заметьте, что результатом системного вызова write является число выведенных символов, в нашем случае - 17 плюс один символ возврата каретки.
  3. _exit выходит из программы с кодом ошибки 0, что традиционно ассоциируется с успешным выполнением.

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


Беглый взгляд на конфигурацию Apache-сервера

Веб-сервер Apache конфигурируется через файл с именем httpd.conf. В примере 2 показана часть простой конфигурации.

Пример 2. Элементарный образец httpd.conf
DocumentRoot "/var/apache/htdocs"
<Directory />
    Options FollowSymLinks
    AllowOverride None
</Directory>
<Directory "/var/apache/htdocs">
    Options Indexes FollowSymLinks MultiViews
</Directory>

Первая строка определяет, где могут быть найдены HTML-файлы. Запросы отправляются к этому каталогу. Если запрос сделан для /project/charter.html, используется содержимое /var/apache/htdocs/project/charter.html. Остальная часть httpd.conf состоит из двух элементов Directory. Все между <Directory ...> и </Directory> относится к выбранной директории и всем поддиректориям. В этом случае первый элемент остальной части httpd.conf применяет две настройки к корневой директории, а второй элемент ссылается на /var/apache/htdocs.

Если многократные элементы применяются к одному запросу к директории, превосходящей по важности все прочие, команды, определенные в них, объединяются. Например, запрос на /project/charter.html будет отдан /var/apache/htdocs/project/charter.html. /var/apache/htdocs вляется поддиректорией /, поэтому Options Indexes FollowSymLinks MultiViews взяты из второго элемента остальной части httpd.conf AllowOverride None из первого.

Можно сконфигурировать множество параметров, и каждый из них имеет значение для работы программы. Остальная часть статьи посвящена исследованию воздействия на производительность этих изменений.


Определение признаков

Прежде чем вы начнете отлаживать систему, необходимо получить представление о том, как система работает сейчас. Запустите Apache с параметром -X , который принудит его работать в однопроцессном режиме отладки. Сделав так, мы получим уверенность в том, что запрос постоянно будет приходить в процесс, который трассируется и устраним издержки, связанные с взаимодействием между процессами.

После того как программа начала свое выполнение, определите ID процесса с помощью команды ps -ef и в ее результатах найдите демона httpd. Как только вы его найдете, подключитесь к процессу следующим образом: truss -c -p PID. Опция -c считывает системные вызовы и отображает их один за другим, а -p показывает, что трассировщик должен присоединиться к работающему процессу.

Сделайте запрос к документу, используя Web-браузер. После того как страница загрузится, вернитесь к приложению truss и нажмите Ctrl-C, чтобы остановить подсчет. Для статической HTML-страницы вы должны увидеть что-то вроде того, что показано в примере 3 (чтобы сделать числа более интересными, этот пример делает один и тот же запрос 100 раз).

Пример 3.Признаки системного вызова
sunbox# truss -c -p 15026
(make the Web request 100 times)
^C
syscall               seconds   calls  errors
read                     .009     200
write                    .020     200
close                    .020     200
time                     .004     300
alarm                    .018    1100
fcntl                    .009     300
sigaction                .007     400
munmap                   .007     100
llseek                   .001     100
pollsys                  .005     100
mmap64                   .008     100
stat64                   .007     100
open64                   .006     100
accept                   .019     100
getsockname              .002     100
setsockopt               .002     100
                     --------  ------   ----
sys totals:              .149    3600      0
usr time:                .120
elapsed:                8.960

truss возвращает список системных вызовов, время, потраченное на один вызов, число вызовов и ошибок, если они были найдены. В конце отчета возвращается общее время, затраченное на системные вызовы, вместе с временем выполнения приложения вместе со временем, потраченным на выполнение приложения. Общее затрачиваемое время неважно для исследуемых целей, потому что оно указывает на время, когда trussбыл запущен и когда прекратил свою работу, и не имеет отношения к Web-запросу.

В примере 3 показан самый простой случай. После получения запроса на соединение от Web-браузера, системный вызов accept открывает соединение. Веб-сервер использует вызов read, чтобы получить все содержимое запроса, который перенаправляется к файлу на диске. Сначала Web-сервер проверяет, что файл существует stat64, открывает файл для чтения с помощью команды open64 и переписывает данные файла в память mmap64. Потом этот файл отправляется назад клиенту с системным вызовом write,а системный журнал генерируется другим системным вызовом write, и сервер выполняет последный вызов read от браузера. Все другие вызовы являются ненужными и не изменятся значительно при изменении конфигурации.

Обрабатываем результаты

Следует заметить, что 100 запросов занимают по времени 0,269 секунды (0,149 + 0,120) и что сервер должен быть способен обрабатывать около 370 страниц в секунду (100/0,269). Эти числа надо воспринимать с изрядной долей скептицизма, потому что они представляют только время, которое процесс тратит на выполнение в CPU, но не реальное время, котрое требуется ему на выполнение. Множество других факторов вносит свой вклад, например, скорость жесткого диска и сети, другие процессы, запущенные на компьютере, и хотя бы тот факт, что исследуемый процесс был запущен в отладочном режиме. Вы также должны учитывать ненужные процессы из общего списка процессов, полученного при трассировке.

Технические приемы, используемые в этой статье направлены на то, чтобы показать относительность измерения времени выполнения операций, и использовании трассировки приложений для удаления ненужных операций. Если вам нужно знать число страниц, которое ваш Web-сервер может обработать за секунду, раздел дополнительные материалы содержит ссылки на программное обеспечение, которое поможет вам в этом.


Трассировка области действия AllowOverride

Apache дает администратору возможность предавать полномочия конфигурирования отдельным пользователям через механизм .htaccess. Этот файл, содержащий дополнительные инструкции для конфигурирования, используемые сервером, если запрошенная директория была сконфигурирована с AllowOverride внутри httpd.conf. В примере 4 показана предыдущая конфигурация, построенная с учетом AllowOverride Limit, который позволяет запрашивать у пользователей логин и пароль для доступа к Web-странице.

Пример 4. Простейший вариант файла httpd.conf с сконфигурированным AllowOverride
DocumentRoot "/var/apache/htdocs"
<Directory />
    Options FollowSymLinks
    AllowOverride Limit
</Directory>
<Directory "/var/apache/htdocs">
    Options Indexes FollowSymLinks MultiViews
</Directory>

Перезапуск процесса httpd и тестов дает результаты, показанные в примере 5.

Пример 5. Результат 100 запросов с активированным ограничением AllowOverride Limit
sunbox# truss -c -t write,read,open64,stat64,mmap64 -p 21136
^C
syscall               seconds   calls  errors
read                     .012     200
write                    .021     200
mmap64                   .007     100
stat64                   .007     100
open64                   .022     500     400
                     --------  ------   ----
sys totals:              .072    1100    400
usr time:                .141
elapsed:               16.660

На первый взгляд, время системных вызовов упало, но это только потому, что проводилась трассировка только для интересующих вызовов с помощью опции -t. Большинство системных вызовов остались теми же, но теперь присутствуют 500 вызовов к open64, 400 из которых возвращают ошибку. Время, потраченное на выполнение open64, также возросло (от 0,006с до 0,22с), как и время со стороны пользователя (от 0.12с до 0.141с).

Время возросло, потому что Apache должен делать дополнительную работу для обработки запросов, хотя мы не сконфигурировали никаких обнулений. Конфигурация AllowOverride Limit добавила заметную нагрузку. Остается вопрос: что вызвало все эти ошибки? Чтобы ответить на него, протрассируем один Web-запрос как показано в примере 6.

Пример 6. Определение причины ошибок системного вызова open64
sunbox# truss -t open64 -p 21136
open64("/.htaccess", O_RDONLY)                  Err#2 ENOENT
open64("/var/.htaccess", O_RDONLY)              Err#2 ENOENT
open64("/var/apache/.htaccess", O_RDONLY)       Err#2 ENOENT
open64("/var/apache/htdocs/.htaccess", O_RDONLY) Err#2 ENOENT
open64("/var/apache/htdocs/test.html", O_RDONLY) = 5

В примере 6 показано, что, когда приходит запрос, Apache проверяет каждую директорию на пути к /var/apache/htdocs и пытается открыть файл .htaccess, который не существует, потому что AllowOverride был сконфигурирован в корневой директории. Apache проверяет каждую директорию на предмет override'ов в .htaccess и выполняет их. Это добавляет времени ожидания из-за избыточного количества системных вызовов, больше ненужной активности со строны пользователя, без упоминания дополнительной дисковой деятельности. Пара десятков секунд на 100 запросов может выглядеть незначительно, но на загруженном сервере это дает о себе знать.

Теперь, с учетом того, что вы уже понимаете смысл просмотра override'ов, идеальное решение - это использовать повсеместно override'ы и не вмешиваться во все, что может быть сконфигурировано в httpd.conf. Подводя итог, ограничьте возможности конфигурации по отношению к каталогам, которые нуждаются в ней. В изученном примере перемещение AllowOverride Limit во второй элемент Directory добавит один дополнительный open64 для поиска .htaccess в /var/apache/htdocs. Поиск во всех родительских директориях - напрасная трата времени, потому что согласно текущей конфигурации никакие файлы из них не будут выданы.


Изучение HostnameLookups

Когда Web-сервер получает запрос, он знает о клиенте только одно - IP-адрес, такой как 129.42.42.212 для IBM.com. Однако Web-сервер не знает, что этот IP-адрес является адресом IBM.com. Для этого он должен выполнить обратный поиск DNS. Это занимает время, и если имя необходимо прежде чем может быть послан запрос, откладывает ответ клиенту. В прошлом Apache выполнял эти обратные поиски по умолчанию, но его поведение изменилось.

Существует другой случай, когда требуется обратный поиск DNS. Когда конфигурируется ограничение в доступе, основанное на имени хоста (вместо IP-адреса), Apache должен сначала преобразовать IP-адрес в имя хоста и затем назад имя хоста в IP-адрес, чтобы быть уверенным, что они совпадают. Потому что имя домена, полученное в результате обратного поиска, может иметь любое значение по желанию хозяина IP-адреса, и второе соединение произодится для того, чтобы убедится, что не происходит получение доступа путем обмана. Может ли трассирование приложения определить влияние разрешающей способности DNS?

Чтобы проверить это, удалите AllowOverride Limit из предыдущего примера и добавьте Allow from ibm.com вместо кода, что по умолчанию Allow from all. Затем сделайте так, чтобы DNS сервер возвращал something.ibm.com для вашей рабочей станции для уверенности в том, что начальная обратная проверка и последующая будут идти через Интернет. При обычном запуске запрос на защищенный Web-сервер занимает 15 секунд. С другой стороны, использование IP-адреса вместо ibm.com займет меньше чем полсекунды. В примере 7 показан подсчет некоторых системных вызовов при использовании DNS для обспечения безопасности.

Пример 7. truss-вывод Web-запроса, который был запрещен из-за недопустимого имени хоста
bash-3.00# truss -c -p 26089
^C
syscall               seconds   calls  errors
read                     .000       5
write                    .000       3
open                     .000       2
close                    .001      10
time                     .000       3
stat                     .000       5
alarm                    .000       8
fcntl                    .000       7       2
sigaction                .000       3
sysconfig                .000       5
pollsys                  .001       5
door_info                .000       2
stat64                   .000       1
open64                   .000       2
so_socket                .001       5
accept                   .000       1
connect                  .002       5
recvfrom                 .000       2
send                     .001       5
getsockname              .000       1
setsockopt               .000       1
                     --------  ------   ----
sys totals:              .011      81      2
usr time:                .004

truss сообщает что процесс работает гораздо меньше времени чем, чем показала проверка со стороны клиента (0,015 с против 15 с). Это потому, что большинство операций с сокетами выполняется асинхронно, то есть сокет опрашивается чтобы узнать присутствуют ли данные, в то время как приложение ждет ответа. Таким образом приложение не потребляет ресурсы центрального процессора, пока ждет результатов. Это объясняет расхождение во времени, возвращенным truss и временем со стороны клиента.

truss не чувствителен к изменению: 0,015 секунды - величина на порядок выше, чем первый простой случай, расмотренный в этой статье. Появилось несколько новых системных вызовов к read, write, close и stat. Вместе с send, connect, so_socket и pollsys эти системные вызовы используются для создания запросов имени. Потому что разрешение имени могло исходить от разнообразных источников, включая локальную файловую систему, несколько мест должно быть проверено. В последующих вызовах время запроса было около секунды, потому что информация DNS была кэширована.

В итоге большая часть задержки исходила из отдаленного блока преобразования имен и разрешения доступа. Этот факт подчеркивает нужду в кэшировании DNS и быстрых DNS-серверах, если вы надеетесь на поиски по имени. Однако лучшее решение состоит в том, чтобы взглянуть с альтернативной точки зрения на проблему. Достаточно простым решением является идея определить группы IP-адресов(например так Allow from 10.0.0.0/8). Такой подход гораздо быстрее чем DNS поиск. Потому что результаты обоих – обратного и прямого – поисков должны совпадать; есть большая возможность, что если вы сможете сделать это с именем, то сможете и с сегментом сети. Другой вариант: Apache может интегрироваться с множеством аутентификационных систем, поэтому аутентификация со стороны пользователя – другая возможность.

Сравнение системных вызовов с библиотечными

Если вы знакомы с программированием сокетов, вы могли бы искать gethostbyname и другие подобные вызовы, которые выполняются для выполнения функции поиска хоста. Эти вызовы из библиотек обеспечены системными библиотеками, такими как libc и libsocket, расположенными в /usr/lib. Вызовы из библиотек заключают в оболочку один или несколько системных вызовов всесте с дополнительной логикой. Вы можете рассматривать их как удобные для программиста интерфейсы для системных вызовов. Например, gethostbyname вызов из библиотеки проходит много шагов, в число которых входит проверка /etc/hosts или поиск в Network Information System (NIS) или DNS, чтобы найти название, основанное на конфигурации сервера. Эти шаги содержат в себе меньшие строительные блоки – системные вызовы, которые предоставляет ядро. В большинстве случаев до этого пункта различие было маленьким. truss может также проверять вызовы из библиотек, но не обеспечивает тот же уровень детальности, что и для системных вызовов.


Заключение

Возможность наблюдать и считать системные вызовы полезна не в только в случае отыскания неисправностей, но также для понимания того, как конфигурация приложения влияет на производительность. Каждое взаимодействие с остальной частью системы приводит к одному или нескольким системным вызовам и каждый запрос добавляет ненужные расходы.Это не говорит о том, что системные вызовы это плохо: программа, которая не взаимодействует с остальным миром - не очень интересна! В любом случае, можно наблюдать использование обращений к системе в измененном приложении, чтобы иметь возможность подумать о том, как добиться максимальной производительности от сделанных изменений.

Ресурсы

Научиться

  • Оригинал статьи (EN)
  • Solve application problems with tracing (EN) (developerWorks, март 2006): статья сфокусирована на использовании трассировки как инструмента для поиска неисправностей.(EN)
  • Performance tuning: Web-сервер Apache поставляется с документом относительно настройки его работы. Эта статья рассматривает два значительных элемента, важных для настройки, но те, кто работал с Apache указывают на ряд других важных моментов.(EN)
  • AIX и UNIX: хотите больше? Сообщество developerWorks предлагает сотни информативных статей и обучающих курсов различной стпепени сложности по AIX и UNIX.
  • developerWorks technical events and webcasts: оставайтесь в курсе технический событий и Web-обзоров сообщества developerWorks. (EN)
  • Podcasts: оставайтесь на связи с техническими экспертами IBM.(EN)

Получить продукты и технологии

  • IBM trial software: создайте ваше новое приложение с помощью программного обеспечения IBM, которое можете загрузить прямо со страницы сообщества developerWorks.(EN)
  • Siege: этот инструмент моделирует загрузку на вашем Web-сервере и помогает определить, сколько он может обработать.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=279123
ArticleTitle=Определите производительность программы после внесения в ее код изменений с помощью трассировки
publish-date=12242007