Text
                    O'REILLY
Тюнинг веб-сервера для профессионалов
Если веб-сайт долго откликается, медленно грузится и вообще работает
как-то не так, — резюме однозначное — тормозит! Но где тормозит — не сразу
ясно даже профессионалу. Это и понятно: между веб-сервером и браузером
пользователя существует множество звеньев, каждое из которых может влиять
на скорость передачи и обработки веб-страницы. Какими бы разнообразными
ни были возможности интернет-портала, они не будут востребованы,
если пользователю приходится долго ждать. Эта проблема стоит не только перед
администраторами больших сайтов, но и перед владельцами небольших персональных
страниц. Иначе зачем вообще что-то публиковать в интернете?
Автор книги не ограничивается освещением настройки только веб-сервера, а рассматривает
все, что так или иначе влияет на работу веб-службы. Последовательно он переходит
от общих принципов построения веб-систем к отдельным ее элементам. В книге содержится
много конкретных советов по выявлению слабых звеньев этой цепочки и их усилению.
Даны ссылки на разнообразные инструменты, с помощью которых можно существенно
улучшить производительность веб-системы.
Информация, которую вы найдете в книге
• архитектура веб-сайта
• планирование производительности
• контроль и мониторинг производительности
• тестирование времени загрузки
• анализ производительности
• надежность
• безопасность
• разбор типовых ситуаций
• общие принципы построения веб-систем
• тонкая настройка браузеров
• клиентские операционные системы
• аппаратное обеспечение клиентских
компьютеров
• телекоммуникационные каналы
• сетевые протоколы
• серверное аппаратное обеспечение
• серверные операционные системы
• серверные приложения
• содержимое веб-сайта
• специализированные серверные
приложения
• Java-приложения
• базы данных
11осститс веб-сайт издательства O'Reilly: www.oreilly.com
•v^, тт^ш^гш^ -' Серия: для профессионалов
*^^ Уровень пользователя: опытный
Посетите наш веб-магазин: http://www.piter.com
ISBN 5-94723-476-9
78594734763
Оптимизация веб-сервера
ДЛЯ ПРОФЕССИОНАЛОВ
O'REILLY
П. Киллелиа


СЕРИЯ
2-Е ИЗДАНИЕ Тюнинг веб-сервера ДЛЯ ПРОФЕССИОНАЛОВ П. Киллелиа С^ППТЕР* Москва • Санкт-Петербург • Нижний Новгород • Воронеж Ростов-на-Дону • Екатеринбург • Самара Киев • Харьков • Минск 2003
ББК 32.988 УДК 681.324 К53 К53 Тюнинг веб-сервера. 2-е изд. / П. Киллелиа. — СПб.: Питер, 2003. — 528 с: ил. — (Серия «Для профессионалов»). ISBN 5-94723-476-9 Эта книга для веб-мастеров, системных администраторов, системных архитекторов, системных интеграторов, программистов веб-приложений, редакторов сайтов. Она поможет повысить производительность веб-сервера, оценить требования проектируемого сайта к оборудованию и программному обеспечению, а также расскажет о вопросах масштабирования сайтов. Производительность рассматривается с точки зрения обычного пользователя — насколько быстро веб-сервер может удовлетворить его запрос. Нередко внимание системного администратора концентрируется на веб-сервере, хотя «узким местом» может быть ие сам сервер, а низкоскоростное подключение клиента к сети, динамическое формирование веб-страницы или производительность базы данных. Лучший путь к повышению производительности веб-системы лежит через хорошее понимание его архитектуры и порядка работы каждого из его элементов. В книге рассматриваются приложения, работающие под управлением как операционной системы Unix, так и Windows. Предполагается наличие у читателя общего знакомства с техническими аспектами работы веб-сайтов. ББК 32.988 УДК 681.324 Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как надежные. Тем не менее, имея в виду возможные человеческие или технические ошибки, издательство не может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности за возможные ошибки, связанные с использованием книги. О 2002,1998 O'RdHy&Associates, Inc. ISBN 0-596-00172-х (англ.) С Перевод на русский язык ЗАО Издательский дом «Питер», 2003 ISBN 5-94723-476-9 С Издание на русском языке, оформление ЗАО Издательский дом «Питер», 2003
Краткое содержание Предисловие 21 Часть I. Предварительные сведения Глава 1. Быстрый и мертвый 32 Глава 2. Архитектура веб-сайта 47 Глава 3. Планирование мощностей 65 Глава 4. Контроль производительности 85 Глава 5. Тестирование на нагрузку 137 Глава 6. Анализ производительности 153 Глава 7. Надежность 172 Глава 8. Безопасность 183 Глава 9. Разбор ситуаций 189 Глава 10. Принципы и схемы 197 Часть II. Подробно об оптимизации Глава 11. Браузеры 212 Глава 12. Операционная система клиента 231 Глава 13. Аппаратное обеспечение клиента 239 Глава 14. Линии связи и оконечные устройства 251 Глава 15. Сетевые протоколы 283 Глава 16. Аппаратное обеспечение сервера 318 Глава 17. Операционная система сервера 349 Глава 18. Программное обеспечение сервера 391 Глава 19. Содержимое 412 Глава 20. Специализированные приложения 425 Глава 21. Java 448 Глава 22. Базы данных 476 Приложение. Обзор продуктов, предназначенных для оптимизации веб-сайта 485 Алфавитный указатель 500
Содержание Предисловие 21 Для чего нужна эта книга? 22 Для кого предназначена эта книга? 23 Сделанные предположения 23 Как устроена эта книга 24 Шрифты 26 Как с нами связаться 27 Другие книги и ресурсы 27 Книги 27 Веб-сайты, посвященные производительности 28 Группы новостей, имеющие отношение к производительности веб 29 Ограничение гарантий 29 Благодарности ко второму изданию 30 Часть I. Предварительные сведения Глава 1. Быстрый и мертвый 32 Проверка браузера 32 Проверка сервера 40 Основные рекомендации 46 Глава 2. Архитектура веб-сайта 47 Компромиссы 47 Сохранение информации и масштабируемость 47 Дублирование и простота 49 Синхронность и асинхронность 50 Связь без логического соединения 50 Планирование и разработка 51 Процедурное и объектно-ориентированное программирование . 52 Основы 53 Браузер 53 Система балансировки нагрузки 54 Веб-сервер 57 Связующие программы 57 База данных 58
Пример архитектуры веб-сайта 58 Один компьютер 58 Стековая архитектура 59 Уровни 60 Linux на мейнфрейме 60 Реальный масштаб времени 60 Тенденции 61 Программы, используемые на широко известных сайтах 62 Примеры конфигураций 62 Низкая нагрузка 62 Средняя нагрузка 63 Большая нагрузка 63 Какие сайты являются наиболее загруженными? 64 Основные рекомендации 64 Глава 3. Планирование мощностей 65 Займитесь подсчетами 65 ...но верьте своим глазам больше, чем цифрам 66 Вопросы, которые нужно себе задавать 67 Какая вам нужна пропускная способность? 76 Время ожидания важнее пропускной способности 77 О пропускной способности 77 Оценка пропускной способности сети веб-сервера 79 Насколько быстрый сервер вам нужен? 80 Сколько памяти нужно серверу? 81 Память для операционной системы 82 Память для httpd 83 Память для содержимого 83 Память для CGI 83 Основные рекомендации . 84 Глава 4. Контроль производительности 85 Параметры производительности 85 Время ожидания и пропускная способность 85 Время ожидания для сети 88 Измерение времени ожидания и пропускной способности сети 89 Коэффициент использования 92 Эффективность 92 Использование сценариев интерпретатора 93 Использование С 94 Использование Perl 96 Контроль производительности сети с помощью Perl 96 Отображение результатов с помощью gnuplot 97
Пример сценария на Perl 97 Компоненты 102 Автоматическая генерация сценариев для контроля с помощью sprocket .... 103 Использование реляционной базы данных для сохранения данных о производительности 109 Помещение данных в базу 110 Получение данных из базы 110 Контроль коэффициента использования с помощью rstat Ill Сохранение данных rstat в реляционной БД 114 Использование данных rstat 115 Получение данных из БД в стандартный поток вывода 115 Построение графиков данных, хранящихся в БД 116 Контроль статистики процессов 119 Использование CGI для запуска программных средств 120 Включение подробного анализа с помощью rstat 120 Работа с Telnet в языке Perl 121 Генерация графиков из результатов работы ps 123 Контроль прочих параметров 127 Контроль с помощью Java 130 Приборная панель на веб-странице 133 Внимание! Избыток контроля вреден для здоровья вашего сайта! 134 SNMP 134 RMON 135 ARM 135 Прочие ресурсы 135 Основные рекомендации 136 Глава 5. Тестирование на нагрузку 137 Подготовка к тестированию 137 Опасайтесь переустановки часов 138 Почему реальная производительность отличается от тестовой? 139 Средства тестирования нагрузки 139 Написание собственных тестовых программ 140 Проблемы с таймером 141 Тестирование на нагрузку при избыточном контроле 143 Синхронизация теста на нагрузку 146 Хаотическое тестирование на нагрузку 146 Как остановить тестирование? 146 Создание нагрузки на сеть 147 Спецификации и эталонные тесты 148 WebStone 150
Содержание 9 SPECweb99 151 ТРС-СиТРС-D 151 Тесты прокси-серверов 152 Тесты производителей 152 CaffeineMark 152 Прочие ресурсы 152 Основные рекомендации 152 Глава 6. Анализ производительности 153 Поиск «узких мест» с помощью analysis.cgi 153 Подслушивание HTTP с помощью sprocket 156 Изучение соединений 157 Анализ файлов журналов 157 Средний объем передачи 159 Распределение размеров файлов 162 Хиты в секунду 163 Переменная нагрузка и длина очереди 165 Когда конкретно записываются хиты? 166 Кто ваш самый частый пользователь? 167 Который из процессов мой? 168 Кто работает с этим файлом? 168 Какие файлы используются моими процессами? 169 Что происходит при зависании БД? 169 Еще немного советов 170 Основные рекомендации 171 Глава 7. Надежность 172 Типичные отказы 172 Переполнение диска 172 У процесса закончились файловые дескрипторы 173 Ошибки при работе с указателями на С 173 Утечки памяти 173 Блокировка потоков 174 Блокировка ресурса завершившимся процессом 175 Перегрузка сервера 175 Система балансировки нагрузки не может обнаружить отказавший компьютер 176 Перегружена подсеть 176 Израсходованы терминалы 176 В базе данных закончились указатели 176 Плохой драйвер устройства 177 Отказы оборудования 177
Отказ питания 177 Администратор перепутал сервер 177 Ошибочное включение файла в шаблон 178 Проблемы с разрешениями 178 Ошибки в путях 178 Проблемы с заплатами 178 Каскадное распространение перегрузки 179 Отказы из-за контроля 179 Повторные обращения вызывают новые отказы 179 Случайная блокировка важных таблиц 179 Использование БД там, где можно обойтись файлами 180 Программа не может подключиться к ВД после отказа 180 Программа не перезапускается после перезагрузки 180 «Раздвоение личности» 180 Брандмауэр блокирует важную службу 180 Чтение данных с экрана не работает из-за того, что меняется дизайн .... 181 Зависимости 181 Борьба с последствиями отказа 181 Основные рекомендации 182 Глава 8. Безопасность 183 HTTPSnSSL 183 Брандмауэры 187 Узлы-бастионы 187 Chroot 188 Основная рекомендация 188 Глава 9. Разбор ситуаций 189 Неограниченный рост таблицы 189 Обратный поиск в DNS замедляет работу с журналом 190 Перекрученный кабель 192 Рост пула базы данных ограничивает производительность 195 Основная рекомендация 196 Глава 10. Принципы и схемы 197 Принципы повышения производительности 197 Иногда приходится проигрывать 197 Измерение меняет объект 197 Знания важнее всего 198 «Бесплатных обедов» не бывает 198 Доходы сокращаются 199 Переносимость уменьшает производительность 199 Абстрагирование уменьшает производительность 200
Защищенность уменьшает производительность 201 Память имеет иерархическую структуру 201 Кэширование зависит от локальности ссылок 202 Операции ввода-вывода всегда медленны 202 Информация относительна 203 Оборудование дешево, программы дороги 205 Целью оптимизации является одновременность выхода из строя компонентов . 205 Хорошее относительно 206 Биты—это деньги 206 Производительность Интернета падает нелинейно 206 Глобальная оптимизация дает наилучшие результаты 207 Что произошло однажды, скоро произойдет снова 207 Правило80/20 207 Люди часто важнее знаний 207 Схемы улучшения производительности 208 Амортизация 208 Кэширование 208 Профилирование 209 Параллельная обработка 209 Используйте то, что знаете 210 Простота 210 Основные рекомендации 210 Часть II. Подробно об оптимизации Глава 11. Браузеры 212 Как работают браузеры 212 Виды браузеров 217 Netscape 217 Internet Explorer 217 Opera 218 Neoplanet 218 WebTV 219 Cello 219 Mosaic 219 lynx 219 Amaya 220 Tango 220 Идеальный браузер 220 Скорость браузера 221 Советы по настройке браузеров 222 Общие рекомендации 222
Советы для Internet Explorer 227 Советы для Netscape 227 Прочие веб-клиенты 228 Gnutella и одноранговые сети 229 Основные рекомендации 230 Глава 12. Операционная система клиента 231 Microsoft Windows 231 Устраните беспорядок в системе 231 Специальные драйверы экрана 232 Память и диски 232 Системный монитор 233 Сетевые утилиты 233 MTU 234 Macintosh 234 Эмуляция 68К 234 Сеть 235 Память и диск 235 Расширения 236 Unix 236 Основные рекомендации 238 Глава 13. Аппаратное обеспечение клиента 239 Процессор 239 ОЗУ 242 Кэш 243 Шина 243 Диск 244 IDE 244 SCSI 245 Фрагментация 245 Видео 245 ММХ 246 Цвета и разрешение 246 Драйверы 247 3D и видеоклипы 247 Тесты для видеоадаптеров 247 Ввод-вывод 247 UART 248 Аппаратное сжатие может приводить к переполнениям 249 BIOS 249 Основные рекомендации 250
Глава 14. Линии связи и оконечные устройства ....... 251 Пересылка и время ожидания 252 Модем — выезд на информационную магистраль 252 Время ожидания и пропускная способность от модема к модему 253 Синхронизация 254 Аппаратное сжатие . . 254 Коррекция ошибок 255 Качество линии 255 Внутренние модемы быстрее 256 Переполнение буферов UART 256 Команды AT и время набора номера 257 Объединение каналов 257 ISDN 257 Кабельные модемы 259 xDSL 259 Еще более скоростные линии 260 56К,Т1иТЗ 260 Frame Relay 261 ATM 261 Спутники 262 Интрасети 262 Сегментирование 262 Оборудование для сегментирования 263 Ethernet 265 Перехват пакетов 267 Буферы сетевых адаптеров 269 Быстрый Ethernet 270 Коммутируемый Ethernet 270 Кабели Ethernet 271 Шум 271 Средства моделирования сетей 272 Интернет 272 В обход Интернета 274 Точки доступа к сети 274 Провайдеры 276 Выбор провайдера 278 Дублирование . . Л 279 Маршрутизаторы 279 Кто виноват? 280 Будущее Интернета 281 ПТТ 281 Основные рекомендации 282
Глава 15. Сетевые протоколы 283 Власть и протоколы 283 Факторы, влияющие на производительность сетевых протоколов 285 Пакеты, кадры и ячейки переменного и фиксированного размеров 285 Совмещенная отправка 285 Конвейер и подтверждение отдельных пакетов 286 Односторонние и двусторонние протоколы 286 Ошибки 286 Количество прыжков 286 Уровни 286 Протоколы веб 287 ARP 287 РРР 287 Протоколы маршрутизации 288 Протокол Интернета 288 TCP 292 ТДСР 302 UDP 303 HTTP 305 FTP 315 NNTP 316 CORBA 316 X 317 Основные рекомендации 317 Глава 16. Аппаратное обеспечение сервера 318 Коробка с проводом 318 Хорошая подсистема ввода-вывода 319 Несколько шин 319 Быстрые диски 319 Много памяти 320 Масштабируемость 320 Сетевой адаптер 320 Шина 322 Оперативная память 323 Характеристики ОЗУ 323 Процессор 324 Архитектура процессора 325 Многопроцессорные компьютеры 328 Тестирование масштабируемости Sun SMP 329 Жесткий диск 342 Архитектура и параметры дисков 342
Содержание 15 IDE 344 EIDE 344 SCSI 345 Fibre Channel 345 RAID 346 Производительность типичных дисков 346 Фрагментация 347 Активность дисков и идентификаторы процессов 348 Основные рекомендации 348 Глава 17. Операционная система сервера 349 Unix и рождение Сети 349 Версии Unix 350 Solaris 351 AIX 352 Digital Unix 352 Linux 352 Irix 353 BSD 353 MachOS 353 Устройство Unix 353 Системные и библиотечные вызовы 353 Процессы и ядро 354 Планирование 354 Контекстядра 355 Unixnhttpd 356 Уменьшение нагрузки на операционную систему 358 Создание процессов 359 Адресное пространство 360 Копирование областей памяти 362 Освобождение памяти 362 Файловая система 364 Оконный интерфейс 372 Версии и заплаты 372 Настраиваемые параметры операционных систем 373 Количество дескрипторов файлов 373 Частота очистки буферов файловой системы 376 Средства контроля Unix 377 ps 377 perfbar 378 perfmeter 378 perfmon 379 rstat 380
rup 380 hstat 380 top 380 xload 381 Трассировщики системных вызовов 381 Программы прослушивания сети 383 netstat 383 vmstat 384 sar 384 Сколько соединений может обслужить мой веб-сервер? 385 Сколько процессов может одновременно выполняться на моем сервере? .... 386 Насколько быстро может мой сервер породить новый процесс? 387 Unix и Windows NT в качестве ОС для веб-серверов 388 Достоинства и недостатки NT 388 Достоинства и недостатки Unix 389 Проект Exokernel 390 Основные рекомендации 390 Глава 18. Программное обеспечение сервера 391 Эволюция веб-серверов 391 Серверы, порождавшиеся демоном inetd 391 Серверы, порождающие процессы 392 Многопоточные серверы 393 Серверы с постоянными соединениями 393 Системные вызовы веб-сервера 393 Как происходит сбой сервера 395 Утечки памяти 397 Настройка Apache и Netscape 397 Короткие пути 397 Не преобразуйте время 397 Буферизуйте запись в журнал 397 Настройка Apache 398 Настройка Netscape 402 Прочие серверы 407 Недостающие функции 409 Прокси-серверы 409 Иерархическое кэширование 410 Основные рекомендации 411 Глава 19. Содержимое 412 Важен размер 412 Лучше не бывает 413
Кэширование и отличия 413 HTML и сжатие 413 gzip 414 Советы HTML-разработчикам 415 Полегче на сервере! 415 Полегче в сети! 416 Полегче с браузером! 417 Полегче с пользователем 418 Берегитесь предвзятых HTML-редакторов . 419 Идите в ногу с миром 419 Используйте средства проверки HTML 419 Объектная модель документа 420 Графика 420 Анимация 422 VRML 422 Аудио 422 Видео 423 Основные рекомендации 424 Глава 20. Специализированные приложения 425 Программисты 425 CGI-программы 425 Внутреннее устройство CGI и вопросы производительности 426 Основные рекомендации 428 бесконечные циклы 428 Неудержимо растущие CGI-программы 429 Защита от зацикливания CGI-программ 430 Не заставляйте клиента ждать 431 Переложите обработку на браузер 432 Файлы cookie 434 Java " 434 Обрабатывайте запросы заранее и кэшируйте результаты 435 Короткая — значит красивая 438 Вопросы масштабирования 438 Разделяйте большие формы на несколько маленьких 438 Поиск в DNS на сервере 439 Отладка и оптимизация 439 Оптимизация CGI 439 Сценарии интерпретатора 439 Perl 440 С 442 Демонизация 444
Производительность при обращении к БД 445 Ведение журналов 445 NSAPInlSAM 446 Объектная модель документа 446 JSP,ASP,PHP 446 Основные рекомендации 447 Глава 21. Java 448 Язык Java никогда не будет достаточно быстрым для пользовательских интерфейсов 448 Java достаточно быстр для серверных приложений 449 Внутренние проблемы с производительностью, присущие Java 449 Проверка границ массивов 449 Блокирующий сетевой ввод-вывод 450 Интерпретация байт-кода 450 Верификация байт-кода 451 Динамическая привязка методов 451 Сбор мусора 451 Косвенная адресация 452 Интернационализация и локализация 452 Объектная ориентированность 452 Стековая ориентация 453 Синхронизация 453 Многопоточное программирование 453 Советы программистам 455 Используйте хорошие алгоритмы 455 Делайте цепочки наследования короткими 455 Используйте стековые переменные 456 Объединяйте классы 456 Используйте библиотеки Java 457 Не опрашивайте 457 «Финализируйте» методы 457 Создавайте поменьше объектов 457 Опасайтесь утечек объектов 458 Попробуйте не пользоваться методами для работы с перемени .... 458 Используйте сложные операторы 458 Используйте шаг типа int 458 (ведите за скоростью доступа к различным переменным 459 Локальные переменные быстрее, чем переменные класса 459 Переменные класса быстрее, чем массивы 459 Используйте собственные методы 460 Используйте тайм-ауты сетевой подсистемы 460 Буферизуйте ввод-вывод 460
Содержание 19 Используйте сокеты вместо URL 460 Используйте UDP 460 Используйте потоки 461 Используйте notify 462 Используйте синхронизацию как можно реже 462 Не помещайте синхронизируемые методы внутрь циклов 463 Следите за родительским потоком 463 Обратный отсчет бывает быстрее прямого 463 Уменьшайте количество строк 463 Используйте строчные буферы или массивы 463 Берегитесь медленных шрифтов 464 Упрощайте метод Paint 464 Двойная буферизация обеспечит плавность анимации . . . 464 Пусть система отлавливает ошибки за вас 464 Не преобразуйте даты и время 465 Берегитесь RMI,EJB и CORBA 466 Компиляторы . 466 Оптимизация 467 Профилируйте свой код 467 JVMPI 468 Декомпиляторы 468 Средства профилирования на уровне операционной системы 469 JIT-компиляторы 469 Статические компиляторы 470 Виртуальные машины 471 Параметры времени выполнения 472 -verbosegc 472 -noverify 472 -Xmsnn-Xmxn 472 Сделайте Рай побольше 472 -train 473 Используйте собственные потоки 473 Используйте архивы .jar 473 Подключаемый модуль Java 473 -start_java 474 Java-процессоры ■:' 474 Тесты для Java 474 Недостатки тестов 475 Веб-сайты, где размещены сведения о производительности Java 475 Основные рекомендации 475 Глава 22. Базы данных 476 Нужна ли вам реляционная база даных? 477 Как узнать, что вам нужна база данных? 477
Альтернативы 477 Повышение производительности 478 Подготовленные операторы и связанные переменные 478 Денормализуйте таблицы 479 Не создавайте курсоры в циклах 479 Прямые соединения 479 Базы данных в основной памяти 479 Многоярусные системы 479 Конфигурация пула соединений . 480 Запросы 480 Индексы 481 Блокировка на уровне строк 481 Объединение веб-сервера и базы данных 481 Сколько соединений может обслужить ваша база данных? 482 Когда база данных перегружена 483 Анализ 483 Основные рекомендации 484 Приложение. Обзор продуктов, предназначенных для оптимизации веб-сайта 485 Недостатки коммерческих средств 485 Средства контроля 486 Средства создания нагрузки 490 Упреждающие загрузчики 491 Оптимизаторы сетей 492 Оптимизаторы MTU 492 Optimal Application Expert 492 Контроль трафика на уровне IP 492 Системы сжатия содержимого 494 Гибриды средств разработки и баз данных 495 Профилировщики и оптимизаторы Java 496 Службы кэширования 496 Профессиональные услуги 497 Средства балансировки нагрузки 497 Средства моделирования 499 Алфавитный указатель 500
Предисловие За четыре года, прошедших с момента выхода первого издания этой книги, на потенциальных возможностях Сети были сколочены огромные состояния, и столь же огромные суммы бесследно исчезли вместе с распавшимися как мыльные пузыри предприятиями. Из крайне туманных прожектов возникли тысячи веб- корпораций, и большинство из них сейчас прозябает в безвестности. Старые корпорации, такие как Cisco, Sun и Oracle, вознеслись на недосягаемые высоты, являясь основными поставщиками оборудования, которое должно было в корне изменить нашу жизнь, но и им пришлось упасть с вершин глубоко вниз. Microsoft все так же остается монополистом в области настольных компьютеров, но и эта монополия становится все более неуместной в сетевом мире. Полностью успешным оказался лишь перенос навязчивой и низкокачественной рекламы с телевидения на веб-страницы. Революция уже завершилась, и пришла пора подвести итог переменам. Вебсайты превратились из новшества в необходимое средство распространения информации. Веб-адреса можно встретить где угодно, и ими уже никого не испугаешь. По телефонным линиям сейчас чаще передают данные, чем разговаривают голосом. Практически у всех фирм и государственных учреждений, а также у миллионов обычных пользователей есть свои веб-страницы. Интернет принимается как должное, оказывая огромное положительное влияние на нашу жизнь. Благодаря Всемирной Паутине мы можем передавать информацию дешевле, быстрее и проще, чем это было возможно когда-либо раньше. В то же время можно сказать, что производительность Интернета стала еще большей проблемой, чем она была четыре года назад, поскольку возрос объем передаваемой и хранящейся информации, а также изменилась природа взаимодействия. К счастью, теперь нам известно гораздо больше о том, чем определяется производительность Сети, какие подходы применимы для ее улучшения, а какие нет. Мы знаем, откуда ждать беды и как с ней бороться. Обо всем этом рассказывает наша книга. В этом издании содержится гораздо больше сведений о программах, которые могут использоваться для слежения за работой сайтов, их загрузкой и для ана-
лиза их производительности. Все программы можно скачать из Сети по адресу: http://patrick.net/software. Кроме того, я включил в книгу множество графиков и примеров решения реальных задач, касающихся производительности разных веб-серверов, с которыми мне пришлось столкнуться за последние несколько лет. Для чего нужна эта книга? Эта книга поможет вам повысить производительность веб-сервера, оценить требования проектируемого сайта к оборудованию и программному обеспечению, а также расскажет о вопросах масштабирования сайтов. Она рассказывает не только обо всем, что относится к сетевым серверам, но также и о самой сети, и о том, что происходит на стороне клиента, поскольку многие веб-сайты существуют внутри интрасетей, администраторы которых могут управлять не только серверами, но и клиентами, и самой сетью. Чаще всего внимание сосредоточивается на HTTP-сервере, хотя обычно «узким местом» является не сам сервер, а подключение клиента, динамическое формирование содержимого и производительность базы данных. Таким образом, чтобы повысить производительность, нам придется уделить внимание и этим, и некоторым другим вопросам. Производительность, которая меня интересует, рассматривается с точки зрения конечного пользователя — насколько быстро веб-сервер способен удовлетворить его запрос. Производительность можно рассматривать и с других точек зрения, например считать определяющей пропускную способность, но в этой книге для нас важнее всего будет восприятие пользователя. Я включил в текст одну дополнительную главу, посвященную надежности, которая также является одним из аспектов производительности. Хотя в книгу и были включены некоторые общие принципы повышения производительности, она содержит гораздо больше практических советов, чем теоретических сведений. Я надеюсь, что мне удастся сделать задачу повышения производительности простой, предоставив читателю алгоритмы, которым ему рекомендуется следовать, и средства, которыми нужно пользоваться. Все это я использовал и сам в реальных ситуациях. Мне хотелось создать у читателя ясное представление о том, какие события и в какой последовательности происходят, когда пользователь запрашивает и просматривает веб-страницу. Понимание происходящего совершенно необходимо для выявления возникающих проблем с производительностью и поиска их решений. Лучшее средство для повышения производительности вашего веб-сайта — это хорошее понимание его архитектуры и структуры используемых приложений. Программные средства тоже небесполезны, но их ценность зависит от того, насколько вы понимаете их назначение. В конечном итоге повышение производительности сводится к затрате времени и денег на достижение максимальной отдачи от имеющихся ресурсов. Впрочем, то же самое можно сказать и о множестве других вещей.
Для кого предназначена эта книга? По нашим представлениям, книга «Тюнинг веб-сервера» может заинтересовать любого человека, работающего с веб-сервером, начиная с автора личной домашней странички, размещенной на настольном компьютере с Linux, и заканчивая авторами большого сайта какой-нибудь фирмы с множеством серверов корпоративного класса и быстрым подключением к Интернету. Автор книги предполагает, что вы знакомы с основами сайтостроительства. Эта книга содержит практические советы по конфигурированию и программированию на уровне приложений. Другими словами, здесь рассказывается о том, что вы можете изменить прямо сейчас, и это касается структуры содержимого, администрирования системы и программирования приложений. До некоторой степени вы всегда зависите от рынка, где вам приходится добывать «кирпичики», из которых строится ваш сайт. Поскольку его производительность зависит не только от параметров настройки, но и от оборудования и используемых программных продуктов, в книгу были включены рекомендации, помогающие сделать правильный выбор. Я также уделил внимание вопросам масштабирования и соответствия открытым стандартам. Книга эта может быть полезна людям, занимающим перечисленные ниже должности (а кроме них, конечно, и многим другим): О системный администратор, О системный архитектор, О системный интегратор, О программист веб-приложений, О редактор сайта, О веб-мастер. Сделанные предположения Эта книга предполагает наличие у читателя общего знакомства с техническими вопросами работы веб-сайтов. В тексте можно встретить описание событий, происходящих при взаимодействии по НТТР-прЬтоколу. Часто встречаются ссылки на другие книги и веб-сайты, где читатели могут почерпнуть дополнительные сведения по заинтересовавшим их вопросам. Примеры, относящиеся к веб-серверам, взяты из мира Unix, поскольку 75% всех веб-серверов работают под управлением операционной системы Unix или одной из ее производных, а для коммерческих сайтов этот процент еще выше. Ббльшая часть оставшихся серверов работает под управлением Windows, поэтому я постарался включить во второе издание больше сведений об этой операционной системе. Предполагаю, что читатель имеет некоторый опыт программирования на языках С, Java или Perl, но это требование не является обязательным.
Как устроена эта книга Первая часть книги посвящена темам, которые могут быть интересны любому человеку, занимающемуся управлением веб-сайтами. Здесь вы найдете советы, позволяющие быстро и просто повысить производительность, рекомендации по оценке требований создаваемого сайта к оборудованию и программному обеспечению исходя из предполагаемой загрузки и быстроты обработки запросов, а также описание типичных параметров производительности сайта и принципов ее повышения. Рис П.1. Последовательность событий
Во второй части книги рассматриваются события» происходящие, когда пользователь с помощью веб-браузера запрашивает с веб-сервера HTML-страницу (рис. П.1). Мы рассмотрим прохождение запроса от клиента через сеть к серверу, затем к микропрограммному обеспечению и базе данных. С точки зрения браузера после отправки запроса ответ на него сам собой каким-то волшебным образом появляется из Сети. С точки зрения Сети ответ таким же волшебным образом появляется из подключенного к ней сервера. Мы рассмотрим всю последовательность обработки запроса браузера, рассказывая о том, что может повлиять на производительность, и устраняя все «белые пятна». Я дам несколько советов, позволяющих определить, какой из этапов обработки является наиболее медленным, и найти «узкое место», после чего повысить его производительность до уровня других элементов цепочки. Вот о чем рассказывают главы этой книги. Часть I. Предварительные сведения О Глава 1 — Быстрый и мертвый. Рассматривает вопросы, относящиеся к наиболее типичным проблемам с производительностью; содержит советы по быстрому повышению производительности сайта. О Глава 2 — Архитектура веб-сайта. Помогает выбрать оборудование и программное обеспечение, так чтобы сайт хорошо работал и мог быть впоследствии расширен. Описывает некоторые крупные коммерческие веб-сайты, используемое ими оборудование и программы. О Глава 3 — Планирование мощностей. Помогает оценить требования будущего сайта к оборудованию. О Глава 4 — Контроль производительности. Содержит программы контроля производительности и примеры их использования. О Глава 5 — Тестирование на нагрузку. Помогает разрабатывать и применять адекватные тесты на нагрузку для вашего веб-сайта. О Глава 6 — Анализ производительности. Описывает поиск «узких мест». О Глава 7 — Надежность. Содержит множество примеров проблем, которые могут приводить к отказу сайта. О Глава 8 — Безопасность. Рассматривает влияние защищенности на производительность. О Глава 9 — Разбор ситуаций. Содержит несколько реальных примеров проблем с производительностью и их решений. О Глава 10 — Принципы и схемы. Описывает главные принципы повышения производительности сайтов. Часть II. Подробно об оптимизации О Глава 11 — Браузеры. Рассказывает о том, что творится в браузерах, и как это можно ускорить, особенно при кажущихся зависаниях.
О Глава 12 — Операционная система клиента. • Содержит описание различных операционных систем и рассматривает влияние их различий на работу браузеров. О Глава 13 — Аппаратное обеспечение клиента. Описывает возможные «узкие места» в аппаратном обеспечении клиента и способы борьбы с ними. О Глава 14 — Линии связи и концевые устройства. Посвящена используемому в Интернете оборудованию. Вы мало что можете сделать с оборудованием, которое принадлежит другим, однако можете выбирать собственное место в Сети. Если же у вас есть своя интрасеть, вы можете оптимизировать все ее параметры. О Глава 15 — Сетевые протоколы. Описывает протоколы, лежащие в основе веб, вопросы их взаимодействия и совместной работы. О Глава 16 — Аппаратное обеспечение сервера, Рассматривает возможные ограничивающие факторы, связанные с оборудованием сервера. О Глава 17 — Операционная система сервера. Дает рекомендации по настройке Unix для установки веб-сервера. О Глава 18 — Программное обеспечение сервера. Сравнивает существующие бесплатные и коммерческие веб-серверы. О Глава 19 — Содержимое. Рассматривает различные варианты содержимого, возвращаемого клиенту, и связанные с каждым из типов вопросы производительности. О Глава 20 — Специализированные приложения. Содержит рекомендации по ускорению процедуры генерации динамического содержимого. О Глава 21 —Java. Рассматривает некоторые вопросы оптимизации Java-приложений и апплетов. О Глава 22 — Базы данных. Описывает некоторые СУБД, их производительность и стоимость. В приложении сделан обзор продуктов, предназначенных для оптимизации веб-сайта. Содержание обзора отражает исключительно мое отношение ко множеству существующих коммерческих продуктов. Шрифты Курсив используется для авторского выделения слов и подстановочных параметров (например, имен компьютеров и т. п.). Моноширинный шрифт применяется для листингов, трассировок, прогонов программ, HTTP-пакетов, имен программ, функций, а также для выделения вводимых с клавиатуры команд в записях прогонов программ. Шрифт без засечек используется для URL-адресов.
Как с нами связаться Мы проверили все сведения, приведенные в этой книге, по мере своих возможностей, однако вы, вероятно, столкнетесь с некоторыми изменениями в реальном мире (и даже с нашими ошибками). Пожалуйста, сообщайте нам обо всех найденных ошибках и присылайте свои предложения для последующих изданий по адресу: 194044, Санкт-Петербург, Выборгская наб., 27/6; телефон 327-13-11; факс 327-13-15; www.piter.com; Email: comp@piter.com Другие книги и ресурсы С этой книги хорошо начинать изучение широкой темы — производительности веб-сайтов. Однако она ни в коей мере не является истиной в последней инстанции. Здесь я привожу список книг, адресов и конференций, где вы сможете найти ответы на те вопросы, на которые моя книга не отвечает, или просто узнать о чем-то подробнее. Книги Читая данную книгу, вы, конечно, заметите, что я часто отсылаю вас к другим книгам, которые раскрывают некоторые вещи подробнее, чем это могу позволить себе я без риска увеличить объем книги вдвое. Вот список этих книг (в авторский список в основном вошли книги, не переведенные на русский язык, поэтому мы сочли возможным и полезным указать русскоязычные книги, имеющие отношение к рассматриваемым темам; все приведенные здесь книги выпущены издательством «Питер*. — Примеч. ред.): О У. Блэк. Интернет протоколы безопасности. Учебный курс. О М. Гук. Аппаратные средства локальных сетей. Энциклопедия. О М. Даконта, А. Саганич. РНР и Java 2: энциклопедия программиста. О Я. Ф. Дарвин. Java. Сборник рецептов. О О. Кирх. Linux для профессионалов. Руководство администратора сети. О Д. Кренке. Теория и практика построения баз данных. О Т. Кристиансен, Н. Торкингтон. Perl: библиотека программиста. О М. Мамаев, С.Петренко. Технологии защиты информации в Интернете. О А. Павлов. CGI-программирование. Учебный курс. О Р. Петерсен. Энциклопедия Linux.
О Й. Снейдер. Эффективное программирование TCP/IP. < О Э. Таненбаум. Компьютерные сети. О Э. Таненбаум. Современные операционные системы. О А. Цимбал. Технология CORBA для профессионалов. Дополнительную информацию об этих книгах можно получить на веб-сайте издательства «Питер» по адресу: www.piter.com. Веб-сайты, посвященные производительности О http^/help.netscape.com/kb/server/971211-7.html Страница, посвященная настройке Netscape. О http://www.apache.org/ Домашняя страница Apache. Особенно см. http://www.apache.org/docs/misc/perf.html. О http://www.apacheweek.com/tips/ Советы по работе с Apache. О http://www.cmg.org/ Домашняя страница группы Computer Management Group. О http://www.cs.cmu.edu/~jch/java/optimization.html Страница Джонатана Хардвика, посвященная оптимизации Java. О http://www.sysopt.com/ Очень популярная страница, заполненная информацией, касающейся оптимизации персональных компьютеров. О http://www. lcomputers.com/f/ftomhardware.html Руководство Тома по аппаратному обеспечению. Обладает заслуженной известностью в мире ПК. О http://www.nlanr.net/Papers/data-inet97.html Отличный обзор измерений производительности в Интернете. О http://www.rationai.com/ Некоторые документы, касающиеся оптимизации производительности приложений. О http://www.cerberus-sys.com/^belleisi/mtujnssjrwin.html Сайт, посвященный оптимизации Winsock. О http://www.w3.org/ Содержит все RFC (Requests for Comments) — описание принципов и протоколов, на которых основан Интернет. О http://www.usenix.org/events/usenix99/fulljDapers/maltzahn/maltzahn_htmi О Уменьшение дискового ввода-вывода для прокси-серверов Сети. О http://www.opensta.org/ Архитектура тестирования открытых систем. 4 Полностью открытый способ тестирования ваших систем*.
См. также: О http://dir.yahoo.rom/(umputers_andJn^^ mance/ О http://www.yahro.rom/COm О http://linuxperf.nl.linux.org/ О htty://www.w3.org/Proto^ О http://www.w3.org/Protocois/HTTP-NG/ О http://ircache.nlanr.net/Cache/reading.html О http://www.sun.com/sun-on-net/performance Группы новостей, имеющие отношение к производительности веб О comp.benchmarks О comp.infosystems.www.authoring.html О comp.infosystems.www.misc О comp.unix.solaris Ограничение гарантий Я не люблю кричать заглавными буквами, но вынужден это сделать: ИНФОРМАЦИЯ ДАЕТСЯ «КАК ЕСТЬ», БЕЗ ГАРАНТИЙ ЛЮБОГО РОДА - ЯВНЫХ, НЕЯВНЫХ ИЛИ ИНЫХ, ВКЛЮЧАЯ БЕЗ ОГРАНИЧЕНИЙ ЛЮБЫЕ ГАРАНТИИ ГОДНОСТИ ДЛЯ ПРОДАЖИ ИЛИ ПРИГОДНОСТИ ДЛЯ ЛЮБОЙ ОПРЕДЕЛЕННОЙ ЦЕЛИ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОР, ЕГО ПОМОЩНИКИ ИЛИ ИХ РАБОТОДАТЕЛИ НЕ МОГУТ НЕСТИ ОТВЕТСТВЕННОСТЬ ЗА ЛЮБЫЕ ЧАСТНЫЕ, СЛУЧАЙНЫЕ ИЛИ КОСВЕННЫЕ УБЫТКИ ЛЮБОГО РОДА, А ТАКЖЕ ВООБЩЕ ЗА ЛЮБЫЕ УБЫТКИ, ПОНЕСЕННЫЕ ИЗ-ЗА ПОТЕРИ ПРИГОДНОСТИ, ДАННЫХ ИЛИ ПРИБЫЛИ, ВНЕ ЗАВИСИМОСТИ ОТ ТОГО, ГОВОРИЛОСЬ ЛИ О ВОЗМОЖНЫХ УБЫТКАХ. Нет никаких гарантий, что хотя бы одно предложение из этой книги поможет вам в какой-то конкретной ситуации. Если вы будете просто менять конфигурацию и ее параметры, не анализируя ситуацию и не отдавая себе отчета в том, что вы меняете и почему, вы можете повредить свое оборудование, потерять данные и даже волосы на голове. Архивируйте все что можно, не проверяйте все сразу на рабочих серверах и будьте аккуратны. Мнения, выражаемые автором в этой книге, не обязательно совпадают с мнениями работодателей автора и издателей книги (O'Reilly & Associates, Inc.).
Благодарности ко второму изданию Снова благодарю Линду Муи, моего редактора из издательства «O'Reilly*, за ее терпение. Спасибо моему отцу Томасу за поддержку моих амбиций и моей матери Диане за то, что сказала, что я должен написать книгу. Моя жена Лиа, сын Якоб и дочь Женевьева заслуживают огромной благодарности за то, что дали мне время закончить книгу. Еще я пообещал Роберту Хелвигу, что упомяну его здесь. Спасибо всем пользователям Интернета за то, что они всегда готовы поделиться тем, что знают. Спасибо Дину Годе и Женсу С. Вэклеру за то, что разрешили включить свой материал в качестве приложений в первое издание. Значительная доля сведений из этих приложений была включена во второе издание. Во втором издании хочется выразить благодарность Сэму Бродкину за подсказку, касающуюся сценария на Java, а также Дэниэлу Леварту за ценные предложения и исправление ошибок. Тбни Паглис снабдил меня большим количеством руководств и бумаг. Работая с Джоном Невинсом и Тори Уэлшем, я узнал о производительности столько же, сколько я изучил за всю предыдущую жизнь. Брайан Робинсон из Гарварда рассказал мне интересный пример из жизни. Спасибо Адриану Кокрофту, Дейву Луглину, Джону Мани и Джою Тревино за их ценные комментарии. Спасибо Рону Уолтерсу за то, что он показал мне модуль telnet для Perl, а также Нафу Фурману за то, что ознакомил меня с интерфейсом Perl DBI. Павел Семфилд снабдил меня множеством ссылок на полезную информацию.
Часть I Предварительные сведения
I Быстрый и мертвый Хотя в этой книге содержится много подробных и конкретных сведений о наблюдении за системами, тестировании нагрузки, анализе проблем, а также некоторые теоретические основы, мне часто приходится обращаться к приведенному ниже короткому списку вопросов и ответов, который позволяет быстро обнаруживать и устранять наиболее типичные неполадки. Поскольку большую часть проблем можно решить, просто прочитав этот список, я начал книгу именно с него. В списке вы встретите множество ссылок на вещи, еще не обсуждавшиеся, о которых речь пойдет далее. Проверка браузера Начнем с вопросов, которые нужно задать себе, если ваш браузер работает медленно или вовсе отказывается работать. Включен ли ваш модем? Если вы пользуетесь внешним модемом, то на нем есть индикатор питания, который должен гореть. Подключен ли ваш модем к компьютеру? Если вы пользуетесь внешним модемом, то убедитесь, что его кабель подключен к компьютеру. Затем попробуйте вручную отправить модему какие-либо данные. В интерпретаторе команд Linux вы можете сделать это следующим образом: % echo AT > /dev/modem В окне командной строки на компьютере с Windows команда должна быть такой: % echo AT > COM2 Если ваш модем подключен к компьютеру, то на нем загорятся индикаторы приема и передачи данных. Если индикаторы не загораются, это означает, что
либо модем вовсе не подключен к компьютеру, либо вы неправильно указали последовательный (СОМ) порт или иной интерфейс в настройках модема на компьютере. Не повешена ли трубка на другом конце линии? У внешних модемов должен быть индикатор с маркировкой CD (carrier detect — есть несущая). Если он не горит (несущей нет), то ваш модем не может передавать данные другому модему. Это может быть вызвано тем, что удаленный модем уже прервал соединение или вы сами потеряли связь из-за высокого уровня шума в линии или слишком долгого бездействия. Передает ли модем данные? Обратившись к веб-странице, посмотрите на индикаторы внешнего модема. Индикаторы отправки и получения данных должны мигать. То же относится к DSL-модемам, кабельным модемам, концентраторам и другому сетевому оборудованию. Индикатор отправки загорается, когда модем пытается передать данные в Интернет. Индикатор получения загорается, когда модем получает что-то из Сети в ответ на свои запросы. Если индикаторы не мигают — значит, модем ничего не передает. Есть ли у вас свой IP-адрес, и настроен ли адрес основного шлюза? В Windows вы можете проверить назначенный вам IP-адрес с помощью команды ipconfig, которая вызывается из окна командной строки. В Linux для той же цели используется команда ipconfig -a. IP-адрес состоит из четырех чисел, разделенных точками, причем каждое из них лежит в диапазоне от 0 до 255. Если у вас есть IP-адрес, проблемы может вызывать неправильная настройка адреса основного шлюза. Для задания этого адреса под Windows или на компьютерах типа Macintosh используется графический интерфейс пользователя. Под Linux нужно использовать команду route, причем формат вызова должен быть такой: % route add default gw <1Р~адрес маршрутизатора> Если вы можете использовать протоколы telnet или FTP, значит, ваш IP-адрес настроен правильно. Если вы можете подключиться к http://www.yahoo.com/ или другим широко известным сайтам с помощью браузера — значит, верно укапан не только IP-адрес, но и адрес основного шлюза. Чтобы убедиться, что ваш браузер не выводит вам только лишь кэшированную копию страницы, попробуйте обратиться к какому-нибудь сайту с регулярно обновляемым содержимым. Для этого хорошо подходят сайты с данными о котировках акций. Не завис ли браузер? Известно, что браузеры могут зависать. С другой стороны, бывает, что им просто нужно время на выполнение какой-либо операции. Подождите лишнюю минуту, особенно если вы только что запросили веб-страницу. Преобразование DNS-имен в IP-адреса может вызывать иллюзию зависания браузера, особенно если система DNS работает медленно. Если через минуту браузер не проявит «признаков жизни*, завершите соответствующий процесс и запустите его снова. Не находится ли ваш браузер в автономном режиме? Многие браузеры способны работать в автономном режиме. При этом они не могут обратиться к Сети, даже если компьютер еще подключен к ней. Убедитесь, что браузер не на-
ходится в автономном режиме, — на это может указывать значок типа «разорванный провод» в правом нижнем углу браузера. Можете ли вы преобразовывать имена в адреса? Ваш DNS-сервер может находиться в аварийном состоянии либо ваши собственные настройки, относящиеся к DNS, могут быть неверны. Попробуйте обратиться с помощью вашего браузера к какому-либо известному IP-адресу. Если вы не храните под рукой бумажку с IP-адресами сайтов, введите, например, http://204.71.200.66 (что соответствует http://www.yahoo.com/). Если по этому URL вы можете получить вебстраницу, a URL http://www.yahoo.com/ у вас не работает — значит, проблема связана с разрешением имен DNS, и вам придется настроить адреса серверов DNS с помощью графического интерфейса пользователя (Windows, Mac) или в файле /etq/resolv.conf (под Linux). Помните, что регистр символов в именах DNS не учитывается, но он может учитываться в той части URL, которая идет за именем компьютера. Не находится ли в аварийном состоянии какой-либо промежуточный маршрутизатор? Если у вас есть такая возможность, попробуйте установить с вебсервером сеанс telnet. Это можно сделать такой командой: % telnet www.yahoo.com 80 Заметьте, через сколько времени появится ответ connected. Если на это требуется больше одной секунды и такое повторяется несколько раз, попробуйте обратиться к тому же серверу с помощью программы traceroute. Эта программа поставляется с большинством версий Unix и имеется в Windows NT (под именем tracert). Коммерческая версия той же программы под названием Net.Medic производится фирмой Vital Signs Software. Если traceroute останавливается на адресе вашего провайдера (ISP), проблема может быть вызвана тем, что провайдер в данный момент не подключен к остальной части Интернета. В некоторых случаях целая область или страна могут быть отключены от остальной Сети из-за сбоя на государственной точке подключения. Исправить вы тут ничего не сможете, остается только ждать. Если для некоторых промежуточных маршрутизаторов программа выводит время порядка десятых долей секунды и более, обратите внимание на имена этих маршрутизаторов. Если они принадлежат вашему провайдеру, вы можете сильно выиграть в скорости подключения к Интернету, сменив провайдера. Если маршрутизатор принадлежит глобальному провайдеру типа MCI или Sprint, вы все равно можете выиграть, сменив своего провайдера, поскольку разные локальные провайдеры могут быть подключены к разным глобальным провайдерам. Если же маршрутизатор относится к тому сайту, к которому вы пытаетесь обратиться, единственное, что можно сделать, — это пожаловаться веб-мастеру этого сайта. Адреса электронной почты веб-мастеров часто указываются на заглавной странице. Если же адрес не указан, часто имеет смысл написать на адрес типа webmaster@<M*i* сайта>. Если у вас нет программы traceroute или tracert, можно попробовать подключиться к нескольким веб-серверам с помощью программы telnet. Если время подключения окажется слишком большим для всех сайтов, значит, дело в одном из маршрутизаторов вашего провайдера или даже в вашем собственном компьютере.
Не перегружен ли удаленный сайт? Если вы работаете с операционной системой Unix, можете попробовать вызвать команду rstat, указав ей в качестве аргумента имя удаленного сервера. Эта программа позволяет получить статистику загрузки сервера. Запуск rstat ничему повредить не может. Если на сервере не работает демон rstatd или запросы rstat блокируются брандмауэром, то вы просто не получите никакого ответа. В главе 4 о программе rstat рассказывается более подробно. Работает ли удаленный сайт? Если в ответ на ваш запрос сразу же приходит сообщение connection refused, это означает, что программное обеспечение удаленного сервера не работает, хотя компьютер еще функционирует и способен отправить TCP-пакет RST вам в ответ. Получение этого пакета означает, что порт, к которому вы обращались, не прослушивается ни одной программой. Если при попытке подключения к сайту не приходит вообще никакого ответа, это означает, что вы совсем не можете связаться с компьютером, на котором работает удаленный сервер, — этот компьютер может быть сломан, выключен или не подключен к сети. Проверить, принимаются ли какие-либо пакеты от удаленного сервера, можно с помощью программы tcpdump в Linux или snoop в Solaris. Есть ли у этого сайта «зеркало*? Если вы пытаетесь обратиться к какому- либо из популярных сайтов, попробуйте найти его «зеркало* (дублирующий сайт), которое может быть не так сильно загружено. Адреса «зеркал* обычно приводятся на заглавной странице сайта. Например, у сайта веб-сервера Apache (http://www.apache.org/) имеются «зеркала* по всему миру. Не скачали ли вы уже большую часть страницы? Возможно, все отлично работает, а вы зря ждете, пока загрузятся последние несколько байт страницы. Нажмите кнопку браузера Остановить (Stop) и посмотрите, не появится ли на экране долгожданная веб-страница. Не слишком ли велик ваш MTU? А может быть, слишком мал? Максимальный передаваемый блок (Maximum Transmission Unit — MTU) — это параметр, определяющий максимальный размер пакета, который может быть отправлен с интерфейса вашего сетевого адаптера. Если это значение слишком велико, пакеты будут отклоняться интерфейсом и возвращаться им для разбиения на более мелкие. Работа с сетью при этом замедлится. Если это значение будет слишком мало, вы будете отправлять множество мелких пакетов вместо нескольких более крупных, что также замедлит работу в Сети. В главе 12 о настройке параметра MTU рассказывается более подробно. Нужен ли вам прокси-сервер? Ббльшая часть крупных фирм не позволяет внутренним пользователям подключаться к Интернету напрямую. Вместо этого пользователи должны подключаться к прокси-серверам, что повышает защищенность и производительность. Все браузеры позволяют указывать адрес прокси-сервера в окне параметров браузера. Организация должна сообщить пользователям адрес и параметры прокси-сервера, с которым они будут работать. Если вы можете подключиться к порту 80 какого-либо популярного сайта с помощью программы telnet, значит, вы подключены к Интернету напрямую, и прокси-сервер вам не нужен. Может ли ваш прокси-сервер работать с HTTPS? Помните, что не все прокси-серверы поддерживают уровень защищенных сокетов (Secure Sockets Lay-
er — SSL). Если ваш прокси-сервер принадлежит к их числу и вы обязаны им пользоваться, то вы в принципе не сможете обращаться к страницам, защищенным с помощью SSL. Адреса таких страниц начинаются с https (в отличие от обычных страниц, начинающихся с http). Большая часть коммерческих веб-сайтов использует SSL для защиты транзакций. Как правило, для передачи вебстраниц по протоколу HTTPS используются порты 443 и 563. Нет ли более быстрого прокси-сервера? В большинстве организаций прокси-серверов обычно бывает несколько, и, естественно, одни серверы при этом более загружены, чем другие. Вы можете заметно повысить производительность, просто выбрав правильный прокси-сервер. Если прокси-серверы работают под управлением операционной системы Solaris или какой-либо другой, поддерживающей демон удаленного доступа к статистике rstatd, вы можете получить сведения о том, какой из этих серверов загружен меньше всего, с помощью программ rstat или perfmeter. В главе 4 о программе rstat рассказывается более подробно. Первая задача — узнать имена прокси-серверов. Вы можете начать с расспросов других пользователей компании. Если ваш браузер настраивается автоматически с помощью файла ргоху.рас, вы можете попробовать вручную скачать этот файл с помощью программы telnet и просмотреть его. Там вы найдете имена прокси-серверов. Было бы здорово, если бы браузеры могли автоматически переключаться между прокси-серверами в зависимости от времени их отклика или на основании статистики, выдаваемой rstat, но, насколько мне известно, пока таких браузеров нет. К счастью, большая часть прокси-серверов не требует никакой проверки подлинности пользователя, поэтому вы можете свободно переключаться с одного на другой в поисках самого быстрого. Вы можете узнать, насколько быстр сайт, к которому вы обращаетесь, указав его URL в одном из окон программы анализа сайтов на http://patrick.net/. Если программа сообщит, что сайт является достаточно быстрым, а вам кажется, что он работает медленно, значит, проблема может быть связана с вашим прокси- сервером или сетью внутри вашей компании. Не блокируете ли вы сами себя? На вашем компьютере может быть установлено программное обеспечение, не позволяющее просматривать содержимое некоторых сайтов. Такое программное обеспечение может работать и на вашем прокси-сервере. Не запущено ли на вашем компьютере слишком много программ? Проверьте, не перегружен ли ваш клиент какими-либо другими задачами помимо браузера. В операционной системе Linux статистику использования ресурсов процессами можно получить с помощью программы top. Эта же программа позволяет завершать ненужные больше процессы. В Windows NT нажатие Ctrl+Shift+Esc открывает диспетчер задач, который работает аналогично программе top. Чем меньше процессов, тем лучше, но нужно отдавать себе отчет в том, какие именно процессы вы завершаете, потому что иначе можно запросто сделать компьютер неработоспособным. Если вы не уверены в том, что делаете, попробуйте просто перезагрузить компьютер, чтобы избавиться от процессов, вызывающих утечку памяти или тормозящих систему каким-либо другим путем. Эти процессы все равно могут запуститься при загрузке системы, но, по крайней
мере, даже если они и расходуют память, при запуске им будет выделено минимальное ее количество. Достаточно ли у вас оперативной памяти? Основным признаком недостатка оперативной памяти является низкая производительность компьютера и постоянное обращение к жесткому диску (свопинг). Это происходит из-за того, что система пытается использовать виртуальную память на жестком диске, когда ей не хватает оперативной памяти. К сожалению, диск работает чрезвычайно медленно по сравнению с ОЗУ. Решений может быть несколько: запускайте меньше приложений, используйте менее ресурсоемкие программы, отключите в браузере поддержку Java или добавьте в компьютер памяти. Достаточно ли быстр ваш процессор? Поверьте, вполне достаточно. В отличие от качества линий связи и объема оперативной памяти производительность процессора практически никогда не сказывается на скорости работы с веб-сайтами. Достаточно ли высока пропускная способность? На стороне клиента плохая производительность чаще всего бывает вызвана недостаточной пропускной способностью линии между провайдером и компьютером клиента. Если вам приходится подключаться по модему, лучше потратиться на самый быстрый из имеющихся в продаже модемов. Правда, прежде чем покупать этот модем, убедитесь, что ваш провайдер поддерживает максимальную скорость модема. ISDN лучше, чем модем, но сложнее в настройке. ADSL и кабельные модемы лучше всего подходят для пользователей, выходящих в Интернет из дома. Если вы подключены к локальной сети, быстрый Ethernet A00 Мбит/с) дает заметный выигрыш в производительности по сравнению с обычным A0 Мбит/с). Быстрый Ethernet может работать в двустороннем режиме, что еще более увеличивает выигрыш в производительности. Не снижает ли вашу производительность избыток графики? Отключение автоматической загрузки изображений может очень сильно увеличить производительность, если проблема вызвана недостатком пропускной способности вашего модема, подключенного к обычной телефонной линии. Конечно, без графики вы многого лишитесь, потому что веб сейчас во многом состоит именно из картинок. С другой стороны, вам не придется читать большую часть рекламы. В Netscape автоматическая загрузка изображений отключается в меню Edit ► Preferences ► Advanced с помощью флажка Automatically Load Images. Даже отключив автоматическую загрузку изображений, все равно можно загрузить и увидеть интересующую картинку, щелкнув на ее значке. Вы можете спросить, как можно узнать, интересует ли вас картинка, если ее не видно. Именно для этого и предназначен тег ALT языка HTML. Подразумевается, что автор сайта должен давать текстовые описания картинок, которые будут выводиться в тех случаях, когда браузер не отображает сами картинки. Аббревиатура ALT означает alternate text (альтернативный текст). Вот пример использования :>того тега: <img src-"images/foo.gif" alt-"Picture of a Foo" width-190 height«24> Большая часть браузеров при отключении автоматической загрузки изображений выводит на панель инструментов кнопку, позволяющую загрузить сразу исе изображения страницы. Многие сайты предлагают пользователю выбрать
одну из нескольких версий в зависимости от скорости его линии. Если пользователь подключен по модему, он может выбрать версию, в которой графики будет мало или не будет вовсе. Можно пользоваться текстовыми браузерами типа lynx, у которого есть то преимущество, что он может быть удаленно запущен в режиме терминала (что не требует поддержки протокола TCP/IP на всем протяжении сети от сервера до клиента). Проще говоря, ваш провайдер может предложить вам подключаться к нему по телефонной линии и работать с программой lynx на компьютере провайдера, а не на вашем собственном. ПРИМЕЧАНИЕ Internet Explorer быстрее, чем Netscape, работает с изображениями, размер которых не указан в теге HTML явно. Не раздражает ли вас длительность загрузки браузера? Часто лучше настроить браузер так, чтобы при его запуске открывалась пустая страница (blank page), чтобы вам не приходилось ждать, пока он загрузит какую-либо другую домашнюю страницу каждый раз, когда вы запускаете его. Особенно загружена графикой и прочими «довесками* домашняя страница Netscape, так что предлагаемые по умолчанию параметры браузера Netscape действительно лучше изменить. Делается это с помощью меню Edit ► Preferences ► Navigator (переключатель Navigator starts with blank page). СОВЕТ Если графика вам не нужна, пользуйтесь браузером lynx, который запускается мгновенно. Не пользуетесь ли вы медленным браузером? Последние версии браузеров используют новые возможности протокола HTTP, позволяющие повысить производительность, но вообще у браузеров есть тенденция становиться медленнее и больше в объеме с каждым поколением. С другой стороны, Netscape 6 был полностью переписан заново и работает гораздо быстрее, чем Netscape 4. (Номер версии 5 компания Netscape просто пропустила.) IE 5 также имеет некоторые преимущества перед своими предшественниками. Очень старые браузеры обычно крайне просты, поэтому могут не поддерживать SSL, JavaScript, Java и другие полезные вещи. С другой стороны, обычно они занимают мало места в памяти и очень быстро работают на современном оборудовании. Браузер Opera (http://www.opera.com/) очень маленький и быстрый, но не бесплатный, если только вы не смиритесь с постоянным мельканием перед глазами рекламы. Достаточно ли велик кэш вашего браузера? Под кэш браузера нужно отводить 25% объема памяти и 10% объема диска компьютера. Это немало, но в данном случае для других приложений все равно будет оставаться достаточно места. Не тратите ли вы время зря на проверку кэшированных ранее страниц? Браузеры кэшируют просматриваемые вами документы и при повторном обращении загружают их из кэша. Поскольку за время между обращениями доку-
мент мог измениться, по умолчанию браузер обычно связывается с сервером и проверяет актуальность всех кэшированных страниц. Если документ на сервере изменился, загружается его новая версия. Если же локальная копия еще актуальна, на экран выводится именно она. Проверка актуальности занимает немного времени, если страница не изменилась, но производительность все-таки можно повысить, отключив автоматическую проверку. При этом вам не придется заново загружать страницы, в которых практически ничего не изменилось. Да, возможно, вы будете получать устаревшую информацию, — но, по крайней мере, вы будете получать ее быстро. Чтобы отключить автоматическую проверку актуальности документов в Netscape, войдите в меню Options ► Network Preferences и установите переключатель Verify Document в положение Never. Если вам кажется, что информация на странице, которую вы видите, устарела, загрузить новую версию очень легко: достаточно щелкнуть мышью на кнопке Reload при нажатой клавише Shift. Чуть медленнее будет работать браузер при выборе пункта Once per session — при этом страницы будут проверяться один раз за сеанс работы с Netscape. Самый медленный вариант — Every time. При этом страница будет проверяться каждый раз при обращении к ней. Не раздражает ли вас продолжительность запуска виртуальной машины Java? Запуск виртуальной машины Java при первом обращении к странице, содержащей Java-апплеты, может занимать 15-20 с. При этом работа браузера приостанавливается, а процесс запуска прервать невозможно. Это может раздражать пользователей. Одно из решений — отключить поддержку Java и включать ее только тогда, когда вам очень нужно поработать с каким-то аппле- том. Другое решение — попробовать последнюю «примочку* (plug-in) от Sun, которая позволяет неограниченно кэшировать апплеты, так что вам не придется скачивать их по нескольку раз. Однако сама эта программа довольно велика, и скачивать ее для установки придется довольно долго. Нельзя ли ускорить работу, сменив провайдера? Если большую часть времени вы работаете с одним и тем же сервером, вы можете заметно выиграть, сменив своего провайдера на того, через которого подключается этот сервер. При этом могут возрасти скорость передачи информации и быстрота отклика. Удачно ли вы выбираете время для путешествия по Сети? Когда в Сети много пользователей, ее быстродействие снижается. Особенно это заметно в организациях, пользователи которых подключаются к Интернету через прокси- серверы. Не выиграет ли ваша организация, установив прокси-сервер? Прокси-сервер, установленный между вашей организацией и Интернетом, будет кэшировать часто запрашиваемые страницы, что уменьшит нагрузку на подключение к Интернету и увеличит скорость обращения к страницам для пользователей. Выигрыш зависит от того, насколько часто происходит обращение к страницам из кэша. Если все запросы будут отправлены на разные URL-адреса, то прокси- сервер не даст никакого выигрыша в производительности, а, напротив, ухудшит ее. На практике некоторые веб-страницы являются очень популярными, и обращение к ним происходит постоянно, поэтому использование прокси-сервера дает заметный выигрыш в производительности.
Прокси-сервер должен быть особенно быстрым, поскольку он должен одновременно являться и клиентом, и сервером. Прокси-серверы записывают на диск большие объемы информации, поэтому их производительность обычно заметно возрастает при использовании кэширующего контроллера диска. Помните, что использование прокси-сервера может сделать невозможной работу с некоторыми Java-апплетами, поскольку апплеты могут подключаться только к тому серверу, с которого они были загружены. Загружаться на компьютер клиента апплеты будут с прокси-сервера, но обычно апплеты на это не рассчитываются. Проверка сервера Теперь давайте взглянем на все это со стороны сервера. Вот вопросы, на которые вам нужно попытаться ответить, если ваш сервер кажется слишком медленным. Не перешел ли ваш сервер в режим энергосбережения? Если сервер установлен на персональном компьютере, то есть смысл отключить функции экономии электроэнергии, а именно остановку дисков и переход в спящий режим. Пользователь, обращающийся к серверу, находящемуся в спящем режиме, почувствует некоторую задержку, поскольку на раскрутку остановленных дисков требуется некоторое время. Некоторые операционные системы, например Мае OS X, могут быстро отправлять запрошенные страницы даже в спящем режиме. Но и такой системе придется выходить из спящего режима для записи журнала на диск, поэтому функции сохранения питания лучше все-таки отключить. Не перегружен ли ваш DNS-сервер? DNS-серверы могут быть перегружены, как и любые другие серверы Интернета. Поскольку поиск в DNS блокирует вызвавший процесс, медленные DNS-серверы могут заметно влиять на производительность других серверов. Проверьте, не приближается ли ваш DNS-сервер к предельной загрузке процессора или сети, изучив его статистику. В главе 4 о сборе статистики рассказывается более подробно. Если вы обнаружили, что проблемы вызваны DNS-сервером, рассмотрите возможность установки дополнительных серверов или перенаправления запросов на другой сервер. Сменить DNS-сервер можно, изменив файл /etc/resolv.conf в Linux, а в Windows это делается с помощью Панели управления. У всех ли изображений на ваших страницах указаны размеры и имеются теги ALT? Браузеры Netscape неспособны отобразить страницу, пока не станут известны размеры всех имеющихся на этой странице изображений. Если в HTML-коде размеры изображений не указаны, браузеру придется загрузить все изображения, прежде чем он узнает их размер и сможет что-то отобразить. Это приведет к значительной задержке перед появлением хоть какого-то содержимого на экране пользователя. Многие пользователи отключают загрузку изображений, но им обычно хочется знать, чего они не видят, особенно если изображения на сайте используются для навигации. Поэтому для удобства пользователя и повышения производительности нужно, чтобы у всех изображений был указан размер и имелся тег ALT, как в приведенном ниже примере:
<img src-"images/foo.gif" alt-MPicture of a Foo" width=190 height=24> У всех ли апплетов есть тег ALT? Многие пользователи отключают поддержку Java, поскольку на запуск виртуальной машины и загрузку апплетов уходит много времени. Как и для изображений, для апплетов можно и нужно указывать альтернативный текст, который будет выводиться на экран пользователя, чтобы тот мог решить, не следует ли ему включить поддержку Java и загрузить страницу еще раз. Этот текст может содержать в себе теги HTML, так что разработчик содержимого может предложить пользователю достойную альтернативу ап- плету и включить ее в тег ALT этого апплета. Нет ли на вашем сайте ненужных или медленных тегов перенаправления? Язык HTML позволяет перенаправлять браузер на другую веб-страницу с указанием задержки. Для этого используется тег МЕТА. Вот пример, в котором задержка составляет 2 с: <МЕТА HTTP-EQUIV - "Refresh" Content - :URL-http://www.go here.com"> Следует избегать перенаправлений везде, где это возможно, поскольку они просто тратят время пользователя. Если же вам приходится использовать перенаправление, ускорьте его, указав нулевую задержку. Не тратит ли ваш веб-сервер время зря на обратный поиск в DNS? Часто веб-серверы по умолчанию настраиваются так, чтобы по IP-адресу клиента находить в DNS его имя, которое затем записывается в журнал и в переменную среды CGI REMOTEJHOST. На это тратится время, а между тем эта операция совершенно избыточна, поскольку программа просмотра журнала может выполнить подстановку имени клиента самостоятельно. У вас может возникнуть желание вовсе выключить запись журнала, но это не самое мудрое решение. Журналы нужны для того, чтобы определять нагрузку на сервер, его пропускную способность, рост нагрузки и другие ценные параметры. А вот доменные имена действительно в журнале не нужны. CGI-программа может самостоятельно выполнять обратный поиск в DNS, если это необходимо. Любой веб-сервер позволяет отключить обратный поиск в DNS с помощью файлов конфигурации. Изучите документацию. Не слишком ли много повторных передач приходится выполнять вашему веб-серверу? При установке соединения по TCP сегмент считается утерянным, если подтверждение его получения не приходит спустя некоторый промежуток времени (обычно 200 мс). Для некоторых пользователей, подключающихся к Интернету по медленным линиям, этого может быть недостаточно. ТСР-сег- менты будут благополучно прибывать на браузер, а сервер будет считать их утерянными и посылать заново, то есть зря расходовать пропускную способность. Увеличение тайм-аута повторной передачи может решить проблему, но учтите, что это действие может и понизить производительность на быстрых ненадежных линиях. Если подключение по TCP существует достаточно долго, этот протокол автоматически адаптируется к качеству линии, но подключения к вебсерверам обычно существуют недолго, поэтому установка начального значения тайм-аута играет большую роль. Не слишком ли далеко вы находитесь от своих пользователей? IP-пакеты но пути от сервера к клиентам обычно проходят несколько развилок. На этих
развилках стоят специальные компьютеры, называемые маршрутизаторами. Они решают, куда именно следует направить каждый пакет. Прохождение пакета через маршрутизатор называется прыжком (hop), а на прыжки тратится некоторое время, хотя и небольшое (обычно 1-2 мс). Поэтому серверы должны находиться как можно ближе к своим пользователям. У провайдеров обычно имеется своя собственная высокоскоростная сеть, соединяющая все точки входящих подключений. Пользователь, подключающийся к Интернету через конкретного провайдера, получит более высокую производительность при обращении к серверам, подключенным к тому же провайдеру, поскольку в этом случае между ним и сервером будет меньше всего маршрутизаторов. Поставщики национального масштаба соединяют множество людей. Если вы знаете, что большая часть ваших пользователей подключается через AOL (America OnLine), подключите один из своих серверов к тому же провайдеру. Хуже всего пытаться обслужить аудиторию другой страны, когда пакетам приходится путешествовать на большие расстояния через множество маршрутизаторов. Сеанс связи по протоколу HTTP из Нью-Йорка с Сиднеем может долго не начинаться, а потом и вовсе остановиться. То же может произойти и в том случае, если сервер и пользователь расположены географически недалеко, но между ними имеется множество маршрутизаторов. Одним из возможных решений может стать размещение данных на одной из служб распространения данных, такой как Akamai. Не перегружено ли подключение вашего сервера? Самым эффективным средством повышения производительности методом «грубой силы» является замена сетевого подключения на более быстрое. Не следует выполнять это действие без предварительного анализа, потому что, например, если сервер перегружен из-за недостатка памяти или низкого быстродействия дисков, ускорение сетевого подключения может привести даже к сбою такого сервера, поскольку увеличится нагрузка на и без того перегруженную память или диск. Не ограничивает ли производительность вашего сервера процессор? Для статических HTML-страниц быстродействие оборудования сервера обычно является достаточным, тогда как для постоянной генерации большого объема динамического содержимого лучше воспользоваться мощным компьютером. Если процессор постоянно загружен на 100%, считайте, что вы нашли проблему, требующую немедленного внимания. Выигрыш от замены процессора целиком зависит от причин проблемы, причем поставщик вряд ли сообщит вам о том, что новое оборудование вам в действительности не нужно. Возможно, вы просто выбрали плохо написанное приложение. Если вы выполнили профилирование приложения и решили, что вам все-таки нужно более мощное оборудование, попробуйте заменить персональный компьютер на Unix-сервер от Sun, IBM или HP. У этих компьютеров гораздо более совершенная подсистема ввода-вывода, и они более выгодны с точки зрения масштабируемости. Следите за использованием аппаратных ресурсов вашего сервера, чтобы вовремя обнаруживать перегрузку. Хватает ли вам памяти? В системе Solaris версии 7 или ниже запустите программу vmstat и изучите столбец sr, где выводится количество запросов на выгрузку памяти в файл. Если это число часто оказывается выше нуля, вам не хва-
тает памяти. Другими показателями недостатка памяти служат обращение к диску (свопинг) и подкачка. В системах Solaris 8 и более поздних можно просто смотреть за объемом свободной памяти. Оперативная память работает в тысячи раз быстрее любого жесткого диска, поэтому считывание данных из оперативной памяти вместо диска может заметно ускорить работу любой программы. В большинстве версий Unix и в Windows NT вся свободная память автоматически используется в качестве кэша файловой системы, поэтому повторное обращение к файлам происходит тем быстрее, чем больше у вас памяти. Веб-серверы также используют свободную память для кэширования данных. Большой объем памяти позволяет увеличить сетевые буферы и выполнять параллельно большее количество CGI-программ. Любое количество памяти можно израсходовать, если одна из программ выбывает утечку памяти. Следите за объемом отдельных процессов с помощью программы top. Это поможет вам выявить источник утечки. Такие программы нужно либо исправлять, либо регулярно перезапускать. Не перегружены ли ваши диски? В системе Solaris изучите вывод команды iostat -х. Постоянное появление задержек обращения к диску свыше 100 мс является достаточным основанием для беспокойства. Покупайте диски с наименьшим временем поиска (seek time), поскольку большую часть времени при случайном чтении жесткие диски тратят на поиск данных (перемещение головок на нужную дорожку). Часто лучше использовать несколько небольших дисков, чем один большой: 10 000 об/мин лучше, чем 7200. Чем больше кэш контроллера, тем лучше. SCSI лучше, чем IDE или EIDE. Но чем лучше диск, тем он дороже... Не выиграете ли вы от использования служб кэширования? Используйте несколько зеркал одинаковой мощности и равномерно распределяйте нагрузку между ними. Сейчас существует множество коммерческих служб типа Akamai, предоставляющих кэширующие серверы. Нагрузка будет до некоторой степени сбалансирована естественным образом, если ваша аудитория будет разбросана но часовым поясам. Не страдаете ли вы из-за ошибок в программах, которые уже исправлены? Новые версии программ обычно работают быстрее и лучше. По крайней мере, гак должно быть. Попробуйте установить последнюю версию операционной системы и веб-сервера и применить к ним все пакеты обновлений (за исключением beta-версий). Иногда лучше не следовать этому совету, поскольку старые иерсии программ обычно потребляют меньше памяти. Не падает ли производительность через регулярные промежутки времени из-за демона сгоп? Сгоп — это демон Unix, который запускает другие программы по заданному расписанию. Если производительность регулярно падает через одинаковые промежутки времени, изучите список задач, вызываемых демоном сгоп или autosys. (Последний представляет собой коммерческую версию сгоп, продаваемую Computer Associates.) Есть смысл просто запустить программу perfmeter (если вы работаете в Solaris) и проследить за производительностью. При необходимости демон сгоп можно просто отключить. Не мешают ли вашему веб-сайту другие процессы? Не запускайте на вашем сервере программ, которые не нужны для его работы. То же относится
и к компьютеру, на котором размещена база данных. Ваш веб-сервер не должен одновременно являться сервером NFS (сетевой файловой системы), почтовым сервером или DNS-сервером. Найдите для этих служб другие компьютеры. С помощью программы top (или диспетчера задач в Windows) вы сможете выявить процессы, пожирающие больше всего ресурсов процессора и памяти. Завершите все ненужные демоны, такие как Ipd. Даже не пытайтесь запустить какой-нибудь оконный интерфейс на веб-сервере. Он вам не нужен, а памяти требует много. Терминала для управления вебсервером вполне достаточно. В Windows у вас не будет выбора, поскольку терминального режима в этой операционной системе нет. Не тратится ли время на SSI? Подключение на стороне сервера (Server Side Include — SSI) крайне неэффективно. Идея SSI состоит в том, что сервер просматривает HTML-код и ищет в нем команды на запуск программ и вставку содержимого. Гораздо лучше динамически генерировать страницу целиком из одной CGI-программы, чем пользоваться SSI. CGI сейчас работает не так медленно, как раньше, поскольку современные операционные системы рассчитываются на одновременную работу множества короткоживущих процессов в соответствии с потребностями Сети. Нужно ли вам динамическое содержимое? Возможно, у вас нет серьезных причин для использования динамической генерации содержимого. Вы можете обновлять статические HTML-страницы несколько раз в день, что дает иллюзию динамической генерации без затрат ресурсов. Все зависит от того, сколько вариантов действий пользователя вы хотите предусмотреть. Если их не слишком много, вы легко можете предугадать их все. Достаточен ли размер пула подключений вашей базы данных? Если у вас есть связующий сервер, обслуживающий пул подключений к базе данных, учтите, что увеличение этого пула при необходимости очень сильно сказывается на производительности. Лучше, если это возможно, запускать сервер с большим начальным размером пула, чтобы его не нужно было увеличивать. Типичным симптомом недостаточности размера пула подключений является резкое падение производительности при увеличении нагрузки. Нет ли утечек в пуле подключений к базе данных? Если вы выделяете подключения к базе данных из пула, но не освобождаете их, это может приводить к ненужному увеличению размеров пула и даже к полной остановке сайта до освобождения подключений по тайм-ауту. Для поиска утечек можно следить за количеством подключений и нагрузкой. В главе 4 приведен сценарий, выводящий на экран графики использования для страницы Weblogic Admin. Исправление ошибок, приводящих к утечкам, требует внимательной проверки кода на наличие команд освобождения подключений, а также на обработку исключительных ситуаций, в которых это освобождение может не выполняться. Не перегружены ли ваши концентраторы, коммутаторы и маршрутизаторы? Нет ли ошибок в их конфигурации? Большая часть сетевого оборудования (концентраторы, коммутаторы и маршрутизаторы) поддерживают протокол SNMP. Программа, использующая этот протокол, позволяет получать статистику по использованию оборудования и количеству сетевых коллизий. Следите за этой статистикой и не допускайте перегрузок. Перегруженные концентраторы чаще
всего являются виновниками неприятностей, и их довольно просто заменить на более высокопроизводительные коммутаторы. Избегайте ошибок в конфигурации Ethernet: например, не делайте одно подключение двусторонним, а другое — односторонним. Не происходит ли внезапных остановок Java-процессов? Это может быть связано с работой сборщика мусора (garbage collector — GC). Поскольку сборщик мусора обычно является однопоточным, в многопроцессорной системе это может приводить к тому, что один процессор будет загружен полностью, а остальные будут простаивать. Для просмотра загрузки процессоров в Solaris используется программа mpstat. Изменение начального и максимального размеров кучи позволяет отложить неизбежный запуск сборщика мусора, но одновременно замедляет его работу. Исключением является виртуальная машина IBM. Кроме того, при запуске виртуальной машины Java полезно бывает указать ключ -verbosegc, чтобы точно знать, в какой момент происходит сбор мусора. Последние версии JDK дают программисту некоторую возможность влиять на процесс сбора мусора. Используете ли вы CORBA, EJB или RMI1? Лучше не надо. Затраты на сборку объектов-параметров огромны. Локальные вызовы методов работают во много тысяч раз быстрее, чем удаленные. Если это возможно, выбирайте в качестве клиента стандартный браузер, а не приложение, выполняющее RMI-вызо- вы. Не тратите ли вы слишком много ресурсов на ведение журнала? Запустите strace в Linux или truss в Solaris, чтобы узнать, чем занимаются процессы вашего сервера. Если вы слишком много ресурсов тратите на ведение журнала, то сразу же об этом узнаете, поскольку увидите много запросов на запись небольших объемов информации в один и тот же дескриптор. Начните с буферизации журнала, чтобы запись осуществлялась большими блоками. Во многих серверах для включения буферизации журнала имеется специальный параметр настройки. Затем попробуйте не записывать в журнал данные из программ Java, чтобы не тратить ресурсы на создание объектов и преобразование между Unicode и ASCII. Не используете ли вы систему слежения за обновлениями? Системы слежения за обновлениями (revision control systems) очень удобны для отслеживания изменений в HTML и программах, но крайне отрицательно влияют на производительность. Копируйте данные на веб-сервер и не пытайтесь заставить его обращаться к ClearCase или другой подобной системе. Сервер вовсе не загружен, но он работает медленно! Иногда с сервером, на первый взгляд, все в порядке, но он все равно работает медленно. Вот возможные причины, о которых мы будем говорить далее в тексте книги: О расширение пула подключений к базе данных; О обратный поиск в DNS; 0 повторная передача пакетов TCP; 1 CORBA — Common Object Request Broker Architecture; EJB — Enterprise Java Beans; RMI — Remote Method Invocation.
О перегрузка концентраторов и коммутаторов; О сбор мусора; О ожидание возвращения из вызова RMI, CORBA или EJB; О запись больших объемов данных в журналы JDBC (или подобные) малыми порциями; О чтение содержимого непосредственно из систем слежения за обновлениями типа ClearCase; О недостаточное количество процессов-демонов Apache или потоков Netscape. Основные рекомендации О Отключите загрузку изображений на стороне клиента. О Отключите Java на стороне клиента. О Отключите проверку актуальности кэшированных документов на стороне клиента. О Добавьте памяти в компьютер-сервер. О Добавьте памяти в компьютер-клиент. О Найдите более подходящее подключение к Интернету. О Кэшируйте содержимое в памяти, если вы работаете с локальной сетью. В противном случае работу будут тормозить диски. О В Интернете самым узким местом является сам Интернет, за ним следуют динамическая генерация содержимого и запросы к базам данных. О Если у вас есть другие вопросы и ответы для быстрой проверки, пишите на p@patrick.net.
2 Архитектура веб-сайта Разработчикам веб-сайтов часто приходится идти на компромиссы. Им нужно подбирать оптимальную конфигурацию и выбирать нужные компоненты из множества существующих. Все зависит от того, к чему вы стремитесь, — нет решения, которое подошло бы всем. В этой главе мы рассматриваем фундаментальные проблемы, с которыми может столкнуться любой. Компромиссы В процессе разработки архитектуры сайта часто возникает необходимость жертвовать одним ради другого, выбирать между сохранением информации о пользователях и масштабируемостью, между дублированием и простотой, между синхронностью и асинхронностью, между соединениями и их отсутствием, между скоростью разработки и тщательным планированием и, наконец, между процедурным и объектно-ориентированным программированием. Сохранение информации и масштабируемость Сам по себе веб-сайт неспособен сохранять информацию об индивидуальных пользователях в промежутках между веб-транзакциями. Пользователи таких сайтов не могут хранить на них никакой информации о себе. Сайт ничего не «помнит» о ваших предыдущих посещениях. Он отправляет вам запрошенную страницу независимо от того, запрашивали ли вы ее раньше, и независимо от того, с какой страницы вы на нее попали. У таких веб-сайтов не бывает проблем с масштабируемостью. Сайты без сохранения состояния могут легко дублироваться, что вместе с распределением нагрузки обеспечивает масштабирование даже в случае работы с динамическим
содержимым (если, конечно, это содержимое допускает дублирование). Примером может являться сайт, на котором размещается информация о котировках акций или прогноз погоды. Поскольку функциональность всех веб-серверов одинакова, пользователь может без всяких проблем получить заглавную страницу сайта с одного сервера, затем щелкнуть ссылку на этой странице и получить другую страницу с другого сервера. Совсем иначе обстоят дела на сервере транзакций, где необходимо сохранение информации о состоянии пользователей, например о входе и выходе из системы, о содержимом покупательской корзины или пользовательского счета. Необходимость сохранения информации о состоянии пользователей является источником большей части проблем с производительностью на сайтах с поддержкой транзакций, ограничивает масштабируемость скоростью получения и обновления информации о пользователях, заставляет серверы постоянно обмениваться этой информацией. Система записей представляет собой базу данных, в которую записываются транзакции, и неизбежно является узким местом. Существует несколько способов уклониться от конфликта между необходимостью сохранения информации о пользователях и необходимостью масштабирования сайта. О Храните сведения о состоянии в явном и компактном виде, например в одном файле cookie, чтобы состояние транзакции помещалось в один пакет. О Не разделяйте сведений о состоянии между браузером, промежуточным сервером и базой данных, чтобы небольшие ошибки не приводили к огромному беспорядку. О Обеспечьте атомарность операции записи состояния в систему записей и проверку успешности выполнения этой операции. Уменьшение объема сведений о состоянии также весьма благоприятно влияет на производительность, поскольку меньший объем данных приходится записывать в базу данных или считывать из нее. Если вы планируете масштабирование сайта с поддержкой транзакций путем дублирования данных о состоянии между серверами, малый объем этих данных облегчит их дублирование. Распределение обработки данных о состоянии между несколькими процессорами потребует интенсивного обмена данными для синхронизации — как в случае с несколькими машинами в кластере, так и в случае с одной многопроцессорной машиной. В первом случае это затронет сетевое соединение между парами компьютеров, а во втором будет производиться синхронизация кэшей процессоров. В обоих случаях количество пар процессоров, нуждающихся в синхронизации, будет экспоненциально расти с ростом числа процессоров. То же относится и к сотрудничеству людей. Чрезмерное увеличение числа работников в группе может привести к падению эффективности из-за роста затрат на общение (например, проведение деловых совещаний). Мне вспоминается один исполнительный директор, который утверждал, что лучший способ ускорить затормозившийся проект — это начать увольнять участвующих в нем сотрудников, поскольку чаще всего проекты тормозятся из-за слишком большого количества задействованного персонала. По-моему, он прав.
Дублирование и простота Да, веб-сайты можно масштабировать, копируя данные с одного сервера на другой каждую ночь. Однако масштабирование через репликацию усложняет администрирование сайта, а чрезмерное усложнение для сайтов смертельно опасно. Гораздо проще реализовать схему с одним авторитетным источником данных. С другой стороны, без репликации масштабируемость будет ограничена скоростью центрального источника данных, которым может являться, например, сервер NFS или реляционная база данных. Особенно сильно это ограничение действует при попытке записи в центральную базу данных, поскольку транзакции с базами данных должны удовлетворять так называемому ACID-крите- рию (Atomicity, Consistency, Isolation, Durability — Атомарность, Непротиворечивость, Изоляция и Долговечность). Для обеспечения непротиворечивости (согласованности) и долговечности транзакции до ее начала необходимо заблокировать данные, с которыми вы собираетесь работать (это и будет изоляция). Это делается для того, чтобы никакой другой процесс не мог изменить и, возможно, разрушить данные в процессе транзакции, которая либо выполняется целиком до успешного завершения, либо полностью отклоняется (атомарность). Поскольку вы работаете с единственным набором данных и обращаетесь к ним строго последовательно, скорость выполнения транзакций будет ограничена тем, как быстро вы можете заблокировать, изменить и разблокировать данные в базе. Блокирование других процессов уменьшает производительность. Согласованность данных требует также синхронизации кэшей с системой записей. Долговечность означает, что данные сохраняются после перезагрузки компьютера. Часто забывают о том, что постоянная полная внутренняя согласованность базы данных не является обязательным требованием. Вполне допустима некоторая несогласованность, то есть противоречивость данных в течение некоторого промежутка времени. Это не приводит к слишком большому риску. Представим себе банк, у которого есть центральная база данных о состоянии счетов и кассовые терминалы с локальным кэшем. За один час с одного счета с одного терминала ATM можно снять не более 200 долларов, и при этом немедленного обращения к базе данных не произойдет: изменения будут кэшированы ATM до конца часа. Это значительно ускоряет транзакцию с точки зрения пользователя. База данных синхронизируется в течение часа с момента транзакции, причем для этого могут использоваться более медленные (но и более дешевые) линии связи. Банк подвергается некоторому риску, потому что за один час пользователь может обойти много терминалов и снять с каждого по 200 долларов, но этот риск считается пренебрежимо малым по сравнению с выигрышем для пользователя и для банка, особенно если банк предъявляет какие-либо требования к минимальному остатку на счете. Служащие банка всегда знают, сколько денег было на каждом счете час назад, но про текущий момент они не могут сказать ничего. Это компромисс между временем ожидания для пользователя, риском для банка, стоимостью передачи информации и сложностью программирования.
Все более популярной становится кластеризация — объединение нескольких компьютеров в один более мощный. Масштабирование веб-сайтов методом кластеризации также ограничено возможностями передачи сведений о состоянии между отдельными компьютерами кластера. По этой причине некоторые программные средства для кластеризации, такие как WebLogic, разделяют сведения о состоянии в любой конкретный момент лишь между двумя компьютерами кластера. При этом входящее подключение пользователя должно направляться на одну из двух машин, хранящих данные о нем, что усложняет схему. Такое решение иллюстрирует фразу Джеймса Гослинга о том, что решение проблемы обычно заключается в перемещении ее в другую часть системы. Репликация медленно меняющихся данных обычно выполняется гораздо легче, чем репликация состояния одной конкретной транзакции. Существует множество готовых решений такой задачи — команды Unix rdist и rsync, кэширу- ющие прокси-серверы, программное обеспечение от компаний типа Marimba, а также коммерческие службы кэширования, такие как Akamai и Inktomi. Синхронность и асинхронность Синхронные вызовы блокируются до возвращения результата. Большая часть веб-страниц заставляет вас бездельничать до тех пор, пока на экране не появится ответ на ваш запрос. Асинхронные вызовы возвращают управление немедленно. Некоторые асинхронные веб-страницы помещают ваш запрос в очередь, после чего немедленно отправляют вам сообщение о том, что ответ будет выдан позже (возможно, отправлен вам по электронной почте). Все зависит от того, готовы ли вы ждать в бездействии до получения ответа или же хотите заняться другими делами. Другой пример синхронного вызова — запрос к базе данных JDBC, блокирующий вызвавший его программный поток до получения результата. При этом масштабируемость ограничивается скоростью базы данных. Если у вас в какой- то момент появится больше запросов, чем потоков, все потоки окажутся заблокированы, и сайт перестанет обслуживать пользователей. С другой стороны, асинхронные системы работы с сообщениями, такие как Tibco и MQ, дают вам возможность отправлять сообщение с запросом и заниматься чем-то другим. Зачем же вообще нужны в таком случае синхронные вызовы? Они обладают тем преимуществом, что вы узнаете результат вызова до продолжения работы. При асинхронном вызове сообщение об ошибке может быть доставлено существенно позже либо не доставлено вовсе. Синхронные вызовы использовать проще, поскольку они не требуют отдельной обработки результатов. Связь без логического соединения Протоколы без логического соединения не требуют поддержания соединения в промежутках между запросами. Протокол HTTP использует логические соединения TCP, но для очередного запроса не обязательно использовать то же соединение, которое использовалось для предыдущего, поэтому его можно назвать протоколом без соединения.
Хотя HTTP неэффективен в том смысле, что для передачи небольших объемов данных этот протокол требует установки и завершения соединения по TCP, именно короткое время жизни соединений обеспечивает масштабируемость HTTR Вероятность одновременного существования множества соединений достаточно мала, потому что эти соединения чрезвычайно коротки. Соединениям не приходится делить между собой ресурсы сервера. Например, вероятность того, что пул сокетов будет исчерпан, невелика, потому что соединения сразу же закрываются после использования. Поскольку протокол HTTP не сохраняет информацию о состоянии, пользователи никак не могут определить, какой именно сервер отвечает на их конкретный запрос. Это облегчает динамическое добавление дублирующих серверов при работе со статическим содержимым и является фундаментальным преимуществом веб перед, к примеру, архитектурой «клиент—сервер*. Планирование и разработка Есть вещи, которые нельзя использовать, пока они не будут готовы полностью. Это самолеты, мосты и ядерные электростанции. В программировании все не так. Можно быстро написать небольшую программку, которая будет делать что- то полезное, выложить ее в сеть, получить отзывы и заняться ее улучшением. Это самый эффективный способ написания программ с точки зрения стоимости. О том, почему дела обстоят именно так, рассказывается на сайте eXtreme Programming (http://vvww^programming.com/whaUs_xp.htm). Основная мысль состоит в том, что в быстро меняющемся мире (например, Интернет) нет смысла писать большие программы «на будущее», поскольку неизвестно, каким будет ото будущее. Важно придерживаться основных принципов, делая программы простыми и гибкими, чтобы иметь возможность быстро реагировать на изменения в окружающем мире. К сожалению, последовательное усовершенствование программ и постоянное изменение требований лишают вас возможности четко сказать руководству, чего именно оно может ожидать на вложенные деньги. Начальству нравятся четкие проекты с фиксированным бюджетом и жестким расписанием, но какой смысл пытаться упорядочить то, в основе чего лежит хаос? Вы лишь погрязнете в сложных науках о нормализованных унифицированных процессах и тому подобных вещах. К тому времени, когда вы что-нибудь разработаете, оно наверняка устареет. Есть еще один пример избыточного планирования. Не стоит создавать математическую модель системы, чтобы с ее помощью пытаться предсказать, какова будет мощность вашей системы. Небольшие изменения в коде могут весьма существенно влиять на производительность, но учесть все мелочи в модели невозможно. Гораздо эффективнее просто тестировать систему по мере ее создания. Моделирование может использоваться для оценки производительности лишь самых простых систем, а если ваша система настолько проста, что ее можно смоделировать, то она наверняка будет настолько быстра, что моделировать ее будет незачем.
Процедурное и объектно-ориентированное программирование Объектно-ориентированное программирование (ООП) предоставляет вам множество способов замедлить работу ваших программ. Изначально оно было придумано для того, чтобы программисты могли создавать повторно используемые компоненты, но ООП редко используется по прямому назначению. Избыточные затраты на «планирование с расчетом на будущее», разработку объектных моделей и обсуждение интерфейсов компонентов обычно сводят к нулю преимущества ООП перед программированием на процедурном языке. ООП не делает код более пригодным для повторного использования, оно не ускоряет время разработки и вообще не дает ничего, что нельзя было бы сделать с той же легкостью на языках С или Perl. Причина, по которой использование языка Java может действительно сокращать время разработки, — наличие множества хороших переносимых библиотек, интерфейсы к которым уже широко известны. Другая причина, по которой кодирование на Java оказывается быстрее, состоит в том, что исключаются ошибки, связанные с использованием указателей. С другой стороны, за это приходится платить: на проверку границ массивов и сборку мусора расходуются ресурсы системы. Все это имеет весьма отдаленное отношение к объектной ориентированности языка Java. Хорошо известно, что объектно-ориентированные программы работают медленнее, чем написанные с использованием процедурного подхода. Причин тому имеется несколько. Во-первых, нарушаются типичные схемы кэширования из-за отсутствия локальности ссылок. Во-вторых, для обращения к родительским классам и их полям обычно используется несколько уровней вложенности. ООП поощряет взаимозависимость классов, а это затрудняет их повторное использование. В действительности ООП неизбежно ведет к образованию пестрого множества самодельных интерфейсов и абсолютных зависимостей между объектами. В результате получается огромный клубок кода, пронизанный переплетением связей, и ни одна часть его не может быть использована без поиска и загрузки всех остальных частей. Программы, вызываемые из интерпретатора Unix, являются гораздо более удачными примерами повторно используемого кода, чем большая часть программ на C++ или Java. Попробуйте воспользоваться хотя бы одним классом из любой библиотеки Java так, как вы бы воспользовались какой-нибудь программой Unix типа cat, Is или wc. He получится! А ведь все программы Unix можно вызывать из других программ, соединяя их каналами для конвейерной обработки, потому что у них у всех имеется одинаковый чудесный простой интерфейс — стандартные потоки ввода, вывода и сообщений об ошибках. Как бы ни было плохо объектно-ориентированное программирование, распределенное ООП еще хуже. Помимо ужасной производительности, программы, написанные с использованием концепции распределенного ООП, чрезвычайно сложны в тестировании, поскольку для связи между объектами не используется простой протокол типа HTTP. Вместо этого при удаленных вызовах методов обычно происходит сборка объектов для пересылки их по сети в качестве параметров. Это означает, что отправка даже одного-единственного символа данных требует огромных накладных расходов на упаковку этого символа в объект,
сборку объекта, а затем восстановление его на другом конце. Распределенное ООП порождает хрупкие, неустойчивые программы, поскольку удаленные вызовы должны быть совершенно корректными, а к ошибкам такого рода программисты обычно заранее не готовятся. Сравните это с веб. Программы CGI вызываются множеством различных клиентов без какого-либо специального протокола. Веб гораздо более снисходительна к программисту. Я не люблю ООП прежде всего потому, что моей целью является достижение максимальной производительности. Бывает, что ООП заметно облегчает кодирование программ. Если вас интересуют другие точки зрения, попробуйте обратиться по адресу: http://martinfowler.com/isa/layers.html. Основы В этом разделе мы рассмотрим основные составляющие элементы архитектурной схемы веб-сайта. Браузер Веб-браузер представляет собой практически идеальный графический интерфейс пользователя (Graphical User Interface — GUI), поскольку он прост, стандартизован и распространен повсеместно. С его помощью можно вывести на экран все, что может быть нужно пользователям: текст, графику, кнопки, поля для заполнения и так далее. Разработка GUI на HTML проста настолько, насколько вто вообще возможно. Для создания GUI на Visual Basic или Java требуется гораздо больше опыта, причем взаимодействие интерфейса с программой обычно осуществляется не в стиле протокола HTTP, что существенно усложняет тестирование и требует от пользователей загрузки интерфейса для каждого отдельного приложения. Практически на всех персональных компьютерах мира сейчас имеется хоть какой-нибудь браузер, способный читать HTML, и нужно быть сумасшедшим, чтобы этим не пользоваться. Особенно плохая идея — оптимизировать сайты под Internet Explorer или Netscape. Ведь главное достоинство веб — повсеместная распространенность И переносимость. Если вы попытаетесь предъявить какие-то лишние требования К пользователям, вы не только заставите отвернуться от вас тех, кто не пользуется рекомендуемым вами браузером, но также подвергнетесь опасности сделать £вой Сайт платформенно-зависимым. Став зависимым от конкретного браузера, ВЫ ограничите не только свободу своих пользователей в выборе браузеров, но исвок!) собственную свободу в представлении содержимого. Зачем лишаться свободы? С появлением стандарта объектной модели документа (Document Object Model — DOM) браузеры могут делать практически все, что доступно всем прочим видам GUI: сортировать столбцы, загружать только данные либо части HTML- страниц, а также отображать множество элементов, которые без этого стандарта пришлось бы реализовать как Java-апплеты. Объектная модель документа под-
держивается браузерами Internet Explorer (IE), Netscape и Opera, хотя и в разной степени. В IE и Netscape используются разные версии DOM; более того, версии Netscape 4 и 6 также отличаются в трактовке DOM. У браузеров могут возникать проблемы при загрузке очень больших документов или поиске по ним, поскольку браузеры часто занимают чрезмерный объем памяти и работают заметно медленнее, чем могли бы. Тем не менее я не могу порекомендовать использовать для распределенных приложений какой- либо другой графический интерфейс пользователя из-за того, что преимущества браузеров затмевают все их недостатки. Система балансировки нагрузки Балансировка нагрузки необходима для масштабирования веб-сайта. Можно распределять нагрузку по разным веб-серверам или запросы от серверов по связующим программам и устройствам. В любом случае вы можете выбирать из множества бесплатных и коммерческих продуктов. Уровень DNS Наиболее часто используемое решение называется круговой системой DNS (Round Robin DNS — RRDNS). Идея состоит в настройке DNS-сервера так, чтобы возвращать в ответ на запрос с именем вашего веб-сервера несколько IP-адресов. Клиент выбирает любой из этих адресов. Обратите внимание: клиенты с Windows выбирают один IP-адрес и в дальнейшем обращаются только к нему, тогда как клиенты с Unix могут переключаться между предложенными IP-адресами. Альтернативный подход: сервер DNS перебирает адреса самостоятельно, возвращая клиенту только один из них в ответ на каждый запрос. Круговая система DNS действительно осуществляет балансировку нагрузки, но результат может отличаться от ожидаемого или желаемого по следующим причинам. О Хотя запросы клиентов распределяются по серверам равномерно, RRDNS не делает попытки найти ближайший или по каким-либо другим параметрам наиболее подходящий сервер для каждого клиента. Время отклика может заметно меняться, если эти серверы располагаются в разных точках Земли или просто неэквивалентны друг другу. О Круговая система DNS не обеспечивает реальной балансировки нагрузки, но в простейшем случае она до какой-то степени выравнивает ее. Реальная балансировка нагрузки подразумевает измерение степени загруженности серверов и распределение новых клиентов в соответствии с этой загруженностью таким образом, чтобы клиенты всегда обращались к серверам, имеющим достаточно ресурсов, чтобы их обслужить. Это особенно важно для вычисли - тельноемких процессов CGI. Нехорошо, если два сложных запроса обрабатываются одним сервером, в то время как другой.сервер загружен на самую малость и занимается обработкой одного простого запроса. О Когда один из серверов, входящих в круговую систему DNS, работает значительно медленнее, чем остальные серверы, возникает особая ситуация, называемая «конвоированием*. Пользователи при этом выстраиваются в очередь
на медленных серверах, а быстрые серверы остаются без запросов. Если вам когда-нибудь приходилось ездить по узкой горной дороге, вы, возможно, сталкивались с чем-то подобным. Никто не может ехать быстрее, чем самая медленная машина. Все остальные догоняют ее и выстраиваются за ней в длинный хвост. При настоящей балансировке нагрузки такой проблемы не возникает, поскольку пользователи распределяются по серверам именно так, чтобы те были одинаково загружены. Если придерживаться нашей аналогии, «машины* получают возможность «обгонять друг друга*. О RRDNS никак не обрабатывает возможные сбои серверов. Пользователи продолжают направляться на отказавший сервер. При реальной балансировке нагрузки надежность сайта повышается, поскольку при сбое одного сервера остальные автоматически берут его клиентов на себя. О Наконец, RRDNS усложняет сохранение данных о состоянии пользователей. Предположим, пользователь работает со своей корзиной, данные о состоянии которой хранятся в памяти сервера. При использовании RRDNS при каждой операции HTTP может быть выбран новый сервер, так что пользователь может даже получить сообщение о том, что он не вошел в систему, поскольку его сеанс открыт на другом сервере. Нельзя заставить клиентов придерживаться один раз выбранного IP-адреса из набора адресов, поскольку существует множество реализаций клиентов DNS. О Если вы решите удалить IP-адрес, вам придется помучиться из-за того, что изменения в системе DNS распространяются медленно и серверы DNS множества пользователей будут предоставлять им кэшированный IP-адрес вашего сервера в течение некоторого заметного промежутка времени. Это означает, что пользователи могут попытаться обратиться по неправильному IP-адресу. В результате они решат, что ваш сайт не работает. Операционная система Windows кэширует таблицу DNS, а клиенты Unix — нет. Это приведет к возникновению множества противоречивых сообщений, если, к примеру, один из двух серверов выйдет из строя. Половина пользователей Windows сообщит, что ваш сайт не работает, а другая половина будет считать, что все в порядке. Пользователи с Unix будут получать сообщения об ошибках при каждом втором обращении к сайту. Уровень IP Более сложное решение предлагается фирмой Resonate в виде коммерческого программного продукта Local Director («локальный направитель*). Local Director работает на уровне протокола IP, отображая один «виртуальный* IP-адрес на реальные IP-адреса нескольких компьютеров. Он действительно измеряет Использование ресурсов всех компьютеров и выбирает из них наиболее подходящий в соответствии с набором изменяемых правил. Эта программа позволяет С легкостью удалить из группы один из серверов при возникновении на нем неполадок (в отличие от круговой системы DNS). Фирма Resonate имеет достаточно хорошую репутацию с точки зрения надежности программного обеспечения.
У записей DNS существует ограничение: в базе может быть не более 32 полей на одну запись, поэтому нельзя указать более 32 IP-адресов для одного имени DNS. Программа Resonate под названием Global Director («глобальный направитель») использует для балансировки нагрузки систему DNS и не страдает из-за этого ограничения. Подробности см. на веб-странице фирмы Resonate (http://www.resonate.com/). Еще один способ балансировки нагрузки на уровне IP состоит в создании двух серверов на разных концах страны и присвоении им одинаковых IP-адресов. Протокол маршрутизации BGP изначально гарантирует, что пакеты TCP не будут блуждать зря: нагрузка на эти серверы будет сбалансирована автоматически. Есть и еще один хитрый метод использования IP для балансировки нагрузки. Он заключается в применении многоадресной передачи. Многоадресная передача — это механизм публикации и подписки, работающий на уровне IP. Некоторые IP-адреса считаются адресами многоадресной передачи. Данные, отправляемые на такой адрес, автоматически передаются всем выразившим свою заинтересованность в их получении, а прочие адресаты их не получают, что заметно экономит пропускную способность сети по сравнению с широковещательной передачей. Многоадресная передача может быть использована в распределении нагрузки веб следующим образом: несколько веб-серверов подписываются на один адрес многоадресной передачи, причем каждый из этих серверов отвечает только на запросы определенного типа (например, запросы с IP-адресов из своего диапазона или запросы на конкретные данные). Все прочие запросы сервером игнорируются. Одна из проблем с многоадресной передачей состоит в том, что все маршрутизаторы между отправителем и получателями должны понимать протокол многоадресной передачи. В настоящее время на это способны не все маршрутизаторы. Подробнее об использовании многоадресной передачи для балансировки нагрузки на веб-серверы читайте по адресу: http://gizmo.lut.ac.uk/~martin/wwwcac/ wwwcac.html. Уровень Ethernet Аппаратные устройства, обеспечивающие балансировку нагрузки, обычно работают на уровне Ethernet, отображая один IP-адрес на несколько интерфейсных карт Ethernet и таким образом разделяя между ними нагрузку. Работа на уровне Ethernet ограничивает возможности аппаратных систем балансировки одной подсетью, тогда как программные системы балансировки нагрузки типа Local и Global Director могут работать в нескольких подсетях. Нужно учитывать и еще один важный фактор: придется ли вам выкидывать аппаратную систему балансировки нагрузки, когда она устареет, или вы сможете приспособить ее куда- то в другое место. Вне зависимости от того, осуществляется ли балансировка нагрузки на уровне DNS, IP или Ethernet, она оказывается более эффективной в том случае, если нагрузка распределяется между серверами приблизительно одинаковой мощности.
Веб-сервер Веб-серверы в настоящее время уже стали обычным товаром. Мой совет: используйте веб-сервер Apache, потому что он бесплатный, очень надежный и быстрый. Вообще говоря, большая часть веб-сайтов в Интернете использует сервер Apache. Информационный сервер Интернета (Internet Information Server — IIS) лучше не использовать — главным образом потому, что он уязвим для опасных вирусов. На эту тему имеется специальный отчет группы Гартнера (Gartner Group). Есть и другая причина, по которой не стоит использовать IIS: Microsoft всегда пытается заставить вас хранить свое содержимое в его собственном недокументированном формате. IIS представляет собой серьезную угрозу переносимости вашего содержимого. Apache прекрасно работает под Windows и не таит в себе такой угрозы. Кроме того, на Apache почти не действуют вирусы1. СОВЕТ Содержимое и журналы веб-сервера следует держать отдельно, на разных физических дисках, чтобы они не мешали друг другу. Связующие программы Любое программное обеспечение, взаимодействующее с веб-сервером и базой данных, может считаться связующим (middleware). Первым связующим ПО был интерфейс CGI, но никто его так не называл. Вскоре после начала широкого распространения CGI Netscape и Microsoft предложили свои API для генерации динамического содержимого непосредственно из процесса веб-сервера. Эти интерфейсы работали гораздо быстрее, но абсолютно не являлись переносимыми и были склонны «завешивать» сервер, в отличие от CGI. После этого на рынок вышла компания Sun с API серверных приложений (сервлетов — servlets) для Java, который по производительности лежит между CGI и серверным API, но является безопасным и переносимым. Большая часть современных связующих программ развилась из сервлетов. Пакет Tuxedo и системы передачи сообщений типа Tibco и MQ также могут использоваться как связующие программы. Компания Sun в настоящий момент продвигает на рынок пакет Enterprise JtvaBeans — масштабируемое решение в области связующего ПО, но у этого пакета имеются серьезные проблемы с производительностью, вызванные использованием удаленных объектов. Удаленные вызовы методов работают гораздо медленнее локальных по множеству причин. Во-первых, между компьютерами физически имеется некоторое расстояние. Скорость света увеличить невозможно, поэтому с данной точки зрения ситуация никогда не улучшится. Во-вторых, при выполнении вызовов RMI компьютерам приходится осуществлять сворку и разборку объектов-параметров. * Здесь автор слишком поверхностно и не очень корректно сравнивает два наиболее распространенных веб-сервера. — Примеч. ред.
Еще одна проблема с EJB связана с тестированием. Вам не удастся легко просмотреть сетевой трафик RMI — во всяком случае, так же легко, как данные HTTP. И написать тестовый клиент для RMI весьма непросто, в отличие от HTTP. Интересно сравнить команду HTTP POST с удаленными вызовами процедур (собственно говоря, POST — тоже удаленный вызов процедуры). Пользователь читает форму, вводит в нее данные, после чего отправляет эти данные программе, выполняющейся на другом конце соединения. Отличие состоит в том, что форма хранится в формате, удобном для чтения, и никто не ожидает, что браузер клиента будет вызывать удаленную программу с частотой, сравнимой с вызовами RMI. Вызовы HTTP POST широко используются для ввода пользовательских данных на веб-сайтах благодаря жесткой стандартизации и универсальному формату аргументов и входных данных. Любой пользователь с любым браузером может передать данные на любой веб-сервер. Простота и переносимость правят миром! База данных Таблицы баз данных должны быть определены, дублированы, разделены и предоставлены для внешнего доступа таким образом, чтобы обеспечивался максимальный уровень параллельности операций и данные передавались по возможности равномерно. Оптимизация баз данных — серьезная тема, на которую уже написано множество книг. Хороший администратор баз данных стоит очень дорого. Пример архитектуры веб-сайта Теперь, когда вы знаете основные элементы архитектуры веб-сайта и изучили противоречивые требования к ним, вам придется решить, как совместить все это в одном целом. Существует великое множество возможных комбинаций программ и оборудования, но их можно разделить на небольшое количество основных категорий, перечислить которые несложно. Сервер статического содержимого легко масштабировать с помощью системы балансировки нагрузки, поэтому рассматривать его не слишком интересно. Вместо этого я решил сосредоточиться на веб-сайтах с поддержкой транзакций, а также на сайтах, состоящих в большой степени из динамического содержимого. Можно получить множество примеров описаний архитектуры, почитав подробности любого тестирования, проведенного каким-либо из поставщиков оборудования или программного обеспечения. Примеры имеются на сайте Web Bench (http://www.spec.org/). Далее мы рассмотрим наиболее типичные ситуации. Один компьютер Большая часть небольших веб-сайтов работает на одном компьютере и обычно использует Linux, Apache, MySQL и Perl (получаем аббревиатуру LAMP). Использование единственного компьютера означает, что между компонентами на
стороне сервера не будет никакого сетевого трафика и, более того, для связи, скорее всего, будет использоваться не относительно медленный интерфейс сетевой карты с терминатором, а чрезвычайно быстрая память с общим доступом. Серверу придется переключаться между различными процессами, а на переключение контекста тратятся ресурсы, но производительность такой машины может быть все равно выше, чем у нескольких специально выделенных компьютеров, соединенных между собой с помощью Ethernet. Трудно сказать, является ли один компьютер более надежным, чем несколько, или же наоборот. Большие веб-сайты тоже могут работать на одной машине. В частности, Oracle отлично функционирует в том случае, если веб-сервер Oracle Web Server и база данных работают вместе. Недостатком данного подхода является масштабируемость: вы ограничены возможностями одного компьютера — если, конечно, вам не удастся благополучно выполнить кластеризацию (сделать это непросто). Аналогичный подход состоит в использовании ровно двух компьютеров, один из которых отводится только под статическое содержимое (например, изображения), а второй — под динамическое, формируемое сервлетами или CGI. Преимущество этого подхода в том, что повышение производительности двух компьютеров можно проводить независимо. У компьютера, обслуживающего статическое содержимое, должно быть достаточно памяти, чтобы все оно туда помещалось. На второй машине должно быть несколько быстрых центральных процессоров. Стековая архитектура Стековая архитектура ограничивает возможности хранения информации о состоянии базой данных. Остальная часть системы представляет собой просто «трубы* (funnels) к базе данных, поэтому вы можете легко выполнять масштабирование, увеличивая количество этих труб и не беспокоясь о распределении нагрузки, обновлении информации о состоянии и других проблемах. Ни в одной из частей стека не происходит кэширования информации о состоянии, поэтому производительность зависит только от того, насколько быстро вы можете обращаться к базе данных и насколько быстро она вам отвечает. Ахиллесова пята в данном случае — это, разумеется, база данных. Примером стека с использованием современного коммерческого программного обеспечения может служить система, осуществляющая балансировку нагрузки между множеством небольших веб-серверов Sun, которые подключаются к своим связующим серверам, представляющим собой сервлеты без информации о состоянии (которые, в свою очередь, используют для обеспечения цельности транзакций программный пакет TUxedo и подключаются к базе данных Oracle). Получается, что каждый веб-сервер, зажатый с двух сторон брандмауэрами, подключается к одному связующему серверу, который подключается к ба- se данных. Связь между элементами осуществляется через сеть, поэтому для ограничения трафика в сегментах сеть должна разбиваться на подсети. Если из- м сбоя отключается один из веб-серверов, соответствующий ему связующий сервер становится бесполезным (и наоборот).
Уровни Многоуровневая архитектура эффективна с точки зрения использования ресурсов. Каждый веб-сервер находит наименее загруженный связующий сервер, что увеличивает общую производительность по сравнению со стековым подходом. Такая схема иногда называется «пхп». Другое преимущество состоит в том, что выход из строя одного компьютера не влияет на использование других компьютеров. Уровень веб-серверов в «демилитаризованной зоне» (участок между Интернетом и локальной сетью), соединенный с уровнем связующих серверов, требует добавления еще одной системы балансирования нагрузки. Для увеличения производительности можно сделать веб-серверы многосетевыми (multihomed) узлами, установив на них по две сетевые карты (одну для Интернета и одну для внутренней сети, где находятся связующий сервер и база данных). Множество небольших компьютеров, специализированных под конкретную задачу, работают гораздо быстрее, чем несколько мощных, и. при этом оказываются надежнее, поскольку выход из строя одного из них не влияет на все остальные. При этом цена в расчете на один компьютер оказывается ниже, но места все это занимает больше и требует больших затрат на администрирование, что может в итоге свести положительный эффект к нулю. Место для компьютеров иногда стоит дороже самих компьютеров, поскольку стоимость его включает затраты на питание и охлаждение. Linux на мейнфрейме Наиболее интересное новое архитектурное решение, о котором я слышал, состоит в том, чтобы запустить тысячу Linux на одном мейнфрейме OS390. Правда, я не слышал, чтобы кто-нибудь реально это использовал. Отличная документация на эту тему находится по адресу: ht^://wvvw.4th.com/tech/linux/vmlinux.shtml. Как и в других вариантах с использованием одного компьютера, в данном случае не возникает никаких проблем с внутренней сетью. Масштабируются мейн- фреймы неплохо, а проблемы с производительностью и размерами уже хорошо изучены. Недостатками являются высокая стоимость мейнфреймов и ограниченность в выборе производителя. Реальный масштаб времени В принципе возможно написать веб-сервер с заранее известными задержками и потреблением ресурсов, хотя я не слышал, чтобы это было действительно кем- то сделано. Точно зная потребность в ресурсах, мы можем точно сказать, сколько пользователей смогут одновременно пользоваться нашим сервером. Это означает, что планирование мощности становится наукой, а тестирование нагрузки — просто подтверждением того, что и так известно. Для того чтобы написать такой сервер, нужно воспользоваться операционной системой реального времени. На настоящий момент операционные системы реального времени используются в основном для встроенных систем, в тех слу-
чаях, где необходимо получить гарантированное время отклика — в машинах, самолетах и военной технике. Однако операционные системы реального времени могут использоваться и для веб-серверов, связующих серверов и баз данных. Сам Интернет имеет переменное время ожидания, но это не умаляет преимуществ, которые дают нам заранее известные мощность и время задержки сервера. Компания TimeSys (http://www.timesys.com/) продает ядро Linux реального времени, а также виртуальную машину Java того же свойства. Их время задержки известно заранее, но обычно оно оказывается несколько большим, чем в системах без гарантированного времени отклика. Кроме того, программист должен уметь профилировать код и пользоваться предоставленными ему возможностями. Тенденции Хотя пропускная способность постоянно растет, задержки в Сети не уменьшаются. Пакеты уже сейчас передаются практически со скоростью света, так что этот параметр вырасти уже не может. Это означает, что передача тысячи небольших пакетов осуществляется за время, пропорциональное расстоянию между точками, так что географическое положение сервера все еще имеет некоторое значение, да и всегда будет иметь. Для компенсации внутренних задержек Интернета существует тенденция отправлять ответы пользователям еще до того, как они их попросят. Статическое содержимое уже сейчас распределяется компанией Akamai по серверам, расположенным по всему миру. Следующим логическим шагом будет распределение приложений, порождающих страницы. Дальше я предвижу, что динамическая генерация страниц будет возложена на сам браузер. До некоторой степени это уже произошло, поскольку современные браузеры могут кэшировать XSL и изображения, после чего обновлять и переформатировать фрагменты данных XML » пределах одной страницы с использованием стандарта DOM для структур данных браузера и языка JavaScript для изменения этих структур. В течение некоторого времени можно было запрашивать фрагменты веб-документов с помощью запроса HTTP Byterange, поддерживаемого большей частью веб-серверов. Проблема в том, чтобы браузер смог объединить этот новый фрагмент документа с той его частью, которая уже была кэширована браузером. Такие вещи уже выполняются с помощью апплетов, но требуют большой самостоятельной работы. С помощью стандарта DOM это делается гораздо проще. Таким образом, большая часть связующих программ может быть исключена из использования. Возможно также, что браузеры смогут сами взаимодействовать с реляционными базами данных, осуществляя запросы SQL для получения и обновления страниц. Здесь вы можете спросить: нельзя ли запихать в браузер и базу данных, если уж мы взвалили на него все остальное? Вообще говоря, она там уже есть и всегда была — в кэше браузера. Кэш не является реляционным, но в нем можно сохранять и искать данные. Основная проблема тут заключается в том, что поль- Юватель не может явно управлять кэшем. Пользователи не могут выполнять поиск по кэшу, помещать туда данные, а также обновлять или удалять их. Если
вы знаете, как работает кэш вашего браузера, вы можете изменить его, но это не то же самое, что обратиться к нему с веб-страницы. После того как мы получим такую возможность, обновление страниц и приложений будет выполняться гораздо быстрее и с передачей меньших объемов данных. Другая область, где возможны значительные улучшения производительности, — это уменьшение количества передаваемых пакетов путем использования протокола TCP для транзакций (Т/ТСР), который позволяет установить соединение по TCP, передать данные и закрыть соединение — и все это одним пакетом. К сожалению, столь значительное улучшение осуществить невозможно, если не обновить стек протоколов TCP на клиентских компьютерах. Программы, используемые на широко известных сайтах На странице http://www.keynote.com/measures/business/business40.html имеется список провайдеров доступа к Интернету и программного обеспечения, используемого 40 большими компаниями. Вы можете получить те же сведения самостоятельно с помощью программ traceroute и telnet, обращаясь к порту 80. Самые популярные провайдеры, по данным Keynote, — UUNET, BBN и MCI, а наиболее популярные веб-серверы — Netscape Enterprise и Apache. Есть и еще сайт с множеством данных по веб — http://www.securityspace.com/. Примеры конфигураций Давайте рассмотрим несколько примеров конфигураций веб-сайтов, рассчитанных на низкую, среднюю и высокую нагрузку. Низкая нагрузка Сайт с низкой нагрузкой обрабатывает от одного до десяти тысяч обращений в день. Такой сайт легко можно установить у себя дома. Типичная конфигурация: хороший компьютер B000 долларов), Linux 2.2 (бесплатно), Apache 1.3 (бесплатно) и связь по кабельному модему A00 кбит/с, 100 долларов в месяц). База данных может быть реализована в обычных файлах, или через хэш-таблицу языка Perl, или как массив в программе CGI, и у вас не возникнет никаких проблем при небольшом числе пользователей и размере базы данных в несколько тысяч записей. После того как частота обращений превысит 1 запрос в секунду или база данных превысит объем в несколько тысяч элементов, вам лучше будет перейти на бесплатную реляционную базу данных MySQL. Слабыми местами в такой конфигурации являются база данных и соединение с Интернетом. Напротив, Apache и Linux способны выдержать заметно большую нагрузку.
Средняя нагрузка Сайт со средней нагрузкой обрабатывает от 10 000 до 1 000 000 обращений в день. Типичная конфигурация — Sun Ultra или Intel Pentium Pro со 128 Мбайт памяти для операционной системы и буфера файловой системы плюс от 2 до 4 Мбайт на каждый процесс сервера. Конечно, чем больше памяти, тем лучше, лишь бы вы могли себе это позволить: такие рабочие станции стоят от 2000 до 20 000 долларов. Под содержимое и журналы лучше отвести отдельные диски (и еще один — под виртуальную память), а размер диска под содержимое должен быть таким, чтобы оно свободно на нем умещалось. Массивы дисков всегда работают лучше при случайном обращении к данным, так как несколько операций поиска может осуществляться параллельно. Количество сетевых интерфейсов можно увеличить, добавив нужное количество сетевых карт lOBaseT или 100BaseT, где верхний предел лежит на уровне 45 карт для некоторых систем Solaris. Веб-сервер Apache прекрасно обслуживает веб-сайты со средней нагрузкой, но вы можете перейти на Netscape или другой коммерческий сервер при повышении нагрузки либо для обеспечения поддержки, либо для обеспечения должного уровня защищенности. Один миллион обращений в день кажется довольно большим числом, но это всего лишь около 12 обращений в секунду (при равномерном распределении по времени дня). Даже 20 обращений в секунду вполне могут быть обработаны большей частью рабочих станций, если сайт содержит только статические страницы и изображения, а не динамическое содержимое. С другой стороны, 20 обращений в секунду — это довольно большая нагрузка с точки зрения Сети. Если на среднестатистический запрос отправляется 10 Кбайт, то мы получаем 10 Кбайт/запросх8 бит/Кбайтх12 запросов/с- 983 040 бит/с. Вам может показаться, что одна линия Т1 со скоростью передачи 1 540 000 бит/с может обслужить эти запросы, но подумайте о том, что трафик веб является, скорее, импульсным, нежели непрерывным, поскольку одно обращение к странице подразумевает передачу всех изображений, апплетов и так далее, поэтому можно ожидать, что пиковая нагрузка будет в 3-5 раз выше средней. Это значит, что вы, скорее Всего, не сможете обслужить миллион запросов в день через одну линию Т1, но сможете обслужить 100 000 таких запросов. Если ваш сайт работает с базой данных, есть смысл использовать мощные коммерческие СУБД типа Oracle, Informix, Sybase, цены на которые лежат в диапазоне от 10 до 50 тысяч долларов. Максимальную производительность можно получить, используя диспетчер подключений от производителя базы данных, но можно написать и свой диспетчер. Лучше всего пользоваться не CGI, а сервле- тами FastCGI либо API серверов — такими, как Apache API, NSAPI или ISAPI. Большая нагрузка Сайт с большой нагрузкой получает более миллиона обращений в день. Множество примеров конфигураций таких сайтов можно найти по адресу: http://www. ipec.org/osg/web99 в разделе Tuning Descriptions. Другие примеры конфигураций Можно поискать по адресу: http://www.sun.com/software/solutions/blueprJnts/.
Какие сайты являются наиболее загруженными? Список ста наиболее загруженных сайтов мира можно найти по адресу: http://www.hotlOO.com/. Данные такого рода получаются в основном из анализа журналов прокси-серверов. Рейтинги сайтов со временем меняются. На момент написания этой книги первая десятка выглядела так: О http://www.yahoo.com О http://www.microsoft.com/ О http://www.lycos.com/ О http://www.aol.com/ О http://www.go.com/ О http://www.google.com/ О http://www.altavista.com/ О http://www.excite.com/ О http://www.chek.com/ О http://www.fortunecity.com/ Основные рекомендации О Помните о том, что иногда приходится идти на компромиссы. О Планируя архитектуру, спросите себя: «Если я решу, что это меня не устраивает, смогу ли я легко сменить эту архитектуру на другую уже после реализации?». О Планируйте сайт с расчетом на будущее, а не так, чтобы он отвечал только вашим сиюминутным потребностям.
3 Планирование мощностей Все процессы можно разделить на два класса. Производительность процессов первого класса определяется подсистемой ввода-вывода, а производительность второго — процессором. Сервер статического HTML обычно ограничен возможностями подсистемы ввода-вывода — скоростью считывания файла с диска и скоростью отправки файла по сетевому интерфейсу. Диски и сетевые карты — это устройства ввода-вывода, гораздо более медленные, чем процессор, поэтому производительность процессора в данном случае не играет решающей роли. Генерация динамического HTML представляет собой прямо противоположный пример. Обычно производительность сервера динамического HTML ограничивается мощностью процессора, то есть создание страницы занимает больше времени, чем отправка ее через сетевой интерфейс. Здесь важнее всего оказывается процессор, особенно если для создания динамических страниц используются шлюзы CGI или Java-сервлеты. Большую часть времени процессор тратит на работу со строками. С другой стороны, если динамическое содержимое формируется из информации, хранящейся в базе данных, ограничителем становится скорость базы данных, которая, в свою очередь, обычно зависит в основном от подсистемы ввода-вывода, поскольку базу данных необходимо считывать с диска. Поэтому планирование мощностей целиком зависит от того, какой именно сайт вы собираетесь строить. Займитесь подсчетами... В процессе оценки возможностей разрабатываемой архитектуры самым важным шляетюя сравнение требуемых значений задержки и пропускной способности С номинальными возможностями всех связей в предложенной конфигурации. Все компоненты должны отвечать этим требованиям с некоторым запасом. Запас
должен покрывать затраты на взаимодействие компонентов, а также возможный рост нагрузки в процессе эксплуатации. Вы можете не заниматься расчетами и прогнозированием, а вместо этого просто купить нечто такое, что удовлетворит ваши текущие требования, рассчитывая обновить нужные элементы при необходимости, но есть несколько причин, по которым стоит все-таки выполнить некоторые вычисления и подумать о том, чего вы ждете от своей системы в будущем. Прежде всего руководство обычно предпочитает хорошо представлять, что оно получит за те деньги, которые во что-то вкладывает. Если вы потратите деньги на систему, которая не сможет работать из-за того, что вы не произвели некоторых предварительных расчетов, вам придется объяснять начальству, почему нужны еще какие-то деньги. Вероятно, вы даже не сможете использовать то, что уже купили, потому что оно окажется несовместимым с более производительным оборудованием, которое вам придется покупать. Кроме того, вы можете серьезно поплатиться за нежелание планировать дальнейший рост своего сайта. Вас могут подстерегать непредвиденные проблемы при масштабировании, обновлении оборудования или изменении платформы. На следующий год вам наверняка потребуется бблыыая производительность, чем в текущем году. Если вы не сможете быстро переместить свое содержимое и приложения на более высокопроизводительное оборудование, пострадаете от этого именно вы. Наконец, системами, которые создавались не по плану, труднее управлять, поскольку их структура сложнее для понимания. Управление обычно стоит дороже, чем само оборудование, поэтому лучше сделать все возможное, чтобы упростить себе эту задачу. ...но верьте своим глазам больше, чем цифрам К сожалению, легко впасть в противоположную крайность и потратить слишком много времени на ненужное планирование. Требования, предъявляемые окружающим миром, меняются со временем, появляются новые технологии, которые вытесняют из жизни старые, поэтому вы никогда не можете знать наверняка, чем вам придется заниматься через год или два. Есть смысл поступить проще: выбрать какое-либо гибкое и масштабируемое оборудование подходящей номинальной мощности и испытать его в системе, зная, что при необходимости вы сможете повысить производительность или изменить архитектуру, если этого потребуют внешние условия или просто появятся новые альтернативы. Выбирайте компоненты, которые хорошо работают вместе с продуктами других производителей, а не такие, которые можно использовать только вместе с продуктами того же поставщика. Такое начало даст вам важное преимущество: вы будете получать реальные сведения о производительности и надежности реального оборудования в реальной работе.
Не полагайтесь на спецификации и рекламные заявления производителей. Они менее надежны, чем собственный опыт или опыт близких друзей. Неприятно, но факт: некоторые производители подделывали результаты тестов на производительность и возможность масштабирования с целью повышения объемов продаж. Реальная система, с которой вы будете работать, даст вам возможность оценивать производительность на уровне подсознания. Это внутреннее чутье поможет вам проверить ваши аналитические модели. Помните, что номинальные характеристики — это не то, что вы получите от оборудования на практике. Ethernet 10 Мбит/с на практике даст вам пропускную способность не более 8 Мбит/с. Попробуйте сами создать себе проблемы, чтобы посмотреть, что ждет вас на следующий год. Лучше, если ваш сервер зависнет по известной причине, когда вы будете сидеть перед ним и ждать этого, чем если это случится по неизвестной причине в четыре утра, когда вы будете еще в постели. Попробуйте испытать средства тестирования нагрузки, перечисленные в главе 4, но следите, чтобы нагрузка и сеть соответствовали тому, что вы будете иметь в реальности. Протестируйте свою систему с помощью модема на 28,8 кбит/с, если вы знаете, что ваши покупатели будут пользоваться именно такими модемами. Придумывать и осуществлять адекватные и полные тесты — непростая задача. Например, никто не держит десяток тысяч модемов только для того, чтобы создать реалистичную нагрузку, поэтому для тестирования загрузки вам придется использовать эмуляцию модема в какой-либо программе. Тестируя свой сайт на передачу больших объемов данных, следите, чтобы задержка не превышала каких-то реальных значений. Проверьте, что случится, если задержка возрастет. Многие приложения весьма чувствительны к задержке и просто разрывают соединение, если им приходится слишком долго ждать ответа. Решив, что оборудование сервера определяет его возможности, вы можете почувствовать желание купить и собрать воедино самые дорогие и мощные компоненты, ожидая, что это даст вам максимально возможную производительность. Это не обязательно так. Например, жесткие диски небольшой емкости обычно менее надежны и производительны по сравнению с более дорогими и объемными жесткими дисками. Однако несколько небольших дисков в составе надежного набора дешевых дисков (Redundant Array of Inexpensive Disks — RAID) дадут вам бблыную производительность и надежность, чем один большой жесткий диск, за те же деньги. У небольших дисков часто оказывается меньшим и время поиска данных — именно потому, что они физически меньше, чем диски большого объема. Поставщики серверов оценивают компоненты, изучая их взаимодействие друг с другом, а вы, полагаясь на них, можете заниматься планированием на более высоком уровне. Вопросы, которые нужно себе задавать Первый шаг в планировании мощностей должен заключаться в том, чтобы выяснить свои требования и записать их на бумаге. Вот несколько вопросов, которые помогут вам выяснить, чего же вы хотите достичь в конечном итоге.
Сколько HTTP-операций в единицу времени вы ожидаете? В отличие от парадигмы «клиент—сервер», в которой самым важным параметром размера является количество одновременных пользователей, для веб-серверов адекватным параметром является количество HTTP-операций (или хитов) в секунду. Редкие сайты обрабатывают более 25 хитов в секунду. Веб-серверы не поддерживают постоянное соединение с браузером, поскольку протокол HTTP 1.0 не ориентирован на установку такого соединения. Пользователь подключается к серверу, запрашивает документ, получает его, после чего отключается. HTTP был создан именно таким — простым и быстрым. При этом веб-страница может состоять из компонентов, хранящихся на разных серверах. Хотя пользователю может казаться, что он подключен к серверу на всем протяжении работы с хранящимися на нем страницами — с точки зрения сервера, пользователь исчезает после каждого запроса и появляется лишь тогда, когда он запрашивает новую страницу и соответствующее содержимое (например, изображения). Эта особенность нагрузки на веб-серверы в настоящее время не является обязательным их свойством, поскольку протокол HTTP 1.1 позволяет пользователю не разрывать соединение после каждого запроса. Хотя продолжительность большинства хитов остается короткой, использование постоянных соединений HTTP 1.1 может привести к тому, что важным параметром производительности сервера станет количество одновременных подключений. Кроме того, Java-аппле- ты могут устанавливать соединение с тем сервером, с которого они были загружены, и держать это соединение открытым довольно долго. Из-за простоты HTTP легко впасть в заблуждение при трактовке параметра «количество соединений в секунду». Например, обычно мы предполагаем, что запросы HTTP обрабатываются последовательно, и время существования соединения очень невелико. Эти предположения верны, если мы обслуживаем относительно небольшое количество пользователей, подключенных через быструю локальную сеть, но не в том случае, если к нам подключается много пользователей с медленными модемами. В последнем случае время жизни соединения наверняка будет заметно больше одной секунды. На каждое соединение будут расходоваться память (под буфер) и время процессора, поэтому при вычислении нагрузки на сервер нужно учитывать количество одновременно обрабатываемых запросов, что характерно для архитектуры «клиент—сервер». Таким образом, мы видим, что скорость сети сильно влияет на способ вычисления производительности сервера. Хотя нагрузка по протоколу HTTP обычно вычисляется в хитах в секунду, а не в количестве одновременных подключении, характер этой нагрузки будет качественно иным, когда все эти пользователи подключены через Ethernet, нежели через модемы на 28,8 кбит/с. Отличие в том, что пользователи с Ethernet рассчитывают на меньшее время задержки при работе с вашим сайтом, а сервер может рассчитывать на меньшее количество одновременных подключений. Поэтому, с одной стороны, пользователи с быстрой связью нагружают сервер сильнее, поскольку ждут от него большего, а с другой стороны — слабее, поскольку меньшее количество одновременных соединений требует меньших затрат памяти.
Какой бы ни была скорость подключения пользователей, запросы HTTP обычно поступают не равномерно, а, скорее, группами, поскольку помимо собственно веб-страниц обычно запрашиваются изображения и тому подобные элементы содержимого. Появление первого запроса говорит о том, что с большой вероятностью скоро будет получено еще несколько запросов. Если бы серверы были более интеллектуальными и более мощными, они бы сами просматривали HTML в процессе отправки его пользователю и находили бы в нем ссылки на встроенные изображения или апплеты, после чего они могли бы начинать поиск этих изображений на своих дисках еще до получения новых запросов от браузера. Нагрузка на сервер представляет собой статистическую функцию, зависящую от времени дня. На рис. 3.1 показан типичный график зависимости нагрузки на сервер от времени в течение одного дня. Если содержимое интересно пользователям по всему миру, нагрузка достигает максимума около полудня по калифорнийскому времени C часа дня в Нью-Йорке и 9 часов вечера в Лондоне). В зависимости от потребительского рынка форма кривой может меняться ото дня ко дню и от недели к неделе. Серверы с информацией о биржевых котировках больше всего загружены по рабочим дням. Серверы с рекламой каких-то событий обычно бывают сильно загружены непосредственно перед этими событиями, а после того как событие заканчивается, нагрузка спадает почти до нуля. Значительные события могут вызывать пиковую нагрузку, в 3-5 раз превышающую среднюю. Средняя нагрузка на все веб-сайты постоянно растет, хотя и достаточно медленно, по мере того как к Интернету подключается все больше пользователей, и этот рост нужно тоже иметь в виду. Сеть не просто расширяется, но расширяется с ускорением, объединяя в себе компьютеры и бытовую технику и используя самые современные технологии для повышения пропускной способности. Рис 3.1. Типичная кривая Sprint NY NAP сайта http://www.nlanr.net/
Помните, что даже миллион хитов в день, если его распределить равномерно, даст не слишком большую нагрузку в хитах в секунду A 000 000 / F0 х 60 х 24) в - 11,6 хитов/с), а ведь лишь немногие сайты до недавнего времени могли похвастаться миллионом хитов. При среднем размере отправляемого в ответ на запрос пакета в 10 Кбайт эта нагрузка оказывается вполне «по плечу» довольно скромному компьютеру, но требует большой производительности от сети: 10240 байт/хит х 11,6 хитов/с х 8 битов/байт х 1,3 (накладные расходы сети) - - 1,2 Мбит/с, что теоретически лежит в пределах возможностей одной линии Т1. Маловероятно, что миллион хитов будет распределен во времени настолько равномерно, но суть в том, что многим организациям, оказывается, по силам содержать достаточно крупный сайт. Какова цель создания веб-сайта? От назначения сайта зависит распределение нагрузки по времени. Например, сайт с материалами для проведения лекций будет испытывать большую нагрузку в учебные часы, и с большой вероятностью запросы будут приходить одновременно. Если рассчитывать на равномерное распределение хитов по времени дня, система получится недостаточно мощной для данной задачи. Рассчитывать нужно на то, что все пользователи практически одновременно будут обращаться к одной и той же странице. Поэтому, если в классе будет 30 человек, вам потребуется сервер, способный обработать 30 хитов в секунду (что соответствует нескольким миллионам хитов в день). Насколько терпеливы ваши пользователи? Другими словами, какие величины задержки и пропускной способности вы хотите обеспечить? Если вы серьезно озабочены повышением производительности, нужно выражать эти величины в цифрах с учетом распределения. Например, вы можете поставить перед собой цель удовлетворять 90% запросов HTTP на файлы размером менее 10 Кбайт со скоростью 5 с и менее на один файл. Имея перед собой такую четкую цель, вы получаете не просто конкретную отправную точку в планировании, но также и четкую характеристику, позволяющую в процессе тестирования определить, было ли ваше планирование успешным. Вы можете даже поставить перед собой цель достичь определенного уровня удовлетворения пользователей, если хотите. Удовлетворенность пользователей зависит от их терпения и не является четко определенной величиной, однако опросы дают конкретные цифры, позволяющие, по крайней мере, оценить, падает эта удовлетворенность или растет. Все это не значит, что вам нужно поставить перед собой лишь один набор целей. Большая часть сайтов устанавливает для всех пользователей одинаковый приоритет, но вполне реально выполнить и сегментирование рынка. Вы можете предоставить ограниченный доступ к высокопроизводительному серверу для некоторых избранных пользователей, а для всех остальных оставить сервер с более низкой производительностью. Эти уровни качества обслуживания могут быть установлены даже для одинакового содержимого, если ваше содержимое хранится на высокоскоростном сервере NFS и два веб-сервера различной мощности обращаются к нему. Аналогичная ситуация будет в том случае, когда два сервера работают с одной базой данных. В любом варианте ограничение количе-
ства пользователей для одного из серверов автоматически сделает этот сервер более производительным, поскольку нагрузка на него будет меньше. Вы можете дифференцировать качество обслуживания в зависимости от скорости сети, возможностей сервера и множества других факторов. Такая дифференциация может показаться в некотором смысле дискриминирующей, но для нее часто имеются достаточно веские практические основания. Например, врачам, скорее всего, нужен быстрый доступ к записям пациентов, в то время как страховые компании могут и подождать несколько дольше, обращаясь к той же самой информации. Таким образом, предоставление высокопроизводительного сервера с ограниченным доступом определенной группе лиц может быть вполне реальным способом достижения конкретных сложных целей. Желаемые значения пропускной способности и задержки следует сравнивать с физическими возможностями ваших пользователей и их ожиданиями. Значение пропускной способности в 50 кбит/с в принципе недостижимо для конечных пользователей, подключающихся с помощью модемов на 28,8 кбит/с. Аналогичным образом задержку в 10 мс невозможно получить, обращаясь из Европы в Канаду, поскольку для этого сигналу пришлось бы путешествовать со скоростью, превышающей скорость света. Ожидания пользователей могут зависеть от качества Сети. Пользователь с модемом на 28,8 кбит/с будет рад ждать появления статической страницы с 5 Кбайт текста 10 с, а изображений или динамического содержимого он будет готов ждать и того дольше. Пользователи, подключающиеся через локальную сеть Ethernet, вправе рассчитывать на большее, но реально пропускная способность для них может оказаться достаточно низкой, поскольку производительность Ethernet нелинейно падает с ростом объема передаваемых данных. По мере приближения нагрузки на сеть Ethernet к максимальному пропусканию задержка отклика будет резко возрастать до тех пор, пока Сетью не станет вовсе невозможно пользоваться. Начинается суровый естественный отбор: когда некоторые пользователи в отчаянии сдаются, для остальных производительность заметно возрастает. Собираетесь ли вы передавать потоки мультимедиа? Потоки мультимедиа (звук и видео) нужно учитывать отдельно от сервера, поскольку природа создаваемой ими нагрузки совсем иная, а объем их, вообще говоря, не определен. Они поглощают заметную часть пропускной способности Сети и предъявляют серьезные требования к задержке. Поток вполне может передаваться в течение многих минут. Это принципиально отличает его от соединения HTTP, которое обычно завершается буквально через несколько секунд. Серверы потокового мультимедиа должны строиться в расчете на конкретное количество одновременных подключений (а не на количество подключений в секунду). Некоторые типы потоков мультимедиа можно передавать по UDP, а не по TCP, что уменьшает нагрузку на систему, поскольку исчезают затраты на обслуживание подключений. Многоадресная поточная передача еще более эффективна в этом отношении, поскольку при ее использовании к одному потоку может подключаться множество клиентов. Будет ли веб-сервер порождать дополнительные процессы? При работе со статическим HTML и изображениями сервер редко бывает «узким местом», но CGI, сервлеты или серверные API, порождающие динамический HTML или
другое аналогичное содержимое, могут замедлить работу вашего сервера практически до полной остановки, особенно если для генерации содержимого требуется обращение к базе данных. Нагрузка, создаваемая CGI и базами данных, очень сильно зависит от используемых приложений, поэтому невозможно проводить какие-то расчеты, не выполнив предварительно подробного анализа производительности приложения. В планировании ориентируйтесь прежде всего на приложение, генерирующее содержимое, поскольку оно будет потреблять больше ресурсов, чем процессы собственно сервера. Рассмотрите возможность переложить часть работы на клиента с помощью Java или JavaScript. Оптимизация баз данных — отдельная и серьезная тема. По поводу увеличения производительности CGI читайте 20 главу настоящей книги. Какие еще процессы должны выполняться на веб-сервере? Какие процессы должны использовать сеть? Не забудьте учесть другие службы, которые будут работать одновременно с веб-сервером. Небольшие фирмы могут по экономическим соображениям использовать один компьютер не только как вебсервер, но и как сервер DNS или NFS. Нагрузка, создаваемая этими службами, будет отрицательно сказываться на производительности веб-сервера. Хуже всего, если веб-сервер будет одновременно являться рабочей станцией для программиста. Мне приходилось использовать веб-сервер в качестве рабочего компьютера, и на нем было совершенно невозможно выполнять обычные действия типа кодирования, компиляции и тестирования из-за резкого падения производительности процессора и Сети при запуске программ CGI, хотя компьютер продолжал вполне прилично реагировать на нажатие клавиш благодаря тому, что у клавиатурных прерываний очень высокий приоритет. В свою очередь, производительность веб-сервера заметно страдала от присутствия за компьютером программиста. Вам может понадобиться использовать подключение к Интернету не только для веб-сервера, но и для обычных пользователей вашей компании. На производительности могут сказываться и локальные помехи: если ваш сервер находится в одной локальной сети с сервером NFS, то вам придется учитывать пропускную способность, нужную этому серверу. Какой масштабируемости вы хотите достичь? Подумайте о том, что случится, когда вы достигнете предельных возможностей для выбранной конфигурации. Сможете ли вы просто добавить новое оборудование для повышения производительности или вам придется все начинать с нуля? Сможете ли вы обновить операционную систему, чтобы работать с этим новым оборудованием? Способность увеличить производительность архитектуры без особых проблем называется масштабируемостью. Масштабируемость может измеряться и в числах: это отношение увеличения производительности к количеству добавленных компонентов оборудования (процессоров, микросхем памяти, сетевых карт и т. п.). Если с одним процессором производительность сервера равна х, а с двумя — 1,6 jc, то масштабируемость равна 0,6. Идеальной масштабируемость была бы в том случае, если бы повышение производительности в точности соответствовало добавляемому оборудованию. Масштабируемость может быть и отрицательной, когда производительность падает с добавлением нового оборудования. Это происходит из-за накладных расхо-
дов на координацию взаимодействия компонентов. Масштабируемость любой системы в какой-то момент становится отрицательной. Обратите внимание, что в определении термина ««масштабирование» стоят слова «без особых проблем». Увеличение производительности не должно требовать крови, пота и слез. Несложно добавить несколько серверов к одному имеющемуся, но сложно сделать это так, чтобы доступ к данным не стал «узким местом». Вам кажется, что можно просто реплицировать или разделить данные между компьютерами, чтобы ускорить доступ к ним? К сожалению, репликация и разбиение данных требуют синхронизации и координации, а это означает дополнительное усложнение. Некоторые связующие программы рассчитаны на распределение нагрузки на несколько компьютеров, но реализовать это все равно непросто. Если вы не запланируете масштабируемость, вы ее не получите. Из соображений масштабируемости добавление процессора в имеющийся компьютер является более предпочтительным по сравнению с добавлением целого дублирующего компьютера, поскольку добавить процессор можно быстро и без проблем. Дублирующий компьютер способен отлично справляться при работе со статическим HTML, но даже и в этом случае синхронизация компьютеров потребует дополнительных затрат. Если же планируется использование баз данных или обработка транзакций, возможности масштабирования следует тщательно продумывать заранее. К сожалению, слишком часто случается так, что люди создают нечто, отвечающее их текущим нуждам, после чего обнаруживают, что это нечто нужно полностью переделывать, чтобы оно стало отвечать новым требованиям. Интернет постоянно растет, в него попадают новые пользователи, поэтому необходимо учитывать этот рост в своих планах. Увы, масштабируемые компоненты чаще всего и стоят дороже. Вот несколько примеров: О диски и контроллеры IDE стоят гораздо меньше, но стандарт SCSI позволяет достичь большей пропускной способности; О аренда линии на 56 кбит/с обычно стоит дешевле, чем аренда такой же полосы на линии Т1, но полосу на Т1 всегда можно увеличить, просто изменив договор, а линию на 56 Кбит придется прокладывать заново; О обыкновенный персональный компьютер имеет ограниченный максимальный объем памяти. Вам может понадобиться добавить в него память, но вы обнаружите, что это просто невозможно, и придется покупать не память, а новый компьютер целиком; О проще начинать работу с Windows NT, чем с Unix, но операционная система Unix может работать как на дешевых 586-х процессорах (на которых NT работать не может), так и на суперкомпьютерах (на которых NT тоже работать не может). Кроме того, Unix может работать и на разных типах процессоров с одинаковой производительностью. ПРИМЕЧАНИЕ Масштабируемость различных компонентов рассматривается в соответствующих главах этой книги. Масштабируемость архитектуры целиком — предмет обсуждения главы 2.
Какой у вас бюджет? Деньги являются одним из важных параметров планирования производительности. Сумма, которую вы можете потратить, определяет верхнюю границу возможной производительности вашего веб-сайта, однако диапазон производительности при одинаковых затратах достаточно широк. Вы можете потратить все деньги на оборудование, неспособное работать в составе одного целого, то есть просто выкинуть их. С другой стороны, аккуратное планирование и расчет конфигурации позволят вам достичь гораздо большей производительности, чем может показаться сначала. В бюджет нужно закладывать обслуживание сайта и его обновление. В конечном итоге эти затраты окажутся больше первоначальных сумм, вложенных в оборудование. Стоимость подключения к сети, администрирования (обработки журналов), анализа и настройки производительности также должна быть включена в бюджет. Насколько доступным должен быть ваш веб-сайт? Под доступностью понимается вероятность того, что система ответит пользователю в любой конкретный момент. Некоторые веб-сайты требуют 100% доступности, в особенности это относится к транзакционным сайтам (банкам и брокерским конторам). Сам по себе Интернет не зря считается надежным, поскольку передаваемые по сети пакеты могут сами обходить сбойные участки. Серверы со статическим содержимым часто дублируются для обеспечения высокой доступности и производительности. Транзакционные сайты обычно не дублируются, поскольку возможность одновременного обращения к нескольким серверам усложняет обработку данных. Поэтому надежность таких сайтов целиком зависит от надежности одиночных серверов, на которых они размещены. Самым уязвимым компонентом оборудования сервера являются жесткие диски, поскольку в них присутствуют движущиеся части. Надежность дисков можно повысить, объединив их в массив RAID. Подробнее об этом рассказывается в главе 16. Другие компоненты оборудования и программного обеспечения сервера также могут влиять на его доступность. Обычные персональные компьютеры обычно не являются слишком надежными: например, у них могут возникать проблемы из-за перегрева, когда при термическом расширении пропадают электрические контакты. Рабочие станции стоят дороже, но в них используются более дорогие компоненты с более высоким качеством. Высочайшей надежностью отличаются мейнфреймы, но они и стоят безумно дорого, поэтому большая часть веб-сайтов работает либо на персональных компьютерах, либо на рабочих станциях Unix. Что касается операционных систем, Windows и Macintosh недостаточно стабильны для серьезных сайтов. Unix — наиболее стабильная операционная система для рабочих станций и персональных компьютеров: она может работать годами, не требуя перезагрузки. Существуют специальные сверхнадежные операционные системы, такие как ОС линейки Tandem, а также аппаратные решения, позволяющие избежать сбоев, но все это стоит лишних денег. Подобные вещи часто используются в банках. Веб-серверы и веб-приложения тоже влияют на доступность сайта. Утечки памяти могут замедлять работу системы и приводить к необходимости переза-
грузки системы. Существуют средства для поиска утечек памяти, такие как Purify (http://www.rational.com/); они помогут вам найти утечки в ваших приложениях, но не в коммерческих, какими являются веб-серверы. Все коммерческие веб-сайты должны быть обеспечены источниками бесперебойного питания (ИБП, или UPS), защищающими как от перебоев в питании, так и от всплесков напряжения в сети. У больших компаний имеются резервные дизельные генераторы, позволяющие обеспечивать серверы питанием столько времени, сколько потребуется. Наконец, подумайте о возможности автоматической отправки сообщений на пейджер администратору системы при падении производительности ниже определенного уровня. В главе 4 приведен пример такого сценария. Производительность может отслеживаться с защищенного от сбоев компьютера или вообще с любого компьютера, подключенного к Интернету. Кластеризация компьютеров (объединение нескольких компьютеров таким образом, что со стороны они воспринимаются как один, но более мощный) может дать вам больший уровень надежности и масштабируемости по сравнению с одним компьютером, но стоит это дорого, причем сложность системы возрастает. В кластере все компьютеры равноправны, и каждый из них следит за состоянием всех остальных. Если один компьютер выходит из строя, остальные берут его нагрузку на себя. У компьютеров может быть общий массив RAID, что обеспечивает общий доступ к нужным данным, но при этом у них не будет общих ненадежных мест. Обратите внимание на отличие от обычной группы серверов. Кластеризация компьютеров с Unix была хорошо разработана в течение нескольких последних лет, а для операционных систем Windows она только начинает зарождаться. Можете ли вы заставить поставщиков конкурировать между собой? Вы можете почувствовать желание купить самое дешевое или самое простое в реализации решение. Часто это означает покупку всех компонентов у одного поставщика, что вполне приемлемо для небольших систем, рост которых в дальнейшем не планируется, но у таких решений есть серьезный недостаток. После того как ваше содержимое или приложение окажется привязанным к конкретному формату, поставщик сможет влиять на вас. Стоимость переделки содержимого и архитектуры под другую платформу обычно достаточно велика, так что Поставщик вполне может запросить высокую цену за обновление или обслужи- пание, и вам придется платить ему, поскольку уход из-под его власти обойдется нам дороже. Смена поставщика, как правило, стоит дороже, чем первичная реализация. Вы не можете все выбросить и начать сначала — придется потратить время и деньги, чтобы сохранить то, что вы уже сделали (например, извлечь данные из формата старого поставщика или переучить программистов). Что еще хуже, вы можете обнаружить, что, хотя вы заплатили за обновление, вам все равно не удастся достичь нужной масштабируемости, производительности или функциональности. Одним из решений этой проблемы является использование открытых стандартов. Под открытыми стандартами я подразумеваю бесплатные опубликованные спецификации, которые реализованы несколькими поставщиками. Это та-
кие стандарты, как TCP/IP, SVR4 Unix, С, Java, XML, а также стандарты, сделавшие Сеть тем, чем она является, — HTTP и HTML. Эй, кто хочет попробовать браузер? Так почему же люди используют платформы, принадлежащие одному производителю? Одна из причин в том, что такие платформы в некоторых случаях продаются бесплатно. Делается это потому, что поставщики рассчитывают многократно окупить начальные затраты, после того как пользователи попадут в зависимость от их платформы. В мире веб хорошими примерами являются Internet Explorer и Internet Information Server. Они поставляются с Windows, поэтому на большей части персональных компьютеров установлены именно эти программы. Наивные веб-разработчики могут решить использовать эти программы, несмотря на их производительность, поскольку им не придется явно платить за их установку в отличие от продуктов Netscape. К сожалению, после того как разработчик начинает использовать в своих программах патентованные штучки типа ISAPI, ActiveX или С#, он больше не сможет использовать для своего содержимого серверы Netscape. Конечно, Netscape тоже играет в эти игры, у него есть свои средства сделать веб- содержимое непереносимым — это расширения JavaScript и HTML. Повторюсь, но все же скажу еще раз, что мораль такова: все зависит от стоимости перехода на продукт конкурирующего производителя. Только постоянная конкуренция производителей, работающих в соответствии с открытыми стандартами, гарантирует прогресс и переносимость. Средства тестирования и анализа, созданные в соответствии с открытыми стандартами, будут работать даже в том случае, если вы смените производителя. Основанием для использования патентованных платформ может быть их высокая производительность по сравнению с любой реализацией открытых стандартов. Например, CGI — открытый стандарт, но производительность шлюзов принципиально низка. NSAPI и ISAPI — патентованные API серверов, использование которых привязывает вас к конкретной серверной платформе, но они легко обгоняют CGI в скорости. Поэтому вам приходится идти на компромисс. Важно, чтобы вы отдавали себе отчет в том, что делаете. Прежде чем куда-то идти, спросите себя: «Если мне там не понравится, легко ли будет выйти обратно?*. Кроме того, есть много других требований, которым должна удовлетворять архитектура веб-сайта, но они лежат за рамками тем, рассматриваемых в этой книге. Среди них уровень безопасности вашего веб-сайта, привычная для программистов среда разработки, а также возможность интеграции нового и существующего оборудования*. Какая вам нужна пропускная способность? Пропускная способность сервера является важнейшим фактором оценки производительности веб-сайта. Формула для определения требуемой пропускной способности проста: количество хитов в секунду х средний размер хита в битах - пропускная способность, бит/с.
Значит, вам нужно каким-то образом определить ожидаемое количество хитов в секунду и средний объем данных, передаваемых в ответ на один запрос (хит). Отсюда вы получите требуемую пропускную способность. Время ожидания важнее пропускной способности Как только пользователи переходят с обычных модемов на более совершенные средства связи, количество пакетов становится более важным параметром производительности, чем просто пропускная способность. Это связано с тем, что все пакеты требуют подтверждения доставки, а скорость света конечна, в то время как пропускная способность растет. Отправка пакета в 1500 байт по линии DSL может потребовать 20 мс, а передача его из сети в компьютер потребует 12 мс (определяется пропускной способностью). Еще 20 мс уйдет на отправку подтверждения обратно отправителю. В этом случае время ожидания в 40 мс оказывается в 3 раза больше, чем пропускная способность. В дальнейшем значение времени ожидания будет только расти. Поэтому количество отдельных элементов на веб-странице должно быть минимальным. С другой стороны, поскольку большая часть браузеров написана с использованием многопоточного программирования, некоторые задержки совпадают во времени. Эксперименты показывают, что оптимальное количество изображений на странице равняется количеству потоков, используемых браузером. Например, Netscape использует четыре потока, поэтому наилучшая производительность получится, если разбить одно большое изображение на четыре маленьких, потому что при этом уведомления будут передаваться одновременно, а не последовательно. Однако это удобно только в том случае, если браузер использует постоянные подключения HTTP, а не тратит ресурсы на разрыв и установку TCP-соединений для каждого подключения. Вот некоторые числа, которые помогут вам оценить важность времени ожидания. Время ожидания при передаче от процессора к памяти составляет порядка 100 не, время ожидания для локальной сети — порядка 1 мс (то есть в 10 000 раз больше). В интрасети время ожидания увеличивается до 5 мс, а в Интернете оно может достигать 10-500 мс. Передача данных через спутник может приводить к времени ожидания порядка секунды и более. О пропускной способности Таблица 3.1 поможет вам оценить пропускную способность. Учтите, что здесь Используется десятичный миллион A 000 000), а не приставка «мега», соответствующая 220 - 1 048 576. В этой таблице не учитывалось время ожидания, которое может меняться даже от бита к биту и оказываться достаточно большим, особенно при запуске компонентов. Если вы в душе романтик, то эта таблица покажется вам коротким рассказом об истории виртуальной реальности, входящей в нашу жизнь, —
от телетайпа к передаче всех оттенков звука, уже возможной сегодня, и к достижению предела возможностей зрительного восприятия в будущем. Таблица 3.1. Сравнение пропускной способности Способ передачи данных Миллионы Комментарий бит/с Тренированная машинистка 0,000035 70 слов/мин х 5 символов/слово ж х 6 бит/символ х М/106 х 1/60 мин/с Модем на 4800 бит/с 0,004800 4800 бит/с х М/106. Это примерно соответствует максимальной скорости, с которой человек может читать Цифровая телефонная линия 0,064000 Голос по старым телефонным линиям передается со скоростью 64 кбит/с 2-канальная ISDN 0,128000 — Веб-сайт: миллион хитов в день 0,925925 10б хитов/день х 80 кбит/хит х по 10 000 байт, равномерное 1/86 400 день/с х М/106 распределение Аудио-компакт-диск 1,411200 44100 Гц х 16 бит х 2 (стерео) х М/106 Т-1 (DS-1 или основная ISDN) 1,544000 24 обычных цифровых телефонных линии + 8 кбит/с избыточных данных Ethernet 10,00000 - Token Ring 16,00000 — Жесткий диск IDE 16,00000 Максимальная пропускная способность Т-3 (DS-3) 44,60000 672 линии DS-0,28 линий DS-1 или 7 линий DS-2 FDDI и быстрый Ethernet 100,0000 — Шина ISA 128,0000 16 бит, 8 МГц Широкополосная ISDN 135,0000 — ATM 154,0000 - 250 миллионов 231,4812 По одному хиту от каждого гражданина 10 000-байтовых хитов в день, США равномерное распределение Шина EISA 264,0000 - Контроллер Wide Ultra SCSI 320,0000 - 100 не RAM 320,0000 32 бита / A00 х 10* ) с х М/106 Gigabit Ethernet 1000,000 - Шина PCI 2112,000 64 бита, 33 МГц AT&T Sonet 2400,000 Оптоволоконная связь на большие расстояния Процессор 3200,000 Гипотетический процессор, выполняющий 32-разрядные инструкции на частоте 100 МГц по одной за цикл
Способ передачи данных Миллионы Комментарий бит/с Человек: передача данных от 5600,000 По оценкам ученых глаза к мозгу Самое быстрое оптоволокно 16000,00 Bell Labs Теоретические возможности 64000,00 — оптоволокна Оценка пропускной способности сети веб-сервера В приведенной ниже таблице приводится количество хитов в секунду (определенного объема), которое может быть обработано при определенной пропускной способности при завышении требований 30% (накладные расходы TCP/IP и т. п.). Дробная часть отбрасывалась, поэтому число 0 означает «менее одного хита о секунду». ТМлица 3.2. Требования к пропускной способности сети Объем 28,8 56 ISDNB) T1 ЮЬТ ТЗ ЮОЬТ хита кбит/с кбит/с 1 Кбайт 2 4 10 132 854 3845 8544 2 Кбайт 12 5 66 427 1922 4272 4 Кбайт 0 1 2 33 213 961 2136 8 Кбайт 0 0 1 16 106 480 1068 16 Кбайт 0 0 0 8 53 240 534 32 Кбайт 0 0 0 4 26 120 267 64 Кбайт 0 0 0 2 13 60 133 132 Кбайт 0 0 0 1 6 30 66 264 Кбайт 0 0 0 0 3 15 33 512 Кбайт 0 0 0 0 1 7 16 1 Мбайт 0 0 0 0 0 3 8 2 Мбайт 0 0 0 0 0 1 4 С помощью этой таблицы можно оценить, к примеру, сколько файлов по 4 Кбайт вы сможете передать по своей линии Т1 за одну секунду. Ответ: 33. По- Мните, что в таблице учитываются только возможности сети и ничего не говорится о том, было ли содержимое статическим или динамическим. Здесь никак Не учитываются возможности вашего жесткого диска или процессора, а также вязы данных, с которой связан сервер. Производительность сервера в плане использования пропускной способности растет нелинейно. Небольшие пакеты требуют относительно больших на-
кладных расходов на обработку заголовков и т. п. Отправка двух пакетов потребует от сервера большего, чем объединение их в один большой пакет. Эта таблица может ввести вас в заблуждение еще в одном смысле. Дело в том, что хиты распределены во времени неравномерно. Часто будут встречаться пики, в несколько раз превышающие среднее значение, а в остальное время нагрузка может быть и вовсе нулевой. Для масштабирования любого из данных типов соединений можно добавлять в компьютер сетевые карты или модемы до тех пор, пока их будет куда устанавливать. После этого можно переходить на другой тип соединения или на другой сервер, более мощный. Таким образом решать проблемы проще всего — добавлять новое оборудование в один сервер. Масштабирование с использованием нескольких серверов обычно влечет гораздо ббльшие трудности и требует добавления системы балансировки нагрузки. Насколько быстрый сервер вам нужен? Пусть дана конкретная пропускная способность сети. Насколько быстрым должен быть сервер? Быстрые диски, шины и процессоры стоят больших денег. Пропускная способность сети накладывает ограничение на оборудование, нужное для работы со статическим содержимым, таким как HTML и изображения. Компьютер на базе процессора Pentium 250 МГц с веб-сервером Apache может полностью потребить всю пропускную способность линии Ethernet A0 мбит/с), поскольку статические страницы расходуют ресурсы подсистемы ввода-вывода, а не процессора. С другой стороны, сайты, использующие множество сервлетов, CGI и других средств генерирования динамического содержимого, обычно потребляют в основном ресурсы процессора. Если у вас есть динамическое содержимое, ориентироваться нужно именно на него. Определяя требуемую производительность, помните, что статические страницы редко являются «узким местом». Серверы обычно бывают достаточно быстрыми для отправки таких страниц, какие бы программы вы ни использовали. «Достаточно быстрые» в данном случае означает «более быстрые, чем исходящая линия связи». Помните, что нет смысла покупать оборудование с ббль- шими возможностями, чем те, которые могут быть реально использованы с имеющейся сетью. Программное обеспечение и операционная система сервера определяют, насколько эффективно вы сможете использовать оборудование сервера. Полное время жизни подключения при выполнении одной передачи по протоколу HTTP через Интернет обычно составляет от 1 до 10 с и обычно определяется пропускной способностью и задержками Интернета и модемов. У сервера при этом остается много свободных ресурсов. Нет смысла стремиться сделать сервер настолько быстрым, чтобы он отвечал на запрос по протоколу HTTP за 1 мс, если передача этого ответа по сети займет тысячи миллисекунд. Не воспринимайте эти слова как утверждение, что производительность вебсервера в Интернете не играет большой роли. Без планирования и оптимизации
сайт, отлично справляющийся с небольшой нагрузкой, может резко потерять производительность при росте нагрузки, особенно если он работает с динамическим содержимым. Однако всегда можно установить сервер и получить приемлемую производительность при небольшой нагрузке вообще без оптимизации, и при этом у вас останется время подумать, что вы будете делать, когда нагрузка возрастет. Многопроцессорные компьютеры (Symmetric Multiprocessing — SMP) используют вычислительные ресурсы нескольких одинаковых процессоров. Серверы SMP легко масштабировать, поскольку вы можете просто добавлять процессоры, платы ввода-вывода, диски и память по мере возрастания требований к производительности. Компьютеры с SMP также автоматически выполняют балансировку нагрузки и обеспечивают определенный уровень избыточности (а следовательно, и устойчивости). Поскольку большая часть данных HTTP передается по TCP, а реализации TCP раньше были однопоточными, не было возможности распределить потоки по разным процессорам. Поэтому от использования нескольких процессоров не было никакого выигрыша. Положение изменилось с появлением Solaris 2.6 и аналогичных операционных систем других производителей, в которые включена многопоточная реализация TCP. SMP может также использоваться для масштабирования многопоточных программ Fast- CGI или Java (для последних многопоточность естественна). Коммерческие тесты производительности обычно не слишком пригодны для прогнозирования возможностей системы, поскольку они проводятся в искусственных условиях с высокоскоростными сетями, которые в реальном мире редко •стречаются и редко применяются рядовыми веб-путешественниками. Использовать результаты тестов можно лишь для сравнения возможностей различных компонентов. Мощность процессоров и уровень параллелизма возрастают, но в течение нескольких лет технологии Java и объектно-ориентированное программирование были способны поглощать все предоставляемые им ресурсы. Сейчас Java входит 1 пору «зрелости», приложения на этом языке становятся гораздо более быстрыми и эффективными. Еще одна серьезная проблема — разбухание приложений. Старые приложения обычно меньше по размерам и работают быстрее, поэтому иногда можно повысить производительность, перейдя от более новой версии к более старой. Сколько памяти нужно серверу? Ответ прост: больше! Память нужна всегда. Самое худшее, что может случиться С сервером, — это полное истощение свободной памяти вплоть до начала свопин- Пи Производительность при частом обращении к виртуальной памяти резко пада- #т, и пользователи быстро теряют интерес к вашему содержимому, которое не Желает появляться на их экранах. Лучше отказать в подключении лишним пользователям, чем заставить их всех страдать от неприемлемой производительности.
Серверы, состоящие из нескольких процессов, — такие, как Apache, — позволяют ограничивать количество этих процессов и количество одновременных подключений к одному процессу. Многопоточные серверы обеспечивают возможность ограничения количества активных потоков. В главе 18 об этом рассказывается подробнее. Вы также можете ограничить количество входящих подключений, изменив параметры входящей очереди подключений TCP. При этом вы сможете гарантировать качественное обслуживание тех пользователей, которым удалось подключиться к вашему сайту. Сервер, которому не хватает памяти, может показывать высокий процент использования процессора, поскольку ему постоянно приходится искать неиспользуемые страницы памяти, которые можно было бы поместить на диск. В этом случае увеличение мощности процессора не поможет — вам нужно увеличить объем памяти. Поиск страниц можно отследить с помощью программы vmstat в Solaris или Системный монитор в Windows NT. В Solaris нужно смотреть на значение столбца sr, где указывается количество запросов на выгрузку страниц в секунду. В NT необходимо следить за загрузкой процессора, которая всегда будет высокой, причем процессор будет работать в основном в привилегированном режиме. Это означает, что процессор не обслуживает веб-сервер, а занимается решением задач операционной системы. У любого компьютера имеется ограничение на максимальный объем памяти, который в него может быть установлен. Учтите, что этот предел автоматически ограничивает масштабируемость данной системы. Когда вы достигнете его, вам придется либо заменить компьютер целиком, либо разгрузить его — например, переложить выполнение сервлетов с веб-сервера на связующий компьютер. Память для операционной системы Начнем с требований, предъявляемых к памяти операционной системой. Linux 2.0 может прекрасно работать с 8 Мбайт ОЗУ, а для Solaris 8 лучше зарезервировать 128 Мбайт, если только вы не уверены, что в вашей конфигурации памяти нужно будет меньше. Мы говорим о той памяти, которая используется только операционной системой, а не сервером и не приложениями. Забавно, но факт: операционная система будет использовать тем больше памяти, чем больше у вас ее будет. Это происходит потому, что ядро использует память под таблицы, в которых хранится информация об использовании страниц памяти. Одна из причин, по которым нагруженным веб-серверам нужна оперативная память, — это существование невежливых клиентов, которые отсоединяются, не закрывая TCP-соединения, напрасно расходующие память ядра. Соединения существуют до тех пор, пока не будут разорваны по тайм-ауту. Это может происходить, когда пользователь выключает свой модем или компьютер с помощью выключателя, а не программным путем. Количество таких подключений на загруженных серверах может быть довольно большим. Команда netstat в системах Unix позволяет быстро определить количество открытых на данный момент соединений (см. «Интервал разрыва» в разделе «TCP» главы 15, где приводятся более подробные сведения о тайм-ауте TCP и разрыве неиспользуемых соединений).
Другая причина, по которой увеличение объема памяти увеличивает производительность загруженных серверов, состоит в том, что активно используемые соединения могут накапливаться из-за ограниченности пропускной способности Интернета. На каждое подключение уходит около 50 Кбайт памяти буфера со- кета TCP/IP вне зависимости от того, используется это подключение или нет. Память для httpd Теперь нужно учесть количество демонов сервера, которые будут выполняться to памяти, оставшейся свободной, после того как операционная система забрала свою часть. Рассчитывайте, что на один демон сервера, выполняемый в отдельном процессе, будет уходить 1-2 Мбайт памяти. Статистика использования памяти может быть получена с помощью программ top и ps. Для многопоточных серверов эксперт Sun по производительности Адриан Кокрофт советует отводить по 1 Мбайт на сервер плюс 100 Кбайт на поток. Эта оценка основана на экспериментах с сервером Netscape 2.0, который может порождать до 32 потоков. Все эти потоки вместе используют 1 Мбайт памяти при отсутствии активности и от 3 до 4 Мбайт в работе (вероятно, из-за кэширования). На каждое соединение требуется 50 Кбайт, а количество соединений будет совпадать с количест- ном выполняемых потоков. Память для содержимого Лучше всего, если у вас будет достаточно памяти для размещения в ней всего статического содержимого. Многие серверы кэшируют последние запрошенные Страницы в памяти даже в том случае, если эти страницы уже находятся в кэше файловой системы. Кэширование сервером может слегка увеличить производительность по сравнению с использованием одного только кэша файловой системы, но при этом объем памяти удваивается. Попробуйте отключить кэш вебсервера и сравните значения производительности и используемой памяти. Вы можете сэкономить память и нисколько не проиграть в производительности. Серверы Netscape (iPlanet) отображают файлы содержимого в память, избегая двойного копирования данных (из файла в ядро и из ядра в буфер процесса). Память для CGI Для того чтобы планировать память под CGI, следует определить, сколько CGI- Ирограмм будет выполняться на вашем сервере одновременно. Чтобы узнать это Количество, нужно определить вероятное количество CGI-запросов в секунду И время, необходимое для обработки этих запросов. Однако время завершения СЛМо зависит от того, сколько CGI-программ будет выполняться! Рекурсивные уравнения могут запутать кого угодно, но оценочные значения всегда можно подучить с помощью программ ps и top, позволяющих посчитать, сколько про- |рамм выполняется в любой конкретный момент. Разумно запастись памятью, достаточной для запуска стольких CGI-программ, «только у вас будет потоков или демонов веб-сервера (в предположении, что каждый поток или демон может запустить CGI-программу одновременно со всеми
остальными). CGI-процессы могут расходовать больше памяти, чем сам процесс httpd, особенно если программа-шлюз написана на интерпретируемом языке (что требует загрузки интерпретатора) или если она обращается к базе данных (для этого может потребоваться загрузка библиотек, обеспечивающих подключение к базе данных). Использование мониторов обработки транзакций (Transaction Processing — ТР) позволяет повысить производительность путем поддержания пула открытых подключений к базе данных, вместо того чтобы открывать для каждого CGI свое подключение. В главе 20 приводятся дополнительные рекомендации, касающиеся уменьшения размера исполняемых файлов CGI. Для выполнения двух копий одной программы не обязательно нужно в два раза больше памяти, поскольку сегмент текста у них может быть общий (в отличие от кучи и стека). С помощью программы Unix size вы можете определить размеры сегментов текста, данных и неинициализированных данных (bss) ваших CGI-программ. Сегменты данных и bss дают вам оценку снизу для памяти, используемой каждым экземпляром программы-шлюза. В процессе работы программа CGI будет потреблять дополнительную память. С помощью программ top и ps вы можете определить, сколько на самом деле используется памяти, которая не является общей для нескольких программ. В Solaris полезно использовать команду ртар -х. Планируйте использование памяти следующим образом. Текстовый сегмент у одинаковых CGI-программ будет общий, а все остальные сегменты, а также стек и куча будут создаваться для каждой CGI-программы отдельно. Посмотрите, что получится, если пользователи будут подключаться по модемам на 28,8 кбит/с, а не по локальной сети: при этом количество параллельно существующих соединений будет большим, а следовательно, большим будет и количество одновременно работающих CGI. Аналогичным образом влияет на ситуацию медленный процессор: количество одновременно выполняемых CGI возрастает, а значит, возрастают и требования к памяти. Основные рекомендации О Запишите технические требования на бумагу. О Помните, что вывод сервера ограничен возможностями сети. О Начинайте оценку мощности сервера с серверных приложений, поскольку они всегда потребляют больше ресурсов, чем собственно веб-сервер. О Выбрав какую-либо архитектуру, спросите себя: «Если я решу, что мне это не нравится, смогу ли я сменить эту архитектуру, после того как реализую ее?» О Планируйте масштабирование в будущем, учитывайте не только сиюминутные нужды. О Отслеживайте производительность, чтобы определить, отвечает ли сайт вашим требованиям.
4 Контроль производительности Начинать оптимизацию веб-сайта нужно с контроля его работы, чтобы представлять себе характерные его особенности и тенденции. Только так вы сможете узнать, на пользу идут ваши труды или во вред. Как мы увидим позже, программы, написанные для контроля производительности, послужат нам в дальнейшем и для тестирования сайта на нагрузку. В этой главе мы определим некоторые параметры производительности. Затем покажем, как можно их контролировать с помощью бесплатного программного обеспечения с сайта http://patrick.net/, не устанавливая на ваших компьютерах никаких программ. Параметры производительности Производительность любой компьютерной системы характеризуется четырьмя классическими параметрами: временем ожидания (latency), пропускной способностью (throughput), коэффициентом использования (utilization) и эффективностью (efficiency). Оптимизация производительности означает минимизацию времени ожидания и максимизацию остальных трех параметров. Определение короткое И ясное, но сама задача оптимизации не слишком проста, поскольку параметры Производительности зависят друг от друга, а также от времени суток, типа содержимого и множества других факторов. Наконец, некоторые параметры производительности могут быть более важными для достижения целей вашего предприятия, чем все остальные. Время ожидания и пропускная способность Временем ожидания называется время между запросом и началом отображения результата (ответа). В некоторых случаях этот параметр определяется как время между запросом и завершением ответа, но такое определение не учитывает пси-
хологию ожидающего, который до начала отображения ответа не знает, был ли принят и понят его запрос. Вы можете также столкнуться с определением, в котором время ожидания определяется как величина, обратная пропускной способности, но такое определение непродуктивно, поскольку при этом из рассмотрения исчезает один из параметров производительности. Время ожидания измеряется в единицах времени — например, в секундах. Пропускной способностью называется количество элементов, обрабатываемых в единицу времени — например, количество передаваемых бит в секунду, или количество миллионов выполняемых инструкций в секунду (MIPS), или количество HTTP-операций в день. Если пропускная способность измеряется в битах в секунду, ее обычно называют полосой пропускания. Пропускная способность вычисляется как отношение количества элементов ко времени, за которое эти элементы были обработаны. Такой расчет может дать точные, но не отражающие сути дела результаты, поскольку он не учитывает изменения скорости обработки в пределах интервала измерения. Приведенные ниже примеры иллюстрируют разницу между временем ожидания и пропускной способностью. О Срочная (в пределах 24 часов) доставка 1000 разных компакт-дисков по 500 Мбайт данных обеспечивает огромную пропускную способность, но плохое время ожидания. Пропускная способность в этом случае равна E00 х 220 х х 8 х 1000) бит / B4 х 60 х 60) с - около 49 млн бит / с, что превышает возможности линии ТЗ D5 миллионов бит в секунду). Отличие в том, что при срочной доставке все биты задерживаются на день, после чего прибывают одновременно, тогда как по линии ТЗ биты начинают прибывать сразу же после отправки. Таким образом, линия ТЗ обладает гораздо лучшим временем ожидания, хотя средняя пропускная способность за день в обоих случаях приблизительно одинакова. Этот пример взят из книги Э. Таненбаума (Tanenbaum) «Компьютерные сети» (издательство «Питер», 2002). О У грузовиков большая пропускная способность, поскольку в них можно много погрузить, но они медленно разгоняются и останавливаются. У мотоциклов пропускная способность низкая, поскольку груза они могут взять немного, но разгоняются и останавливаются они значительно быстрее, чем грузовики, а кроме того, они могут проскальзывать сквозь пробки, поэтому время ожидания у них меньше (лучше). О Супермаркеты стремятся достичь максимальной пропускной способности для каждого кассира, поскольку это позволяет им обойтись меньшим количеством кассиров. Один из способов достичь такого результата заключается в увеличении времени ожидания для покупателей, которые при этом выстраиваются в очередь к кассе, пока у них не кончится терпение. Брайан Вонг выразил эту дилемму следующей фразой: «Пропускная способность — это мера производительности организации, тогда как время ожидания — мера индивидуальной производительности». Супермаркет, конечно, не стремится к тому, чтобы расходовать ваше личное время, но он заинтересован в увеличении собственной (организационной) производительности.
О Одна женщина обладает пропускной способностью 1 ребенок в 9 месяцев (если не принимать в расчет возможность появления двойни или тройни). Девять женщин могут родить 9 детей за 9 месяцев, что дает этой группе пропускную способность 1 ребенок в 1 месяц, хотя время ожидания уменьшено быть не может (даже 9 женщин не могут родить 1 ребенка за 1 месяц). Этот несколько оскорбительный, но незабываемый пример взят из книги Фредерика Брукса «Мифический человеко-месяц» (The Mythical Man- Month). Хотя у систем с высокой пропускной способностью время ожидания обычно достаточно мало, никакой обязательной связи между этими величинами нет. В только что приведенном примере срочная доставка компакт-дисков давала высокую пропускную способность при большом времени ожидания. Большие жесткие диски обычно обладают высокой пропускной способностью, но и большим временем ожидания, поскольку они имеют большие физические размеры, из-за чего головкам требуется больше времени для перемещения. Время ожида- мия пакетных сетевых соединений также имеет тенденцию увеличиваться вместе с пропускной способностью. По мере того как вы приближаетесь к максимальной пропускной способности, все большее количество пакетов оказывается ожидающим отправки, поэтому возрастает время ожидания. В особенности это характерно для Ethernet, где допустимы столкновения пакетов, вызывающие повторную передачу (с расчетом на то, что при повторной передаче столкновения не произойдет). Кажется очевидным, что увеличение максимальной пропускной способности должно уменьшать время ожидания для сетей с коммутацией пакетов. Однако уменьшена может быть лишь одна из составляющих времени ожидания, определяемая перегруженностью сети; прочие же составляющие, связанные со временем работы маршрутизаторов и конечностью скорости передачи, уменьшены быть не могут. Наконец, низкая пропускная способность может обнаруживаться одновременно с малым временем ожидания. При работе с модемом на 14 400 бит/с первые биты данных могут быть получены достаточно быстро, в то время как на доставку большой картинки целиком может потребоваться много времени из-за Низкой пропускной способности. При работе с Интернетом важно помнить, что Время ожидания часто оказывается более важным, чем пропускная способность. Например, большая часть времени при запросе HTML-файла объемом 2 Кбайта Через модем на 28,8 кбит/с тратится на ожидание обработки запроса и начала Отображения результата, а не на завершение вывода файла. График зависимости времени ожидания от нагрузки сильно отличается от Графика зависимости пропускной способности от нагрузки. Время ожидания растет экспоненциально, а график имеет характерную форму зеркально отображенной буквы L. Пропускная способность сначала растет линейно, а затем выходит на уровень насыщения. Просто посмотрев на график тестирования нагрузки, вы сразу же можете понять, какой именно график вы видите перед Собой: времени ожидания или пропускной способности.
Время ожидания для сети Каждый этап передачи данных по сети от клиента к серверу и обратно вносит свой вклад в значение времени ожидания завершения HTTP-операции. Трудно бывает определить, где именно в сети нарастает большая часть времени ожидания, но в Unix имеются два широко распространенных средства, которые могут вам в этом помочь. (Помните, что мы говорим о времени ожидания для сети, а не о времени ожидания приложений, которое уходит на то, чтобы приложение, выполняемое на сервере, отправило в сеть свой ответ на пришедший из сети запрос.) Если к вашему веб-серверу обращаются через Интернет, большая часть времени ожидания, скорее всего, связана с принципом работы маршрутизаторов, которые принимают входящие пакеты в буфер, просматривают заголовки и в соответствии с ними передают пакеты дальше. Даже после того, как решение об отправке пакета принято, маршрутизатор ждет освобождения интерфейса, который может быть занят отправкой других пакетов. Поэтому время ожидания пакетов сильно зависит от количества маршрутизаторов между клиентом и веб-сервером. Маршрутизаторы связаны друг с другом линиями связи, которые также могут различаться по времени ожидания и пропускной способности. Одной из необычных, но важных особенностей Интернета является возможность изменения маршрута между любыми двумя точками сети в любой момент времени. Время ожидания может меняться от пакета к пакету. Пакеты могут даже приходить в неправильном порядке. Текущий маршрут пакетов и время, которое тратится на прыжки между маршрутизаторами, можно получить с помощью программы traceroute, которая имеется в большинстве версий Unix (см. страницу руководства man traceroute). Некоторые добрые люди предоставляют доступ к traceroute со своих веб-серверов, то есть вы можете узнать маршрут и время ожидания пакетов, передаваемых на ваш сервер с другого узла Интернета (то есть в противоположную сторону). Вот ссылка на один из таких серверов: ht!p://vw\w.slac.stanford.e^ Посетите также http://www.internetweather.com/, где вы найдете датчики времени ожидания, измеренного для пакетов, передаваемых от данного узла до серверов различных ISP. Учтите, что по умолчанию программа traceroute выполняет обратный поиск в DNS для всех IP-адресов промежуточных серверов, чтобы вывести на экран их имена, но это задерживает вывод результатов. Вы можете отключить поиск в DNS с помощью параметра командной строки -п, а также изменить количество пакетов, отправляемых на очередной маршрутизатор (по умолчанию — три), с помощью параметра -q. Вот пример вызова программы traceroute: % traceroute -q 2 www.um1ch.edu traceroute to www.umich.edu A41.211.144.53). 30 hops max. 40 byte packets 1 router.cableco-op.com B06.24.110.65) 22.779 ms 139.675 ms 2 mvl03.mediacity.com B06.24.105.8) 18.714 ms 145.161 ms 3 grfge000.mediacity.com B06.24.105.55) 23.789 ms 141.473 ms 4 bordercore2-hssiO-0.SanFrancisco.mci.net A66.48.15.249) 29.091 ms 39.856 ms 5 bordercore2.WinowSprings.mci.net A66.48.22.1) 63.16 ms 62.75 ms 6 mer1t.WinowSprings.mci.net A66.48.23.254) 82.212 ms 76.774 ms
7 f-umbin.c-ccb2.umnet.umich.edu A98.108.3.5) 80.474 ms 76.875 ms 8 vyMw.umich.edu A41.211.144.53) 81.611 ms * Если вас не интересует время отклика промежуточных маршрутизаторов, а интересует только время передачи пакета от вашего компьютера на какой-либо другой компьютер Интернета и обратно, воспользуйтесь утилитой ping. Эта программа отправляет пакеты протокола управляющих сообщений Интернета (Internet Control Message Protocol — ICMP) на указанный в строке вызова узел, измеряя время ожидания ответа этого узла в миллисекундах. Задержка в 25 мс считается вполне приличной, тогда как 250 мс — это уже многовато. Подробнее о данной программе см. страницу руководства man ping. Вот пример использования программы ping: % ping MWM.umich.edu PING wvjw.umich.edu A41.211.144.53): 56 data bytes 64 bytes from 141.211.144.53: icmp_seq-0 Ш-248 time-112.2 ms 64 bytes from 141.211.144.53: icmp_seq-l ttl-248 time-83.9 ms 64 bytes from 141.211.144.53: icmp_seq-2 ttl-248 time-82.2 ms 64 bytes from 141.211.144.53: icmp_seq-3 ttl-248 time-80.6 ms 64 bytes from 141.211.144.53: icmp_seq-4 ttl-248 time-87.2 ms 64 bytes from 141.211.144.53: icmp_seq-5 ttl-248 time-81.0 ms — www.umich.edu ping statistics — 6 packets transmitted. 6 packets received. OX packet loss round-trip min/avg/max - 80.6/87.8/112.2 ms Измерение времени ожидания и пропускной способности сети Пытаясь измерить время ожидания для пакетов, передаваемых между вашим и каким-то удаленным компьютером, программа ping использует сообщения 1С MP; последние на самом деле обрабатываются маршрутизаторами не так, как сегменты TCP, в которых передаются данные по протоколу HTTP Пакеты 1С MP обладают более низким приоритетом — некоторые маршрутизаторы могут их просто игнорировать. Более того, по умолчанию программа ping отправляет пакеты весьма небольшого размера (по 56 байт). Некоторые версии ping допускают отправку пакетов произвольного размера. По этим причинам программа ping не всегда позволяет точно измерить время ожидания HTTP, но может да- ийть данные для хорошего первого приближения. С помощью telnet и программы Unix talk вы можете почувствовать время ожидания соединения на себе. Самый простой способ измерить время ожидания и пропускную способность Сгти — это очистить кэш браузера и измерить, сколько времени потребуется *му на то, чтобы загрузить конкретную страницу с вашего сервера, попросить кого-то из друзей получить эту же страницу с вашего сервера через Интернет, или просто войти в систему на удаленном компьютере и выполнить команду time lynx -source http://patrick.net/>/dev/null. Этот метод иногда называется «контролем производительности Сети с секундомером».
Использование FTP Еще один способ оценки пропускной способности сети состоит в передаче файлов на удаленную систему и обратно по протоколу FTP. Протокол FTP похож на HTTP в том, что он тоже передает данные по сети в пакетах TCP. У этого метода есть свои подводные камни, но если вы будете внимательны, результаты будут отражать реальное состояние сети. Не стоит чересчур доверять числам, выводимым программой передачи файлов по FTP. Первые две значащие цифры могут быть правильными, но все последующие вполне могут быть неверны из-за внутренних погрешностей программ. Что более важно, различные части системы будут определять производительность FTP в зависимости от того, что именно вы будете делать с этим протоколом. Другими словами: от того, что вы сделаете, зависит, что именно вы измерите. Чтобы измерять пропускную способность сети, а не жесткого диска локальной или удаленной системы, нужно устранить влияние производительности дисков на результаты измерений. По этой причине не стоит передавать по FTP множество мелких файлов, каждый из которых будет требовать обращения к диску в момент считывания и в момент создания копии. Аналогичным образом следует ограничить размер передаваемых файлов, поскольку большой файл может просто не поместиться в кэше файловой системы передающего или принимающего компьютера, что также потребует обращения к диску. Чтобы гарантировать присутствие файла в кэше передающего компьютера, нужно выполнить передачу этого файла по меньшей мере дважды, отбросив результаты первого измерения. Не стоит записывать данные на диск принимающего компьютера. В некоторых версиях FTP вывод можно просто перенаправить в /dev/null. Команда при этом выглядит приблизительно следующим образом: ftp> get bigfile /dev/null Попробуйте использовать команду FTP hash для получения более реалистичного ощущения пропускной способности и времени ожидания. Команда hash печатает символы # после передачи каждого блока данных. Размер блоков, обозначаемых символом #, зависит от реализации FTP, но программы обычно сообщают этот размер, когда вы включаете режим hash. ftp> hash Hash mark printing on A024 bytes/hash mark). ftp> get ers.27may 200 PORT command successful. 150 Opening BINARY mode data connection for ers.27may C62805 bytes). mmummiimmimmimmnmmimiimimmmmmm 226 Transfer complete. 362805 bytes received in 15 sees B4 Kbytes/sec) ftp> bye 221 Goodbye. С помощью Perl или языка сценариев Expect вы можете автоматически запускать тесты FTP через одинаковые промежутки времени. Другие языки сценари-
ев не могут управлять терминалами порождаемых процессов. Если вы запустите FTP из сценария, то выполнение сценария будет приостановлено до тех пор, пока FTP не завершится, поэтому вы не сможете продолжить сеанс FTP Язык Expect был разработан специально для того, чтобы справиться с этой проблемой. Подробная документация по нему приведена в книге Дона Либса «Exploring Expect» (O'Reilly & Associates). Для автоматической записи результатов тестирования можно использовать программу autoexpect. Другие способы измерения производительности Можно, конечно, скачивать содержимое с вашего сервера по протоколу HTTP и считать это тестированием производительности сети, однако при таком способе тестирования невозможно отделить производительность сети от производительности самого сервера. Вот еще несколько средств тестирования сети. О ttcp. Это старая программа на С, созданная в 1985 году и предназначенная для тестирования скорости соединений по TCP. Она выполняет подключение к порту 2000 и передает буферы или данные из стандартного потока ввода. Скачать ее можно по адресу: ftp://ftp.arl.mil/pub/ttcp/, а в некоторых системах Unix она входит в комплект поставки. Попробуйте выполнить в своей системе команды which ttcp и man ttcp, чтобы узнать, если ли у вас исполняемый файл и документация от этой программы. О Nettest. Более современная программа (созданная приблизительно 1992 году), доступна по адресу: ftp://ftp.sgi.com/sgi/src/nettest/. Использовалась для накопления статистики производительности службы vBNS (http://www.vbns.net/). О bing. Программа bing пытается измерять полосу пропускания между двумя узлами Интернета. Подробнее см. по адресу: http://web.cnam.fr/reseau/bing.html. О chargen. Служба chargen, определенная документом RFC 864 и реализованная в большинстве версий Unix, отправляет обратившемуся к ней пользователю случайные символы с максимально возможной скоростью. Вместе с каким-либо измерительным средством она может использоваться для определения этой максимально возможной скорости. В режиме TCP служба передает непрерывный поток данных, тогда как в режиме UDP она отправляет пакет случайной величины в ответ на каждый полученный пакет. Оба варианта службы работают на заранее известном порту 19. Результаты измерений, выполненных с помощью chargen, нельзя считать надежными, поскольку невозможно отличить пакеты, сброшенные на компьютере-отправителе из-за переполнения буфера, от пакетов, сброшенных на компьютере- получателе. О NetSpec. Эта программа упрощает тестирование сети, позволяя пользователям управлять процессами на нескольких узлах с помощью набора демонов. Ее можно скачать по адресу: http://www.tisl.ukans.edu/Projects/AAI/products/ne- tspec.oid/.
Коэффициент использования Коэффициентом использования называется доля используемых возможностей компонента. Вам может показаться, что нужно стараться достичь максимального коэффициента использования всех компонентов, чтобы получать за затраченные деньги как можно больше, но на самом деле все обстоит несколько сложнее. Время ожидания для жестких дисков и Ethernet резко ухудшается при больших значениях коэффициента использования. Многие из компонентов достигают максимальной производительности при значении коэффициента использования около 70%. Поставляемая с большей частью версий Unix программа perfmeter является удобным средством графического отображения коэффициента использования вашей системы. Эффективность Эффективность обычно определяется как отношение пропускной способности к коэффициенту использования. Если из двух компонентов один имеет ббль- шую пропускную способность при одинаковом коэффициенте использования, этот компонент считается более эффективным. Если пропускная способность компонентов одинакова, но у одного из них более низкий коэффициент использования, этот компонент также является более эффективным. Данное определение удобно для сравнения компонентов, но в других отношениях не может считаться удовлетворительным, поскольку, согласно ему, один из параметров производительности представляет собой всего лишь отношение двух других параметров. Удобнее измерять эффективность как производительность на единицу стоимости. Обычно такая эффективность называется экономической: вы измеряете, сколько вы реально получаете за свои деньги. Интернет во многом обязан своей популярностью тому факту, что экономически он гораздо более эффективен по сравнению с существовавшими ранее альтернативами в отношении передачи небольших объемов информации. Электронная почта намного эффективнее бумажной в экономическом отношении. В обоих случаях передается приблизительно одинаковый объем информации, но электронная почта обладает практически нулевым временем ожидания и близкими к нулю дополнительными издержками: отправка двух сообщений стоит не больше, чем отправка одного сообщения. Веб-сайты, предоставляющие сведения о продуктах, обладают более низким временем ожидания и оказываются дешевле, чем печатные рекламные буклеты. Поскольку пропускная способность Интернета растет быстрее, чем его стоимость, некоторые области экономики целиком заменяются на свои более дешевые альтернативы, особенно на рынке для предпринимателей, который не страдает излишней сентиментальностью. В первую очередь в виртуальное пространство переходит статическая информация: деловые бумаги, журналы,
книги, компакт-диски и видеофильмы. После этого интернет становится средством общения в реальном времени. Экономическая эффективность Интернета для общения в реальном времени позволяет этому средству связи угрожать не только телефонным линиям, но и автомобильной и авиационной отраслям промышленности. Телекоммуникации заменяют физическое присутствие. Большая часть рабочей силы обычно просто передает друг другу биты информации — либо с помощью компьютеров, либо по телефону, либо в обычном разговоре (который можно считать видеосвязью с низким временем ожидания и пропускной способное™ в несколько гигабит в секунду). Только из-за потребности в обычном разговоре сотрудникам приходится покупать машины, чтобы ездить на работу. Машины ужасно неэффективны, а телекоммуникации позволяют нам экономить средства. Посчитайте, сколько машин стоит на каком-нибудь загруженном проспекте в крупном городе в час пик. Это просто медленно текущая река металла, безумно дорогостоящая, если учесть стоимость машин, бензина, водительского времени, а также стоимость дорожных работ, страховок и смертей. И большую часть дня эти машины просто бездействуют на стоянке около офиса. А если избавиться от стоянок — да и от офисов? Стоимость передачи данных не просто падает — она надает все быстрее и быстрее. Стоимость автомобилей не может падать с той же скоростью. Пользование гигабитными линиями связи между офисом и домом будет неизбежно стоить намного дешевле, чем путешествие на работу на машине, — как для сотрудника, так и для нанимателя. А с гигабитным оптоволокном вполне реально достичь :к|)фекта присутствия. Использование сценариев интерпретатора Производительность сети легко измерить самостоятельно, написав несколько сценариев, измеряющих время получения HTML с веб-сервера — то есть время ожидания. Если у вас есть текстовый браузер lynx, созданный в университете штата Канзас, вот способ быстро узнать время получения ответа от любого сер- игра Интернета: % time lynx -source http://patrick.net/ 0.05user 0.02system 0:00.74elapsed 9*CPU ПРИМЕЧАНИЕ В некоторых системах вместо команды time используется команда timex. Конечно, в полученном результате учитывается время запуска программы lynx, но если вы выполните команду дважды и отбросите первый результат, вто- |юй будет достаточно точным и правильным, поскольку исполняемому файлу упх не придется загружаться с диска. Помните, что результат включает не только время ожидания для сети, но и время ожидания для сервера. Фактически сюда входит все время, не являющееся системным или пользовательским. В нашем примере это 0,67 с (подключение по кабельному модему к быстрому серве-
ру). Даже в случае наличия очень быстрого подключения к сети на Интернет уходит все равно большая часть времени ожидания. Простые измерения времени ожидания можно выполнить и с помощью бесплатной программы webget, написанной на языке Perl, запуская ее вместо lynx. Можно и просто запускать программу GET, устанавливаемую вместе с библиотекой LWP для Perl. Замечательное свойство lynx состоит в том, что его можно запускать из сеанса Telnet, — поэтому, если вы хотите узнать, как работает ваш сайт с точки зрения какого-то другого узла Интернета, и у вас есть учетная запись на этом узле, вы можете войти в систему на удаленной машине и выполнить приведенную выше команду time lynx. В результате будет выведено время ожидания для удаленного узла. Если вы хотите не просто измерить производительность веб-сервера один раз, а постоянно ее контролировать, приведенный ниже тривиальный сценарий интерпретатора поможет вам сделать это. Обратите внимание, что мы никуда не сохраняем получаемую страницу, а направляем ее в /dev/null, поскольку нас интересует только время ее получения. Результаты измерений выводятся в стандартный поток сообщений об ошибках: #!/bin/bash while true do time lynx -source http://patrick.net/ > /dev/null sleep 600 done Если вы назовете приведенный выше сценарий топ, то результаты можно будет сохранять из стандартного потока сообщений об ошибках (дескриптор 2) в файл log с помощью следующей команды bash: $ mon 2>1og Использование С Написание сценариев интерпретатора представляет собой наименее эффективную форму программирования, поскольку практически каждая строка сценария порождает новый исполняемый файл. В листинге 4.1 мы приводим текст короткой программы на С, полученной из тестового клиента (глава 11), которая печатает время, потраченное на загрузку домашней страницы веб-сайта. Она гораздо более точна и эффективна, но и написать ее было существенно сложнее. Загрузить ее можно по адресу: http://patrick.net/software/latency.c. Листинг 4.1. Измерение времени ожидания: программа на С ♦include <stdio.h> ♦include <errno.h> ♦include <netdb.h> ♦include <netinet/in.h> ♦include <sys/socket.h> ♦include <sys/time.h> ♦define PORT 80 ♦define BUFSIZE 4000
int maindnt argc. char *argv[]) { int sockfd. count; char *request - "GET / HTTP/1.0\n\n"; char reply[BUFSIZE]: struct hostent *he; struct sockaddrjn target: struct timeval *tvs: /* время запуска */ struct timeval *tvf; /* время завершения */ struct timezone *tz; if ((he-gethostbyname(argv[l])) -- NULL) { herror("gethostbyname"): exit(l): } if ((sockfd - socket(AFJNET. SOCK_STREAM. 0)) - -1) { реггог("socket"); exit(l): } target, s in_f ami 1 у - AFJ NET; target.sin_port - htons(PORT); target.sin_addr - *((struct in_addr *)he->h_addr); bzero(&(target.sin_zero). 8); if (connect(sockfd. (struct sockaddr *)&target. sizeof(struct sockaddr)) — -1) { реггог("connect"): exit(l); } tvs - (struct timeval *) malloc(sizeof(struct timeval)): tvf - (struct timeval *) malloc(sizeof(struct timeval)): tz = (struct timezone *) malloc(sizeof(struct timezone)); gettimeofday(tvs. tz); send(sockfd. request. strlen(request). 0); if ((count - recv(sockfd. reply. BUFSIZE. 0)) — -1) { perrorC'recv"): exit(l): } gettimeofday(tvf. tz); printf("W bytes received in W microseconds\n". count. (tvf->tv_sec - tvs->tv_sec) * 1000000 + (tvf->tv_usec - tvs->tv_usec)): close(sockfd); return 0; ) Компилируется эта программа следующим образом: X gec -о latency latency.с
А запускается так: % latency patrick.net А вот что может получиться в результате ее работы: 2609 bytes received in 6247 microseconds Использование Perl Хотя программа на С — это замечательно, она написана на чересчур низком уровне, чтобы ее можно было легко изменять или обновлять. В листинге 4.2 приведена аналогичная программа на языке Perl, которая работает быстрее, чем сценарии интерпретатора команд, но медленнее, чем программа на С. Мы используем библиотеку LWP:: User Agent, поскольку это проще, чем работать с со- кетами напрямую. Библиотека Time::HiRes нужна нам потому, что по умолчанию таймеры в Perl работают с разрешением 1 с. Листинг 4.2. Измерение времени ожидания: программа на Perl #!/usr/local/bin/perl -w use LWP: :L)serAgent; use Time::HiRes 'time'.'sleep': Sua - LWP::l)serAgent->new: Srequest - new HTTP::Request<'GET'. "http://$ARGV[0]/"): Sstart - t1me( ): Sresponse - $ua->request($request); Send - timet ); Slatency - Send - Sstart: print length($response->as_string( )). " bytes received in Slatency seconds\n": Контроль производительности сети с помощью Perl Мы с легкостью расширим приведенный выше пример на языке Perl и получим из него полезную систему контроля. В этом разделе я расскажу о том, как можно создать автоматизированную систему слежения за производительностью вебсайта с помощью Perl и gnuplot. Существуют коммерческие программы для управления браузерами, которые в некоторых случаях могут оказаться полезными, но у них есть масса недостатков. Обычно они требуют использования патентованного языка сценариев. Чаще всего эти программы могут выполняться только под Windows, поэтому их тяжело запустить из командной строки. Это также означает, что вы не можете запустить их сквозь брандмауэр или из демона сгоп. Их трудно превратить в программы для тестирования нагрузки, поскольку они управляют отдельными экземплярами браузера, то есть для каждого тестового клиента вам придется загрузить свой браузер. Большая часть таких программ не позволяет отображать
результаты в сети. Наконец, они очень дороги. Мое решение, использующее Perl и gnuplot, лишено всех этих недостатков. Я отдал предпочтение языку Perl, а не Java, потому что в Perl разриты средства работы со строками, а также имеется отличная библиотека LWR Главная же причина в том, что для Perl есть бесплатные реализации SSL. Когда я начал заниматься контролем сайтов, бесплатных библиотек SSL для Java не было, хотя сейчас они уже есть. Отображение результатов с помощью gnuplot Программа gnuplot, которую можно скачать по адресу: http://www.gnuplot.org/ (никакого отношения к проекту GNU она не имеет), была выбрана мной для построения графиков, поскольку она позволяет формировать изображения формата PNG (Portable Network Graphics — переносимая сетевая графика). Сайт http://www.gnuplot.org/ в последнее время труднодоступен, но у меня на сайте по адресу: http://patrick.net/software/ имеется копия gnuplot для Linux. Зеркало вебсайта gnuplot находится по адресу: http://www.ucc.ie/gnuplot/. Сначала я использовал библиотеку GIF Тома Боутелла, с помощью которой формировал изображения в формате GIF, но Том убрал свою библиотеку из открытого доступа из-за спора об интеллектуальной собственности, разгоревшегося вокруг Unisys, у которой имеется патент на алгоритм сжатия, используемый форматом GIF. Формат PGN ни в чем не уступает формату GIF, но свободен от проблем с патентами. Правда, старые браузеры могут оказаться неспособными распознавать формат PNG. Программа gd, также созданная Томом Боутеллом, и ее переделка для Perl, созданная Линкольном Штейном, вероятно, столь же удобны для построения графиков, как и gnuplot, но я с ними работать не пробовал. Программа gnuplot считывает команды из стандартного потока ввода или из конфигурационного файла. Она может строить изображения во множестве форматов. Ниже я привожу пример файла с настройками для gnuplot Вы можете запустить эту программу и набрать help, чтобы получить достаточно ясное описание ее возможностей, или обратиться к веб-сайту http://www.gnuplot.org/. Я превращал наборы изображений в формате GIF в анимацию с помощью бесплатной программы gifside. Есть другая удобная программа, предназначенная для использования в оконной системе X Window. Называется она animate. Я все еще ищу переносимую бесплатную программу для вывода координат графиков, выделения частей изображений, увеличения, поворота, растяжения и редактирования изображений прямо на веб-странице. Если вы слышали о таких программах, пожалуйста, пишите на адрес p@patrick.net. Пример сценария на Perl Несложно скачать веб-страницу с помощью языка Perl и библиотеки LWP. Сложнее справиться с прокси-серверами, cookie, SSL и формами входа в систему. Приведенный в листинге 4.3 сценарий способен на все это. Он позволяет скачать домашнюю страницу сайта, войти на сервер, выйти из него и построить •се характерные значения времени на графиках. Я запускаю мои программы для
контроля и тестирования нагрузки с компьютера, находящегося в той же физической сети, что и веб-сервер. Таким образом я гарантирую, что время ожидания сети не станет «узким местом» и пропускная способность сети позволит мне выполнять серьезные тесты на нагрузку. Листинг 4.3. Контроль производительности сайта: сценарий Perl #!/usr/local/bin/perl -w use LWP::UserAgent; use Crypt::SSLeay; use HTTP:-.Cookies; use HTTP .-.Headers; use HTTP::Request: use HTTP:Response: use Time::HiRes 'time','sleep*: # константы: $DEBUG - 0; Sbrowser - 'Mozilla/4.04 [en] (Xll: I: Patrix 0.0.0 1586)': Srooturl - 'https://patrick.net': $user - "pk": Spassword - "pw": Sgnuplot - "/usr/local/bin/gnuplot"; # глобальные объекты: Scookiejar - HTTP::Cookies->new: $ua - LWP: :L)serAgent->new: MAIN: { $ua->agent($browser); # браузер используется при всех вызовах Sua. # домашняя страница Slatency - &get('7home.html"): Slatency - -1 unless index "<title>login page</title>" > -1: # проверяем, что мы получили страницу &log("home.log\ Slatency): sleep 2: Scontent - "user-Suser&passwd-Spassword"; # вход Slatency - &postC71ogin.cgi\ Scontent): Slatency - -1 unless m|<title>welcome</title>|: &log("login.log". Slatency): sleep 2: # получение страницы content Slatency - &getC7content.html"): Slatency - -1 unless m|<title>the goodies</title>|: &log("content.log". Slatency): sleep 2: # выход
Slatency - &get("/logout.egi"); Slatency - -1 unless m|<title>bye</title>|; &logClogout.log". Slatency): # построение графиков 4$gnuplot /home/httpd/public html/demo.gp4: } sub get { local (Spath) - @_; Srequest - new HTTP:: Request С GET'. "SrooturlSpath"): # Если был получен ответ, его cookie добавляются в новый запрос, if (Sresponse) { Scookie_jar->extract_cookies(Sresponse); Scookie jar->add_cookie_header($request): } if (SDEBUG) { print $request->as_string( ): } # Начинаем. Sstart - time( ); Sresponse - $ua->request($request): Send - time( ): Slatency - Send - Sstart: if (!Sresponse->is_success) { print Srequest->as_string( ). " failed: \ Sresponse->error_as_HTML: } if (SOEBUG) { print ■Vnffllflffffflfllfflffffflfffflfff Got Spath and result was:\n": print Sresponse->content: print ■fffffflflflllllflfflfffffllllff» Spath took Slatency seconds.\n": } Slatency: } sub post { local (Spath. Scontent) - @_: Sheader - new HTTP::Headers: Sheader->content_type('application/x-www-form-urlencoded'): Sheader->content_lengthAength(Scontent)): Srequest - new HTTP::RequestС POST'. "SrooturlSpath". Sheader. Scontent):
# Если был получен ответ, его cookie добавляются в новый запрос if (Sresponse) { Scookie_jar->extract_cookies(Sresponse): $соок i e_j а г ->add_cook i e_header(Srequest): } if ($DEBU6) { print $request->as__string( ): } # Выполнение программы Sstart - time( ): Sresponse - $ua->request($request): Send - time( ); Slatency - Send - Sstart: if (!Sresponse->is_success) { print Srequest->as__string( ). " failed: ". $response->error_as_HTML; } if (SDEBUG) { print Лп##ЩШШ//Ш//^Ш//0Щ#### Got Spath and result was:\n": print Sresponse->content: print "#даЩ#ЖЩЩЩЩЖ##### Spath took Slatency seconds.\n": } Slatency: } # Запись данных в журнал производится в таком формате, чтобы потом строить изображение с помощью gnuplot. sub log { local (Sfile. Slatency) - @_: Sdate - 4date +"XY Xm %6 XH XM XS'\ chop Sdate; # Соответствует команде gnuplot: set timefmt "%y Xm Xd XH XM XS" open(FH. "»Sfile") || die "Could not open Sfile\n": # Установка точности printf FH "Xs X2.4f\n". Sdate. Slatency: close(FH): } В результате мы получаем набор файлов журналов, в которых записаны время и значение времени ожидания. Чтобы получить из этого график, нам придется составить конфигурационный файл gnuplot. В листинге 4.4 приведен пример такого файла, предназначенного для построения графика времени ожидания для домашней страницы сайта.
Листинг 4.4. Конфигурационный файл gnuplot. График времени ожидания set term png color set output '7home/httpd/public_html/demo.png" set xdata time set уlabel "latency in seconds" set bmargin 3 set logscale у set timefmt "XY %m %6 %H *M %S" plot "demo.log" using 1:7 title "time to retrieve home page" Обратите внимание, что результаты работы записываются в файл формата PNG непосредственно в каталог веб-сервера public_html. Поэтому, чтобы увидеть результат работы программы, мне достаточно выбрать нужную ссылку из закладок моего браузера. Тедерь я могу создать задание для демона сгоп, чтобы он запускал этот сценарий каждую минуту, и у меня получатся журнал производительности моей веб-страницы и постоянно обновляемый график. Для редактирования файла crontab используется команда crontab -е. Вот пример записи в моем файле crontab. ПРИМЕЧАНИЕ Если вы незнакомы с планировщиком заданий сгоп, используемым в Unix, выполните команду man crontab и прочитайте все, что выведет компьютер. # MIN HOUR DOM MOY DOW Commands #@-59) @-23) A-31) A-12) @-6) (Note: 0-Sun) * * + * • cd /home/httpd/public_html: ./monitor.pl На рис. 4.1 показан пример графика для реального сайта, который я контролировал более года. В этом подходе есть одна небольшая проблема, которая проявляется при постоянном обращении к одной и той же странице. Первое обращение к странице занимает примерно на 200 мс больше, чем все последующие, выполненные тем же процессом Perl. Это, видимо, связано с необходимостью создания интерпретатором Perl соответствующих объектов для сохранения запроса и ответа. Объекты не уничтожаются, поэтому повторное создание их при последующих обращениях не требуется. Вместо того чтобы запускать программу с помощью сгоп, вы можете превратить этот сценарий в функциональный тест, отображая все загруженные страницы в браузере Netscape, чтобы иметь возможность наблюдать за тем, как это будет происходить, а также проверять, что все страницы загружаются правильно. Открыть веб-страницу http://patrick.net/ из Perl в браузере Netscape можно такой командой: system "netscape -remote ,openURL(http://patrick.net)'":
Рис. 4.1. График для контролируемого сайта Вы можете перенаправить вывод браузера на любой компьютер Unix, на котором выполняется сервер X Window System, или на компьютер с Microsoft Windows, на котором запущен эмулятор системы X Window типа Exceed. Управление браузером Netscape из сценария описано в документе http://home.netscape. com/newsref/std/x-remote.html. Компоненты В этом разделе приведен список компонентов, необходимых для того, чтобы с помощью Perl контролировать производительность веб-сайта. Чтобы найти и скомпилировать все компоненты, вам придется потрудиться, но после того как вы сделаете это, в ваших руках окажутся необычайно мощные средства для написания всевозможных сценариев контроля и тестирования нагрузки. На своем опыте я знаю, что эти компоненты можно компилировать в том порядке, в котором они приведены ниже. За исключением gcc и Perl, все остальное можно скачать с моего сайта по адресу: http://patrick.net/software/. Perl можно скачать с сайта http://www.perl.com/, а дсс можно взять по адресу: ftp://prep.ai.mit.edu/, а также с множества других сайтов по всему миру: О gcc; О perl 5.004_04 or better; О openssl-0.9.4;
О Crypt-SSLeay-0.15; О Time-HiRes-01.20; О MIME-Base64-2.11; О URI-1.03; О HTML-Parser-2.23; О libnet-1.0606; О Digest::MD5-2.07; О libwww.perl-5.44; О gnuplot. Автоматическая генерация сценариев для контроля с помощью sprocket Теперь, когда вы разобрались с тем, как писать сценарии для контроля производительности на языке Perl, я скажу вам, что делать это вручную не обязательно. Я изменил и усовершенствовал прокси-сервер Сети, написанный Рэнда- лом Шварцем, таким образом, что он автоматически генерирует сценарии для контроля производительности — правда, с некоторыми ограничениями. Усовершенствованный прокси-сервер я назвал sprocket. Это программа на Perl, которая порождает программу на Perl, поэтому с ней может быть трудно разобраться, но ее можно скачать с сайта http://patrick.net/software/sprockeVsprocket и пользоваться ею, даже если вы не понимаете, как она работает. А вот как надо работать с этой программой. 1. Для начала вам понадобятся все перечисленные выше компоненты, которые могут быть загружены с сайта http://patrick.net/software/. 2. После установки компонентов скачайте программу sprocket с сайта http://pat- rick.net/software/sprocket/sprocket. Эта программа невелика и должна загрузиться буквально за пару секунд. Поместите ее в каталог, откуда вы сможете просматривать получающиеся изображения формата PNG. Для этого подойдет, например, каталог вашего веб-сервера public_html. 3. Теперь настройте прокси-сервер вашего веб-браузера. Он должен соответствовать используемому программой sprocket (порт 8008). В Netscape 4 выберите Edit ► Preferences ► Advanced ► Proxies ► Manual Proxy Configuration ► View ► HTTP Proxy. После настройки прокси-сервера запустите sprocket с параметром -s (scripting), перенаправив вывод в файл сценария, который вы хотите создать. Например, так: % sprocket -s > myscript.pl В процессе формирования сценария в стандартный поток ошибок будут выводиться сообщения. Выглядеть они могут так:
# scripting has started (ЖС when done) # set your proxy to <URL:http://localhost:8008/> # then surf to write a script # scripted a request # scripted a request # scripted a request В этом примере мы обратились к двум страницам, что привело к отправке трех запросов HTTP, потому что на одной из страниц присутствовала картинка. Просмотрев страницы, которые вы хотите контролировать, нажмите клавиши Ctrl+C, чтобы выйти из sprocket. Если вы запустите программу еще раз, сразу же после завершения, вы можете получить сообщение об ошибке port in use. Подождите минуту или две. Созданный файл myscript.pl содержит сценарий, который способен повторить практически все действия, выполненные вами во время работы с браузером. Единственное исключение: sprocket не записывает ответы set-cookie, поскольку они уникальны для сеанса, во время которого вы записывали сценарий. Созданный сценарий будет принимать новые ответы set-cookie, поэтому при каждом запуске сценария будет открываться новый сеанс работы на сервере. В листинге 4.5 приведен пример только что созданного сценария myscript.pl. Листинг 4.5. Сценарий, порожденный sprocket #!/usr/bin/perl use Socket; use Time::Hi Res 'time'.'sleep'; $proto - getprotobyname('tcp'): fvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvwvvvvvvvvvvvvvvvvvvvvv $host - "vahe"; $port * 80; $request - 'GET / HTTP/1.0 Accept: image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. image/png. */* Accept-Charset: iso-8859-1.*.utf-8 Accept-Encoding: gzip Accept-Language: en Host: vahe User-Agent: sprocket/0.10 Proxy-Connection: Keep-Alive $proof - 'HTTP/1.1 200 OK'; Srequest — s|[\r\n]*$|\r\n|: # удаление лишних \г\п foreach(@cookies) { Srequest .- "Cookie: $_\r\n": # реагируем на cookie } Srequest .- "\r\n": # завершаем запрос переводом строки
socket(SOCK. PFJNET. SOCK_STREAM. Sproto): Sstart - time( ); Siaddr - gethostbyname($host): Spaddr - sockaddr_in(Sport. Siaddr): connect(SOCK. Spaddr); Sold_fh - select(SOCK); # сохраняем старое значение fh $| - 1: # отключаем буферизацию select(Sold_fh): # восстановление print SOCK Srequest: ^response - <S0CK>; Send - time( ): Spath - Srequest: Spath — тГСА-Z]* (.*) HTTP|: Spath - SI: Sfile - Spath: Sfile — s|/|_|g: open(FILE. "»$file") || die "cannot create file": Sdate - ^date +'%m %6 %H SM %S *Y": chop Sdate: # validate response here if (grep(/Sproof/. (^response)) { print FILE Sdate. " ". Send - Sstart. "\n": } else { print FILE Sdate. " -l\n": } close FILE: Sgnuplot_cmd - qq| set term png color set output "Sfile.png" set xdata time set ylabel "latency in seconds" set bmargin 3 set logscale у set timefmt "Xm %6 %H ZM %S XY" plot "Sfile" using 1:7 title "Spath" with lines I: openCGP. "|/usr/local/bin/gnuplot"): print GP Sgnuplot_cmd: close(GP): foreach (^response) { /Set-Cookie: (.*)/ && push(Gcookies. SI):
} print; close(SOCK): # #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Shost - "vahe": Sport * 80: Srequest - 'GET /webpt_sm.gif HTTP/1.0 Accept: image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. image/png Accept-Charset: iso-8859-l.*.utf-8 Accept-Encoding: gzip Accept-Language: en Host: vahe Referer: http://vahe/ User-Agent: sprocket/0.10 Proxy-Connect!on: Keep-Alive Sproof - "HTTP/1.1 200 OK': Srequest — s|[\r\n]*$|\r\n|: # удаляем лишние \r\n foreach(@cookies) { Srequest .- "Cookie: $_\r\n"; # реагируем на cookie } Srequest .- "\r\n": # завершаем запрос пустой строкой socket(SOCK. PF_INET. SOCK_STREAM. Sproto): Sstart - time( ): Siaddr - gethostbyname(Shost); Spaddr - sockaddr_in(Sport. Siaddr): connect(SOCK. Spaddr): Sold_fh - select(SOCK): # сохраняем старое значение fh S| - 1: # отключаем буферизацию select(Sold_fh): # восстановление print SOCK Srequest: ^response - <SOCK>: Send - time( ): Spath - Srequest: Spath - m|A[A-Z]* (.*) HTTP|: Spath - SI: Sfile - Spath: Sfile - s|/|_|g: open(FILE. "»$file") || die "cannot create file":
$date - 'date +"%ro %6 %H *M %S *Y": chop $date: # подготовка ответа if (grep(/$proof/. ^response)) { print FILE $date. " ". Send - Sstart. "\n"; ) else { print FILE Sdate. " -l\nH: } close FILE: $gnuplot_cmd - qq| set term png color set output "Sfile.png" set xdata time set уlabel "latency in seconds" set bmargin 3 set logscale у set timefmt "%m %6 %H SM %S SY" plot "Sfile" using 1:7 title "Spath" with lines I: openFP. "|/usr/local/bin/gnuplot"); print GP $gnuplot_cmd: close(GP); foreach (^response) { /Set-Cookie: (.*)/ && push(@cookies. $1): } print: close(SOCK): r fvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Shost - "vane": Sport - 80: Srequest - 'GET /specs/index.html HTTP/1.0 Accept: image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. image/png. */* Accept-Charset: iso-8859-l.*.utf-8 Accept-Encoding: gzip Accept-Language: en Host: vahe Referer: http://vahe/ User-Agent: sprocket/0.10 Proxy-Connection: Keep-Alive
Sproof « 'HTTP/I.1 200 OK'; Srequest — s|[\r\n]*S|\r\n|; # удаляем лишние \r\n foreach(©cookies) { Srequest .- "Cookie: S_\r\n"; # реагируем на cookie ) Srequest .- "\r\n": # завершаем запрос пустой строкой socketCSOCK. PF_INET. SOCKJTREAM. Sproto): Sstart - time( ): Siaddr - gethostbyname(Shost): Spaddr - sockaddrjn(Sport. Siaddr); connect(SOCK. Spaddr): Sold_fh - select(SOCK); # сохраняем старое значение fh S| - 1: # отключаем буферизацию select(Sold_fh); # восстановление print SOCK Srequest: ©response - <SOCK>: Send - time( ); Spath - Srequest: Spath — шГСА-Z]* (.*) НПР|: Spath - SI: Sfile - Spath: Sfile — s|/|_|g: open(FILE. "»Sfile") || die "cannot create file": Sdate - 'date + 'Xm Xd XH XM XS XV *: chop Sdate: # формирование ответа if (grep(/Sproof/. ©response)) { print FILE Sdate. " ". Send - Sstart. "\n"; } else { print FILE Sdate. " -l\n": } close FILE: Sgnuplot_cmd - qq| set term png color set output "Sfile.png" set xdata time set уlabel "latency in seconds" set bmargin 3 set logscale у set timefmt "Xm Xd XH XM XS XY" plot "Sfile" using 1:7 title "Spath" with lines
open(GP. "|/usr/loca1/bin/gnuplot"): print 6P $gnuplot_cmd: close(GP); foreach (^response) { /Set-Cookie: (.*)/ && push(@cookies. $1): } print: close(SOCK); r^^^^^^^^^^ ^ Как видите, созданный сценарий написан на низком уровне и не содержит подпрограмм. При этом в нем много повторяющихся фрагментов. Однако эти особенности облегчают настройку сценария. Учтите, что вы не можете записать сеанс работы с SSL (если только пользователь не даст вам разрешения), поскольку если бы вы могли «подслушивать» сеансы SSL на прокси-сервере, это бы означало, что SSL не работает! Немного потрудившись, можно отключить SSL на веб-сервере, записать сеанс, после чего изменить сценарий myscrlpt.pl так, чтобы он использовал SSL. Сценарий, предназначенный для контроля производительности, будет записывать в журнал временную метку и значение времени ожидания для каждого запрашиваемого объекта, после чего автоматически генерировать график результатов. Журнал и график будут помещаться в тот же каталог, в котором находится sprocket. Имя файла журнала будет совпадать с URL запрошенной страницы — с тем исключением, что символы / будут заменены на _. Имя графика будет совпадать с именем файла журнала и иметь расширение .png. При первом запуске сценария gnuplot выведет предупреждение, что на каждом графике имеется только одна точка, поэтому масштабирование осей невозможно. Это предупреждение можно спокойно игнорировать. Использование реляционной базы данных для сохранения данных о производительности Естественно хранить результаты контроля производительности в файле, но можно помещать их и в реляционную базу данных. Это потребует несколько больших усилий по настройке, да и обратиться к данным, хранящимся в базе, не так просто, как к обычному файлу, но преимущества базы велики. О Все ваши данные хранятся в одном месте, поэтому, когда вам понадобится узнать, какой была производительность конкретной страницы месяц назад, вам не придется искать файлы журналов по всем дискам. Конечно, хранение данных в одном месте означает и то, что вы можете их все сразу потерять.
О Вы сможете легко выполнять запросы. Вместо того чтобы вручную рыться в огромном файле, вы сможете делать запросы на языке SQL, указывая интересующий вас диапазон времени. О Язык SQL содержит множество встроенных математических функций, позволяющих легко выполнять сравнения и обработку. О Если вы можете подключиться к базе данных по сети, то вы получаете удаленный доступ к данным, что не всегда возможно в случае их хранения в обычном файле. Помещение данных в базу Если для контроля вы используете Perl, можете попробовать сохранять данные в базу с помощью Perl DBI (Database Interface). Вам придется скачать и установить пакет Perl DBI и драйвер для вашей базы данных. Рассмотрим пример программы на языке Perl, помещающей данные в базу. Вместо того чтобы, как в предыдущем примере, выполнять команду print FILE $date. " ". Send - Sstart. "\n";, можно использовать приведенный ниже код, в котором предполагается, что есть таблица perfdata с полями для URL, даты и времени ожидания: use DBI: Sdbh « DBI->connect("dbi:Oracle:perf'\ "patrick". "passwd") or die "Can't connect to Oracle: $DBI::errstr\n": $sth - $dbh->prepare("insert into perfdata values CSurV. to_date('$yyyy $mon $dd $hh $mm $ss\ 'YYYY MM DO HH24 MI SS'). Send - Sstart)"): Ssth->execute( ): Sdbh->disconnect or warn "Disconnect failed: SDBI::errstr\n": Одна из проблем с данными заключается в том, что их бывает очень много и все время появляются новые. Через некоторое время данные начинают действовать на диск, как программа с утечкой памяти действует на операционную систему. Первый метод борьбы с ростом объема данных состоит в том, чтобы не записывать близкие к нулю значения. При этом большая часть данных будет сбрасываться. Другая стратегия состоит в преобразовании ежедневных данных в среднюю величину за неделю после того, как они устареют хотя бы на месяц, а еженедельные средние можно преобразовывать в средние за месяц после того, как пройдет год, и так далее. Этот подход используется в бесплатном средстве контроля Big Brother. Получение данных из базы Поместив данные в базу, вы наверняка захотите как-либо их использовать. В листинге 4.6 приведен пример, в котором мы получаем из базы данные за сегодняшний день и печатаем их.
Листинг 4.6. Работа с базой данных #!/usr71ocal/bin/perl use DBI; $dbh - DBI->connectrdbi:Oracle:perf\ "patrick". "passwd") or die "Can't connect to Oracle: $DBI::errstr\n": $url - "/home.html": $sth - $dbh->prepare("select timestamp. latency from latency where trunc(timestamp)«trune(sysdate) and url»$url"); $sth->execute( ): $gnuplot_cmd - qq| set term png color set output "Surl.png" set xdata time set ylabel "latency in seconds" set bmargin 3 set logscale у set timefmt "%m %6 XH ЯМ %S ХГ plot и-" using 1:7 title "Spath" with lines I: while(($timestamp. Slatency) - $sth->fetchrow_array) { $gp_cmd .- "Stimestamp $latency\rf: } $gp_cmd .- "е\пи: $sth->finish( ); $dbh->disconnect or warn "disconnect failed: $DBI::errstr\n": openCGP. "|/usr/local/bin/gnuplotM): print GP $gp_cmd: close(GP): Контроль коэффициента использования с помощью rstat Программа rstat — это клиент удаленного вызова процедур RPC. Я написал ее для получения и вывода статистики с любого компьютера, на котором работает демон rpcrstatd — партнер-сервер этой программы. Демон rpc.rstatd много лет используется такими средствами, как программа perfmeter фирмы Sun и команда rup. Программа rstat представляет собой просто новый клиент для старого демона. То, что демон rpcrstatd уже установлен и работает на большей части компьютеров Solaris и Linux, является огромным его преимуществом перед другими средствами, которые требуют установки специальных агентов. Мой клиент rstat компилируется и работает в системах Solaris и Linux и может получать статистику с любого компьютера, на котором работает демон
rpc.rstatd. Этот компьютер может работать под управлением систем Solaris, Linux, AIX и OpenBSD. Демон rpc.rstatd запускается в Solaris из файла /etc/inetd.conf. Я планирую портировать клиент rstat на другие платформы. По своим свойствам он аналогичен vmstat, но обладает перед ним некоторыми преимуществами. О Вы можете получать статистику, не входя в систему на удаленном компьютере, даже через Интернет. О В журнал записывается временная отметка. О Выводимые данные могут быть сразу преобразованы в график с помощью gnuplot. Возможность удаленного запуска означает, что вы можете с одного компьютера централизованно контролировать производительность нескольких компьютеров. У программы есть и серьезный недостаток: она не позволяет измерять количество запросов на освобождение памяти (столбец sr программы vmstat). Программа rstat не сможет связываться с демоном через большую часть брандмауэров, поскольку она использует порт 111 (RPC), который обычно блокируется брандмауэрами. Программу rstat можно скачать по адресу: ht^://patrick.net/software/rstat/rstat.html. Как отмечалось ранее, программа perfmeter фирмы Sun также является клиентом rpc.rstatd и также может записывать статистику удаленного сервера в файл. Однако мне не удалось запустить perfmeter без графического интерфейса, хотя, наверное, это можно сделать с помощью Xvfb (виртуального буфера кадров системы X Window). Запуская rstat укажите имя или IP-адрес компьютера, производительность которого вы хотите контролировать. Помните, что на этом компьютере должен выполняться демон rpc.rstatd. Команда rup здесь особенно полезна, поскольку при запуске без аргументов она просто выводит список всех компьютеров локальной сети, на которых запущен демон rstatd. Если компьютера в списке нет, вам придется запускать на нем rstatd вручную. Чтобы запустить rpcrstatd в Red Hat Linux, выполните команду /ete/rcd/initd/rstatd start от имени привилегированного пользователя. В Solaris нужно сначала попробовать запустить клиент rstat поскольку демон inetd обычно настроен на автоматический запуск rpc.rstatd при получении запроса от rstat Если клиент завершается с ошибкой «RPC: Program not registered*, убедитесь, что в файле /etc/inet/inetd.conf есть приведенная ниже строчка, и убейте демон inetd командой kill с ключом -HUP, чтобы демон заново прочел файл inetd.conf. rstatd/2-4 tli rpc/datagram_v wait root /usr/lib/netsvc/rstat/rpc.rstatd rpc.rstatd После этого вы сможете просмотреть статистику любого компьютера так, как это сделано в нижеследующем примере: % rstat enkldu 2001 07 10 10 36 08 0 0 0 100 0 27 54 1 0 0 12 0.1 Эта команда выведет усредненные данные за одну секунду, после чего программа завершится. Если вы хотите выполнять непрерывный контроль, укажите
интервал запросов в секундах в качестве аргумента командной строки. Вот пример, в котором каждая строчка вывода появляется через две секунды: % rstat enkidu 2 2001 07 10 10 36 28 0 0 1 98 0 0 7 2 0 0 61 0.0 2001 07 10 10 36 30 0 0 0 100 0 0 0 2 0 0 15 0.0 2001 07 10 10 36 32 0 0 0 100 0 0 0 2 0 0 15 0.0 2001 07 10 10 36 34 0 0 0 100 0 5 10 2 0 0 19 0.0 2001 07 10 10 36 36 0 0 0 100 0 0 46 2 0 0 108 0.0 жс Чтобы получить сведения о способе использования программы, формате результатов, номере версии и адресе веб-страницы с обновлениями, запустите программу без параметров: % rstat usage: rstat machine [interval] output: yyyy mm dd hh mm ss usr wio sys idl pgin pgout intr ipkts opkts coll cs load docs and src at http://patrick.net/software/rstat/rstat.html Обратите внимание, что заголовки столбцов выровнены так же, как выводимые данные. Выводимые данные могут показаться непосвященному просто мешаниной цифр, но на самом деле они полезны, и формат их выбирался таким образом, чтобы обеспечить простоту построения графиков с помощью программы gnuplot, которую можно скачать по адресу: http://www.gnuplot.org/ или http://patrick.net/ software/. Программа может построить график данных из любого поля. Чтобы создать график из данных rstat, перенаправьте вывод этой программы в конвейер или файл (rstat.out — в нашем примере). Затем создайте приведенный в листинге 4.7 файл конфигурации gnuplot (enkidu.gp — в нашем примере). После этого просто вызовите gnuplot enkidu.gp — и программа создаст файл PNG с именем enkidu.png, который можно будет показать на веб-странице. Листинг 4.7. Конфигурационный файл gnuplot для построения графиков статистики rstat set term png color set output "enkidu.png" set xdata time set timefmt "%V %m Sd %H SM SS" set bmargin 3 set y21abel "load" set ylabel "context switching" set ytics nomirror set y2tics nomirror plot "rstat.out" using 1:17 axes xlyl title "context switching". \ "rstat.out" using 1:18 axes xly2 title "load" На рис. 4.2 показан пример изображения формата GIF со статистикой по переключению контекста и нагрузке (поля 17 и 18), созданного с помощью rstat п gnuplot.
Рис. 4.2. График данных rstat Сохранение данных rstat в реляционной БД Статистику rstat, как и данные о времени задержки, разумно сохранять в базе данных, чтобы впоследствии с большим удобством ими пользоваться. Приведенная ниже команда SQL может применяться для создания таблицы для данных rstat в базе данных Oracle. create table rstat ( machine varchar2B0). timestamp date not null, usr numberC). wio numberC). sys numberC). idl numberC). pgin numberF). pgout numberF). intr numberF). ipkts numberF). opkts numberF). coll numberF). cs number(8). load numberO.l) w
В листинге 4.8 приведен пример программы на Perl, запускающей rstat, которая выделяет из вывода нужные поля и помещающей данные в базу. Листинг 4.8. Помещение результатов работы rstat в БД #!/usr/local/bin/perl use DBI: $machine - "vatche": Sinterval - 60: $dbh « DBI->connect("dbi:Oracle:perf". "patrick". "passwd") or die "Can't connect to Oracle: $DBI::errstr\n": open(RSTAT. "rstat Smachine Sinterval |") II die "could not start rstat": while(<RSTAT>) { (^УУУУ. *mon. Sdd. $hh. $mm. $ss. $usr. $wio. $sys. $idl. $pgin. Spgout. $intr. Sipkts. Sopkts. Scoll. $cs. $load) - split(/\s+/): $sth « $dbh->prepare("insert into rstat values ('Smachine'. to_date('Syyyy $mon Sdd Shh Smm Sss*. 'YYYY MM DD HH24 MI SS'). Susr. Swio. Ssys. Sidl. Spgin. Spgout. Sintr. Sipkts. Sopkts. Scoll. $cs. Sload)"): Ssth->execute( ): } # Если rstat завершится, нужно хотя бы отключиться от БД. Sdbh-disconnect or warn "Disconnect failed: SDBI::errstr\n": Использование данных rstat Но вот данные о работе системы оказались в базе данных. Как теперь ими пользоваться? Ответ прост: так же, как и любыми другими данными, хранящимися в реляционной базе. Пусть вам нужно вычислить среднее значение использования ресурсов процессора системой и пользователем за 8 октября 2001 года между 9 и 16 часами. Приведенный ниже запрос позволяет получить нужное значение. select avg(sys + usr) from rstat where timestamp between to_date('2001 10 08 09'. 'YYYY MM DD HH24') and to_date('2001 10 08 16'. 'YYYY MM DD HH24') and machine»'mars': Получение данных из БД в стандартный поток вывода Часто бывает полезно иметь возможность обрабатывать данные, хранящиеся в базе, с помощью средств командной строки Unix — таких, как grep, sort и др. Большая часть средств работы с SQL не слишком хорошо взаимодействует со стандартными потоками ввода и вывода. Приведенный в листинге 4.9 сценарий на языке Perl позволяет извлечь данные из базы в файл, если у вас имеется мо-
дуль DBI и используется база Oracle. Он называется sql.pl, и скачать его можно по адресу http://patrlck.net/software/. Листинг 4.9. Получение данных rstat из БД #!/usr/local/bin/perl use DBI; $ENV{ORACLE_HOME} - Vpath/to/ORACLE/product": $dbh - DBI->connect("dbi:Oracle:myinstance", "mylogin". "mypassword") or die "Can't connect to Oracle: $DBI::errstr\n"; $sql - $ARGV[0]: $sth - $dbh->prepare($sql); $sth->execute( ): while(@row - $sth->fetchrow_array) { print "@row\n"; } $sth->finish( ); $dbh->disconnect or warn "Disconnect failed: SDBI::errstr\n": Построение графиков данных, хранящихся в БД Получить одно число хорошо, но интереснее узнать, как определенная величина меняется со временем. Приведенный в листинге 4.10 сценарий позволяет любому пользователю с помощью шлюза CGI просмотреть графики данных, собранных с помощью rstat. На экран выводится график зависимости одной величины от времени. Вам придется изменить этот текст, включив в него реальные значения ORACLEJ-ЮМЕ, ваш пароль и имя пользователя системы Oracle, а также имена компьютеров. После этого сценарий будет готов к работе. Скачать его можно по адресу: ht^://patrick.net/software/graph.cgi. Листинг 4.10. Построение графика статистики rstat из БД #!/usr/local/bin/perl #Author: Patrick Killelea #Date: 12 April 2001 # Нужно заменить переменные "myinstance". "mylogin". и "mypassword" правильными # значениями use DBI: $ENV{0RACLE_H0ME} - Vopt/ORACLE/product": print qq|Content-type: text/html\n\n|: print qq|<HTML><HEAD><TITLE>generate a graph</TITLE>
<meta http-equiv - "Pragma" Content - "no-cache"> <meta http-equiv * "Expires" Content - "Thu. Jan 1 1970 12:00:00 GMT"> </HEAD><BODY><Hl>generate a graph</Hl>|; if (SENV{'REQUEST J1ETH0D'} eq 'POST') { readCSTDIN. Sbuffer. $ENV{'CONTENT_LENGTH'}): @pairs = split(/&/. Sbuffer); foreach $pair (@pairs) { (Sname. Svalue) - split(/-/. $pair): Svalue — tr/+/ /: Svalue — s/S([a-fA-F0-9][a-fA-F0-9])/pack("C". hex($l))/eg: $contents{Sname} - Svalue: } } Smachine - $contents{"machine"}: Sparameter « $contents{"parameter"}: Sdaterange - Scontents{"daterange"}: if (Smachine && Sparameter && daterange) { Vbin/rm tmp/*.gir: Sdbh « DBI->connect("dbi:Oracle:myinstance", "mylogin". "mypassword") or die "Can't connect to Oracle: SDBI::errstr\n": Ssql - "select to_char(timestamp. 'YYYY MM DD HH24 МГ). Sparameter from rstat ": if (Sdaterange eq "today") { Ssql .- "where timestamp between trunc(sysdate) and sysdate and machine»'Smachine' ": if (Sdaterange eq "yesterday") { Ssql .- "where timestamp between trunc(sysdate) - 1 and trunc(sysdate) and machine»'Smachine'": if (Sdaterange eq "t-7") { Ssql .- "where timestamp between trunc(sysdate) - 7 and sysdate and machine»'Smachine'": if (Sdaterange eq "t-30") { Ssql .- "where timestamp between trunc(sysdate) - 30 and sysdate and machine»'Smachine'": if (Sdaterange eq "t-365") { Ssql .« "where timestamp between trunc(sysdate) - 365 and sysdate and machine-'Smachine'":
$sth « $dbh->prepare($sql); $sth->execute( ) || print $dbh->errstr: (Stimestamp. $item) - $sth->fetchrow_array: # проверяем наличие данных if ($t>imestamp) { $date - 'date*; chop $date; open(GP. "|/usr/local/bin/gnuplotH): print GP $gp_cmd; print GP qq| set xdata time set timefmt "*Y %m %6 %H SM" set term gif set xlabel "graph made on $date" set bmargin 4 set ylabel "Sparameter" set output "tmp/$$.gif" plot '-' using 1:6 title "Sparameter on Smachine" with lines It 2 I: while(($timestamp. $item) - $sth->fetchrow_array) { print GP "Stimestamp $item\n"; } print GP "eXn"; •close(GP): $sth->finish( ): $dbh^disconnect or warn "acsiweba disconnect failed: $DBI::errstr\n": print "<p><img src-\"tmp/$$.gif\"><p>": print "graph was generated from this query:<p> $sql\n"; } else { print "Sorry. I do not have the requested data for that time range for Smachine."; } } print qq| <F0RM METH0D=MP0ST" ENCTYPE-Happlication/x-www-form-urlencoded"> <P>select a machine <SELECT NAME«"machine"> <0PTI0N SELECTED VALUE-"venus">venus database <0PTI0N VALUE«"mars">mars backup database OPTION VALUE«"pluto">pluto middleware <0PTI0N VALUE«"saturn">saturn nfs <0PTI0N VALUE="earth">earth middleware
</SELECT> </P> <P>select a parameter <SELECT NAME-Mparameter"> <OPTION SELECTED VALUE="usr">user cpu <OPTION VALUE-"wio">wait io cpu OPTION VALUE-"sys">system cpu OPTION VALUE=Hidl">idle cpu OPTION VALUE-"pgin">pgs in per second OPTION VALUE-"pgout">pgs out per second OPTION VALUE-"intr'^interrupts per second OPTION VALUE»"ipkts">network in pkts per second OPTION VALUE-"opkts">network out pkts per second OPTION VALUE="coir>conisions per second OPTION VALUE^'cs'^context switches per second OPTION VALUE-oad">load: procs waiting to run </SELECT> </P> <P>select a date range <SELECT NAME-'daterange'^ OPTION SELECTED VALUE-иtodayH>today OPTION VALUE«"yesterday">yesterday OPTION VALUE-"t-7">last 7 days OPTION VALUE-4-30">last 30 days OPTION VALUE«"t-365">last 365 days </SELECT> </P> <P> <INPUT TYPE«"submit" NAME«"graph" VALUE-"graph"> </p><HR><P>|; print qq|</FORM>Questions? Write <A HREF»"mai1 to:p\@patrick.net">p\@patrick.net</A> </B0DY></HTML>|; Контроль статистики процессов Очень важно знать, какие процессы используют большую часть процессорного времени или других ресурсов компьютера. Демон rpc.rstatd, упомянутый ранее, не выдает информации о процессах. Коммерческие программы, такие как Measureware, требуют установки потенциально «глючных» удаленных агентов для получения информации о процессах, а данные хранятся ими в патентованных форматах. Часто бывает неприемлемо устанавливать неизвестные программы на важных рабочих компьютерах, а использование патентованного (то есть закрытого) формата никогда не может считаться преимуществом. В этом разделе мы рассмотрим альтернативные бесплатные программы, предназначенные для получения тех же данных с веб-сервера и сервера telnet с помощью сценария Perl.
Использование CGI для запуска программных средств Несложно создать программу CGI, которая будет запускать ps, vmstat, sar, top или любую другую программу системного контроля, предназначенную только для использования локальными пользователями. Например, работая с Apache, вы можете скопировать файл /bin/ps в каталог /home/httpd/cgi-bin/nph-ps и получить таким образом версию ps, которую можно напрямую запускать из веб. Префикс nph- добавляется для того, чтобы веб-сервер не ожидал наличия заголовков и не добавлял их сам. В противном случае веб-сервер будет ожидать появления заголовка content-type в выводе программы ps и сообщит об ошибке, поскольку ps такого заголовка не выдаст. Заголовок nph- сообщает Apache, что беспокоиться о заголовках не следует («nph* обозначает «nonparsed headers» — «необрабатываемые заголовки»). В результате получившийся документ будет отображаться браузером не слишком прилично, но, по крайней мере, его можно будет обработать с помощью сценария. Вы можете также написать программу CGI, которая будет вызывать ps, добавлять нужный заголовок и выполнять другие операции по обработке, но при этом каждый раз будет порождаться один лишний процесс. Я запускал ps в качестве CGI с помощью очень маленького веб-сервера mat- hopd с сайта http://www.mathopd.org/. Документация по этому веб-серверу практически отсутствует, распространяется он в исходных кодах, но достаточно прост. Сервер прекрасно компилируется в Linux, но требует некоторой доводки в Solaris, где его необходимо компилировать с ключами —InsI и -Isocket. У этого сервера есть преимущество: он даже меньше, чем Apache, выполняется в одном процессе и не запрашивает дополнительную память после запуска. Я имею достаточно веские основания, чтобы утверждать, что в этой программе нет утечек памяти, но в любом случае несложно написать задачу для демона сгоп, которая будет убивать этот сервер каждую ночь и перезапускать его заново, если возможность утечки памяти вас беспокоит. Сервер mathopd однопоточен. Если вы направите его журнал в /dev/null, то он не будет потреблять место на диске. Скомпилированная копия его находится на моем веб-сайте по адресу: http://patrick. net/software/. Включение подробного анализа с помощью rstat Приведенный в листинге 4.11 сценарий отслеживает использование процессора, и если доля времени бездействия падает ниже пороговой величины, сценарий запускает программу ps как CGI и отправляет результат ее работы администратору системы, который таким образом может определить, какой именно процесс загружает систему больше всего. Этот сценарий можно вызывать как задание демону сгоп или просто в бесконечном цикле. Я предпочитаю запускать его как задание сгоп, поскольку обычно либо долго работающие процессы становятся источниками утечек памяти, либо их просто убивают.
Листинг 4.11. Вызов ps при повышении процента использования ресурсов #!/usr/local/bin/perl use LWP::UserAgent; Sthresh «50; # пороговое значение использования процессора # пользователем, после которого вызывается ps Smachine = www.patrick.net: $\ - "\п": # добавляем перевод строки # выделение статистики использования процессора $_ - Vopt/bin/rstat Smachine4: (Syyyy. Smon. Sdd. $hh. Smm. $ss. $usr. $wio. $sys. $idl. Spgin. Spgout. Sintr. Sipkts. $opkts. Scoll. $cs. Sload) - split(/\s+/): if (Sidl < Sthresh) { print "Smachine is under $thresh\n": Sua - LWP::UserAgent->new: Srequest - new HTTP::Request С GET'. "http://Smachine/nph-ps"); Sresponse - Sua->request(Srequest): if (!Sresponse->is_success) { die Srequest->as_stnng( ). и failed: ". Sresponse->error_as_HTML: } open (MAIL. *|/bin/mail hostmaster@bigcompany.com'); print MAIL 'From: hostmistress@bigcompany.com': print MAIL 'Reply-To: hostmistress@bigcompany.com': print MAIL "Subject: Smachine CPU too high"; print MAIL "": print MAIL "CPU idle time is less than SthreshU on Smachine": print MAIL "Here are the top 10 processes by CPU on Smachine"; print MAIL Sresponse->content: print MAIL "\nThis message generated by cron job /opt/bin/watchcpu.pl": close MAIL: } Работа с Telnet в языке Perl Запуск веб-сервера для сбора статистики требует установки программ на работающих компьютерах, которой следует избегать по многим причинам. Новые программы могут вызвать утечку памяти или других ресурсов, создать бреши н системе безопасности; да и вообще это лишняя головная боль. К счастью, все, что нужно для создания вполне приличной системы контроля, — разрешение на использование средств и интерфейсов, которые, скорее всего, уже установлены. Это демон rstatd, SQL, SNMP и Telnet. Они, вероятно, не будут работать сквозь брандмауэр, в отличие от средств, основанных на веб-сервере, но система контроля в большинстве случаев находится (и должна находиться) по ту же сторону брандмауэра, что и веб-сервер. Самым гибким из всех интерфейсов является Telnet, поскольку в сеансе Telnet можно сделать все, что может сделать пользователь, сидящий за клавиату-
рой компьютера. В листинге 4.12 приведен пример сценария, который входит в систему на компьютере, чье имя указано в командной строке, запускает ps и записывает результаты в стандартный поток вывода. Листинг 4.12. Работа с ps через Telnet #!/usr/local/bin/perl use Net::Tel net; $host = $ARGV[0]; $user - "patrick"; Spassword - "passwd"; my Stelnet - Net;:Telnet->new($host): $telnet->1ogin($user. Spassword); my ©lines - $telnet->cmdGusr/bin/ps -o pid.pmem.pcpu.nlwp.user.args"); print ©lines; $telnet->close; Возможность запускать из Telnet программы и использовать их вывод в сценарии Perl очень полезна, но и ее можно использовать неправильно — например, запустив множество таких сценариев из заданий сгоп. На вход в систему расходуется небольшой участок места на диске (например, в Linux запись о входе делается в журнале /var/run/utmp). Следите за тем, насколько вы загружаете систему своим контролем, иначе сами станете виновником проблем с производительностью. Чтобы завершить создание системы контроля производительности процессов с использованием telnet и ps, нам нужно научиться сохранять данные в реляционной базе данных. Для этого необходимо определить таблицу. Вот пример такого определения, позволяющего хранить данные ps в Oracle. Я использую ее для хранения данных, возвращаемых командой Solaris /usr/bin/ps -о pid,pmem,pcpu, nlwp,user,args. create table ps( machine varchar2B0). timestamp date not null. pid numberF). pmem numberO.l). pcpu numberO.l). nlwp numberE). usr varchar2(8). args varchar2B4) ); А в листинге 4.13 приведен сценарий на языке Perl, который может подключаться к компьютерам через Telnet, запускать ps и сохранять выводимые этой программой результаты в базе данных. Листинг 4.13. Сохранение результатов работы ps в БД (работа через Telnet) #!/usr/local/bin/perl $ENV{0RACLE_H0ME} - Vopt/ORACLE/product";
use DBI: use Net: -.Telnet: $user = "patrick": $pwd - "telnetpasswd"; $machine = $ARGV[0]: my $telnet - Net:-.Telnet->new($machine); $telnet->timeoutD5): $telnet->login($user.$pwd): my @lines - $telnet->cmd('/usr/bin/ps -e -o pid.pmem.pcpu.nlwp.user.args'): $telnet->close: $dbh = DBI->connect("dbi:Oracle:acsiweba". "patrick". "dbpasswd") or die "Can't connect to Oracle: $DBI::errstr\n": foreach (@lines) { # Выкидываем строки формата # PID SMEM «CPU NLWP USER COMMAND # # и помещаем значения полей в БД вида # # Name Null? Type # # MACHINE VARCHAR2B0) # TIMESTAMP NOT NULL DATE # PID NUMBERF) # PMEM NUMBERC.1) # PCPU NUMBERC.1) # NLWP NUMBERE) # USR VARCHAR2(8) # ARGS VARCHAR2B4) if (/(\d+) +(\d+\.\d) +(\d+\.\d) +(\d+) +(\w+) .*Didentifier-(\w+)/) { $sth = $dbh->prepare("insert into ps values C$machine\ sysdate. "$Г. '$2*. •$3\ '$4'. '$5'. ^б")"): $sth->execute( ): } } $dbh->disconnect or warn "Disconnect failed: $DBI::errstr\n": Генерация графиков из результатов работы ps Вот мы поместили все результаты работы ps в базу данных. Что теперь с ними делать? Разумеется, строить графики, как мы поступали с данными rstat. В листинге 4.14 приведен пример сценария CGI, который будет заниматься именно этим, а ниже, на рис. 4.3, — график, созданный с его помощью. Чтобы запустить сценарий, поместите его в каталог cgi-bin вашего веб-сервера, после чего запро-л сите соответствующий ему URL с помощью браузера.
Листинг 4.14. Построение графика (CGI) #!/usr/local/bin/perl use DBI: $ENV{0RACLE_H0ME} - "/opt/ORACLE/product": print qq|Content-type: text/html\n\n|: #<meta http-equiv - "Pragma" Content - "no-cache"> #<meta http-equiv - "Expires" Content - "Thu. Jan 1 1970 12:00:00 GMT"> print qq|<HTMLxHEADxTITLE>generate a graph</TITLE> </HEAD><BODY><Hl>generate a graph</Hl>|: if (SENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN. Sbuffer. SENV{'CONTENT_LENGTH'}): ©pairs - split(/&/. Sbuffer): foreach Spair (@pairs) { (Sname. lvalue) - split(/-/. $pair); lvalue — tr/+/ /: lvalue — s/*([a-fA-F0-9][a-fA-F0-9])/pack("C\ hex($l))/eg: $contents{Sname) - Svalue: } ) Smachine - $contents{"machine"}: Sargs - Scontents{"args"}: Sdaterange - Scontents{"daterange"}: Sparameter - Scontentsj"parameter"}; if (Smachine && Sparameter && daterange) { Vbin/rm tmp/*.gif4: # possible removal of someone else's gif before they saw it $dbh - DBI->connect("dbi:Oracle:acsiweba". "patrick". "dbpasswd") or die "Can't connect to Oracle: SDBI::errstr\n"; Ssql - "select to_char(timestamp. 'YYYY MM DD HH24 МГ). Sparameter from patrick.ps if (Sdaterange eq "today") { Ssql .« "where timestamp between trunc(sysdate) and sysdate and machine-'Smachine'"; } if (Sdaterange eq "yesterday") { Ssql .- "where timestamp between trune(sysdate) - 1 and trunc(sysdate) and machine-'Smachine'": } if (Sdaterange eq "t-7") {
Ssql .« "where timestamp between trunc(sysdate) - 7 and sysdate and machine=,$machine'"; } if ($daterange eq "t-30") { $sql .« "where timestamp between trunc(sysdate) - 30 and sysdate and machine-'Smachine"": } if ($daterange eq "t-365") { $sql .« "where timestamp between trunc(sysdate) - 365 and sysdate and machine»'Smachine'": } $sql .- " and args-'Sargs'": fprint "<p>start of query ". %date4: $sth - $dbh->prepare($sql): $sth->execute( ) || print $dbh->errstr: (Stimestamp. Si tern) - Ssth->fetchrow_array; # get one sample row to be sure we have data if (Stimestamp) { #print "<p>end of query ", 4date4: Sdate - 4date'; chop Sdate: open(GP. "|/usr/local/bin/gnuplot"): print GP Sgp_cmd: print GP qq| set xdata time set timefmt "XY %m Xd %Н *M" set term gif set xlabel "graph made on Sdate" set bmargin 4 set уlabel "Sparameter" . set output "tmp/SS.gif" plot '-' using 1:6 title "Sargs Sparameter on Smachine" with lines It 2 I: while((Stimestamp. Si tern) - Ssth->fetchrow_array) { print GP "Stimestamp Sitem\n": } print GP "e\n": close(GP): $sth->finish( ): Sdbh->disconnect or warn "acsiweba disconnect failed: SDBI::errstr\n":
fprint "<p>end of plotting ". 'date4: print "<p><img src-\"tmp/$$.gif\"><p>"; print "graph was generated from this query:<p> $sql\n"; } else { print "Sorry. I do not have the requested data for that time range for Smachine.": } } print qq| <F0RM METH0D-"P0ST" ENCTYPE-"application/x-www-form-urlencoded"> <P>select a machine <SELECT NAME-"machine"> <0PTI0N SELECTED VALUE-"mars">mars middleware <0PTI0N VALUE»"venus">venus middleware <0PTI0N VALUE-"mercury">mercury middleware </SELECT> </P> <SELECT NAME-"args"> <0PTI0N SELECTED VALUE-"purchase">purchase app <0PTI0N VALUE-"billing">billing app <0PTI0N VALUE-"accounting">accounting app </SELECT> </P> <P>select a parameter <SELECT NAME-"parameter^ <0PTI0N SELECTED VALUE-"pmem">pmem OPTION VALUE-"pcpu">pcpu OPTION VALUE-"nlwp">nwlp </SELECT> </P> <P>select a date range <SELECT NAME-"daterange"> OPTION SELECTED VALUE-"today">today OPTION VALUE-"yesterday">yesterday OPTION VALUE-"t-7">last 7 days OPTION VALUE-,,t-30">last 30 days OPTION VALUE-"t-365">last 365 days </SELECT> </P> <P> <INPUT TYPE-"submit" NAME-"graph" VALUE-"graph"> </P><HR><P>|; print qq|</FORM>Questions? Write <A HREF-"mailto:p\(apatrick.net">p\@patrick.net</A> </BODYx/HTML>|; На рис. 4.3 приведен пример графика, построенного этим сценарием. Из графика видно, что одно из приложений вызывает утечку памяти. Видны на нем и результаты перезапуска системы 11.03 и 11.07.
Рис. 4.3. График результатов ps Контроль прочих параметров Вы можете контролировать не только время ожидания, но и содержимое вебстраниц. Например, сервер приложений Weblogic позволяет обратиться к защищенной паролем веб-странице, на которой отображается количество используемых подключений к базе данных в любой момент времени. Эта страница ориентирована на восприятие человеком, но если знать, каким образом можно автоматически обрабатывать содержимое веб-страниц, мы сможем извлечь из этой страницы данные и записать их в журнал, после чего даже построить график. Мы можем перехватить заголовок, содержащий идентификатор пользователя и его пароль, закодированные в формате MIME. В листинге 4.15 приведен пример сценария, загружающего страницу Weblogic T3AdminJDBC, выделяющего из нее количество используемых подключений и записывающего эти данные в файл. Листинг 4.15. Работа с сервером Weblogic: получение данных из веб-страницы #!/usr71ocal/bin/perl use LWP::UserAgent: use HTTP::Headers: use HTTP::Request:
use HTTP::Response: Sgnuplot - "/usr/local/bin/gnuplot": MAIN: { Sua - LWP::UserAgent->new: $ua->timeoutF0); # Тайм-аут 1 минута &get("http://$ARGV[0]/T3AdminJDBC"): s/<.*?>/ /g: # удаляем все теги HTML /cxn_pool +(\d+) +(\d+)/: # ищем нужную строку &1од("схп_рооГ. $1. $2): 'Sgnuplot *.дрч: } sub get { local ($url) - @_; Srequest - new HTTP:: Request С GET'. "SurD; # Имя пользователя и пароль (в формате Base 64). $request->push_header("Authorization" »> "Basic slkjSLDkf98aljk98797"); Sresponse - $ua->request($request): if (!Sresponse->is_success) { #die $request->as_string( ). " failed: ". Sresponse->error_as_HTML: # LWP считает HTTP-перенаправление ошибкой. } # Помещение ответа в строку для удобства проверки $_ - Sresponse->content: } # Запись журнала в формате, удобном для построения графика gnuplot. sub log { local (Sfile. Sconnections. Spool) - @_; Sdate - 4date +'XY Xm Xd %H XM XS"; chop Sdate: # Соответствующая команда gnuplot: set timefmt "XY %m Xd XH XM XS": openCFH. "»Sfile") || die "Could not open Sfile\n": printf FH "Sdate Sconnections Spool\n": close(FH): } Записав данные в файл, мы можем построить график, изменив соответствующим образом содержимое конфигурационного файла gnuplot.
set term png color set output "connections.gif" set xdata time set timefmt "SH ZM %S" set xrange [0 00 00м:4 00 00"] set xlabel "mountain time" set format x "%H:%H" set bmargin 3 set ylabel "connections" set yrange [0:100] plot "connections.log" using 4:7 title "connections" w 1 It 3 В результате получается график, аналогичный приведенному на рис. 4.4. Рис. 4.4. График количества активных подключений к базе данных в течение дня. Утечек нет Мы можем сохранить данные о количестве подключений в самой базе данных так же, как мы сделали это с данными ps. После этого нужно будет изменить сценарий динамической генерации графика для построения этих данных. Это очень полезно при поиске «утечек» в пуле подключений, то есть таких подключений, которые не освобождаются после завершения работы с ними. Обычно это происходит из-за плохой обработки ошибок, когда ошибка приводит к сбою программы. На рис. 4.5 показан пример 30-дневного графика, полученного с помощью сценария CGI. Видно, как ведут себя подключения к базе данных между перезапусками сервера приложений Weblogic (сервер перезапускался в 13.10, 25.10, 30.10 и 11.03).
Рис 4.5. Количество подключений к базе данных. Видна утечка Контроль с помощью Java Вам не обязательно пользоваться языком Perl только потому, что он нравится мне. В листинге 4.16 вы найдете пример программы на Java, которая следит за количеством продаж первого издания этой книги на сервере Amazon.com. Я написал программу на языке Perl, которая делала то же самое, а Ян Дарвин, автор книги «Java Cookbook», показал мне, что на Java это сделать ничуть не сложнее. Благодарю его за приведенный ниже пример. Листинг 4.16. Программа на Java, анализирующая содержимое веб-страницы import Javaло.*: import com.darwinsys.util.FilelO; import java.net.*: import Java.text.*: import java.util.*: import org.apache.regexp.*: /** График статистики продаж книги с сайта интернет-магазина. * @автор: Ян Дарвин. ian@darwinsys.com, автор книги Java Cookbook. * почти дословный перевод с Perl на Java. * @автор Патрик Киллелиа <p@patrick.net>: оригинальная версия на Perl. * из второго издания книги "Web Performance Tuning".
* (aversion $ld: BookRank.java.v 1.10 2001/04/10 00:28:02 ian Exp $ */ public class BookRank { public final static String ISBN = 937175307": public final static String DATA_FILE - "lint.sales": public final static String GRAPHJILE - "lint.prig": public final static String TITLE - "Checking С Prog w/ Lint": public final static String QUERY = " "http://www.quickbookshops.web/cgi-bin/search?isbn=": /** Считывание данных с веб-страницы и занесение в журнал */ public static void main(String[] args) throws Exception { // Поиск строк следующего формата: // <b>QuickBookShop.web Sales Rank: </b> // 26.252 // </font><br> // Исходная формулировка Патрика Киллелиа: поиск числа с запятой. // вывод без запятой и пробела".". Пропускаются числа меньше 100.000. RE г - new RE(" Sales Rank: </b>\\s*(\\d*).*(\\d+)\\s"): // В Java: приходится использовать "[\d.]+" для выделения числа, // вызов NumberFormat.getlnstanceO.parseC ) для преобразования // к типу int. // Соединяемся с адресом URL и создаем класс Reader. BufferedReader is - new BufferedReader(new InputStreamReader( new URLCQUERY + ISBN).openStream( ))): // Ищем нужную строку в виде одной длинной строки. String input - FilelO.readerToString(is): // Если число найдено, оно записывается в журнал, if (r.match(input)) { PrintWriter FH - new PrintWriter( new FileWriter(DATA_FILE. true)): String date - // 'date +'*m *d *H *M %S *Y'4; new SimpleDateFormatCMM dd hh mm ss yyyy "). format(new Date( )): // Paren 1 - число тысяч. РагепB) - последние три знака. FH.println(date + r.getParen(l) + r.getParenB)): FH.close( ): } // Вне зависимости от того, были получены новые данные или // нет. строим график всех имеющихся данных с помощью внешней // программы. Можно использовать gnuplot. R или любую другую // аналогичную программу. Еще лучше - графические API Java. String gnuplot_cmd - "set term png color\n" + "set output V" + GRAPHJILE + "\"\n" + "set xdata time\n" +
"set ylabel \"Book sales rank\H\n" + "set bmargin 3\nH + "set logscale y\n" + "set yrange [1:60000] reverse\n" + "set timefmt \M*Y %т %6 %H SM *S\"\n" + "plot \"" + DATAJILE + "\" using 1:7 title \"H + TITLE + "\" with lines\n" Process p - Run ti me. get Runt i me ( ).exec('7usr/local/bin/gnuplot"): PrintWriter gp - new PrintWriter(p.getOutputStream( )): gp.print(gnuplot_cmd): gp.close( ): } } А вот оригинал на языке Perl (листинг 4.17). Листинг 4.17. Программа на Perl, анализирующая содержимое веб-страницы #!/usr/local/bin/perl -w # Настройка агента и прокси-сервера. # use LWP::UserAgent: Sua - LWP::UserAgent->new: $ua->proxy('http'. 'http://httpprox:8080'): # Получение данных и запись их в журнал. # $url - ,,http://www.ama2on.com/exec/obidos/ASIN/1565923790/и: Srequest - new HTTP:-.Request С GET*. "SurD: Sresponse - $ua->request($request): $_ - $response->content; mjAmazon.com Sales Rank: </b>\s*(\d*).*(\d+)\s|s && do { open(FH. "»wpt.sales") || die "Could not open wpt.sales\n"; Sdate - 'date +'%m %6 SH *M %$ *Y": chop $date: printf FH "Ss Ss\n". Sdate. $1.$2: close(FH): }: тйштттшшнш # Обновление графика . # нтмтнтиттм $gnuplot_cmd - qq| set term png color set output "sales.png" set xdata time set ylabel "Amazon sales rank"
set bmargin 3 set logscale у set yrange [1:30000] reverse set timefmt "*m %6 SH *M %S %У1 plot "wpt.sales" using 1:7 title "web performance tuning" with lines I: open(GP. "|/usr71ocal/bin/gnuplotM): print GP $gnuplot_cmd: close(GP): Приборная панель на веб-странице Настроив обновление нескольких графиков с помощью заданий сгоп, вы можете решить, что можно поместить эти графики на всеобщее обозрение, чтобы те, кого это интересует, могли на них посмотреть. В листинге 4.18 приведен текст HTML, который поможет вам это сделать. Он создает квадратную таблицу с четырьмя изображениями. Листинг 4.18. Таблица с четырьмя графиками (код HTML) <html> <head> <title>System Dashboard http://patrick.net/graphs.html</tit1e> <meta http-equiv - "Refresh" Content - 00"> <meta http-equiv - "Pragma" Content - "no-cache"> <meta http-equiv - "Expires" Content - "Тли. Jan 1 1970 12:00:00 GMT"> </head> <body bgcolor="#ffffff"> <tab1e co1s=2> <tr> <td><IMG SRC="users.png"></td> <td><IMG SRC-"purchases.png"x/td> </tr> <tr> <td><IMG SRC-"cpu.png"></td> <td><IMG SRC="disk.png"></td> </tr> </table> </body> </htm1> Число 300 означает количество секунд между обновлениями четырех графиков. Прочие теги МЕТА пытаются отключить кэширование в браузере, из-за которого графики могут долго не обновляться. Если у вас будет больше четырех графиков, вывести их на одной странице может быть тяжело, поэтому есть смысл переключаться между двумя страницами: <МЕТА HTTP-EQUIV = "Refresh" Content - 00:URL=http://patrick.net/moregraphs.htmV> Если вам не нравится видеть на приборной панели кнопки браузера, никакого отношения к веб-серверу не имеющие, вот вам файл HTML со сценарием на
языке JavaScript, выводящим окно приборной панели без всяких кнопок (листинг 4.19). Листинг 4.19. Вывод окна браузера без кнопок <html> <head> <title>Dashboard Launcher</title> </head> <body bgcolor="#ffffff"> <script language="JavaScript"> <!- function MM_openBrWindow(theURL.winName.features) { //v2.0 wi ndow.open(theURL.wi nName.features): } //-> </script> <a href-"index.htmlH one!ick=MMM_openBrWindow('graphs.html". *width=640.height=480.resizable=r)"> pop </body> </html> Внимание! Избыток контроля вреден для здоровья вашего сайта! Контролировать веб-сайт полезно, но слишком много хорошего — это уже плохо. Служба Keynote позволяет контролировать веб-сайты, обращаясь к ним с компьютеров, разбросанных по всей территории США. Если каждый их агент будет настроен на ежеминутное обращение к вашей странице, 60 агентов вызовут нагрузку, равную одному обращению в секунду. Система балансировки нагрузки Resonate также может обращаться к страницам один раз в минуту. И вы можете еще повысить нагрузку на сайт своим избыточным контролем. Старайтесь, чтобы процент возможностей системы, расходуемых на ее контроль, был невысок. SNMP Простой сетевой протокол управления (Simple Network Management Protocol — SNMP) представляет собой стандартный метод слежения за состоянием компьютеров, приложений и пропускной способности сети. Это бесценное средство оптимизации производительности. Протокол SNMP появился в сообществе
Unix, но сейчас он реализован для большинства платформ. Существует множество средств управления SNMP, из которых вы можете выбрать наиболее подходящее вам. Производят их компании HP, IBM, 3Com, Cabletron, Sun и Cisco. Вы можете избежать добавления трафика SNMP к трафику вашего веб-сайта, настроив отдельную сеть для управления по протоколу SNMP, хотя это будет стоить вам больших денег. Все контролируемые устройства и приложения называются агентами, и каждому сопоставляется база MIB (Management Information Base), определяющая контролируемые параметры и возможности управления, доступные агенту. RMON RMON (Remote MONitoring — удаленный контроль) — это база SNMP MIB для Ethernet, определенная документом RFC 1757 (ранее RFC 1271). RMON II может контролировать трафик HTTP и других протоколов уровня приложений и выдавать по ним статистику. RMON позволяет контролируемым приложениям сигнализировать об ошибках самостоятельно, чем отличается от традиционного механизма опроса, используемого SNMP. Многие коммерческие системы, такие как Tivoli, HP OpenView, Sun Netmanager, понимают и используют RMON. ARM Стандартный интерфейс измерения отклика приложений (Application Response Measurement API — ARM) дает возможность измерять потребление ресурсов конкретным приложением даже в распределенной среде. Он был разработан совместно компаниями Hewlett-Packard и Tivoli Systems. Это хорошая вещь, но требует от разработчиков использования API в своих программах. На данный момент весьма немногие производители делают свои программы ARM-совместимыми. Веб-сайт рабочей группы ARM находится по адресу: http://www.cmg.org/. Прочие ресурсы Приведу еще несколько веб-ресурсов, относящихся к измерению производительности. Это сайт Unpack, на котором Java сравнивается с Fortran (http://www.netlib.org/benchmarg/linpackjava/); сайт Netperf, на котором имеется большая база данных результатов измерения производительности, произведенного с помощью бесплатной программы Netperf (http://www.netperf.org/); наконец, сайт с данными о производительности Java (http://www.cs.cmu.edu/~jch/java/ benchmarks.html).
Основные рекомендации О Не доверяйте измерениям производительности, если они не являются предельно близкими к реальной ситуации, в которой будет работать ваш сайт. О Измеряйте реальную производительность веб-сайта, а не просто нагрузку на уровне системных ресурсов. Ведите журналы. О Не контролируйте слишком много параметров, иначе сами станете причиной части своих проблем.
5 Тестирование на нагрузку Тестирование веб-сайта на нагрузку необходимо для определения его возможностей, а также — что более важно — для выявления недостатков конфигурации и пограммного обеспечения, которые могут проявляться только при большой нагрузке (в особенности — неуловимых проблем многопоточного программирования, из-за которых сайт может зависнуть или отказать). После того как ббль- шая часть ошибок будет устранена, вы должны получить красивую логарифмическую кривую насыщения пропускной способности с ростом нагрузки или красивую экспоненциальную кривую запредельного нарастания времени ожидания при превышении нагрузкой возможностей вашего сайта. Подготовка к тестированию Хорошее тестирование на нагрузку требует долгой и тщательной подготовки. О Нужно создать тестовые учетные записи пользователей. О Таблицы баз данных и содержимое должны быть сравнимы с тем, что будет иметь место на практике. О Нужно синхронизировать параметры тестовых и рабочих систем. О Для тестирования необходимо подготовить реалистичный набор URL. О Следует обеспечить эмуляцию возможных скоростей клиентских линий связи. О том, какие URL запрашивают пользователи с вашего сайта, вы можете узнать из журналов, но на создание адекватного и реалистичного теста на основании данных журналов уходит слишком много времени. На самом деле в журналах просто недостаточно данных для воспроизведения поступающих запро-
сов, поскольку входные данные HTTP POST в журналы не записываются, как не записывается любая другая информация из заголовков HTTP. Помните, что в журналы заносится время завершения отправки ответа, а не время получения запроса. Это означает, что файлы журналов неточно отражают временное распределение запросов, поступающих на ваш сайт. Трудно обеспечить и эмуляцию реального распределения скоростей клиентских линий связи. Некоторые средства тестирования сайтов на нагрузку позволяют настраивать скорость эмулируемого модема, но общего алгоритма для этого не существует. Не существует также способа определить, насколько быстры ваши пользователи. Теоретически вы могли бы измерить время между получением запроса GET на файл HTML и получением последующего запроса GET с того же IP-адреса на изображение из этого файла HTML, но это слишком грубый метод измерения, поскольку в файлы журналов время записывается с точностью до секунд. Не забудьте сделать ограничение на количество открытых дескрипторов для каждого процесса на компьютере, предназначенном для генерации запросов, достаточно высоким, чтобы получить возможность реально генерировать нужную нагрузку. Обычно для этого хватает команды ulimit -n 1024. Не совершайте классическую ошибку, забывая об этом! Сначала запустите тест на время ожидания вообще без нагрузки, чтобы получить начало отсчета. Затем измеряйте время ожидания по мере роста нагрузки, чтобы проверить, не становится ли оно слишком большим в пределах тех нагрузок, на которые рассчитан ваш веб-сервер. Продолжайте выполнение тестирования до тех пор, пока время отклика не стабилизируется на каком-то значении. Попробуйте оставить систему в таком состоянии на несколько дней, чтобы выявить утечки памяти. Обязательно тестируйте все возможные ситуации с возникновением ошибок явно. Разработчики обычно предполагают, что ошибки будут возникать редко, и не слишком задумываются о производительности системы в случае их появления. Между тем большое количество ошибок может быть причиной крайне низкой производительности. Опасайтесь переустановки часов Во многих системах Unix постоянно работают демоны timed или xntpd, которые регулярно устанавливают на часах ядра правильное время в соответствии с данными, принимаемыми по сети от централизованного источника. Делается это с помощью системных вызовов adjtime и adjtimex. В обычной ситуации демоны точного времени очень полезны, но если корректировка часов произойдет в процессе тестирования, результаты могут оказаться неправильными. Представьте себе, что вы считываете значение текущего времени и начинаете измерения. Затем, по завершении измерения, вы снова считываете показания системных часов. Если же в это время часы были переставлены, вы можете получить даже отрицательную продолжительность операции (в том случае, когда конечное время окажется меньше начального). С моими собственными тестами это происходило много раз. Единственный способ обезопасить себя — завер-
шить демоны timed или xntpd на время выполнения тестов, убедившись, что их не запустит сгоп. Почему реальная производительность отличается от тестовой? Трудно обеспечивать полную синхронизацию тестовой системы с рабочей. У них имеется великое множество параметров, и если внутри хотя бы одной пары из них будет небольшое различие, производительность систем может оказаться отличающейся во много раз. Пусть ваши серверы работают под управлением Solaris. Вот что вы можете сделать, чтобы обеспечить хотя бы приблизительное их соответствие. О Обработайте вывод команды prtconf с помощью команды diff, чтобы проверить, нет ли отличий в конфигурации памяти, дисков или процессора. О Обработайте файлы /etc/system обоих компьютеров с помощью команды diff. О Распечатайте параметры баз данных и сравните их с помощью diff. О Сравните конфигурационные файлы сгоп или autosys, а также вывод команды ifconfig -а на обоих компьютерах. О Сравните параметры сети. В листинге 5.1 приведен небольшой сценарий интерпретатора, который выводит список параметров ndd. Листинг 5.1. Вывод параметров ndd for parm in 'ndd /dev/tcp \? | cut -fl -d" " | grep -v Jiash | grep -v status | grep -v \V do /usr/ucb/echo -n $parm /usr/ucb/echo -n " " ndd /dev/tcp $parm done Этот сценарий называется dumpndd.sh, а скачать его можно по адресу: http://patrick.net/software. Средства тестирования нагрузки Если веб-сайт не состоит из одного лишь текста, тестирование его на нагрузку может быть весьма сложным. Вы хотите знать, как поведет себя сайт, когда к нему одновременно обратится миллион пользователей с браузерами, но ни у кого нет достаточного оборудования для запуска миллиона браузеров на отдельных компьютерах. Поэтому большая часть тестов проводится с помощью небольших программ, эмулирующих браузеры. По мере увеличения реалистичности тестирования (загрузка изображений, использование HTTP 1.1, SSL и т. п.) эмуляторы по размеру начинают приближаться к самим браузерам. Самым реалистич-
ным решением является программа, управляющая реальным браузером, но это решение лишено масштабируемости. Другая проблема с эмуляторами заключается в том, что для написания тестирующего сценария вам часто приходится слишком глубоко анализировать веб-страницу Страницы, отправляющие содержимое, обычно вызываются с некоторыми параметрами, вводимыми пользователем. Эти параметры должны учитываться эмулятором. Вы можете записать сценарий с помощью прокси-сервера веб sprocket из главы 4, но в таком сценарии параметры не будут обобщены, в нем будут записаны только те конкретные параметры, которые вы укажете. Многие программы могут автоматически формировать тестовые сценарии в процессе веб-серфинга, но создаваемые ими тесты обычно управляют браузером, а это, как мы уже отмечали, лишает решение масштабируемости. Кроме того, проблему параметризации тестов все равно приходится решать пользователю. Написание собственных тестовых программ Если вы хотите проверить поведение сервера для сотни хитов (запросов), проще всего сделать это с помощью приведенного в листинге 5.2 сценария интерпретатора команд. Затем можно найти разность времени окончания и начала тестирования, поделить ее на 100 (число хитов) и получить количество хитов в секунду для вашего веб-сервера. Этот сценарий порождает для каждого хита новый экземпляр браузера lynx, поэтому он крайне неэффективен, да и время измеряет не слишком точно, — но, по крайней мере, вы видите, как легко написать простое средство тестирования на нагрузку на языке интерпретатора команд Unix. Листинг 5.2. Тестирование на нагрузку: сценарий интерпретатора команд #!/bin/bash CNT-0 date while [ 00й -ne H$CNT" ] do lynx -source http://patrick.net/ > /dev/null & CNT=*expr $CNT + Г done date Такую же программу можно написать на языке Java или Perl и получить более точные результаты и более серьезную нагрузку благодаря устранению задержек из-за запуска браузера lynx. В листинге 5.3 приведен простой однопоточный сценарий на языке Perl, обращающийся^ к странице, затем ожидающий 1/80 часть секунды, снова обращающийся к странице и так далее 100 раз. Если бы страница загружалась бесконечно быстро, мы получили бы 80 хитов в секунду. Затем сценарий делает то же самое с задержкой 1/79 секунды и так далее до достижения задержки между обращениями величиной в 1 секунду. Теоретически это должно давать красивую кривую нагрузки для любой страницы, которая при низкой частоте обращений возрастает линейно, а затем выходит на насыщение по мере приближения к пределу производительности веб-сервера.
Листинг 5.3. Тестирование на нагрузку: сценарий на языке Perl #!/usr71ocal/bin/perl -w use LWP: rllserAgent; use Time::Hi Res 'time*.'sleep*: Sua » LWP::UserAgent->new; Srequest - new HTTP:: Request С GET'. "http://1ocalhost/index.html"): Shits - 100: Shps - 80: # Try to do 100 hits at 80 hits per second, then 100 at 79 hits per second. ... while (Shps) { Si - Shits: Sstart - time( ): while (Si-) { Sua->request(Srequest): sleep A/Shps): } Send - time( ): print "Shps ". Shits / (Send - Sstart). "\пи; Shps-: } Проблемы с таймером Когда я запустил этот тест, кривая оказалась вовсе не такой гладкой, как я рассчитывал. На рис. 5.1 показан результат. Рис. 5.1. Кривая нагрузки при наличии проблем с таймером
Вы видите, что производительность перестает расти, но мне кажется, что это происходит слишком резко. Откуда берется такая ступенька? Связано это с прерываниями таймера. Ядро измеряет время в сотых долях секунды. Это означает, что приостановка выполнения на 1/80 часть секунды реально длится ровно столько же времени, сколько и приостановка на 1/79 часть секунды, поэтому мы получаем тот же результат. Чтобы понять это, подумайте о том, что 1/80 равна 0,0125, а 1/79 — это 0,0127. Отличие в 0,0002 с, а мы можем измерять время лишь с разрешением 0,01 с. К счастью, прерывание таймера можно настроить. В Linux для архитектуры Intel для этого нужно изменить одну строку в файле /usr/include/asm/param.h: #define HZ 100 Я изменил это значение на 1000 и перекомпилировал ядро, чтобы проверить, смогу ли я вызывать команду sleep с разрешением в 1 мс. Изменение прерывания таймера имеет тот недостаток, что оно приводит к нарушению работы драйверов устройств, которые рассчитаны на конкретное значение этого прерывания, но их тоже можно перекомпилировать, если у вас есть исходный код, после чего драйверы должны снова заработать. В любом случае клавиатура прекрасно работала и без перекомпиляции драйвера. После этого я испытал более примитивную версию теста, измеряющую лишь возможности команды sleep. #!/usr71ocal/bin/perl -w $hps - 80; while ($hps) { Sstart » time( ): sleep (l/$hps): Send - time( ); print l/$hps. " ". Send - Sstart. "\n"; $hps-: } Запустив эту программу при частоте ядра 100 Гц и еще раз при частоте 1000 Гц, я получил результат, показанный на рис. 5.2. Теперь я мог вызывать команду sleep на 1 мс, а не на 10, как обычно. Изменение приоритета процесса не влияет на результаты. Точно так же не поможет использование альтернативного способа приостановки процесса с помощью оператора select языка Perl: select undef. undef. undef. (l/$hps): Подводя итоги, скажу, что возможность проведения тестов на нагрузку ограничивается разрешением таймера ядра. Уменьшение частоты замедлит систему по причинам, обсуждавшимся выше, да и чрезмерное увеличение частоты тоже приведет к замедлению, поскольку слишком много времени будет тратиться на обработку прерывания таймера. Лучше всего оставить значение таким, каким оно было изначально, если только вам не нужно поменять его для какого-либо конкретного теста.
Рис. 5.2. Более гладкая кривая нагрузки Тестирование на нагрузку при избыточном контроле В главе 4 мы обсуждали, как можно контролировать производительность вебсайта с помощью сценария Perl, написанного вручную либо автоматически с помощью прокси-сервера sprocket. Преимущество любого метода контроля, в котором не запускается браузер, состоит в том, что вы получаете хороший тест на большую нагрузку, запустив множество экземпляров контролирующей программы одновременно. Сценарии контроля, управляющие браузером, лишены этого преимущества. Компьютер Sun E450 с 1 Гбайт памяти может выполнять 300-500 копий сценария на Perl одновременно, не приближаясь к пределам своих возможностей (обычно заканчивается память). Хотя это не такой элегантный способ тестирования на нагрузку, как, скажем, многопоточное приложение, простота покрывает все его недостатки. Достаточно создать сценарий интерпретатора команд, который будет запускать 100 или около того сценариев контроля в фоновом режиме, — и вот вы получили столько же виртуальных пользователей. Каждый виртуальный пользователь должен вести запись в собственный файл. В противном случае при записи в один файл
данные могут перемешаться. Блокировка файла могла бы предотвратить это, но тогда замедлилась бы работа тестирующей программы. Сценарий интерпретатора мог бы выглядеть следующим образом: #!/bin/sh ./monitor.pl userOOl > resultsOOl & ./monitor.pl user002 > results002 & ./monitor.pl user003 > results003 & ./monitor.pl user004 > results004 & ./monitor.pl user005 > results005 & После завершения всех тестов результаты легко объединить в один файл с помощью команды cat % cat results* > aggregate Поработав еще немного, вы можете создать сценарий, который будет запускать сначала одного виртуального пользователя, потом двух, потом трех и так далее, измеряя среднее время ожидания с ростом нагрузки. Так вы можете получить классическую экспоненциальную кривую роста времени ожидания с увеличением количества пользователей. В листинге 5.4 приведен сценарий, который делает именно это. Листинг 5.4. Увеличение количества виртуальных пользователей #!/bin/bash # Это очень простой тест, в котором виртуальными клиентами являются процессы, а не # потоки. Обратите внимание, что в файлах результатов будет только одно число, если # вы обратитесь к sh вместо bash. Возможно, это указывает на наличие ошибки в sh. ulimit -n 1024 # start clean if [ -f results.1 ]: then /bin/rm results.*: fi if [ -f averages ]; then /bin/rm averages; fi # Тест запускается с RUN-1 пользователем, затем с 2 пользователями, затем # с 4 пользователями и так до МАХ пользователей. RUN-1 МАХ-1024 while С H$RUNH -le "$НАХ" ] do USER-1 # Start up RUN number of users, while [ "SUSER- -le "$RUNM ] do echo starting user SUSER tiny script » results.$RUN & USER-'expr SUSER + V done wait # ожидание завершения пользователей sleep 2 # для повышения точности
avg.pl results.$RUN » averages echo Done running $RUN users. RUN«4expr $RUN \* Г done Ниже приведен файл конфигурации gnuplot для построения результатов. На рис. 5.3 показаны сами результаты. set term gif set output "load.gif" set title "results of load test of CPU-bound process" set ylabel "time in seconds" set logscale x plot \ "results.1" using A):($1/1000000) notitle. \ "results.2" using B):($1/1000000) notitle. \ "results.4" using D):($1/1000000) notitle. \ "results.8" using (8):($1/1000000) notitle. \ "results.16" using A6):($1/1000000) notitle. \ "results.32" using C2):($1/1000000) notitle. \ "results.64" using F4):($1/1000000) notitle. \ "results.128" using A28):($1/1000000) notitle. \ "results.256" using B56):($1/1000000) notitle. \ "results.512" using E12):($1/1000000) notitle. \ "results.1024" using A024):($1/1000000) notitle. \ "averages" using B**$0):($1/1000000) title "average" with lines Рис 5.З. Среднее время ожидания
Синхронизация теста на нагрузку Если для эмуляции большого количества пользователей вы будете использовать большое количество процессов, которые должны будут одновременно делать одно и то же, вам придется столкнуться с проблемой синхронизации их действий. Самый простой способ одновременной отправки какого-то сигнала всем процессам — создание файла. Если все процессы заняты проверкой существования этого файла, они все обнаружат его появление приблизительно одновременно. Вот часть программы на Perl, которая проверяет наличие файла 10 раз в секунду. Папка /tmp в системе Solaris обычно находится в памяти, поэтому обращение к /tmp соответственно не требует обращения к диску. Учтите, что для вызова команды sleep с дробным значением количества секунд вам нужно установить пакет Time::HiRes: while (! -e "/tmp/go") { sleep 0.1: } Если все виртуальные клиенты выполняют эту строку, начать тестирование вы можете командой touch /tmp/go. Файл появится, и все процессы продолжат свое выполнение приблизительно в один и тот же момент. Более сложный способ синхронизации набора процессов состоит в отправке им сигнала. Если вы установите обработчик сигналов, все процессы войдут в него также приблизительно одновременно. Хаотическое тестирование на нагрузку Вам может понадобиться имитировать реальных пользователей, щелкающих по ссылкам случайным образом, с помощью пользователей виртуальных. Это легко можно сделать в Perl, добавив команду sleep rand(w) между действиями, где п — максимально возможное время случайной задержки. Как остановить тестирование? Иногда бывает нужно остановить все тестирующие процессы одновременно. Команда /bin/kill в Linux (не та команда kill, которая вызывается из интерпретатора обычно) убивает процессы по именам. Поэтому если у вас есть множество процессов с именем session, вы можете прикончить их все одной командой: % /bin/kill session Если у вас нет версии kill, завершающей процессы по имени, в листинге 5.5 приведен сценарий на языке Perl, который может это делать. Я назвал его zap. Вы можете скачать его по адресу: http://patrick.net/software/zap.pl. Листинг 5.5. Завершение процессов по имени #!/usr/local/bin/perl die "Usage: zap <proc name> [-9]\nH unless $ARGV[0]:
@procs » *ps -еГ: # Зависит от ОС. VICTIM: foreach $proc (@procs) { if ($proc — /$ARGV[0]/) { #($pid) = $proc — Г *(\d*).*/: # Solaris ($pid) - $proc — Пл ]+ *(\d*).*/: # Linux if ($pid eq $$) { next VICTIM; } # Себя не убей. if ($ARGV[1] — /-9/) { kill -9 $pid\- } else { print "$proc"; print "Kill this one? ": Sanswer - <STDIN>: if (Sanswer — /y/) { # Ответ, начинающийся с «у», считается # положительным kill $pid': } } } } Создание нагрузки на сеть Иногда бывает нужно проверить на нагрузку вашу сеть, а не веб-сервер. Создать нагрузку на сеть можно разными способами. Старая команда spray вышла из употребления и не распространяется больше с Red Hat Linux, но есть и другие программы. Некоторые из них перечислены ниже. О ping. У команды ping есть параметр flood, позволяющий нагрузить до предела, но крайней мере, Ethernet lOBaseT, если вы отправите пакет максимального размера F5 507 байт). Вот какой командой можно обратиться к IP-адресу 1.2.3.4 с максимальной частотой: % ping -f -s 65507 1.2.3.4 Помните, что это, по сути, атака типа «отказ в обслуживании» (Denial of Service — DoS attack), поэтому не пробуйте выполнить эту команду в сети, которой пользуются другие люди. О Netcat. Аналогичным образом можно воспользоваться бесплатной программой Netcat (nc), созданной Томасом Уэлдом. Копия дистрибутива имеется на моем веб-сервере по адресу: http://patrick.net/software/. Этот пример позволяет направить вывод команды yes на порт веб-сервера: % yes АААААААААААААААААА | пс www.webserver.com 80 > /dev/null
О chargen. Еще одно забавное и простое средство создания нагрузки — порт chargen. Вы можете обратиться к нему с помощью telnet, а затем направить вывод в /dev/null, чтобы нагрузить именно сеть, а не свой жесткий диск: % telnet testmachine chargen > /dev/null С помощью этих средств я смог достичь нагрузки в 86 Мбит/с на 100 Мбит/с линии Ethernet. Оценку я делал с помощью счетчиков пакетов ndd. Спецификации и эталонные тесты Нужно различать спецификации и эталонные тесты. Отдельные параметры можно тестировать несколькими способами, поскольку некоторые особенности реализации не влияют на результаты тестов. Например, нагрузка HTTP может быть одинаковой вне зависимости от оборудования и программ, использовавшихся для ее создания, и независимо от реально передаваемых битов содержимого. С другой стороны, некоторые спецификации целиком определяются тестовыми программами или пакетами, поэтому единственный способ проверить сайт — это запустить конкретную тестовую программу. В данном разделе мы рассмотрим и спецификации и тесты. Суть аттестации (benchmark) заключается в получении статистических данных о производительности, которые могут использоваться для сравнения продуктов. Для этого нужно обеспечить постоянство всех внешних условий для тестируемого объекта, после чего измерить его производительность. Если единственное отличие между измерениями — сам компонент, то и отличие в результатах должно быть связано только с самим компонентом. Точное определение тестируемого компонента может быть достаточно сложным. Например, вы пытаетесь сравнить производительность Solaris и Irix, на которых работают серверы Netscape. Переменными в названных тестах оказываются не только операционные системы, но и оборудование. По одному только эталонному тесту мы не сможем сказать, какие отличия связаны с операционной системой, а какие — с оборудованием. Вам пришлось бы провести анализ операционных систем и оборудования, что гораздо сложнее. Можно рассматривать эталонный тест как сознательное превращение тестируемого компонента в «узкое место» системы. Когда он оказывается самым слабым звеном, пропускная способность и время ожидания системы определяются только этим компонентом и отражают его свойства. Сложность в том, чтобы убедиться, что тестируемый объект действительно является самым слабым звеном, поскольку небольшие отличия в схеме тестирования могут сделать «узким местом» какой-либо другой компонент системы, как мы видели ранее при тестировании сети с помощью FTP. Например, если вы тестируете пропускную способность оборудования сервера, вам придется обеспечить гораздо большую пропускную способность сети, чем та, которая в принципе может понадобиться серверу, иначе результаты окажутся одинаковыми для любого оборудования (и равными полосе пропускания сети).
Один из недостатков эталонных тестов, измеряющих максимальную пропускную способность конкретных компонентов, — возможность некорректной экстраполяции, а именно выдвижения предположения, что производительность конфигурации линейно зависит от нагрузки в более широком диапазоне, чем это на самом деле есть. Хорошим примером является сервер с быстрой линией связи. Быстрым серверам нужно меньше памяти на то же количество соединений HTTP, поскольку соединения и процессы CGI на таком сервере являются короткоживущими. Чтобы получить десятую часть производительности сервера в сети, работающей в 10 раз медленнее тестовой скорости, вам понадобится более одной десятой памяти, чтобы памяти хватало на достаточное количество параллельно существующих соединений и процессов CGI, а также на саму операционную систему. Некоторые тесты могут быть невоспроизводимыми из-за особенностей сетей Ethernet, где количество коллизий есть величина случайная. В среднем результаты могут меняться незначительно, но два раза подряд одно и то же число вы не получите. Мораль в том, что нужно искать тест, отражающий в максимальной степени именно ту ситуацию, в которой вам предстоит работать. Если вы будете обслуживать пользователей с модемами на 56 кбит/с, найдите тест, который будет определять максимально возможное количество пользователей для вашего сервера именно с такими модемами, а не таких, которые подключаются по линии ТЗ. Внимательно читайте формулировку теста, прежде чем решать, что он вам подходит. Например, я часто тестирую физическую скорость оборудования моего сервера. Он не сдвинулся ни на дюйм за несколько месяцев, так что скорость у него нулевая. Однако в качестве веб-сервера он вполне хорош. Поскольку меня не волнует, может ли мой сервер двигаться, я не пользуюсь этим тестом в качестве эталонного. Как определить, чем будет заниматься ваш сервер в реальной работе, чтобы подобрать для него хороший тест? Лучше всего начать с файлов журналов. Они отражают именно реальную работу вашего сервера — по крайней мере, в терминах операций HTTP и количестве переданных байтов. Вы можете заменить про- фаммное обеспечение, операционную систему или оборудование какими-либо другими, дать серверу поработать некоторое время, а затем сравнить файлы Журналов. Однако этот способ может не отразить точных результатов, поскольку нагрузка со временем меняется, а периоды измерений могли совпасть с периодами пониженной активности пользователей. Журналы ничего не скажут о пиковой производительности сервера, поскольку они показывают только то, чего достиг ваш сервер на данный момент. Если же из журналов становится ясно, что со сменой компонента сервер смог выдержать значительно большую нагрузку (или перестал справляться с имеющейся), это уже кое-что значит. Внимательно относитесь к мелкому шрифту в описании тестов. Рассматри- ашйте тесты в свете теории информации. Если вы точно знаете, что вы получите, то это уже не информация. Задачей тестирования является проверка способности компьютера быстро обрабатывать информацию, то есть справляться с
реальной неопределенностью желаний пользователя. Если вы настроите всю систему так, чтобы для тестирования она давала наивысшие результаты, вы оставите слишком мало неопределенности, поэтому результаты не будут иметь никакого отношения к реальным пользователям системы. Одна из программ для тестирования, использованная создателями веб-сервера Zeus, работает именно в этом стиле. Она выдает запросы на один и тот же файл, который после первого же запроса кэшируется в памяти. По сути дела, этот тест иллюстрирует, насколько быстро сервер может принимать соединения и отправлять данные из буфера, а не показывает реальную скорость поиска нужного файла. Это напоминает мне историю, которую однажды рассказал мне друг во время занятий по программированию. Ему нужно было написать калькулятор, работающий с римскими цифрами. Он точно знал, какие тестовые задания будут предложены калькулятору для проверки его работоспособности, поэтому вместо того чтобы написать полезный калькулятор, что потребовало бы большой работы, он просто написал хэш-таблицу, в которой искался ответ на заданный вопрос. Представьте себе наивного создателя сайта, который не понимает, что его файл кэшируется браузером, запрашивает этот файл несколько раз и решает, что сервер способен передавать данные с огромной скоростью. Не стоит также искать или создавать тест, в котором ваш сайт будет хорошо выглядеть. Это все равно что выстрелить в мишень, а затем нарисовать «яблочко» вокруг стрелы. Называется такой метод «benchmarketing» (тестирование для рынка) и является, скорее, правилом, чем исключением, для поставщиков, которые полагаются на недостаток времени и желания у покупателей проверять методику тестирования. Если вы сравните противоречивые заявления поставщиков оборудования и программ для веб, то увидите, что в разных тестах измеряются разные параметры либо тесты просто настолько плохи и результаты вообще невозможно как-то трактовать. Ниже мы кратко рассмотрим некоторые стандартные эталонные тесты производительности веб. WebStone Первый тест для веб-серверов назывался WebStone и был разработан фирмой Silicon Graphics. WebStone имитирует действия множества клиентов, обращающихся к веб-серверу с множества компьютеров и запрашивающих один и тот же набор файлов. На каждом компьютере может работать несколько экземпляров программы-клиента. Последние версии WebStone способны тестировать производительность CGI и серверного API, а не только статического HTML. Программа WebStone обладает определенными недостатками. Правила тестирования не слишком жестки, поэтому они оставляют много возможностей для бенчмаркетинга, о котором говорилось выше. Клиентские компьютеры обычно подключаются к веб-серверу по 100 мегабитной сети, но скорость сети тестом не регламентируется. Набор файлов также достаточно мал и может быть кэширо- ван, а следовательно, производительность дисков при таком тестировании не обязательно учитывается.
Наконец, WebStone тестирует только HTTP GET, но не HTTP POST. (POST используется для отправки информации из форм на CGI.) Спецификация WebStone выложена в открытый доступ. Хорошее описание тестов лежит на сайте http://www.mindcraft.com/webstone/. Фирма Mindcraft, купившая WebStone от Silicon Graphics, запускает этот тест в популярных конфигурациях оборудования и программного обеспечения веб-серверов, после чего публикует результаты в веб. SPECweb99 Более суровый тест производительности веб-сервера поставляется корпорацией SPEC (Standard Performance Evaluation Corporation). Спецификация не распространяется бесплатно, но имеет значительные преимущества перед другими существующими тестами веб-серверов, поскольку правила выполнения более жесткие и включают, например, обязательное выполнение операций HTTP GET с файлами различного размера. Нагрузка моделируется так, чтобы соответствовать реально возможной для поставщика услуг Интернета. Что более важно, это единственный тест, не созданный производителем аппаратного или программного обеспечения для веб-серверов, поэтому у него меньше всего шансов оказаться изготовленным под конкретный продукт или конкретного производителя. Обратитесь к веб-сайту http://www.specbench.org/osg/web99/. Посетите также http://open.specbench.org/osg/web/results/ — там приведены некоторые результаты тестирования. Корпорация Spec публикует и результаты тестов для Java — см. http://www.spec.org/. ТРС-С и TPC-D Та же инфраструктура Интернета, которая позволяет пользователю запрашивать конкретный документ HTML, может, в принципе, использоваться для передачи серверу запросов на выполнение транзакций, таких как пересылка денег с одного счета на другой. К обработке транзакций предъявляются более серьезные требования, чем к обычным веб-службам, например обеспечение атомарности операций. Не может и не должно быть никакой неопределенности в том, заплатили вы по счету или нет. Обработка транзакций фундаментально отличается от работы сервера HTML и в смысле используемых протоколов, и в плане сложности. Разработаны тесты, предназначенные специально для систем обработки транзакций, которые существовали задолго до возникновения веб. Стандартные тесты называются ТРС-С it TPC-D. Они были созданы советом Transaction Processing Council. Самый «древний» из широко распространившихся тестов назывался debit—credit (дебет—кредит) и имитировал снятие денег со счета и помещение их обратно. Однако у него были серьезные недостатки, поскольку он был плохо специфициро- иан и позволял получить любые желаемые результаты, например, путем кэширования всех данных в памяти. Этот тест был вытеснен хорошо специфицированными тестами ТРС-А и ТРС-В, но на данный момент они уже устарели.
Результаты ТРС-С и TPC-D включают не только производительность, но также возможности масштабирования и общую стоимость владения. Более подробное описание средств тестирования систем обработки транзакций приведено на веб-сайте ТРС http://www.tpc.org/. Тесты прокси-серверов Тест Wisconsin Proxy Benchmark использует только протокол HTTP/1.0 без постоянных соединений. См. http://www.cs.wjsc.edu/^cao/wpbl.0.html. Ребята из Squid разработали собственный пакет для тестирования прокси- серверов, о котором можно получить сведения по адресу: http://www.ircache.net/ Polygraph/. Тесты производителей Для широко распространенных приложений, являющихся собственностью фирм-производителей, таких как SAP и Oracle Financials, часто бывает возможно использовать только тесты и результаты самих поставщиков. CaffeineMark Тест CaffeineMark для Java может использоваться как средство отладки. Он ненадежен, поскольку не проверяет вызовы методов, выделение памяти, синхронизацию или средства времени выполнения. Можно настроить приложения на Java так, чтобы тест CaffeineMark выдавал любые результаты. Тест этот был создан Pendragon. Прочие ресурсы Среди прочих веб-ресурсов, относящихся к тестированию, можно упомянуть сайт Unpack (где Java сравнивается с Fortran) http://www.netlib.org/benchmark/ linpackjava/ и страницу тестирования Java по адресу: http://www.cs.cmu.edu/~jch/java/ benchmarks.html. Некоторые виды атак могут использоваться и для тестирования. Среди них атаки типа Syn, Ping of Death, Land, Smurf. Есть много бесплатных хакерских программ, которые могут вызывать запредельную нагрузку различного рода; большая часть их предназначена для разрушения веб-серверов. Основные рекомендации О Не верьте тестам, если они не воспроизводят реальную ситуацию, в которой вы собираетесь работать. О Не забудьте увеличить ulimit для клиентов, генерирующих нагрузку.
6 Анализ производительности Самое важное, что вам нужно знать о своей системе, — это то, что, плохо разбираясь в системе, нельзя хорошо ее настроить. Сложные системы оказываются зависимыми от нескольких человек, которые действительно в них разбираются. 1;сли эти люди уйдут из фирмы, у вас возникнут большие проблемы. Еще одна загвоздка в том, что количество проблем растет гораздо быстрее, чем количество зависящих друг от друга «функций». Большее количество функций означает гораздо большее количество проблем. К счастью, всем веб-сайтам приходится до определенного уровня соответствовать некоторым стандартам, иначе с ними не могли бы работать разные браузеры. Благодаря этому в ваше распоряжение поступает несколько стандартных приемов для поиска проблем. Поиск «узких мест» с помощью analysis.cgi Первым шагом в поиске проблемы с производительностью является разбиение производительности на пять категорий: время поиска в DNS, время установки соединения, время молчания сервера, время передачи и время завершения соединения. Этапы всегда повторяются в одном и том же порядке. Я написал программу для автоматического хронометрирования каждого из этих этапов, ||юрмирования графика результатов и выдачи короткой рекомендации. Программа называется analysis.cgi и может быть запущена с моей домашней страницы http://patrick.net/. Просто введите URL в соответствующее поле, и программа попытается построить график для компонентов на этом URL. На рис. 6.1 приведен пример графика, построенного для моей собственной домашней страницы, й также рекомендация.
Рис 6.1. График, построенный analysfsxgl для patridc.net advice for http://patr1ck.net/ DNS I spent a cumulative 0.4052 seconds resolving hostnames. No problem with DNS. network It took a cumulative total of 0.0650 seconds to set up the connections to download your content. The average time to connect was 0.0325 seconds. The latency to make a connection to your site was OK. I spent 0.001? seconds closing the socket. server There was a cumulative 0.1334 seconds of server silence. The average period of server silence was 0.0667 seconds. Your server 1s using HTTP 1.1. which has better performance than HTTP 1.0. Good. content Your content was a total of 4984 bytes. Including headers. It would take at least 0.7120 seconds to download the content over a 56 Kbps modem. It would take at least 0.0791 seconds to download the content over a 500 Kbps DSL line. Your content size 1s well suited for surfing with a 56K modem: less than 3 seconds. Here are URLs of the 2 elements on the page, with server response headers:
http://patrick.net:80/webpt_sm.gif HTTP/1.1 200 OK Date: Mon. 23 Apr 2001 19:14:29 GMT Server: Apache/1.3.9 (Unix) Last-Modified: Tue. 07 Nov 2000 05:56:29 GMT ETag: "Haaa93-865-3a07998dM Accept-Ranges: bytes Content-Length: 2149 Connection: close Content-Type: image/gif http://patrick.net/ HTTP/1.1 200 OK Date: Mon. 23 Apr 2001 19:14:29 GMT Server: Apache/1.3.9 (Unix) Last-Modified: Sat. 03 Mar 2001 22:56:46 GMT ETag: Hllaaa81-929-3aal76aeM Accept-Ranges: bytes Content-Length: 2345 Connection: close Content -Type: text/html Multiple copies of the same element are counted only once, on the assumption that the browser is smart enough to reuse them, summary The total is 1.3168 seconds. The bottleneck was transmission. Отсюда мы видим, что «узким местом» является время передачи. Чтобы эта страница загрузилась быстрее, нужно загружать ее по более быстрому подключению — это наиболее эффективный способ повышения производительности. Размер содержимого D984 байт) и так достаточно мал, поэтому здесь заметного улучшения быть не может. Серверы в данном случае тоже ускорять бессмысленно, поскольку выигрыш от этого будет очень невелик. Рассмотрим общие рекомендации для пяти возможных «узких мест». О Если «узким местом» является DNS — значит — либо моему клиенту analy- sis.cgj должен быть указан более быстрый DNS-сервер, либо имя вашего вебсайта нужно более активно распространять по DNS-серверам сети Интернет, где оно будет кэшироваться. Более популярные сайты обычно работают несколько быстрее, поскольку их имена кэшируются на большем количестве серверов DNS. О Если «узким местом» является время установки соединения — значит, проблема наверняка с сетью. Возможно, в процессе установки соединения из-за перегрузки концентратора был утерян пакет. Нужно проверить маршрутизаторы, интерфейсы и кабели на наличие ошибок конфигурации и неполадок оборудования.
О Если «узким местом» является время молчания сервера — значит, сервер чем-то перегружен, и его работу можно заметно ускорить установкой более совершенного оборудования или оптимизацией серверного приложения или базы данных. О Если «узким местом» является время передачи — значит, слишком мала скорость подключения клиента или слишком велик объем передаваемого клиенту содержимого. О Если «узким местом» является время закрытия соединения — значит, проблема опять-таки связана с сетью. Подслушивание HTTP с помощью sprocket Часто бывает полезно следить за трафиком HTTP при получении веб-страницы. Это позволяет установить соответствие между активностью сети и тем, что вы видите в окне браузера. Одним из способов является настройка веб прокси-сервера на распечатку запросов и ответов HTTP по мере их передачи. Такой прокси-сервер можно бесплатно скачать по адресу: http://patrick.net/software/sproc- ket/sprocket. Распечатка всех пакетов HTTP включается с помощью ключа командной строки -d (dump — распечатка). Конечно, с защищенными соединениями SSL это не работает — иначе зачем был бы нужен этот уровень? Какое-то представление об отправляемом по SSL запросе можно получить с помощью трассировщика системных вызовов типа truss в Solaris или strace в Linux либо запустив браузер в отладчике (если у вас есть его исходный код). Исходный код браузера Mozilla можно скачать по адресу: http://www.mozilla.org/. Вот пример подслушанного с помощью sprocket трафика HTTP. Сервер sprocket запускается следующим образом: % sprocket -d При этом выводится сообщение, аналогичное приведенному ниже: set your proxy to <URL:http://localhost:8008/> установите адрес прокси-сервера <URL:http://localhost:8008/> Настройте свой браузер в соответствии с данной рекомендацией, после чего обратитесь к какой-нибудь веб-странице и наслаждайтесь результатом: GET http://vahe/ HTTP/1.0 Accept: image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. image/png. */* Accept-Charset: iso-8859-l.*.utf-8 Accept-Encoding: gzip Accept-Language: en Host: vahe User-Agent: sprocket/0.10 Proxy-Connection: Keep-Alive HTTP/1.1 200 OK Connection: close
Date: Mon. 23 Apr 2001 21:07:13 GMT Accept-Ranges: bytes Server: Apache/1.3.9 (Unix) (Red Hat/Linux) Content-Length: 2345 Content-Type: text/html Content-Type: text/html: charset=iso-8859-l ETag: ,,54802-929-3a967bd6" Last-Modified: Fri. 23 Feb 2001 15:03:50 GMT Client-Date: Mon. 23 Apr 2001 21:07:13 GMT Client-Peer: 127.0.0.1:80 Title: welcome to patrick.net X-Meta-DESCRIPTION: advice on increasing the performance of your web site X-Meta-KEYWORDS: web. performance, tuning, book <!DOCTYPE HTML PUBLIC M-//W3C//DTD HTML 3.2//ENH> <HTML> <HEAD> <TITLE>welcome to patrick.net</TITLE> И так далее. В принципе, при этом вы получаете достаточно сведений, чтобы хорошо представлять, что именно передается по проводам. В итоге это должно помочь вам найти способ уменьшения объема содержимого. Изучение соединений 1-лце один хороший способ постичь работу вашего сайта — слежение за соединениями в процессе их установки и завершения. Реализовать такую слежку можно, запустив команду netstat в бесконечном цикле на веб-сервере, связующем сервере или базе данных. В NT достаточно указать команде netstat количество секунд между повторными запусками. В Linux netstat нужно запустить с ключом -с, чтобы получать информацию о соединениях раз в секунду. Количество открытых подключений к базам данных часто может превышать сотню. Чтобы в списке присутствовали только новые соединения, необходимо включить ведение журнала приемника Oracle и выполнить команду tail -f <файл_жур- нала>. Теперь в журнал будут выводиться только новые соединения. Анализ файлов журналов И каком-то смысле у всех веб-серверов имеется встроенное средство контроля производительности — это программа ведения журналов самого сервера. Вебмастеру остается только правильно интерпретировать данные журналов. Формат «строка на передачу» не слишком удобен для анализа путем непосредственного чтения. Необходимость извлечения из файлов журналов максимума полезной ин- <|юрмации дала жизнь целой небольшой индустрии программных пакетов для
просмотра журналов и построения графиков. Примеры таких пакетов включают Interse, его бесплатный аналог net.Analysis (http://www.netgen.com/), а также встроенную программу analyze серверов Netscape. Эти программы полезны, но вы можете и просто импортировать журнал в электронную таблицу и с ее помощью построить множество различных графиков. Хорошая электронная таблица по графическим возможностям не уступает специализированным пакетам для обработки журналов, а преимущество у нее в том, что она у вас уже есть. Для предоставления администратору дополнительной информации некоторые веб-серверы используют расширенные форматы ведения журналов, записывая, в частности, реальное время завершения передачи. Кроме того, в журнал могут записываться IP-адреса или имена компьютеров клиентов. Разбросаны ли они по всему Интернету или находятся в интерсети, состоящей из 50 локальных сетей? Или все в одном здании? Если вы можете выяснить это из IP-адресов, то производительность можно будет повысить, разместив свои серверы вблизи мест с наибольшей концентрацией пользователей. Как можно узнать количество соединений в день и распределение их по времени дня? Если ваш веб-сервер уже работает, то он представляет собой отличный источник сведений о той нагрузке, на которую вам нужно рассчитывать, потому что журналы веб-сервера могут сообщить вам, какую часть полосы пропускания вы уже используете, растет эта доля или падает и как быстро. Конечно, может оказаться так, что в журналах будет отражена производительность «узкого места» системы, а не потенциальная ее мощность или уровень ожидании пользователей. Файлы журналов веб-серверов чаще всего ведутся в общем формате журналов (Common Log Format — CLF), и одна строка, соответствующая одной операции HTTP, содержит следующие поля в порядке перечисления: 1) доменное имя или IP-адрес запрашивающего компьютера; 2) имя пользователя; 3) пароль, если производится обращение к файлам с управлением доступом, а если иначе — дефисы; 4) дата обработки; 5) запрос клиента; 6) код ответа HTTP; 7) количество переданных байтов. Изучите содержимое файла modJog_config.html из дистрибутива Apache. В нем вы найдете более подробные сведения о формате файла журнала и возможных его изменениях. Apache позволяет записывать длительность соединения, a Netscape Enterprise — нет. Если вы включите один из дополнительных параметров журнала Netscape, он перестанет использовать кэш статических файлов, что скажется на производительности. Ни Netscape, ни Apache не включают заголовки в количество переданных байтов, поэтому результат вычисления пропускной способности будет несколько занижен, если вы будете вычислять полное количество переданных байтов непосредственно по данным журнала.
Например, вот строка журнала сервера NCSA: client8.isp.com - - [21/Aug/1997:16:56:57 -0500] "GET /recipe.html HTTP/1.0" 200 217 Вычислить количество завершенных HTTP-операций в секунду можно, подсчитав количество строк, относящихся к какому-нибудь временному интервалу, и поделив это количество на длительность интервала. Аналогичным образом можно получить пропускную способность в байтах в секунду, поделив количество байтов, переданных на протяжении некоторого временного интервала, на длительность этого интервала. В приведенном выше примере файл recipe.html имеет размер 217 байт, но нужно помнить, что сервер передал клиенту заголовки HTTP, которые в журнал не попали. Эти заголовки выглядят так: HTTP/1.0 200 Document follows Date: Sat. 30 Aug 1997 04:31:18 GMT Server: NCSA/1.4.2 Content-type: text/html Last-modified: Mon. 16 Dec 1996 04:51:12 GMT Content-length: 217 Данный заголовок сам по себе содержит 174 байт, которые составляют в данном случае 45% от общего количества переданной сервером информации. Размер заголовков возрастает по мере увеличения возможностей веб-серверов и может быть довольно значительным, если конкретный сайт использует большое количество файлов cookie. С помощью команды Unix tall -f вы можете получить представление о загруженности сервера в данный момент. Найдите журнал доступа к серверу (который может называться, к примеру, accessjog) и попробуйте набрать такую команду: % tail -f accessjog Команда tail выводит на экран последние несколько строк файла, а параметр -f указывает, что файл еще не завершен и программе следует продолжать выводить строки, по мере того как они добавляются к файлу. При обращении к сайту новых пользователей на экране будут появляться новые строки. Это может происходить с небольшой задержкой, связанной с буферизацией записи в журнал. Журналы полезны как иллюстрация текущего состояния системы, но ограничены в возможностях использования в качестве средства диагностики производительности. Журнал никогда не скажет вам о тех пользователях, которые пытались связаться с вашим сайтом, но не смогли. Ошибки записываются только для тех соединений, которые были установлены. Слабый уровень загрузки сер- нера может указывать на наличие проблем с производительностью, а не на избыток мощности. Низкая популярность вашего сайта может быть связана с низкой его производительностью. Средний объем передачи Обычный объем одной передачи по протоколу HTTP составляет около 10 Кбайт. Тексты, как правило, имеют меньший объем — около 5 Кбайт на страницу, а изображения больший (около 15 Кбайт). Если ваш сайт представляет собой дерево документов из статических HTML-страниц, текста и картинок GIF, рассчитать
средний размер файла достаточно просто. Я написал небольшой сценарий, который сделает это для вас (листинг 6.1). (Возможно, вам придется указать путь к программе perl и проверить доступность команды find.) Листинг 6.1. Вычисление среднего объема файлов системы #!/usr/local/bin/perl # Вычисляет средний размер всех файлов *.html и *.gif # в указанном каталоге и всех его подкаталогах или в текущем каталоге. $ARGV[0] - "." unless $ARGV[0]: (afiles - *find $ARGV[0]\- chop @files: foreach (@files) { if (A.htmlS/ || /\.gif$/) { $count++; $sum +- -s: # print -s. "\n": # Удалите символ #. чтобы вывести размер всех файлов } } $avg - int($sum/$count): print "Average size is $avg bytes.\n"; Запустите этот сценарий, указав в командной строке путь к каталогу publicjitml: % avgsize.pl /home/patrick/public_html Average size is 12038 bytes. Хотя данный сценарий и дает возможность быстро определить средний размер статического содержимого, это всего лишь первое приближение, поскольку вы получаете средний размер файлов, доступных пользователю, а не средний размер реально отправляемых файлов (равный количеству байтов, переданных за какой-то промежуток времени, поделенному иа количество файлов, содержащих эти байты). Журнал даст вам более реальную картину среднего объема передаваемых данных, поскольку в него записываются реальные объемы передач, включая и результаты работы шлюзов CGI. В листинге 6.2 приведена усовершенствованная версия сценария из листинга 6.1, которая находит средний размер файлов по журналу (последнее число строки в стандартном формате журнала) и печатает его. Размер заголовков при этом не учитывается. Строки журнала, завершающиеся символом -, соответствуют разного рода ошибкам и учитываются в данном сценарии как 0-байтовые передачи. Листинг 6.2. Вычисление среднего объема передаваемых файлов #!/usr/local/bin/perl # Вычисление среднего объеиа файлов, записи о передаче которых имеются # в журнале фориата CLF.
while (<>) { / (\d*)$/; $count++; $sum +« $1: l $avg » int($sum/$count): print "Average size is $avg bytes.\n": Запустите этот сценарий, указав в командной строке имя файла журнала: % avgsize.pl /opt/apache_1.2.4/logs/access_log Average size is 5515 bytes. Средний объем реально переданных файлов составил менее половины среднего объема файлов содержимого, потому что чаще всего передавалась моя домашняя страница, которая имеет небольшой размер и состоит в основном из текста. Журналы, вообще говоря, нельзя считать абсолютно точными, поскольку, как мы видели, в них не записываются сведения о размере заголовков, а также сведения о нагрузке, создаваемой приложениями, не использующими HTTP (например, Java-апплетами и программами nph, добавляющими заголовки HTTP самостоятельно). Распределение размеров передаваемых файлов может быть важнее среднего размера передаваемых файлов. При планировании веб-сайтов чаще всего предполагается, что распределение размеров файлов будет иметь классическую ко- локолообразную форму. Реально оно может быть совсем не таким. Может оказаться, что 95% передач будет иметь объем около 10 Кбайт каждая, а среднее окажется близким к 50 Кбайт из-за того, что оставшиеся 5% представляют собой файлы большого размера — программное обеспечение, изображения с высоким разрешением, звуковые файлы и видео. Это, скорее, бимодальное (двухвершинное) распределение, а не колоколообразная кривая, и встречается такое распределение достаточно часто. Сценарий, дающий распределение размеров, а не только их среднее, был бы более полезен, чем приведенный в листинге 6.2. Такой сценарий мы даем в листинге 6.3. Распределение передач большого объема по времени может быть крайне неравномерным. Например, если ваш сайт используется для распространения программного обеспечения, при появлении на нем новых версий программ объем передач будет резко возрастать. Если ваш сайт снабжает операторов апплетами для работы с базами данных, нагрузка может становиться значительной в начале рабочего дня, когда пользователи начинают работу и загружают апплеты. Хороший вариант архитектуры для таких ситуаций предусматривает наличие двух веб-серверов, один из которых обслуживает запросы на файлы небольшого размера (большинство запросов), а другой — редкие запросы на файлы большого размера. HTTP отлично подходит для прозрачного распределения хитов между серверами. Нет никакого правила, по которому изображение JPEG, включенное и веб-страницу, должно было бы поставляться тем же сервером, что и сама страница. Обращение к другому серверу может несколько замедлить работу из-за
необходимости поиска в DNS, но вы можете указать в ссылке на изображение IP-адрес компьютера, а не его имя, и тогда никаких потерь не будет. Распределение размеров файлов Очень важно представлять себе вид распределения размеров передаваемых файлов. Эта информация поможет решить, нужно ли вам иметь несколько серверов, нацеленных на свои характерные размеры файлов. К счастью, большая часть веб-серверов ведет свои журналы в одном и том же формате CLF (Common Log Format). Связующие серверы, такие как Weblogic фирмы ВЕА, также используют этот формат. В последнем поле каждой строки такого журнала указывается количество байтов, переданных в ответ на запрос, исключая заголовок HTTP. Это делает несложным написание сценария на языке Perl, который вычислял бы распределение размеров файлов (листинг 6.3), а также файла конфигурации gnuplot, который обеспечивал бы построение графика этого распределения. Все это можно скачать по адресу: http://patrick.net/software/. Листинг 6.3. Вычисление распределения размеров файлов #!/usr71ocal/bin/perl $\ - "\п": while(<>) { if C/\s(\d+)\s*$/) { $bucket{$l}++; } } foreach $key (sort keys Sbucket) { print $key. " ". $bucket{$key}: } Ниже приведен файл конфигурации gnuplot для построения результатов работы сценария из листинга 6.3. set term png color set output "distribution.gif" set logscale x set logscale у set xlabel "size of response" set ylabel "number of responses" plot "out" title "response size distribution" На рис. 6.2 показан пример графика бимодального распределения нагрузки веб-сайта, являющегося сервером динамически формируемых графиков. Явно виден разрыв между размерами файлов HTML A000-10 000 байтов) и изображений A0 000-100 000 байтов). Обратите внимание, что этот сайт редко поставляет файлы одного и того же размера.
Рис. 6.2. График бимодального распределения Хиты в секунду В листинге 6.4 приведен небольшой сценарий на языке Perl, позволяющий с помощью файла журнала получить распределение нагрузки (хиты в секунду) за день. Его можно скачать по адресу: http://patrick.net/software/hsp.pl. Помните, что время отправки ответа записывается после ее завершения, а не тогда, когда поступает соответствующий запрос, поэтому вы получаете количество хитов, которые завершились в конкретную секунду, а не количество одновременно полученных запросов. Листинг 6.4. Распределение нагрузки за день #!/usr71ocal/bin/perl $\ - "\п"; while(<>) { /(:\d\d:\d\d:\d\d)/: # часы, минуты, секунды #/(:\d\d:\d\d):\d\d/; # хиты в минуту $кеу - $1:
$кеу — s/:/ /g: # удаление символа :. чтобы gnuplot мог обработать вывод $bucket{$key}++: # добавление хита в корзину этой секунды } foreach $key (sort keys Sbucket) { print $key. " ". $bucket{$key}: } Записав результаты работы этого сценария в файл, вы сможете построить график нагрузки с помощью приведенного ниже файла конфигурации gnuplot (http://patrick.net/software/hps.gp). set term png color set output "hps.gif" set xdata time set timefmt "*H *M %S" set xrange [0:00":3:59"] set ylabel "hits per second" plot "out" using 1:4 notitle with lines На рис. 6.3 приведен пример результатов работы сценария и gnuplot. Рис. 6.3. Распределение нагрузки в течение дня
Переменная нагрузка и длина очереди Внезапный всплеск активности может вызвать большую задержку в обработке. Чтобы понять, почему это происходит, рассмотрим систему, получающую один запрос в секунду и тратящую секунду на обработку этого запроса. Никаких задержек не возникает. Но что, если однажды запрос не придет, а в следующую секунду мы получим два запроса? Возникнет очередь запросов на обработку длиной в один запрос, и если запросы будут продолжать поступать с той же частотой, каждому из них придется ждать лишнюю секунду, чтобы попасть в начало очереди. Возьмем более реалистичный пример. Пусть на обработку запроса уходит десятая часть секунды, а запросы прибывают со скоростью 4 запроса в секунду. Система работает прекрасно, поскольку занятой она оказывается лишь 4 десятых каждой секунды. Очереди нет. Внезапно мы получаем за 1 с 25 запросов, и этот всплеск длится 3 с, а затем активность снижается до обычных четырех запросов в секунду. На протяжении этих трех секунд очередь растет со скоростью 25 — 10 = 15 запросов в секунду, поэтому в результате в ней оказывается 45 запросов. Сколько времени займет их обработка? Очередь сокращается со скоростью 10 - 4 = 6 запросов в секунду, поэтому потребуется 7,5 с, прежде чем она исчезнет. На протяжении этих 7,5 с время отклика будет гораздо хуже, чем обычная десятая доля секунды. На рис. 6.4 приведен график, иллюстрирующий эту ситуацию. Рис. 6.4. Пик нагрузки и рост очереди
Пользователю, который обратится к сайту в тот момент, когда в очереди будет находиться 45 запросов, придется ждать ответа 4,5 секунды. Эти 4,5 секунды в 45 раз хуже обычного времени отклика. Большая нагрузка, даже кратковременная, очень быстро ухудшает время отклика, причем на восстановление уходит много времени. Кажется, что десятой доли секунды вполне достаточно для большей части сайтов, но на самом деле это неверно, если активность пользователей сайтов имеет пики хотя бы средней величины. Время ожидания незагруженной системы должно быть как можно более коротким — либо нужно использовать параллельную обработку для распределения нагрузки между серверами или процессорами. Когда конкретно записываются хиты? К сожалению, почти все веб-серверы и серверы приложений записывают время только в секундах, а не в миллисекундах, и они не сообщают вам, что именно было записано в журнал: начало запроса, середина его обработки или окончание отправки ответа. Если вы подумаете на эту тему, то поймете, что записи в журнал нужно производить в момент окончания отправки ответа, поскольку записываются сведения об успешности этой отправки и размере переданных данных. Я смоделировал ситуацию, в которой 94 пользователя обратились к одной и той же динамической странице приблизительно одновременно (в течение 1 с), и записал начало каждого запроса и конец соответствующего ответа с точностью до миллисекунды для каждого из 94 пользователей. Затем я сравнил это с записями из журнала. Результаты приведены на рис. 6.5. По левой вертикальной оси отложено количество хитов на каждую секунду в соответствии с журналом, а по правой вертикальной оси — «число пользователей», позволяющее следить за временем начала и окончания обслуживания 94 пользователей. Из рис. 6.5 видно, что 94 входящих запроса в секунду, полученных между секундами 22 и 23, не превращаются в 94 запроса в секунду в журнале. Вместо этого информация о запросах записывается после завершения их обработки, причем записывается предшествующая секунда. Первые 9 запросов датируются секундой 24. Некоторые из них, судя по всему, завершились сразу же после секунды 24, но я отношу это на счет внутренних задержек моего сценария. Самое главное, что нужно понять из этого примера: 94 запроса в секунду превратились в 20 запросов в секунду в течение нескольких секунд. Поэтому из журнала узнать точное количество запросов в секунду нельзя. Нужно помнить еще и о том, что отправка ответов в отличие от записи в журнал не откладывается. Пользователи могут получить ответы гораздо раньше, чем информация об отправке этих ответов будет записана на стороне сервера. Это особенно актуально в случае медленной обработки журналов, связанной, например, с обратным поиском в системе DNS.
Наконец, отметьте также, что во всех журналах веб-серверов и связующих серверов результаты записываются только после завершения отправки ответа и только с точностью до целых секунд. Было бы полезно записывать и момент получения запроса, и момент завершения ответа с точностью до миллисекунд. Рис. 6.5. Задержка отметок времени в журнале Кто ваш самый частый пользователь? В Unix очень легко посмотреть в файлы журналов доступа access.log и найти IP- адрес самого частого пользователя. Например, чтобы получить количество хитов для каждого IP-адреса, попробуйте ввести такую команду: % sort log* | awk '{print $1}' | unlq -с | sort -n Результат будет выглядеть примерно так, как показано ниже. Количество хитов приводится в первом столбце, а IP-адрес — во втором. 12 39.203.39.11 13 2.39 48.111 13 39.34.10.22
Который из процессов мой? Если вы собираетесь контролировать использование ресурсов конкретными процессами, вам нужно знать их идентификаторы (process ID — PID). Узнать PID несколько сложнее, чем кажется сначала, поскольку на больших серверах Unix часто работают сотни процессов, и эти серверы время от времени приходится перезагружать. После перезагрузки все РГОы меняются. Один из простых путей для идентификации процессов состоит в создании идентификатора пользователя для всех процессов, которые вы собираетесь запускать. После этого вы сможете искать нужные идентификаторы командой ps -u <имя_полъзователя>. Недостаток этого метода в том, что вам придется создавать нового пользователя каждый раз при установке новой программы. Еще одна проблема состоит в том, что некоторые программы типа веб-серверов автоматически порождают новые копии самих себя, поэтому вы все равно не сможете точно указать какой-то конкретный процесс. Вы можете обработать результат работы программы ps с помощью команды grep, указав ей имя вашей программы, но результат может вас поразить тем, как часто меняются эти имена. Большая часть программ может самостоятельно управлять выводом программы ps, изменяя значение элемента массива argv[0] (для программистов на С). Вы можете применить отличительный, но не используемый параметр командной строки типа -MYPROC при запуске и перезапуске процесса, но такие отличительные строки часто обрезаются из-за ограниченности строк вывода ps. Бывает проще найти свой процесс по используемому им порту, а не по выводу команды ps. Если вы знаете, какой порт прослушивает ваш процесс, вы можете найти его в системе Solaris, дав команду Isof -i: <port>. Например, чтобы узнать PID веб-сервера, прослушивающего порт 80, дайте команду Isof -i:80. По адресу: http://patrick.net/software/ вы можете скачать копию Isof для Solaris. Другое аналогичное средство называется identd и используется для поиска процесса, работающего с конкретным соединением TCP/IP. Эта программа работает на многих версиях Unix. Третье, чрезвычайно полезное, средство называется fuser. В Linux команда fuser 80/tcp сообщит вам, каков PID процесса, использующего порт 80. В зависимости от типа ядра и версии fuser формат команды может быть и таков: fuser -n tcp 80. Наконец, в Linux ту же информацию может дать команда netstat -p. Кто работает с этим файлом? Программа fuser позволяет найти процесс, работающий с конкретным файлом. Указав в командной строке имя файла, вы получите РШы всех процессов, в которых этот файл открыт. В Linux программа fuser может возвращать РШы для процессов, использующих порты TCP и UDP. Для получения более подробных сведений введите команду man fuser.
Какие файлы используются моими процессами? Если вы используете трассировщик системных вызовов, такой как strace в Linux или truss в Solaris, вы можете обнаружить тысячи запросов на запись в конкретный дескриптор, но не будете знать, к какому файлу этот дескриптор относится. Поскольку запись в файлы может являться «узким местом», важно знать, с какими именно файлами идет работа. К счастью, узнать это легко: найдите PID вашего процесса, а затем найдите этот номер в каталоге /ргос. Там вы увидите каталог с именем fd, в котором каждый дескриптор будет содержать символьную ссылку на реальный файл. Например, если PID вашего веб-сервера равен 480, выглядеть содержимое этого каталога может так: # Is -1 /ргос/480/fd total О lr-x— 1 root root 64 Маг 29 09:30 0 -> /dev/null 1-wx— 1 root root 64 Mar 29 09:30 1 -> /dev/null 1-wx— 1 root root 64 Mar 29 09:30 15 -> /var/log/httpd/errorjog lrwx— 1 root root 64 Mar 29 09:30 16 -> socket:[475] 1-wx— 1 root root 64 Mar 29 09:30 17 -> /var/log/httpd/access_log 1-wx— 1 root root 64 Mar 29 09:30 18 -> /var/run/httpd.lock.473 (deleted) 1-wx— 1 root root 64 Mar 29 09:30 2 -> /var/log/httpd/errorjog 1-wx— 1 root root 64 Mar 29 09:30 21 -> pipe:[466] lr-x— 1 root root 64 Mar 29 09:30 3 -> /etc/initlog.conf lr-x— 1 root root 64 Mar 29 09:30 8 -> pipe:[466] Что происходит при зависании БД? Поучительно бывает заблокировать критическую таблицу в базе данных и посмотреть, что случится с веб-сайтом. Например, вы можете заблокировать и позже разблокировать таблицу в Oracle приведенной ниже операцией с откатом: lock table user_data in exclusive mode: rollback: Это можно сделать для того, чтобы узнать, сколько запросов пользователей накапливается в очередь к базе данных на конкретное количество щелчков с веб-сайта. Кроме того, вы можете просто сымитировать перегруженность базы данных и посмотреть, что именно в вашем сервере выйдет из строя. Наконец, вы можете узнать, какие страницы зависят от базы данных. В листинге 6.5 приведен сценарий на PL/SQL, написанный Боско Албукерка — гуру по базам данных. Этот сценарий выводит количество запросов SQL, ожидающих обработки. Назовите этот сценарий waiting и вызовите его из интерпретатора sqlplus со значком @: > ^waiting;
А вот и сам листинг: Листинг 6.5. Количество ожидающих обработки запросов к БД col sid format 9999 heading "Sess|ID" col event format a30 heading "Wait Event" wrap col state format alO heading "Wait State" trunc col siw format 999999999 heading "Waited So|Far (cs) " col wt format 999999999 heading "Time|Waited (cs)" col pi format 999999999 heading "pi" col p2 format 999999999 heading "p2" col p3 format 999999999 heading "p3" set lines 132 pages 100 select sid . event . state. seconds_in_wait siw. wait_time wt. pi. p2. p3 from v$session_wait where event NOT IN CSQL*Net message from client'. 'Null event*. •rdbms ipc message", 'rdbms ipc reply', 'pmon timer') order by sid Еще немного советов О Создайте хорошую топологическую схему со всеми серверами и соединениями. О Оптимизацию следует начинать с самых высоких уровней (то есть с архитектуры). Определите, какие этапы обработки или компьютеры могут быть исключены. Низкоуровневую оптимизацию следует откладывать напоследок, поскольку она дает меньший выигрыш, а изменение архитектуры все равно может свести на нет все усилия. О Наиболее вероятными источниками проблем с производительностью являются самодельные приложения, архитектура, базы данных, Интернет и жесткие диски. О Попробуйте запустить тест на нагрузку, когда в системе не будет никаких других пользователей и процессов (например, глубокой ночью), чтобы узнать максимально возможную производительность текущей конфигурации. Это позволяет различить плохое качество приложений и избыточную нагрузку на систему. Если производительность оказывается низкой даже при отсутствии сетевой нагрузки и одном пользователе, то виноваты приложения. Если производительность не очень плоха, но и не хороша, дело может быть в недостаточно качественной обработке ошибок данным приложением. О Контролируйте размер процессов для поиска утечек памяти. О Ищите ошибки с помощью журналов сервера.
О Проверяйте физические соединения кабелей и устраняйте перегибы и возможные источники интерференции (близко расположенные радиопередатчики, к примеру). Помните, что проблемы с производительностью всегда означают огорчения людей, а устранение проблем означает, что вы делаете людей счастливыми, а не просто решаете какие-то технические вопросы. Основные рекомендации О Изучите средства, позволяющие узнавать РШы и определять активность соответствующих процессов. О Не ожидайте от журналов излишней точности. О Помните, что в журналы записывается время окончания отправки ответа, а не время получения запроса.
/ Надежность Кажется, существует бесчисленное множество различных поломок, которым подвержены веб-сайты. Это затрудняет систематическую проверку Чем дольше я работаю с веб-сайтами, тем больше удивляюсь фантазии, с которой сложные системы находят возможности сломаться. Типичные отказы Я не могу привести здесь исчерпывающий список, поэтому сосредоточу внимание на наиболее типичных проблемах, из-за которых возникают отказы веб-сайтов. Если вы найдете способ избавиться от этих стандартных проблем, те проблемы, которые у вас все же возникнут, будут еще более достойными противниками. Если ваш отказ не подпадет под приведенную ниже классификацию, пишите мне по адресу: p@patrick.net. Мне будет интересно узнать о чем-то новом. Переполнение диска Наиболее вероятной причиной отказа системы является переполнение диска. Хороший администратор системы всегда следит за использованием дисков и регулярно сбрасывает данные на резервные носители (например, магнитные ленты), освобождая диски. Журналы могут очень быстро расходовать дисковое пространство. Журналы веб-сервера, SQL*Net, JDBC и сервера приложений являются своего рода утечками дискового пространства. Одной из профилактических мер может быть хранение журналов в отдельной файловой системе, а не в той, которая используется операционной системой. Веб-сервер все равно может зависнуть, когда
файловая система, где хранятся журналы, переполнится, но сам компьютер, по крайней мере, зависнет при этом с меньшей вероятностью. У процесса закончились файловые дескрипторы Если веб-серверу или другому важному процессу нужно больше дескрипторов, чем ему разрешено открыть, он зависнет или будет выдавать ошибку до тех пор, пока не получит желаемое. Дескрипторы открываются для файлов и сокетов, причем веб-серверы используют как те, так и другие, поскольку копируют файлы с дисков в сетевые соединения. По умолчанию большая часть интерпретаторов разрешает использовать 64 дескриптора, то есть любой процесс, запускаемый из такого интерпретатора, может открыть одновременно не более 64 объектов. К счастью, чаще всего справиться с этим ограничением можно с помощью команды ulimit. Например, команда ulimit -n 1024 позволит всем процессам, запускаемым из интерпретатора, открывать 1024 дескриптора. Если вы хотите узнать, сколько дескрипторов используется в данный момент, а также получить список файлов, на которые эти дескрипторы указывают, можете изучить содержимое системного файла /proc/<pid>/fd в системах Solaris и Linux. Ошибки при работе с указателями на С Программы, написанные на С или C++, такие как API-модули веб-серверов, могут привести к сбоям, поскольку единственная ошибка в разыменовывании указателя (то есть при обращении к ячейке памяти, на которую он указывает) приводит к завершению процесса операционной системой. Опытные программисты на С знают это и аккуратно используют указатели. Аналогом ошибок с указателями в Java является обращение к пустой ссылке на объект. Пустые ссылки не обязательно приводят к немедленному завершению работы виртуальной машины, давая программисту шанс корректно обработать ошибку как исключительную ситуацию. Java не требует в этом отношении такого внимания, но за это приходится платить производительностью. Утечки памяти Программисты C/C++ страдают еще от одной проблемы, связанной с использованием указателей. Утечка памяти происходит при утере ссылок на выделенную память. Это обычно случается, когда память в подпрограмме выделяется, но не освобождается. Указатели на эту память после возвращения из подпрограммы теряются, а память, с точки зрения операционной системы, считается используемой процессом. В итоге программа использует все больше и больше памяти, ухудшая производительность компьютера до тех пор, пока у него полностью не закончится оперативная память и пространство на диске и он не остановится. Одним из решений проблемы является внимательный анализ кода с помощью средств профилирования программ, таких как Purify, которые позволяют найти потенциальные утечки. Однако это не поможет найти утечки в библиоте-
ках, созданных другими программистами, для которых исходный код недоступен. Другое решение состоит в завершении и перезапуске процесса через равные промежутки времени. Именно по этой причине веб-сервер Apache создает и завершает дочерние процессы. Согласно документации Linux на функцию malloc, новые ее версии обладают некоторой защитой против ошибок указателей и утечек памяти — естественно, за счет производительности. Современные версии библиотеки libc для Linux (новее 5.4.23) и GNU libc B.x) включают реализацию malloc, которую можно настраивать с помощью переменных окружения. Когда установлена переменная MALLOC_CHECK_, используется специальная, менее эффективная реализация, которая считается устойчивой по отношению к простым ошибкам, таким как повторный вызов free с тем же аргументом или переполнение на один байт. Не от всех таких ошибок можно защититься, поэтому утечки памяти все равно — возникают. Несмотря на то, что в Java нет указателей как таковых, программы на Java ведут себя по отношению к памяти еще хуже, чем программы на С, поскольку в Java очень часто создаются объекты, а сборщик мусора не освобождает память, пока не исчезнут все ссылки на объект. Даже после запуска сборщика мусора память возвращается только самой виртуальной машине, а не операционной системе. В результате программы на Java стремятся использовать всю отведенную им кучу и никогда не уменьшаются в размерах. Они могут перерасти максимальный размер кучи в несколько раз из-за сохранения кода благодаря компиляции «на лету» (Just in Time — JIT). Аналогичная проблема возникает при выделении соединения с базой данных из пула, если это соединение не освобождается после работы с ним. Некоторые пулы поддерживают таймеры активности, автоматически освобождающие соединения при отсутствии активности в течение некоторого времени, но этого может быть недостаточно, чтобы спасти ваш сайт, если очень плохая программа будет быстро расходовать соединения. Блокировка потоков Выигрыш в производительности, даваемый использованием потоков, получается за счет надежности. В основном проигрыш в надежности связан с возможностью возникновения блокировок потоков, когда один поток ждет освобождения ресурса другим потоком, а тот ждет, когда первый освободит какой-то другой ресурс. Представьте, что вы пытаетесь разойтись со встречным пешеходом на тротуаре и при этом оба делаете шаг в одну и ту же сторону, затем в другую итак далее. Вообразите, что это будет продолжаться вечно, — и вы получите представление о том, что такое блокировка потоков. Для таких блокировок не существует простого лекарства, поскольку возникают они редко, нерегулярно и, как правило, лишь при больших нагрузках. Тестирование программ чаще всего не создает достаточной нагрузки для проявления ошибок синхронизации потоков. Проблема блокировки потоков возникает в любом языке, в котором используются потоки. Поскольку программировать потоки на Java гораздо проще, чем на С, многопоточное программирование ис-
пользуется большим количеством программистов, а соответственно и блокировки становятся более частым явлением. Уменьшить вероятность возникновения блокировки можно путем более частого употребления ключевого слова synchronized в программах на Java, но за это приходится платить производительностью. Внутри баз данных при больших нагрузках тоже могут возникать блокировки. Блокировка ресурса завершившимся процессом Если в программе используются долгоживущие блокировки, такие как блокировка путем создания файла, и данная программа завершается досрочно, не освободив ресурс, другие процессы не смогут работать. Это вызовет возникновение новых сбоев. В такой ситуации блокировку приходится удалять вручную. Перегрузка сервера Веб-серверы Netscape создают отдельный поток для каждого соединения. Когда у веб-сервера Netscape Enterprise заканчиваются потоки, он зависает и не может обслужить даже уже установленные соединения. Если у вас есть механизм распределения нагрузки, который способен обнаружить зависание сервера, его доля нагрузки может быть перераспределена на другие серверы, на которых от :т>го также могут закончиться потоки. Так может зависнуть вся система. Новые соединения все равно будут приниматься на уровне операционной системы, но приложение (веб-сервер) не будет их обслуживать. Пользователь будет видеть сообщение connected в строке состояния браузера, но больше он ничего не увидит. Один из способов избавиться от этой проблемы — установить параметр RqThrottle в файле obj.conf равным некоторому числу, меньшему, чем количество потоков, чтобы новые соединения не принимались сервером в том случае, если количество уже принятых превышает RqThrottle. Тем, кто не смог подключиться, будет казаться, что сервер не работает, а для тех, кто подключился, может сильно ухудшиться время отклика — но, по крайней мере, сервер не зависнет. Количество доступных дескрипторов файлов должно превышать количество потоков, иначе эти дескрипторы станут «узким местом». Предположим, вы решили ограничиться четырьмя процессами httpd и значением RqThrottle = 1000. Тогда на компьютере будет выполняться до 4000 потоков. Максимальное количество дескрипторов для одного потока должно быть равно, по крайней мере, 1024. Учтите, что программа типа netstat может выдать для одного процесса более 4000 сокетов, поскольку соединения открываются до того, как их принимает приложение. Если вы установите ограничение на использование памяти для процессов httpd, в файле журнала могут появляться сообщения типа Fatal, cannot allocate memory (фатальная ошибка, невозможно выделить память). Вам придется немного поэкспериментировать, чтобы определить, какое ограничение подействует раньше — RqThrottle или ограничение на память.
Система балансировки нагрузки не может обнаружить отказавший компьютер Круговая система DNS функционирует как простейший тип системы балансировки нагрузки, но она не может обнаружить вышедший из строя сервер и перенаправить его клиентов на другой сервер. Отказ одного сервера из пары при использовании круговой системы DNS зависит от операционной системы клиента. Компьютеры с Windows кэшируют один адрес и всегда им пользуются. Поэтому для таких пользователей веб-сайт будет казаться либо нормально работающим, либо отказавшим — в зависимости от того, какой адрес был кэширован операционной системой. Клиенты Unix обращаются к DNS каждый раз, поэтому сайт будет казаться им то работающим, то неработающим. Resonate и другие системы балансировки нагрузки, работающие на уровне IP, не страдают от этого недостатка, поскольку не зависят от клиента. Они перенаправляют трафик в зависимости от состояния серверов. Перегружена подсеть По различным причинам возможно возникновение перегрузки какого-либо сегмента сети. Устанавливайте дублирующие системы в разных подсетях, чтобы они не отказывали одновременно. Израсходованы терминалы Для приложений типа Telnet, которые обращаются к псевдотерминалам сервера, превышение количества доступных терминалов означает, что новые сеансы не будут приниматься. Решение заключается в создании большего количества псевдотерминалов. Способ осуществления зависит от операционной системы. В базе данных закончились указатели Многие базы данных работают с фиксированным количеством указателей (cursors) — областей памяти, содержащих результаты обработки запросов. После считывания всех данных эти области освобождаются, но большое количество одновременных запросов может превысить ограничение на количество указателей. При этом новые запросы будут помещаться в очередь и не будут обрабатываться до тех пор, пока для них не освободится указатель. Эта проблема неочевидна для разработчиков, но проявляется при тестировании на нагрузку. Впрочем, ваш администратор базы данных вполне может о ней знать. Аналогичные проблемы могут быть связаны с недостатком места под таблицы или ограничением на значение порядкового номера. Такие проблемы говорят о том, что нужно искать хорошего администратора базы данных, чтобы он установил правильные значения параметров и обеспечил высокую производительность
базы данных. Большинство поставщиков баз данных предоставляют и средства для их контроля и моделирования, позволяющие справиться с такими ситуациями. Плохой драйвер устройства Unix очень надежен в работе с программами пользовательского уровня, такими как веб-серверы, серверы приложений и базы данных, но программы уровня ядра легко могут завесить всю систему, поскольку обладают совершенно неограниченными возможностями. Новые программы добавляются в ядро при загрузке новых драйверов — например, для работы с конкретной сетевой картой Ethernet. Такие модули ядра следует загружать с особой осторожностью. Не существует никакого средства борьбы с ошибками, можно только стараться найти хорошие драйверы. Отказы оборудования Наиболее вероятен отказ жестких дисков, поскольку в них есть движущиеся части, но отказать может и память, и даже процессор — обычно из-за перегрева. Существует очень надежное оборудование, но продается оно по очень высокой цене. Лучше использовать избыточные системы из дешевых компонентов: дублировать диски, установить несколько процессоров, кластеризовать компьютеры и обеспечить балансировку нагрузки с помощью средств типа Resonate. Отказ питания Большая часть коммерческих сайтов обеспечена источниками бесперебойного питания, но проблемы все равно возникают. Шнуры питания лучше расположить так, чтобы за них никто не запнулся и не выдернул их из розетки. Детей нельзя пускать в комнаты с важными компьютерами: они любят большие красные выключатели и не могут удержаться, чтобы что-нибудь с ними не сделать. Администратор перепутал сервер Ситуация, в которой перезагружается или перенастраивается не тот сервер, возникает достаточно часто. Работая по протоколу Telnet, не всегда упомнишь, с каким именно компьютером работаешь в данный конкретный момент, особенно если выводится подсказка привилегированного пользователя (#). Можно принять следующие меры предосторожности: включить в подсказку имя компьютера, запретить удаленный вход под именем привилегированного пользователя, а также подключить файловые системы / и /usr как доступные только для чтения. Никто, кроме настоящего администратора системы, не должен иметь прав привилегированного пользователя на реально работающих серверах.
Ошибочное включение файла в шаблон Еще одна классическая ошибка — включение лишних файлов в шаблон. Например, команда gnuplot *.gp заставит gnuplot построить все файлы с расширением .др, но не обязательно будет запущен только один экземпляр gnuplot. Это означает, что конфигурационные параметры одного файла будут использоваться для построения графиков содержимого всех остальных файлов. Посмотрев на конфигурационный файл странно выглядящего графика, вы не заметите ничего неправильного, поскольку проблема возникла из-за того, что график был построен в соответствии с одним из предыдущих конфигурационных файлов. Более тонкая проблема может возникнуть, если сама операционная система использует шаблоны. Например, если сценарий сервера Netscape, выполняемый при загрузке системы и называющийся S98.netscape в каталоге /etc/rc.d/rc3.d, скопировать в S98.netscape.orjglnal, то он будет вызываться операционной системой сразу после S98.netscape. Операционная система запустит все файлы, начинающиеся с S и двух цифр. Проблемы с разрешениями Всем программистам CGI приходится столкнуться с тем, что правильный сценарий CGI отказывает при первом его запуске на реальном веб-сервере. Причина в том, что большая часть таких серверов работает под именем nobody, а на этого пользователя накладываются серьезные ограничения. Разработчик же, скорее всего, тестировал свой сценарий, запуская веб-сервер под своим собственным именем. CGI чаще всего принадлежит его разработчику, а выполнение его не разрешается «прочим пользователям». После того как сценарию CGI дается разрешение на запуск прочими пользователями, он снова отказывает, поскольку ему нужно производить запись в файл или каталог, доступ к которому прочим пользователям запрещен. Ошибки в путях Ошибки в путях, как и ошибки с разрешениями, возникают, когда программа разрабатывается под именем одного пользователя, а выполняется под именем другого или в другой среде. Например, задания стоп работают с минимальным объемом переменной PATH, поэтому они не могут обращаться к тем исполняемым файлам, к которым обычно имеет доступ разработчик. Разработчик пишет задание сгоп и думает, что с ним все в порядке, а когда демон сгоп запускает его, возникает ошибка. Хорошая мера предосторожности — использовать полные имена файлов во всех заданиях сгоп. Проблемы с заплатами Вы можете избежать множества проблем с надежностью, установив в своей системе нужные заплаты (patches). Администратор системы должен периодически
проверять их наличие и устанавливать на рабочих компьютерах подходящие заплаты. В Solaris команда showrev -p выводит список уже установленных заплат. Список нужных заплат зависит от того, с какой операционной системой вы работаете. Поставщик операционной системы должен знать, какие заплаты являются жизненно важными для работы системы. Каскадное распространение перегрузки Когда компоненты системы зависят друг от друга, может возникать цепная реакция распространения перегрузок. Если связующему серверу нужна информация из базы данных, а работа базы данных замедляется, все потоки связующего сервера в какой-то момент могут оказаться ждущими ответа от базы данных. Когда связующий сервер не ответит на запрос от контролирующей системы, его могут счесть отказавшим, даже несмотря на то, что он все еще нормально работает. Отказы из-за контроля Системы контроля предназначаются для того, чтобы искать отказы, но они и сами иногда становятся их причиной. Программы типа FirstWatch и Tivoli, которые могут перезапускать серверы, способны также завершать работу нормально функционирующих систем. Например, когда база данных достигает максимально возможного количества соединений, FirstWatch решает, что она отказала, поскольку она не может создать для него новое соединение, — и перезагружает ее, разрывая все открытые соединения (несмотря на то, что они все нормально работали). Другим примером являются контролирующие программы Keynote, разбросанные по всем США, которые обращаются к веб-странице, требующей интенсивных вычислений. Они могут создать гораздо более тяжелую нагрузку, чем та, на которую сайт был рассчитан. Агенты Resonate, проверяющие состояние неб-сайтов, также могут являться источниками значительной нагрузки. Одним из решений является включение режима слежения за файлом журнала или выводом программы truss, а не постоянное обращение к веб-сайту. Повторные обращения вызывают новые отказы Плохая схема обработки ошибок, предусматривающая повторное установление соединения или повторный запуск процесса без какой-либо задержки, может просто «затопить» систему. Что еще хуже, программу, обрабатывающую ошибки таким образом, может быть нелегко остановить именно из-за того, что она слишком занята повторными попытками. Случайная блокировка важных таблиц Не давайте всем подряд право блокировать важные файлы или строки баз данных. Веб-сайт может полностью остановиться из-за того, что кто-то забудет снять блокировку, приняв сделанные изменения, перед тем как уйти на обед. Таблицы и строки блокируются при внесении в них изменений и разблокируются только после того, как эти изменения принимаются.
Использование БД там, где можно обойтись файлами Базы данных очень полезны в некоторых случаях, но использование их для хранения небольших объемов информации, которую можно было бы с той же легкостью хранить в файлах, означает, что вы просто напрашиваетесь на проблемы. Базы данных гораздо сложнее файлов. Программа не может подключиться к БД после отказа Удостоверьтесь, что пул базы данных автоматически восстанавливается после ее отказа. Проведите тестирование после внезапной перезагрузки БД и проверьте, восстановится ли работа системы полностью. Проблемы такого рода возникали, в частности, у пулов Weblogic. Программа не перезапускается после перезагрузки Убедитесь, что все важные программы включены в сценарии запуска /etc/red, что обеспечивает их автоматический перезапуск после перезагрузки. Многие компьютеры под управлением Unix могут работать месяцами или даже годами без всяких проблем. Когда же возникает необходимость перезагрузить их, может оказаться, что веб-сервер нужно запускать вручную, потому что его никто не добавлял в сценарий автозапуска. Короткоживущие задачи могут запускаться демоном сгоп, что даст им возможность пережить перезагрузку, поскольку демон cron (crond) автоматически перезапускается после перезагрузки. «Раздвоение личности» Дублирующие системы, предназначенные для решения проблем с надежностью, могут и вызывать их. Пусть у вас есть резервная база данных, а основная в какой- то момент начинает работать слишком медленно. С некоторой вероятностью, в зависимости от условий, основная база данных может восстановиться и решить, что она все еще основная, тогда как резервная база активизируется и тоже будет считать себя основной. Чтобы не возникало подобных «шизофренических» синдромов, необходимо аккуратное планирование отказоустойчивых схем. Брандмауэр блокирует важную службу Брандмауэры должны мешать плохим программам и не мешать хорошим. Делают они это путем блокирования всех портов, за исключением тех, которые жизненно необходимы для веб-сайта. К сожалению, про порт не всегда можно сказать, что он жизненно важен, пока он не будет заблокирован брандмауэром. Аналогичная проблема возникает, когда люди из отдела безопасности удаляют строки из /etc/inetd.conf и /etc/services.
Чтение данных с экрана не работает из-за того, что меняется дизайн Удивительно, но программы, считывающие данные со страниц, предназначенных для чтения человеком, используются достаточно часто. Опасность в том, что, когда меняется представление данных, программа перестает работать, потому что она не может их найти в нужном месте. Чтение данных с экрана неприемлемо в качестве долгосрочной стратегии, но оно может использоваться в течение некоторого времени с учетом соответствующего риска. Зависимости Все отказы происходят из-за зависимостей. Чтобы отказов было меньше, нужно уменьшить количество зависимостей. С другой стороны, наличие зависимостей вызвано экономическими причинами. Например, программа, использующая общие библиотеки, зависима от этих библиотек и не будет работать без них. Изменение в этих библиотеках или в их размещении может привести к отказу программы. Зато размер исполняемого файла программы становится меньше. Альтернатива — программа, прошедшая статическую компоновку. Она оказывается больше, поскольку содержит библиотечный код, но такая программа не откажет из-за изменения в системных библиотеках или в их размещении. Другим хорошим примером является количество приложений, которые должны работать на одном компьютере. Если вы запустите их несколько десятков, нее они смогут влиять друг на друга. Что еще хуже, непросто будет выяснить, какое именно виновато в произошедшем сбое. Если же каждое приложение будет выполняться на своем компьютере, они не смогут влиять друг на друга непосредственно — и можно будет сразу определить, какое именно приложение отказало; но это стоит больших денег, поскольку требует покупки оборудования и его размещения. Вот зависимости, которых следует опасаться: О зависимости между программными модулями, создаваемыми вами; О зависимости от функций конкретных браузеров; О зависимость от единственной операционной системы; О невозможность автоматического подключения к БД после отказа; О зависимость от сетевой файловой системы и др. Борьба с последствиями отказа II некоторых случаях вам придется полностью остановить работу сайта, чтобы пернуть его в строй. Кое-что можно сделать заранее, чтобы облегчить себе работу.
О Не делайте сайт более сложным, чем это необходимо. Чем меньше движущихся частей, тем лучше. Опасайтесь новых функций, которые, по сути, не дают ничего существенного. Все должно быть именно тем, чем кажется. Когда вы решите, что ваш веб-сайт прост настолько, насколько это возможно, сделайте его еще проще. О Документация должна быть очень подробной, но не должна описывать все компоненты системы. Нарисуйте все сети, IP-адреса, компьютеры и приложения на больших картинках. Когда возникнет аварийная ситуация, требующая немедленных действий, у вас будет время лишь на несколько строк текста. О Убедитесь, что имеется заранее заготовленная страница «Сайт не работает», которую можно будет сразу же начать выдавать пользователям, когда сам сайт откажет. Если у вас есть постоянные пользователи, подумайте о создании системы оповещения, которая будет информировать их об отказах и планируемом времени восстановления сайта. О Пользуйтесь системой Resonate или аналогичной, которая позволяет вывести один сервер из работы для профилактики или восстановления, не нарушая работу сайта в целом. Основные рекомендации О Программируйте и планируйте конфигурацию, ориентируясь на все возможные и невозможные неприятности и неполадки. О Уменьшайте количество зависимостей.
О Безопасность Безопасность веб-сайтов часто приходится покупать за счет производительности. Однако некоторые меры, повышающие защищенность, могут одновременно и увеличивать производительность. Например, простой сайт без Java и JavaScript имеет меньше уязвимых мест. Если вы не будете пользоваться вебсервером Microsoft IIS, производительность сайта, скорее всего, будет выше, и при этом вы обезопасите себя от заражения множеством вирусов, действующих только на IIS. В этой главе я освещу несколько вопросов безопасности с точки зрения их влияния на производительность. HTTPS и SSL Защищенный протокол передачи гипертекста (Secure HTTP — HTTPS) представляет собой обычный HTTP, передаваемый через уровень защищенных соке- тов (Secure Socket Layer — SSL). По умолчанию для этого протокола использу- гтся порт 443. Уровень SSL обеспечивает шифрование всего проходящего трафика, что защищает вас от раскрытия ваших секретов людьми, перехватывающими пакеты где-то в Интернете. Зашифрован будет не только обычный гскст, но даже заголовки HTTP и изображения. Можно было бы, наверное, сэкономить часть ресурсов процессора, не расходуя их на шифрование изображений (то есть встраивая в страницы ссылки на сервер изображений, не защищенный протоколом SSL), но браузеры не допускают присутствия незащищенных изображений на страницах, передаваемых через SSL. В HTTPS используется шифрование с открытым ключом достаточной длины, чтобы обеспечить обмен секретными ключами, после чего собеседники пе- |>сходят на шифрование с секретными ключами, обеспечивающее большее быст-
родействие. Секретные ключи могут кэшироваться на обеих сторонах, поэтому последующие соединения с тем же сайтом обычно осуществляются быстрее, чем первое, — по крайней мере, в течение времени жизни ключа в кэше. Веб-сервер Netscape Enterprise позволяет настраивать количество записей в кэше подключений SSL с помощью параметра SSLCacheEntries в файле magnus.conf. По умолчанию значение этого параметра равно 10 000. HTTPS может серьезно ухудшать производительность из-за того, что объем передач при работе с небольшими файлами иногда возрастает чуть ли не в 10 раз. В основном это связано с необходимостью обмена секретными ключами и защиты этой процедуры с помощью открытых ключей. Затраты на шифрование и расшифровку полезных данных оказываются по сравнению с этим пренебрежимо малыми. Я использовал 40-разрядное шифрование вместо 128-разрядного в некоторых тестах на нагрузку и не обнаружил никакой разницы, поскольку шифрование осуществляется очень быстро. Самым «узким местом» является установка соединения SSL, а не использование этого соединения. Если ваш сайт поддерживает SSL, подумайте о покупке аппаратного ускорителя шифрования. Это плата расширения, подключаемая к серверу и обеспечивающая аппаратное порождение пары ключей для соединения SSL. На рынке лидируют карты nCipher (http://www.ncipher.com/) и Rainbow (http://www.rainbow. com/). Интересно отметить особенность взаимодействия SSL и SMP: в процедуре генерации ключей SSL в серверах Netscape Enterprise используется множество вызовов malloc(). По умолчанию в большинстве операционных систем функция malloc() не многопоточна, поэтому, если не подключить многопоточную реализацию этой функции специально, заниматься генерацией ключей может только один процессор, даже если их на данном компьютере несколько. Я запускал тесты на время отклика и пропускную способность под нагрузкой с картой nCipher и в ее отсутствие. На тестовом компьютере Sun E450 с четырьмя процессорами работал веб-сервер Netscape Enterprise 3.6 в системе Solaris 2.6. Для небольшого A Кбайт) статического файла, передаваемого по SSL, в отсутствие нагрузки время отклика изменялось при добавлении карты с 75 до 25 мс. Хоть это и в три раза быстрее, для человека 50 мс — ничтожный промежуток времени. Я провел тестирование и с большим файлом A5 Мбайт). Никакой разницы между работой при наличии карты и при ее отсутствии обнаружить не удалось. Это кажется разумным, поскольку карта ускоряет только процесс установки соединения SSL, а не обмен зашифрованными данными. Из всего этого следует, что при небольшой частоте поступления новых соединений покупать аппаратный ускоритель смысла нет. С другой стороны, наличие карты может значительно повысить пропускную способность в том случае, если запросы на соединение поступают с большой частотой. Приведенный в листинге 8.1 сценарий использовался мной для создания нагрузки. Он запрашивает с сервера небольшой статический файл (изображение) с возрастающей частотой. Один экземпляр этого сценария неспособен создать максимальную нагрузку, поскольку запросы поступают строго последовательно, но если запустить достаточное количество экземпляров одновременно, можно достичь практически любой желаемой нагрузки.
Листинг 8.1. Тестирование сервера HTTPS на нагрузку #!/usr/bin/perl use LWP: -.UserAgent: use Crypt::SSLeay: use HTTP::Headers; use HTTP::Request: use HTTP::Response: use Time::HiRes 'time'.'sleep': $\ - "\n": # Добавляет перевод строки в печатаемые сообщения Srooturl = https://l.2.3.4*: # IP-адрес HTTPS-сервера $path - 7images/test.gif: # имя запрашиваемого файла MAIN: { Sua - LWP::UserAgent->new: Srequest - new HTTP::Request('GET'. "SrooturlSpath"); $max - 80: $hps - 1: while ($hps <- $max) { $i - $hps: Sstart - time( ): while ($i-) { Sresponse - $ua->request(Srequest): if (!$response->is_success) { die $response->error_as_HTML: } sleep A/Shps); } Send - time( ): print "$hps ". $hps / (Send - Sstart): $hps++: sleep 1: } } Веб-сервер я запускал три раза в различной конфигурации. В первом случае я указал строку security off в файле конфигурации magnus.conf, тем самым отключив защиту. Во втором случае я включил защиту и подключил карту nCipher, раскомментировав соответствующие строки в файле obj.conf. Наконец, в третий раз я включил защиту, но отключил карту nCipher, закомментировав относящиеся к ней строки в obj.conf. В каждом случае я проводил три теста и усреднял получившиеся значения с целью добиться большей гладкости графика. На рис. 8.1 показаны результаты моих трудов. Из графика сразу же становится ясно, что лучше всего, с точки зрения производительности, вовсе не пользоваться SSL, но если это необходимо — подключить карту-ускоритель. Хуже всего работает SSL без ускорителя. Пропуск- мая способность без SSL составляет 25 хитов в секунду; с SSL и картой nCipher — 17 хитов в секунду, а без этой карты — 9. Обратите внимание, что при низкой частоте поступления запросов (скажем, менее 5 хитов в секунду) графики совпадают, так что не имеет значения, есть ли у вас ускоритель SSL. Учтите, что это всего лишь сравнительный тест, а не абсолютная мера производительно-
сти сервера. Я запустил 16 копий сценария-клиента, и это исчерпало возможности компьютера, на котором он работал, а сервер при этом обслуживал 70 хитов в секунду без ускорителя. Рис. 8.1. Сравнительная производительность SSL SSL 3.0 позволяет кэшировать сеансы SSL, поэтому новые соединения по TCP, поступающие от того же браузера к тому же серверу, могут пользоваться существующими сеансами. Это означает, что серверам не обязательно генерировать пару ключей для каждого соединения; вместо этого одни и те же индивидуальные ключи могут использоваться для нескольких транзакций HTTP. В сервере Netscape Enterprise 4.0/iPlanet Web Server директива SSL3SessionTimeout в файле magnus.conf управляет кэшированием сеансов SSL3. По умолчанию время жизни кэшированного сеанса составляет 86 400 секунд, то есть 24 часа. Параметр SSLCacheEntries указывает максимальное количество кэшированных сеансов SSL. Важно помнить еще об одной особенности SSL: зашифрованные данные плохо сжимаются, что замедляет передачу данных, поскольку исключает использование встроенных в модемы алгоритмов сжатия. Например, текст обычно сжимается «на лету» более чем вдвое, но при передаче его через SSL выигрыш в скорости исчезает. С другой стороны, многие серверы могут быть настроены на передачу данных с автоматическим сжатием их программой gzip, а браузеры,
в свою очередь, могут расшифровывать передаваемые в сжатом виде данные. На это способны последние версии Netscape и Internet Explorer. Использование сжатия gzip вместе с SSL может восстановить скорость передачи до прежнего уровня и даже повысить ее за счет ресурсов процессоров сервера и клиента. Существует открытая реализация SSL, созданная Эриком Янгом. Называется она SSLeay. Если вы хотите получить представление о производительности SSL вашего сервера, можете воспользоваться эталонным тестом speedy поставляемым с этой реализацией. Брандмауэры Брандмауэры (firewalls) — это маршрутизаторы, обычно используемые для блокирования всего трафика, за исключением передаваемого через конкретные порты. Обычно это порты веб (80 и 443). Это позволяет отгородить интранет от Интернета, поскольку после установки брандмауэра вы больше не сможете подключаться к локальной сети извне с помощью telnet и работать в режиме терминала. Но достигается такая защищенность за счет некоторого усложнения сети. От хорошо настроенного аппаратного брандмауэра, блокирующего большую часть портов, производительность практически не страдает. Брандмауэры могут также шифровать весь трафик, что значительно увеличивает время ожидания (в 2 раза и более). Пара простых правил поможет вам уменьшить отрицательное влияние брандмауэров: используйте аппаратные брандмауэры и помещайте наиболее часто используемые правила в начало списка, чтобы они считывались в первую очередь. Брандмауэры могут работать параллельно. Узлы-бастионы Узлы-бастионы представляют собой нечто более сложное, чем брандмауэры. Часто для создания таких узлов используются обычные персональные компьютеры и рабочие станции. По сути своей узел-бастион представляет собой прокси- сервер для запросов, поступающих из-за пределов вашей организации, поэтому иногда такие узлы называются обратными прокси-серверами. Узлы-бастионы осуществляют просмотр входящих пакетов на предмет наличия в них подозрительных последовательностей данных. Все пакеты обязательно проходят проверку, после чего направляются на соответствующий интерфейс. Проверка может осуществляться на уровнях разных протоколов, что отличает бастион от обычного маршрутизатора, просматривающего только заголовки IP. Брандмауэры не разрывают соединений ТРС, а бастионы разрывают, после чего создают новое соединение во внутренней сети, так что внешний мир не видит ваши внутренние IP-адреса. Бастионы и веб-серверы обычно располагаются между двумя брандмауэрами в демилитаризованной зоне. Это еще больше замедляет доступ к серверу внутри организации.
Chroot Многие веб-серверы запускаются командой chroot, что должно повышать уровень безопасности, поскольку при этом корнем файловой системы становится другой каталог. Однако у такого решения есть два недостатка. Во-первых, все системные библиотеки и файлы, которые могут понадобиться веб-серверу, должны быть помещены в этот каталог. Все, что находится снаружи, после запуска с помощью chroot будет веб-серверу недоступно. Во-вторых, каждое обращение к файловой системе вызывает дополнительные накладные расходы, поскольку все обращения обрабатываются командой chroot. Основная рекомендация О Подумайте об аппаратном ускорителе SSL, если SSL вам необходим.
Zj Разбор ситуа ци й В данной главе мы разберем несколько примеров из реальной жизни. Все эти события произошли на самом деле, хотя некоторые имена и обстоятельства пришлось изменить, чтобы защитить виновных. Неограниченный рост таблицы Домашняя страница веб-сайта одной газеты обычно генерируется из запроса к базе данных примерно за одну секунду. В конце января была добавлена новая функция — персонализация веб-страницы. Каждый раз, когда пользователь обращается к домашней странице, в базе данных ищутся новости, которые могли бы этого пользователя заинтересовать. Пользователей радует нововведение, но контроль системы показывает, что добавление функции вызвало резкий скачок премени ожидания. Однако еще хуже было то, что контроль показал постоянный рост этого времени (рис. 9.1). Обнаружилось, что таблица базы данных со всеми новостями полностью сканировалась на предмет наличия подходящих новостей при каждом входе пользо- нателя в систему, а таблица эта постоянно и непрерывно росла. Решение проблемы заключалось в том, чтобы добавить к таблице новый индекс, устанавливающий соответствие между новыми сообщениями и теми пользователями, которым эти новости подходили. Время ожидания вернулось к прежнему значению, то есть к тому, которое было до нововведения. Индекс же создавался одной командой SQL, выглядевшей примерно так: create index news_index on news_story(user. story_age. alreadyjread):
Рис. 9.1. Рост времени ожидания после добавления новой функции Обратный поиск в DNS замедляет работу с журналом Брайан Робинсон из Гарвардского университета был так добр, что разрешил мне включить в книгу описание произошедшей с ним истории. При работе с сервером Netscape Server под Unix у него не возникало никаких проблем со статическими страницами, до тех пор пока не исчерпывалось количество потоков, после чего возникали гигантские задержки продолжительностью до двух минут. У страниц со включениями на стороне сервера (Server-Side Include — SSI) проблемы возникали всегда, когда начинал расти счетчик занятых потоков (время отклика порядка 10 с), а когда количество потоков достигало максимума, задержки тоже становились огромными. При этом время отклика часто совпадало со временем отсутствия в системе свободных потоков (в одном случае — более 15 мин). В плохие периоды ему приходилось видеть постепенное накопление занятых потоков Netscape, за которым следовало внезапное одновременное их освобождение — и все это при постоянной нагрузке. Больше всего страдала производительность страниц SSI, причем наибольшие спады наблюдались тогда, когда количество потоков достигало максимума, заданного конфигурацией. Производи-
тельность страдала и в те моменты, когда сервер Netscape увеличивал количество активных потоков. Обычно страницы SSI отправлялись пользователю через 250 мс, но при увеличении счетчика занятых потоков это время возрастало до 10 с (рис. 9.2). Производительность статических HTML-страниц падала только тогда, когда заканчивались потоки. Рис. 9.2. Время ожидания при использовании SSI Ключом к разгадке стал журнал сервера Netscape, в котором наблюдались пики активности до 350 хитов в секунду, в то время как тестовые программы абсолютно точно не выдавали более 10 хитов. Из этого стало ясно, что между отправкой страницы клиенту и записью сообщения об этом в журнале существовала задержка. Это означало, что процедура помещения записи в журнал содержала какие-то медленные этапы, а одним из этапов являлся обратный поиск в DNS. Затем Брайан измерил задержку между получением страницы на браузере и появлением записи в журнале, и график этой задержки оказался в точности соответствующим графику количества занятых потоков. Это свидетельствовало о том, что в возникающих задержках «виновата» подсистема ведения журналов. После отключения обратного поиска в DNS все задержки исчезли (рис. 9.3).
Рис. 9.3. После отключения обратного поиска в DNS Перекрученный кабель Контроль веб-сайта из той же локальной сети показывает, что статические страницы поставляются либо мгновенно, либо с некоторой постоянной задержкой. В результате на графике (рис. 9.4) появляются горизонтальные полосы. Поскольку веб-сервер работает на компьютере с операционной системой Solaris, мы можем подсмотреть, что происходит при обращении к веб-серверу на уровне пакетов, с помощью команды snoop. Параметр командной строки -t d позволяет выводить разницу во времени между пакетами. Впрочем, здесь можно было бы воспользоваться и свободно распространяющейся программой tcpdump: # snoop -t d server port 80 В листинге 9.1 приведен сценарий интерпретатора, скачивающий страницу с помощью команды GET библиотеки Perl LWP. Стандартный поток вывода направляется в /dev/null, поэтому время, затраченное на получение страницы, на экране не печатается. Обратите внимание, что программа /bin/time записывает сообщения в стандартный поток сообщений об ошибках.
Рис. 9.4. Некоторые страницы поставляются с одинаковой задержкой Листинг 9.1. Сценарий интерпретатора: получение веб-страницы #!/bin/bash while true do /bin/time GET http://server/file.html l>/dev/null sleep 1 done Мы запустили этот сценарий и некоторое время следили за временем ожидания. Когда мы обнаружили задержку при выполнении очередного запроса, мы сразу же изучили результат трассировки этого запроса. Чтобы разобраться в прицеленном ниже примере, вам потребуются какие-то знания протокола TCP, но самое главное, что нужно знать, — это то, что в одной строке выводятся сведения об одном пакете. Вот пример, в котором в первом столбце выводится время с момента получения предыдущего пакета: 0.65715 client -> server TCP 0=80 S=64474 Syn Seq=3316330059 Len=0 Win-8760 0.00007 server -> client TCP D-64474 S-80 Syn Ack=3316330060 Seq=956551078 Len=0 Win-8760 3.09232 server -> client TCP D-64474 S-80 Syn Ack-3316330060 Seq=956551078 Len-0 Win-8760 0.00234 client -> server TCP D-80 S-64474 Ack-956551079 Seq=3316330060 Len-0 Win-8760
0.00210 client -> server TCP D-80 S=64474 Ack-956551079 Seq-3316330060 Len=79 Win=8760 0.00018 server -> client TCP D-64474 S-80 Ack-3316330139 Seq=956551079 Len-0 Win-8760 0.00170 server -> client TCP D-64474 S-80 Ack-3316330139 Seq=956551079 Len-788 Win-8760 0.00048 server -> client TCP D-64474 S-80 Fin Ack-3316330139 Seq-956551867 Len-0 Win-8760 0.00105 client -> server TCP D=80 S-64474 Ack-956551867 Seq-3316330139 Len-0 Win-8760 0.00006 client -> server TCP D-80 S-64474 Ack-956551868 Seq-3316330139 Len-0 Win-8760 0.00356 client -> server TCP D-80 S-64474 Fin Ack-956551868 Seq-3316330139 Len-0 Win-8760 0.00157 server -> client TCP D-64474 S-80 Ack-3316330140 Seq-956551868 Len-0 Win-8760 В третей строке мы видим, что компьютер отправил дублирующий пакет SYN, безрезультатно прождав получения подтверждения (АСК) 3,09232 секунды. Подождав еще немного, мы обнаружили еще один ответ с задержкой и просмотрели результаты его трассировки: 0.66140 client -> server TCP D-80 S-63644 Syn Seq-3123165939 Len-0 Win-8760 0.00118 server -> client TCP D-63644 S-80 Syn Ack-3123165940 Seq-666055481 Len-0 Win-8760 0.00112 client -> server TCP D-80 S-63644 Ack-666055482 Seq-3123165940 Len=0 Win-8760 0.00182 client -> server TCP D-80 S-63644 Ack-666055482 Seq-3123165940 Len-79 Win-8760 0.00032 server -> client TCP D-63644 S-80 Ack-3123166019 Seq-666055482 Len=0 Win-8760 0.00188 server -> client TCP D-63644 S-80 Ack=3123166019 Seq=666055482 Len-788 Win-8760 0.00069 server -> client TCP D-63644 S-80 Fin Ack-3123166019 Seq-666056270 Len-0 Win-8760 3.09849 server -> client TCP D-63644 S-80 Fin Ack-3123166019 Seq-666055482 Len-788 Win-8760 4.59986 server -> client TCP D-63644 S-80 Fin Ack-3123166019 Seq-666055482 Len-788 Win-8760 0.00191 client -> server TCP D-80 S-63644 Ack-666056271 Seq-3123166019 Len-0 Win-8760 0.00410 client -> server TCP D-80 S-63644 Fin Ack-666056271 Seq-3123166019 Len=0 Win-8760 0.00128 server -> client TCP D-63644 S-80 Ack-3123166020 Seq-666056271 Len-0 Win-8760 Мы видим, что сервер отправил один и тот же пакет FIN своему клиенту трижды. Первый пакет был потерян, второй был отправлен спустя 3,09849 с, но тоже был потерян, после чего был отправлен третий пакет D,59986 с задержки). Этот пакет был подтвержден, но клиенту пришлось прождать 10 лишних секунд. Узнав о том, что в сети периодически пропадают пакеты, мы решили, что перегружен концентратор, подключающий сервер к локальной сети, однако замена
концентратора коммутатором ничего не дала. Наконец обнаружилось, что кабель, размещенный под полом, перекручен — возможно, из-за того, что при прокладке монтер бросил его под пол свернутым в кольца, а затем просто потянул на другой конец. После того как кабель был выпрямлен, горизонтальные полосы исчезли с графика. Итак, пакеты терялись из-за электрических наводок, вызванных перекручиванием. Рост пула базы данных ограничивает производительность Задержки времени отклика веб-сайта коррелировали с ростом пула соединений базы данных JDBC. Чтобы доказать связь между задержками и ростом пула, было проведено два теста. Размер пула был установлен равным 10 соединениям. Затем к веб-сайту обратилось 94 тестовых клиента примерно в одну секунду. Записывались время запуска и завершения всех 94 клиентов, а также зависимость размера пула от времени. На рис. 9.5 показаны графики результатов. Размер пула отложен по левой вертикальной оси, а количество клиентов — по правой. Время в секундах отложено по горизонтальной оси, но начинается оно с 628, а не с нуля, что связано с форматом записи времени в программах-клиентах. Рис. 9.5. Рост пула соединений Волнистая вертикальная линия на 633-й секунде показывает момент начала поступления запросов на веб-сайт. Запросы заканчиваются около 658-й секун-
ды, после чего размер пула стабилизируется. Размер пула соединений JDBC считывался с экрана веб-страницы Weblogic JDBCAdmin, на которой он выводится среди прочих данных. Среднее время отклика составило порядка 27 с. После этого мы установили размер пула равным 70 и запустили тест еще раз (рис. 9.6). Теперь среднее время отклика упало до 7 с. Рис. 9.6. Пул подключений большего размера Очевидно, что гораздо лучше иметь большой пул подключений, если база может это обеспечить, поскольку веб-сайт неспособен ответить пользователю, пока размер пула не увеличится настолько, чтобы принять все накопившиеся запросы. В данной ситуации есть еще несколько усложняющих факторов, о которых не следует забывать. Производительность увеличивается с уменьшением потоков Weblogic, но это может ограничить возможности сайта, поскольку на каждый запрос JDBC отводится один поток. Во-вторых, может оказаться, что соединения с базой данных не освобождаются после использования из-за ошибки программиста. В результате соединения существуют на 4 мин дольше, чем следовало бы (тайм-аут связующего сервера). Небольшое изменение в программе легко решит эту проблему. Основная рекомендация О Читайте о проблемах других людей, чтобы найти решения своих собственных проблем. Пишите по адресу: p@patrlck.net, если у вас есть примеры проблем и их решений, относящиеся к вашему собственному веб-сайту.
10 Принципы и схемы Существует несколько принципов повышения производительности, применимых в любой ситуации, и несколько общих схем, позволяющих характеризовать ли ситуации. Им и посвящена настоящая глава. Принципы повышения производительности В последующих разделах обсуждаются некоторые общие принципы повышения производительности. Иногда приходится проигрывать Невозможно определить заранее без подробного анализа, удастся ли повысить производительность системы. Приходится рисковать своим временем, поскольку может оказаться, что ничего путного сделать нельзя, особенно если вы ограничены в финансовом или временном отношении. Нужно сравнить потенциальную сложность анализа и возможный выигрыш. Только если последний значителен, можно попробовать повысить производительность; в противном случае не стоит и время тратить. Измерение меняет объект Физик по имени Вернер Гейзенберг в свое время отметил, что любой акт измерения влияет на изучаемый объект, изменяя его, пусть даже на весьма малую величину, поэтому любым измерениям присуща неопределенность. Это утверждение называется принципом неопределенности, и оно, без сомнения, применимо к измерениям производительности компьютеров.
Классический пример: вы запускаете программу ps, чтобы увидеть, какие процессы выполняются на вашем сервере, и обнаруживаете, что единственный всегда выполняемый процесс — это сама программа ps. Конечно, так и должно быть, поскольку процесс ps обязательно должен выполняться, чтобы иметь возможность определить состояние других процессов. Аналогично, когда вы измеряете производительность компьютера, занятого какой-то другой работой, вы измеряете не чистую нагрузку, создаваемую полезной работой, но общую нагрузку, в которую входят и ваши измерения. Пусть это не введет вас в беспокойство и разного рода рекурсивные измышления. Неопределенностью можно пренебречь, если измерение проводится быстро и слабо влияет на объект, — поэтому пусть ваши измерения будут именно такими. Знания важнее всего Пробираясь по комнате в потемках, легко поставить себе на колено синяк. Если включить свет, путешествовать станет гораздо безопаснее. Свет дает вам знание, помогающее наилучшим образом проложить ваш маршрут. То же можно сказать и о повышении производительности. Чем лучшее представление вы имеете о проблеме, тем легче ее решить. Ваша путеводная звезда —документация на вашу рабочую станцию, программное обеспечение и маршрутизаторы. Займитесь чтением документации. Руководство пользователя никогда не покажется скучным, если в нем найдется средство, способное облегчить ваши муки. Хорошо экспериментировать с параметрами и измерять производительность, но лучше знать, почему параметры как-то влияют на систему, и понимать, как они взаимодействуют друг с другом и с подсистемами. Это знание хранится в руководствах и статьях. Увеличение производительности в одном месте может стоить уменьшения ее в другом. Если вы не знаете, сколько заплатили, то не можете сказать, стоило ли это делать. «Бесплатных обедов» не бывает Целью повышения производительности является достижение больших результатов без обязательного повышения затрат, однако в реальности приходится платить за любое повышение производительности, пусть даже только усилиями, затрачиваемыми на понимание проблемы и поиск решения. В некоторых случаях приходится покупать новое оборудование, изменять архитектуру системы, а иногда — терять переносимость, удобство обслуживания, защищенность, надежность или время разработчиков. Чтобы достичь более высокой производительности сервера, можно повысить тактовую частоту его шины, но при этом система будет иметь больше шансов на сбой. Можно отключить брандмауэр и не устанавливать шифрование, но тогда вы станете уязвимее для атак хакеров. Можно написать все программное обеспечение для веб-сервера на языке ассемблера, оптимизируя его вручную, или купить специальные процессоры для ускорения веб-приложений, но сложность обслуживания и размер затрат почти
наверняка сведут возможный выигрыш на нет. К сожалению, правда и то, что улучшение производительности системы в расчете на конкретные условия, скорее всего, приведет к ухудшению производительности при выходе за рамки этих условий. Суть в том, чтобы не покупать слишком дорого. Бесплатных обедов не бывает, но дешевые найти можно. Доходы сокращаются По затратам можно определить момент, когда пора заканчивать улучшать производительность системы в том виде, в котором она вам досталась. Когда вы только начинаете настройку системы, обычно легко бывает найти самые очевидные недостатки и устранить их. По мере вашей работы новые возможности для повышения производительности искать становится все труднее, они делаются нее более конкретными, зависимыми от конфигурации и ожидаемых условий использования. Когда доходы не стоят вложений, оптимизацию можно считать завершенной. Стоимость оценивается субъективно, но я попробую привести условия, при выполнении которых можно считать, что работа окончена, — по крайней мере, на данный момент. О Пользователи больше не замечают улучшений. О Вы перестали придерживаться хорошего стиля программирования, пытаясь достичь большей производительности, и это сделало код непереносимым и необслуживаемым. О Вы подумываете о том, чтобы переписать все на ассемблере. О Ваши затраты в расчете на одну просмотренную пользователем страницу оказываются такими, что на эти деньги можно было бы нанять человека, который принимал бы запросы по телефону и отправлял бы нужные сведения по факсу. О Вы становитесь очень раздражительны. Предельная оптимизация — это движущаяся цель, поскольку ваша конфигурация, условия использования и набор доступных компонентов постоянно меняются, что делает невозможным достижение максимума. В конце концов оказывается выгоднее придерживаться стандартных протоколов и API, а не разрабатывать свои собственные или покупать чьи-то чужие запатентованные решения, потому что тогда ваши усилия оплачиваются переносимостью в рамках нескольких поколений систем, а это дает вашим вложениям больше возможностей окупиться. Переносимость уменьшает производительность Между переносимостью и производительностью всегда идет война. Максимальная производительность достигается в системах, рассчитанных на вполне определенные условия, а переносимость определяется как способность функцио-
нировать в самых различных условиях. Невозможно подготовиться ко всем ситуациям, поэтому приходится выбирать между переносимостью и производительностью. Полностью оптимизированное программное обеспечение оказывается привязанным к конкретной платформе, поскольку оно должно использовать все полезные особенности этой платформы, например специальные регистры процессора или системные вызовы. С другой стороны, переносимые программы не могут использовать функции, доступные только на одной из платформ. В противном случае эти программы не были бы переносимыми. На следующем уровне проявляется зависимость улучшений от предполагаемых условий использования. При изменении условий такие улучшения почти наверняка приведут к снижению производительности. Компромиссы бесчисленны. Потеря переносимости программ в погоне за скоростью не значила бы так много, если бы переносимое обеспечение не являлось таким ценным товаром. Переносимость на уровне исходного кода означает, что его не нужно переписывать для запуска на другой платформе. Достаточно лишь повторной компиляции. Это позволяет экономить на разработке и открывает программам широкий рынок. Переносимость на уровне объектного кода (примеры — Java и Smalltalk) хороша как для разработчиков, так и для пользователей, поскольку разработчики могут сосредоточиться на написании программ, а не на обеспечении переносимости, а пользователи могут выбирать ту платформу, которая им удобна. Никакой выгоды в том, чтобы привязывать себя к конкретной платформе, для пользователя нет. Другого рода переносимость мы получаем, следуя открытым сетевым стандартам, дающим даже непереносимому самому по себе программному обеспечению возможность связаться с другими компьютерами. Своим расцветом Всемирная Паутина обязана именно переносимости протокола HTTP. Он может не обеспечивать максимально возможной производительности для любого конкретного компьютера, но, поскольку он был реализован на великом множестве компьютеров, ключевым фактором становится возможность использовать этот протокол для связи. Любой браузер может обратиться к любому веб-серверу только потому, что они разговаривают на одном языке. Урок прост: можно купить производительность за счет переносимости, но это будет пиррова победа. Со временем за нее придется заплатить слишком большую цену. Абстрагирование уменьшает производительность Программирование на языках высокого уровня, когда все больше мелочей берет на себя среда разработки, позволит вам достичь лишь весьма среднего уровня производительности, но никогда — высшего. Программируя на языках высокого уровня или автоматически генерируя запросы SQL, вы даете программе заботиться об оптимизации вашей системы, лишаясь понимания и власти в обмен на простоту разработки. Иногда результат стоит того, иногда нет.
Защищенность уменьшает производительность Защищенность — это дополнительное ограничение, которое вы накладываете на свою систему, а любые ограничения уменьшают вашу свободу в повышении производительности. Установка соединения по SSL занимает довольно много времени, брандмауэры замедляют передачу пакетов, а необходимость ввода паролей замедляет работу пользователя. Безопасность необходима, но ее влияние на производительность обычно достаточно значительно. Память имеет иерархическую структуру Веб можно представлять себе как самый медленный и дешевый из видов памяти вашего компьютера. Хотя веб в действительности находится вовсе не внутри вашего компьютера и большая его часть доступна вам только для чтения, она хорошо вписывается в общую иерархическую структуру памяти (рис. 10.1). Рис. 10.1. Иерархическая структура памяти На каждом из уровней иерархии памяти приходится делать выбор между стоимостью и производительностью, причем стоимость практически линейно связана со скоростью доступа. Последние использовавшиеся данные какого-либо уровня обычно каптируются следующим, более быстрым, уровнем. Целью кэширования является повышение производительности благодаря использованию наиболее быстрой памяти большую часть времени. При этом необходимо минимизировать количество обращений к данным, не находящимся в кэше. Конечно, полностью избавиться от обращений к нижним уровням за отсутствующими в кэше данными вам не удастся, иначе эти уровни не были бы нужны. Однако
эти обращения стоят дорого, поскольку время обращения к данным нижних уровней относительно велико. Часто говорят, что веб уничтожает (или сокращает) расстояния, но это не совсем верно. За свой жесткий диск вам приходится заплатить лишь однажды, после чего вы можете пользоваться им весьма долгое, хотя и конечное время. За отправку и получение данных по Интернету приходится платить каждый раз. Поэтому в отношении веб кэширование не только увеличивает производительность, но и снижает стоимость. Если вы собираетесь использовать данные много раз, дешевле хранить их в кэше, чем передавать на сколько-нибудь значительное расстояние. Хранение информации — это тоже своего рода передача ее, только во времени, а не в пространстве. Перемещение хранящегося на носителе бита из настоящего момента в более поздний аналогично перемещению этого же бита из одной точки пространства в другую по какому-либо передающему каналу. В обоих случаях нужно обеспечить сохранность передаваемых битов, причем для этого используются одинаковые схемы контроля и коррекции ошибок. Кэширование зависит от локальности ссылок Если бы обращение к памяти производилось абсолютно случайным образом, кэширование не могло бы существенно повысить производительность. Данные, хранящиеся в кэше, постоянно замещались бы новыми, считываемыми из случайных областей памяти, причем повторное обращение к той же области через небольшой промежуток времени, за который данные не успели бы уйти из кэша, было бы маловероятным. К счастью, доступ к памяти подчиняется определенным закономерностям. Ячейки памяти, обращение к которым производилось недавно, являются вместе со своими соседями наиболее вероятными кандидатами на повторное обращение. Это свойство называется локальностью ссылок. Обращения к памяти имеют тенденцию группироваться в адресном пространстве и во времени. Поэтому алгоритмы, кэширующие содержимое недавно считанных ячеек и их соседей, действительно улучшают производительность. Например, достаточно хорошо работают схемы кэширования, используемые в буфере файловой системы Unix или в кэшах веб-браузеров. Операции ввода-вывода всегда медленны Ввод-вывод (I/O) означает поступление информации в компьютер и выдачу оной из него. Кроме того, этот термин применим и к отдельным компонентам компьютера. Ввод-вывод не относится к числу сильных сторон компьютеров. Они гораздо лучше осуществляют вычисления, чем выводят их результаты. К сожалению, веб практически полностью состоит из ввода и вывода информации: доступ к сети, доступ к файлам содержимого и журналов на дисках, вывод на экран.
Именно по этой причине скорость процессора и близко не лежит по важности к скорости шины и скорости линии связи для браузеров и серверов. Хуже всего осуществляют ввод-вывод механические устройства. Никакое устройство с движущимися частями не может работать с теми скоростями, с которыми работает электроника остальных компонентов компьютера. Поэтому самой медленной частью веб-сервера является жесткий диск. Насколько медленной? Сравните время доступа к оперативной памяти E0 не) со временем доступа к диску C мс). Второе почти в сто тысяч раз больше. Очевидно, что количество обращений к диску нужно по мере возможности стараться свести к минимуму, особенно если у вас достаточно оперативной памяти. Исторически сетевой ввод-вывод был гораздо медленнее внутренних линий связи компьютера (шин), но современные сетевые адаптеры и другое оборудование (типа гигабитного Ethernet) позволяют загрузить как шину, так и процессоры большинства компьютеров. Если эта тенденция продолжится и на уровне сетей больших масштабов, а проблемы с временем ожидания будут устранены эффективным кэшированием, можно будет говорить о создании действительно распределенной вычислительной машины, вычислительная мощность и устройства памяти которой будут разбросаны по всему Интернету Но на данный момент Интернет соревнуется с жесткими дисками за последнее место в конкурсе на быстроту компонентов веб. Информация относительна Теория информации определяет информацию как нечто уменьшающее неопределенность. Когда компьютер прослушивает сетевое соединение, значение бита, который должен быть получен следующим, неопределенно. Когда бит прибывает, неопределенность исчезает. Информация сообщает нам о том, чего мы еще не знали. Можно ли конкретный бит назвать информацией, зависит от того, что именно мы уже знаем. Сервер может уменьшить количество передаваемых битов, используя то, что клиент уже знает. Этот факт используется алгоритмами кэширования. Когда клиент не знает, актуальны ли хранящиеся в его кэше данные, он отправляет запрос на сервер, описывая в этом запросе имеющуюся у клиента информацию. Сервер сообщает, актуальна ли эта информация. Именно таким образом работают заголовки if-modified-since в протоколе HTTP. Это экономит значительную долю пропускной способности Интернета и повышает производительность. Существует несколько простых правил, касающихся использования уже имеющейся у клиента информации. Эти правила можно применять к решению проблем с производительностью. О Обновляя информацию, пересылайте только изменения. Например, вместо шлюза CGI можно использовать апплет, отправляющий запросы на сервер. Шлюз отправляет пользователю всю HTML-страницу целиком, вместе с графикой, каждый раз при изменении данных, что расходует пропускную способность сети и замедляет производительность. Апплет позволяет получить
и отобразить на экране только данные (например, курс акций), составляющие значительно меньший объем информации. В этом случае повторная передача графики или текста HTML не требуется. О Оптимизируйте систему, используя знания о тех условиях, в которых вам предстоит работать. Вам не нужно готовиться ко всему, если произойти может лишь немногое. Например, обращение к файлам на серверах HTTP производится не случайным образом: текстовые файлы HTML содержат ссылки на другие файлы — в частности, графические изображения, которые почти всегда запрашиваются непосредственно после самой HTML-страницы. Оптимизируя систему с учетом этого, разумно записать все файлы данной страницы на жесткий диск непосредственно после самой страницы, что уменьшит время поиска данных. Это может не сработать на сильно загруженном сервере, с которого постоянно запрашиваются разные страницы, но сама мысль ясна. Если вы знаете, что все пользователи в какой-то момент будут запрашивать в основном какую-то конкретную страницу, вы можете оптимизировать систему с учетом этого, переместив эту страницу в кэш файловой системы или сервера заранее. Хорошим источником информации об условиях работы являются файлы журналов. В некоторых отношениях повышение производительности веб является более простым делом, нежели оптимизация компьютерных программ вообще, поскольку вы можете узнать много ценных сведений об условиях работы сервера и клиента HTTP. О В процессе оптимизации нужно учитывать имеющиеся знания о данных. Конечно, биты есть биты, но систему можно настроить на данные разного рода. Например, некоторым видам данных соответствуют известные распределения размеров файлов. Веб-сайт, предоставляющий пользователям возможность скачивать большие файлы, достигает более высокого уровня производительности, увеличив объем данных, которые могут относиться к одному узлу ino- de, и обеспечит более высокую производительность сети, убедившись, что размер максимального передаваемого блока (MTU) не превышает минимального значения этой величины на всем протяжении сети от сервера до клиентов. О Используйте все, что знаете о пользователях. Какого рода сжатие поддерживается браузером клиента? Может ли браузер задействовать повышающие быстродействие новшества HTTP 1.1 и Java 1.2? На какие время ожидания и пропускную способность рассчитывает пользователь? Все эти знания помогут вам обеспечить лучшее соответствие ожиданиям пользователей. Интересный факт о сжатии и информации: любая схема сжатия данных требует соглашения между отправителем и получателем об алгоритме восстановления исходных данных. Соглашение может быть простым механизмом, сокращающим избыточность, но оно может также содержать в себе какие-то данные. Таким образом работают некоторые схемы сжатия речи для полицейских радиосетей. Люди обычно издают лишь ограниченный набор звуков. Можно получить высокую производительность при низкой пропускной способности, ис-
пользуя кодовую книжку этих звуков и передавая только коды и дополнительные параметры, позволяющие сделать звучание более естественным. Именно такая схема сжатия дает полицейским радиостанциям характерное для них звучание. В свое время некоторыми фирмами делались попытки ускорить и улучшить работу в веб аналогичным образом — путем отправки всем пользователям службы компакт-дисков с изображениями и звуками, чтобы при работе с сайтами загружались только текст и, ссылки на изображения и звуки, хранящиеся на компакт-дисках. Эта идея не прижилась, поскольку один компакт-диск ничтожно мал по сравнению с огромным океаном постоянно меняющейся Сети. Оборудование дешево, программы дороги Мне придется смягчить это утверждение. Оборудование не так уж дешево, а программы, предназначенные для широкого рынка, могут, напротив, быть действительно дешевы. Но если вам нужно быстро решить проблему с производительностью, наиболее экономически выгодным решением является покупка более ;>ффективного оборудования. Программы писать дорого, столь же дорого их отлаживать, причем, к сожалению, нельзя распределить стоимость своих программ между пользователями. Программы пишутся долго, а хорошие программисты берут большие деньги за спою работу. В отличие от производительности оборудования, производительность программистов не растет экспоненциально, поскольку программисты все- IX) ЛИШЬ ЛЮДИ. Целью оптимизации является одновременность выхода из строя компонентов Веб-система может считаться оптимизированной, когда в ней не остается больше «узких мест». Это определение ничего не говорит об общей пропускной способности системы. Даже система с очень низкой пропускной способностью технически может считаться оптимизированной. Целью оптимизации является отсутствие незадействованных мощностей; другими словами, все компоненты должны израсходовать свои ресурсы в один и тот же момент. Эта идея не нова. Генри Форд в свое время нанял специалиста, который изучал машины на свалках, чтобы определить, какие их части дольше всего работали, и при проектировании последующих модификаций автомобилей качество этих частей преднаме- |>енно снижалось для экономии денег. Нет смысла в том, чтобы одни компоненты системы работали значительно дольше, чем другие. Я не рекомендую вам ухудшать отдельные составляющие системы до тех пор, пока все они не начнут работать одинаково плохо. Форд старался снизить стоимость производства машин на конвейере, а вы вряд ли являетесь столь же крупным производителем веб-систем. Скорее всего, вам нужно повысить произ-
водительность одной системы. Цель у вас противоположная: нужно найти самое слабое звено системы и улучшить его. Интересно отметить, что чем хуже оптимизирована система, тем ее проще настраивать. Когда один из компонентов тормозит систему большую часть времени (например, большой объем содержимого, передаваемый по медленному модему), сразу ясно, что именно им и нужно заняться в первую очередь. Устраняя одну проблему за другой, вы дойдете до того, что все компоненты станут источниками проблем в одинаковой степени. Тогда оптимизацию можно считать завершенной. Поскольку веб-системы обычно являются динамичными и в них постоянно добавляются новые элементы, поиск самого слабого звена в любой конкретный момент может быть достаточно сложен. Вместо того чтобы тратить все время на поиск ускользающей слабины, которую нужно устранить, лучше поставить себе конкретную цель в плане производительности и попытаться достичь ее, пусть даже одни компоненты при этом будут работать несколько хуже, чем другие. Тем не менее, если большая часть компонентов при этом будет простаивать, проблему все равно нельзя будет считать решенной. Хорошее относительно Нужно контролировать производительность и вести соответствующий журнал, который будет служить как эталоном для оценки результатов оптимизации, так и источником подсказок при поиске «узких мест». Информация в журналах должна храниться, по крайней мере, годами, а лучше — вечно, если у вас достаточно для этого места. Конечной мерой производительности является удовлетворенность пользователя, поэтому стоит завести журнал жалоб на производительность. Рассматривайте жалобы как бесплатные сведения об уровне производительности. Биты — это деньги Почтовое ведомство США доставляет посылки разного размера приблизительно с одной и той же скоростью. В веб скорость прибытия пакета определяется его размером: чем пакет меньше, тем он быстрее прибывает. Неважно, насколько хорошо оптимизирована ваша система, если ваше содержимое слишком велико. Пусть его объем будет мал. Не добавляйте на свои страницы все, что попадается вам на глаза, только потому, что вы можете это сделать. Не принимайте данные неограниченного объема от своих пользователей. Всегда устанавливайте для них конкретные ограничения. Производительность Интернета падает нелинейно Производительность служб Интернета падает очень резко, как только вы переходите определенную точку. Система не замедляется постепенно, с ростом на-
грузки, — напротив, все останавливается так резко, как будто вы врезались головой в бетонную стену. Это связано прежде всего с тем фактом, что интернет представляет собой носитель общего пользования наподобие шоссе, и потому он подвержен заторам и пробкам, в точности как автомобильные дороги. Глобальная оптимизация дает наилучшие результаты Вряд ли вы достигнете большого улучшения производительности, слегка поменяв какие-то параметры. Хороших результатов можно достичь, лишь выбросив отдельные сегменты вашей архитектуры целиком или удалив некоторые этапы обработки. Чтобы достичь самых лучших результатов, анализируйте архитектуру прежде всего на самом верхнем уровне. Таким образом у вас к тому же будет меньше всего шансов потратить время зря. Если же вы займетесь оптимизацией какого-то отдельного этапа на низком уровне, в конце концов может выясниться, что этот этап лучше всего просто выкинуть. Что произошло однажды, скоро произойдет снова Звучит неправдоподобно, но это так. Я думаю, это обусловлено тем, что условия, вызвавшие первое событие, остаются в силе спустя некоторое время после его наступления. Когда кто-то звонит по телефону, он скорее позвонит сразу же еще раз, потому что забыл что-то сказать, чем позвонит некоторое время спустя. Кэширование работает эффективно потому, что велика вероятность повторного обращения к данным, прежде чем они окажутся вытесненными из кэша. Если бы это было не так, кэширование только замедляло бы работу являясь лишним промежуточным звеном. Правило 80/20 Восемьдесят процентов времени программа выполняет 20% кода. Это правило действует почти всегда. Именно поэтому профилирование и оптимизация являются весьма рациональными способами борьбы с недостаточной производительностью. Правило 80/20 применимо и ко многим другим вещам. Экономист Парето отмечал, что 80% богатств обычно сосредоточены в руках 20% представителей любого общества. Люди часто важнее знаний То, кого вы знаете, все еще важнее, чем то, что вы знаете. Особенности веб- служб и производительности меняются так быстро, что ни один человек не может уследить за всем. Ваши собственные секреты, позволяющие улучшить производительность веб-сайта, вряд ли помогут вам так же сильно, как множество друзей, готовых поделиться с вами опытом. Чтобы завоевать их доверие, вам
придется помогать им, делиться с ними своими секретами. Множество полезных людей можно встретить в конференциях comp.jnfosystems.www.servers.* и comp.Jnfosystems.www.misc. Как сказал Бернард Шоу, «если у нас с другом есть по одному яблоку и мы обменяемся ими, то у нас так и останется по одному яблоку. Но если у нас есть по одной идее, то после обмена идей у каждого из нас станет по две». Схемы улучшения производительности Способы улучшения производительности можно объединить в схемы — это полезнее, чем давать множество конкретных советов. В последующих разделах обсуждаются некоторые схемы, представляющие собой группы конкретных методов. Амортизация Увеличение производительности часто осуществляется путем амортизации издержек на множество транзакций. О Протокол HTTP 1.1 позволяет использовать одно и то же ТСР-соединение для загрузки нескольких файлов. Эта функция называется постоянным соединением. Затраты на установку и разрыв TCP-соединения распределяются между несколькими файлами, вместо того чтобы ложиться целиком на каждый из них заново. О Файлы .jar языка Java работают аналогичным образом, группируя файлы .class в пакет, который может быть загружен через одно соединение TCP, тогда как без этого для каждого класса пришлось бы создавать свое соединение. Недостаток архивов в том, что они могут содержать классы, которые никогда вам не понадобятся. О Наконец, еще одним примером является изображение-карта (imagemap). Вместо того чтобы отправлять пользователю несколько небольших изображений, можно переслать ему одно большое. Если по небольшим изображениям можно было щелкать и затем переходить по соответствующим ссылкам, то для отдельных областей большого изображения-карты сохраняется та же функциональность. Кэширование Кэширование — это самый важный и наиболее широко используемый метод повышения производительности. Идея проста: часто используемые данные должны быть всегда иод рукой. Кэширование помогает только в том случае, если некоторые данные действительно используются чаще, чем другие, — но так оно обычно и бывает. О Нередко можно выиграть в производительности, проиграв в свободном месте на жестком диске, запустив шлюзы CGI с наиболее характерными входными данными от виртуальных пользователей и сохранив все результаты. После этого пользователи смогут быстро обращаться к статическим HTML-страницам, вместо того чтобы каждый раз ждать генерации динамического HTML.
О Большой объем памяти уменьшает потребность в обращении сервера к жесткому диску. Unix кэширует часто используемые файлы в оперативной памяти, не загружая их с диска, но только если этой памяти достаточно. О Прокси-серверы веб снижают нагрузку на линию связи фирмы с Интернетом и ускоряют доступ к наиболее популярным веб-страницам, кэшируя эти популярные страницы. Профилирование Профилирование означает изучение условий использования либо для поиска «узких мест» в коде, либо для оптимизации программ в расчете на реальный мир. В общем случае программа должна работать быстрее, если учесть следующие соображения. О Системы профилирования кода находят наиболее часто выполняемую составляющую программы, чтобы разработчик мог оптимизировать ее — возможно, даже переписав на ассемблере. Виртуальная машина HotSpot Java VM динамически находит наиболее часто используемый код и компилирует его в «родной» код компьютера «на лету». О Вы можете профилировать своих пользователей и использовать приобретенные сведения для того, чтобы приблизить к ним свой веб-сайт. Например, если большинство ваших пользователей — японцы, производительность вашего сайта станет выше, если вы разместите свой веб-сервер в Японии. О Можно профилировать время загрузки файлов вашими потребителями и определять таким образом пропускную способность их линий. Корректируйте свое содержимое с учетом того качества доступа к Интернету, которое характерно для ваших пользователей. Параллельная обработка Во многих ситуациях, возникающих при работе с веб, выигрышной оказывается стратегия разделения задач между несколькими исполнителями. О Netscape и некоторые другие браузеры одновременно открывают несколько подключений к серверу и посылают запросы параллельно, рассчитывая на то, что сервер сам определит наиболее эффективный способ обслуживания этих запросов, вместо того чтобы посылать запросы последовательно, в случайном порядке. О Программы на Java выигрывают в скорости благодаря многопоточности, позволяющей отдельным потокам продолжать работу даже тогда, когда прочие потоки заблокированы. Например, если пользователю, работающему с приложением на Java, нужно заполнить поля ввода для входа в систему, приложение в это время может скачивать дополнительные файлы классов, отведя для этого отдельный поток. Не выстраивайте задачи в последовательную цепочку, если в этом нет необходимости. О Многопроцессорные системы (Symmetric Multiprocessing — SMP) могут распределять потоки между процессорами и выполнять операции параллельно.
Используйте то, что знаете Не стоит недооценивать важность даже самых тривиальных сведений: О Вы знаете, что следующее за запросом HTML-страницы обращение наверняка будет сделано к изображению, на ней находящемуся. Поэтому теоретически веб-серверы могут читать HTML и заранее подготавливать изображения к отправке. О После однократного использования соединение наверняка понадобится снова. Именно поэтому в HTTP 1.1 введены постоянные соединения. О Если ваш веб-сервер может определять характер запросов конкретного пользователя, он может оптимизироваться с учетом этих сведений — например, подготавливая заранее содержимое, которое в противном случае генерировалось бы динамически. Простота Многое можно выиграть благодаря стремлению к простоте и избавлению от всего лишнего. О У внутренних модемов нет кабелей, соединяющих их с системной шиной, поэтому они не только быстрее работают, но и стоят меньше. Кроме того, для них нельзя купить неподходящий кабель, поскольку, как мы только что отметили, кабель им вовсе не нужен. О Упрощение и сокращение содержимого, удаление фреймов, таблиц и лишних изображений может очень сильно сократить время его загрузки. Хорошим примером является поисковый сервер Yahoo!. О Использование статического содержимого и полный отказ от шлюзов CGI значительно улучшают время отклика за счет гибкости. Помните, что самый быстрый способ что-то сделать — вовсе не делать этого. Если вы можете удалить часть системы — значит, вам следует это сделать. Нужно находить избыточные элементы и удалять их, но лучше всего мыслить еще более глобально. Может быть, ваши пользователи способны работать со своими собственными веб-серверами. Может быть, лично вам для вашего бизнеса Интернет вообще не нужен. Тогда все проблемы с производительностью веб исчезнут сами собой. Основные рекомендации О RTFM. О KISS (keep it simple, stupid — сделай это проще, дурачок!). О Минимизируйте количество операций ввода-вывода. О Везде, где возможно, передавайте по сети только изменившиеся данные. О Кэшируйте все, что можно. О Лучше делиться секретами, чем скрывать их.
Часть II Подробно об оптимизации
11 Браузеры Идея программы просмотра гипертекста — браузера — не нова. Многие пакеты, предназначенные для работы с текстом, такие как FrameMaker, и многие форматы, такие как PDF, позволяют создавать и включать в документы гиперссылки. Идея создания гипертекстового браузера на основе общих стандартов, в частности ASCII и сокетов Unix, впервые была использована в системе Gopher типа «клиент—сервер». Gopher был придуман и реализован в университете штата Миннесота. Gopher оказался очень простым и быстрым, но ссылки предлагались пользователю в виде меню, размещавшегося отдельно от текста. Кроме того, Gopher не предусматривал автоматической загрузки изображений. Первый недостаток был устранен с изобретением HTML, а второй — с созданием в 1993 году первого графического браузера HTML под названием Mosaic в Национальном центре вычислительных приложений (National Center for Supercomputing Applications — NCSA) университета штата Иллинойс. Большинство студентов, создавших Mosaic, на следующий год вошли в команду основателей Netscape. Попытка перевода Mosaic на коммерческую основу привела к основанию фирмы Spyglass, которая продала лицензию компании Microsoft для создания Internet Explorer. Netscape и IE последние несколько лет были на переднем крае по усовершенствованию браузеров, но основная функция браузера — получение и отображение гипертекста и картинок — осталась неизменной. Как работают браузеры Основная функция браузера очень проста. Любой программист, хорошо знающий Perl или Java, способен написать простейший рабочий текстовый браузер за один день. Браузер устанавливает соединение с веб-сервером по протоколу
TCP, обычно подключаясь к порту 80, и запрашивает документ, используя синтаксис HTTP. По этому соединению браузер получает HTML-документ, обрабатывает его и отображает на экране, каким-то образом выделяя некоторые элементы текста, которые являются ссылками на другие документы или изображения. Когда пользователь выбирает одну из ссылок, щелкая по ней, все начинается снова: браузер запрашивает следующий документ. Несмотря на все усовершенствования HTML, HTTP и Java, основные функции всех браузеров абсолютно одинаковы. В листинге 11.1 приведен код на языке С, позволяющий запросить домашнюю страницу с любого веб-сервера. Я начал с небольшого примера, иллюстрирующего подключение к серверам вообще, взяв его с замечательной веб-страницы, посвященной программированию с использованием сокетов Интернета, которая находится по адресу: http://www.ecst.csuchico.edu/~beej/guide/net/. Затем я изменил этот пример, добавив в него запрос веб-страницы. Вообще говоря, похожий код используется в любой программе-клиенте для Unix. Саму программу можно скачать по адресу: http://patrick.net/software/tiny.c. Листинг 11.1. Запрос домашней страницы с веб-сервера (язык С) #include <stdio.h> #include <errno.h> linclude <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #define PORT 80 Idefine BUFSIZE 4000 int maindnt argc. char *argv[]) { int sockfd. count: char *request - "GET / HTTP/1.0\n\n": char reply[BUFSIZE]: struct hostent *he: struct sockaddrjn target: if ((he=gethostbyname(argv[l])) -- NULL) { herror("gethostbyname"); exit(l): } if ((sockfd - socket(AF_INET. S0CK_STREAM. 0)) -- -l) { реггог("socket"): exit(l): } target.sin_family - AF_INET; target.sin_port = htons(PORT); target.sin_addr = *((struct in_addr *)he->h_addr); bzero(&(target.sin_zero). 8): if (connect(sockfd. (struct sockaddr *)&target.
sizeof(struct sockaddr)) — -1) { pernor("connect"): exit(l): } send(sockfd. request. strlen(request). 0): if ((count - recv(sockfd. reply. BUFSIZE. 0)) == -1) { perrorCrecv"): exit(l); } reply[count] - '\0'; printfC'fcs". reply): close(sockfd): return 0: } Скомпилировав эту программу командой % gcc -о tiny tiny.с, вы сможете обращаться к веб-серверам, вызывая ее следующим образом: % tiny patrick.net Программа выводит содержимое домашней страницы сервера в стандартный поток вывода. Давайте теперь изучим функциональные возможности современных браузеров подробнее, обращая внимание на все, что связано с производительностью. Перво-наперво браузер должен обработать адрес URL, введенный в поле Location:, или распознать ссылку, на которой вы щелкнули. Это должно выполняется очень быстро. Затем браузер проверяет содержимое своего кэша на предмет наличия в нем запрошенной страницы. Поиск ведется по хэшированной базе данных, устанавливающей соответствие между URL-ами и содержимым кэша. Динамическое содержимое в кэш не помещается, но если поставщик содержимого не указал нулевое время жизни документов в заголовке HTTP, а браузер недостаточно «умен», чтобы распознать в URL обращение к шлюзу, динамические страницы тоже будут кэшироваться. Если запрошенная страница имеется в кэше и пользователь потребовал от браузера (с помощью параметров настройки) проверки наличия обновленных версий кэшированных страниц, то браузер попытается сэкономить время, сделав запрос HTTP HEAD со строкой if-modified-since, позволяющий проверить актуальность кэшированной страницы. Если сервер ответит, что страница с тех пор не обновлялась, браузер отобразит на экране то, что хранится в его кэше. Если нужной страницы в кэше нет либо она там есть, но устарела, браузер запросит текущую версию страницы с сервера. Чтобы подключиться к веб-серверу, клиент должен знать IP-адрес сервера. Браузер обычно получает от пользователя или из HTML только полное доменное имя сервера (типа www.piter.com), а не IP-адрес, поэтому клиенту приходится искать адрес сервера в DNS. Это осуществляется путем обращения к распре-
деленной базе данных доменных имен и IP-адресов, которая называется DNS (Domain Name Service — служба доменных имен). Клиент запрашивает локальный сервер имен, который либо сразу выдает ответ, либо запрашивает сервер более высокого уровня до тех пор, пока ответ не будет получен. Если IP-адрес сервера известен, клиент может обратиться к этому серверу напрямую. Если IP- адрес найти не удается, запрос выполнен быть не может и браузер отображает сообщение No DNS Entry или что-нибудь в этом роде. Проблема с производительностью заключается в том, что поиск в DNS обычно реализуется как блокирующий системный вызов. Браузер не может делать ничего вообще до тех пор, пока не получит ответа на свой запрос, направленный в систему DNS. Если ваш локальный сервер имен перегружен, браузер зависнет до тех пор, пока не закончится время ожидания, установленное операционной системой. Это время довольно велико и может достигать нескольких минут. Службы DNS, как и многие другие службы Интернета, при росте нагрузки начинают работать экспоненциально медленно. Единственный способ избежать замедления работы, связанного с DNS, — вовсе не пользоваться системой доменных имен. Вы можете указывать IP-адреса в HTML или вводить их вручную. Для пользователя это непривычный способ, поскольку имена DNS гораздо легче запоминаются, чем IP-адреса, и еще потому, что непривычно видеть IP-адрес в поле Location окна браузера. В нормальной ситуации разрешение запроса DNS занимает не более нескольких десятых долей секунды. Однако в плохих условиях система может работать просто невыносимо медленно. Клиентская часть DNS называется резольвером. Резольвер обычно представляет собой, скорее, набор библиотечных вызовов, чем отдельную программу. В Unix, к примеру, резольвер является частью библиотеки libc, используемой большинством программистов на С в своих приложениях. Некоторые резольве- ры кэшируют последние запросы, поэтому последующие запросы выполняются гораздо быстрее первого, однако Unix так не делает. После того как клиент узнает IP-адрес сервера, он формирует HTTP-запрос, в котором описывает свои возможности и пожелания, после чего передает документ операционной системе, которая должна обеспечить его передачу. Формируя запрос, браузер проверяет наличие файлов cookie, связанных с требуемой страницей или соответствующим доменом DNS, и отправляет эти файлы вместе с запросом, что позволяет веб-серверу идентифицировать повторное появление клиентов. Запросы обычно невелики по объему — не более нескольких сотен байт. Операционная система пытается установить с сервером TCP-соединение и передать ему запрос браузера. Браузер ждет результата, а если ничего не дожидается, то выходит по тайм-ауту. Отсутствие ответа может быть вызвано перегруженностью сервера и невозможностью приема очередного соединения, сбоем сервера или разрывом линии связи. После получения ответа от сервера операционная система передает его браузеру, который затем проверяет заголовок на наличие корректного кода ответа HTTP и новых файлов cookie. Если код ответа корректен, браузер сохраняет все cookie, обрабатывает HTML или изображение, после чего начинает формировать вывод на экран. Обработка HTML требует больших вычислительных за-
трат. Скорость процессора можно почувствовать, загрузив из кэша или по очень быстрой сети большую HTML-страницу (более 100 Кбайт, например). Помните, что обработка текста производится отдельно от его верстки и отображения. Netscape откладывает отображение обработанного текста на экране до тех пор, пока не будут известны размеры всех изображений. Если размеры изображений не указаны в теге <IMG>, браузеру придется запросить и получить все изображения, прежде чем пользователь увидит на экране хоть что-то. Порядок компоновки HTML-страницы зависит от конкретного браузера. В Netscape 4.x веб-страницы компоновались после того, как размер всех изображений становился известен. Происходило это в следующем порядке. 1. Компонуется текст. Имеющиеся гиперссылки проверяются по журналу и выделяются другим цветом в случае, если пользователь уже посещал их. 2. Отображаются границы всех изображений, а также текст, заданный тегом ALT, и условные значки, обозначающие отсутствие изображений. 3. Отображаются сами изображения — возможно, даже в процессе загрузки (progressive JPEG, например), когда качество изображения улучшается но мере поступления новых данных. 4. Загружаются вспомогательные фреймы (возвращение к этапу 1). Браузер может открыть не одно, а несколько соединений с сервером. В этом можно убедиться собственными глазами, запустив netstat -с на клиенте под управлением Linux и запросив страницу с несколькими изображениями с помощью Netscape. Скорее всего, вы увидите четыре открытых соединения, для которых в столбце состояния будет выведено слово ESTABLISHED (установлено). В некоторых браузерах количество одновременных подключений может быть изменено, но Netscape, судя по всему, не может использовать более четырех соединений. Клиенты с быстрым подключением к Интернету выиграют от использования большего количества одновременных соединений. Клиенты с медленным подключением могут не обнаружить выигрыша, если они и так используют всю пропускную способность своей линии. Каждое из нескольких одновременных соединений может работать в режиме постоянных соединений HTTP 1.1, то есть по нему можно последовательно получить несколько страниц. В последующих версиях HTTP будет возможность конвейерной обработки внутри одного постоянного соединения. Конвейерная обработка подразумевает начало обслуживания нового запроса до окончания отправки результатов старого. Запросы и ответы могут накладываться друг на друга, и браузеру придется их сортировать. HTTP 1.1 будет использоваться автоматически, если ваш браузер и сервер, с которым вы взаимодействуете, поддерживают его. Прогресс процесса загрузки можно контролировать в Netscape по сообщениям, появляющимся в строке состояния: появление там нового URL означает отправку запроса на HTML-страницу, изображение или Java-апплет. Обычно бывает трудно понять, какому изображению на странице соответствует соединение, указанное в строке состояния. Когда пользователь нажимает кнопку браузера Stop, серверу немедленно отправляется пакет RST Это называется аварийным завершением соединения. Ее-
ли сервер в момент нажатия кнопки Stop был занят выполнением программы CGI, процесс-шлюз «не узнает» о завершении соединения до тех пор, пока не завершит свою работу и не попробует отправить результат веб-серверу, чтобы тот переслал страницу клиенту В Unix процесс CGI в такой ситуации получит сигнал SIGPIPE, поскольку сокет веб-сервера больше не будет способен принимать данные. Виды браузеров Существует довольно много браузеров, но только некоторые из них распространены широко. Подробный список вы можете найти по адресу: http://www.boutell.com/ openfaq/browsers/. Статистика по стоимостям акций приведена на сайте http://www. cen.uiuc.edu/bstats/latest.html. Все перечисленные ниже браузеры выделяются из общего ряда либо своей распространенностью, либо своими уникальными возможностями. Netscape Netscape Navigator (или просто Netscape) был первым коммерческим браузером, но он стал проигрывать Internet Explorer. Netscape 4 представлял собой версию Netscape 3 после капремонта, a Netscape 6 был переписан заново с целью включить в него новый движок «Gecko». Начиная с версии Netscape 1.0 все браузеры этого семейства способны поддерживать постоянные соединения, но только с помощью заголовка Connection.Keep-Alive, а не как часть полной реализации HTTP 1.1. В главе 15 я расскажу о HTTP подробнее. Браузер Netscape перенесен на Linux, Solaris, Macintosh, Windows и многие другие платформы. В реализации Netscape 4 для Windows была ошибка, из-за которой браузер каждый раз перезагружал страницу заново при изменении размеров окна программы. Если страницу нельзя кэшировать, возникают проблемы с производительностью, поскольку пользователь может скачать страницу, изменить размер окна, чтобы лучше ее видеть, и обнаружить, что ему придется ждать загрузки страницы снова. Производительность Netscape 6 выше, чем у Netscape 4, и сам браузер имеет меньший объем. Netscape 6 поддерживает объектную модель документов (Document Object Model — DOM), позволяющую использовать новые виды динамического содержимого. В комплект стандартной установки Netscape 6 не входит виртуальная машина Java, но она присутствует в «полной» установке. Исходный код браузера Netscape доступен по адресу: http://www.mozilla.org/. Это дает возможность улучшать производительность Интернета всему сообществу, а не только программистам фирмы Netscape. Лично я надеюсь, что кто-нибудь напишет фильтр, позволяющий отключать мерцающую GIF-рекламу. Internet Explorer Internet Explorer (IE) входит в комплект поставки всех версий Windows и Windows NT. Поскольку Windows монопольно властвует на рынке коммерческих операционных систем для персональных компьютеров, практически на всех ПК
уже установлен Internet Explorer. Этот факт, с учетом отсутствия сколько-нибудь серьезных различий между браузерами, подавляет желание пользователей тратить время на установку какого-либо другого браузера. У Internet Explorer имеются определенные возможности, из-за которых его можно порекомендовать пользователям. Во-первых, он отправляет запросы на документы с заголовком протокола HTTP 1.1, что означает полную поддержку им HTTP 1.1. Помимо постоянных соединений HTTP 1.1 подразумевает возможность загрузки диапазона байтов документа, продолжение прерванных передач и другие вещи, повышающие производительность в определенных условиях. IE отображает в первую очередь текст страницы, что позволяет вам начать читать еще до того, как будут загружены какие-либо изображения. Современные версии IE поддерживают DOM, но несколько отличным от Netscape 6 образом. Авторам приходится писать по-разному для разных браузеров. Существуют версии IE для Windows, Macintosh и Solaris, но версии не для Windows обладают меньшей функциональностью. Netscape 3.0 приблизительно вдвое быстрее загружает и отображает веб-страницы по сравнению с Internet Explorer 3.0. Разница эта мотивируется тем, что IE должен поддерживать поточную модель СОМ. Версии Netscape 4.x и 6.x я не тестировал. Индикатор прогресса IE растет непрерывно, если только удается установить соединение. Это дает пользователю иллюзию того, что что-то происходит, даже если удаленный сервер сломался и уже ничего не шлет своему клиенту. IE 6 не поддерживает Java. Чтобы получить поддержку апплетов па Java в IE 6, нужно установить Java Plug-In от фирмы Sun, который можно скачать по адресу: http://java.sun.com/. Opera Браузер Opera, который можно скачать по адресу: http://www.opera.com/, очень невелик собой (меньше 2 Мбайт), но обладает всеми функциональными возможностями описанных выше программ. Он распространяется бесплатно, если вы согласны терпеть специальный рекламный заголовок, но вы можете заплатить и получить версию, в которой рекламы не будет. Браузер этот обладает определенными качествами, позволяющими рекомендовать его пользователю: скоростью, возможностью отключать GIF-анимацию, а также увеличивать или уменьшать масштаб просматриваемой страницы. Он поддерживает DOM и JavaScript, а также Java, но только при установке дополнительного компонента, значительно увеличивающего объем браузера. Версии Opera уже созданы для Windows, Mac и Linux. Я не запускал на нем никаких тестов, но по сравнению с Netscape и IE он кажется очень быстрым. Neoplanet Браузер Neoplanet поддерживает JavaScript, имеет небольшой объем (меньше 5 Мбайт), но быстро работает. Самая последняя версия на данный момент — пятая. У него есть несколько недостатков, связанных с ошибками программистов, из-за
которых я не использую его в качестве своего основного браузера. Скачать его можно по адресу http://www.neoplanet.com/. WebTV WebTV — это устройство, превращающее обычный телевизор в веб-браузер. Браузер WebTV (программа) зашивается в это устройство. У него имеется множество ограничений и никаких особых положительных качеств, благодаря которым его можно было бы порекомендовать пользователям, за исключением того, что он работает с телевизором. Он до некоторой степени поддерживает JavaScript. Номер последней версии — 2.0. Cello Номер последней версии Cello — 1.0. Разработка, судя по всему, прекратилась it 1994 году, но браузер все еще можно скачать по адресу: http://www.law.cornell.edu/ cello/cellotop.html. Mosaic Первый веб-браузер был разработан Марком Андерссеном и другими сотрудниками и студентами университета штата Иллинойс. Назывался он NCSA Mosaic, и его все еще можно скачать по адресу: http://www.ncsa.uiuc.edu/SDG/Software/mosaic-w/. Раньше Mosaic выделялся из общего ряда наличием встроенной поддержки gzip-сжатия и распаковки, но сейчас эта поддержка обеспечивается и Netscape, и Internet Explorer. Вы можете настроить Apache так, чтобы он сообщал браузеру о том, что файл запакован архиватором gzip, добавив в файл конфигурации Apache srm.conf следующие строки: # AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress # information on the fly. Note: Not all browsers support this. AddEncoding x-compress Z AddEncoding x-gzip gz Это полезно для больших текстовых файлов, размер которых gzip может уменьшить более чем наполовину, но для маленьких файлов сжатие лучше не включать, как и для файлов, которые не могут быть сильно сжаты, поскольку время лагрузки не изменится, а ресурсы на упаковку и распаковку затратить придется. Еще одна причина, по которой сжатие содержимого может не дать заметного выигрыша, состоит в том, что модемы и так используют свои собственные алгоритмы сжатия. Mosaic работает в Unix, Windows и Macintosh. Когда-то этот браузер пользо- иался преимуществами бесплатной программы, распространяемой вместе с исходным кодом, но его разработка завершилась на версии 3.0. lynx lynx — это текстовый браузер, который можно скачать по адресу: http://lynx.browser, org/. Создан он был в университете штата Канзас. С помощью внешних прило-
жений этот браузер способен даже отображать картинки. Преимуществами lynx являются бесплатное распространение с открытым исходным кодом, а также возможность запуска его под другими учетными записями и напрямую по РРР. Ключ -source позволяет вести журнал получения данных. К тому же этот браузер очень быстр. Ключом -source мы уже пользовались в главе 5. Еще одна очень полезная функция — возможность проверить ссылки на сайте с помощью команды lynx -traversal -crawl <URL>. lynx поддерживает SSL при добавлении определенных изменений в его исходный код, но вместе с этим пропадает способность проверять ссылки на сайтах. Последняя версия на момент написания этой книги имеет номер 2.8.1. Amaya Amaya — бесплатный браузер с открытым исходным кодом, распространяемый W3C. Его можно скачать по адресу: http://www.w3.org/Amaya. Он не отличается особенно высокой производительностью или устойчивостью, но может быть использован как редактор HTML. Скачав страницу, вы сразу же получаете возможность редактировать ее прямо в браузере. Я думаю, что это полезная функция, которую должны иметь все браузеры. Tango Tango — это целая система, состоящая из браузера, клиента электронной почты и редактора HTML, специально ориентированная на работу с огромным количеством языков (более 90), включая арабский, китайский и тайский. Браузер этот поддерживает фреймы, SSL и cookie, чего должно быть достаточно для большинства веб-сайтов. Его можно скачать по адресу: http://atzl.com/tango.htm. Иногда его путают с набором средств Tango Web development tools, созданным With- Enterprise (http://www.wltango.com/). Идеальный браузер Идеальный браузер, как я его представляю, должен иметь некоторые необычные свойства. О Он должен давать пользователю возможность перекрывать директивы заголовков HTTP, запрещающие кэширование, чтобы пользователь мог сам решать, нужно ему кэшировать некоторые страницы или нет. О Он должен кэшировать полностью обработанные страницы, чтобы при нажатии клавиши Back мгновенно появлялась предыдущая страница. Сейчас же эту страницу приходится загружать в необработанном виде с диска или, что еще хуже, по сети. О Он должен позволять отключить всю GIF-анимацию нажатием одной кнопки.
О Он должен по желанию пользователя отображать весь трафик HTTP, включая переданный до включения шифрования SSL. Это полезно, если хочешь узнать, какие именно данные были переданы командой HTTP POST. О При желании должна быть возможность открыть исходный код HTML и заголовки HTTP для всех загруженных страниц в редакторе по выбору пользователя, причем редактируемое содержимое должно заново отображаться браузером, включая динамически генерируемые страницы. О Пользователь должен иметь возможность редактировать данные и заголовки запросов GET и POST перед их отправкой. О Браузер должен показывать, сколько времени было затрачено на установку соединения, поиск в DNS, ожидание ответа сервера и передачу данных. О С помощью параметра командной строки этот браузер должен запускаться без графического интерфейса пользователя. О Он должен позволять создавать различные тесты. Сценарии должны формироваться во время работы с графическим интерфейсом, но сохраняться на языке Perl, чтобы их легко можно было редактировать. О Он должен уметь выбирать лучший прокси-сервер из списка на основании реальной производительности всех прокси-серверов. О Он вообще не должен поддерживать Java-апплеты. О Он должен поддерживать загрузку диапазона байтов, требуемую HTTP 1.1, чтобы можно было загрузить только ту часть страницы, которая изменилась с момента последнего к ней обращения. Скорость браузера Скорость браузера вряд ли станет «узким местом» просто потому, что средняя пропускная способность TCP-соединения от точки до точки составляет около 50 Кбайт/с, тогда как большинство браузеров способны обрабатывать и отображать данные быстрее. Статистика быстродействия браузеров приведена по адресам http://www.keynote.com/measures/toplO.html и http://www.orckit.com/. Мой собственный примитивный эталонный тест дал следующие результаты: Netscape 4 на старом портативном компьютере Pentium 166 под управлением Linux 2.0 может обрабатывать большой файл HTML, загружаемый из кэш-памяти или по локальной сети на 10 Мбит/с со скоростью около 100 Кбайт/с. Еще один тест был таким. Я заставил Internet Explorer 5.5 на компьютере с Windows NT 4.0 со 128 Мбайт памяти прочитать файл размером 69 Мбайт. Это заняло 23 минуты, что в среднем составляет около 47 Кбайт/с. Когда я попытался пролистать содержимое, браузер завис, поэтому нельзя считать, что он способен работать в таких условиях. Opera 3.62 показал сравнимые результаты па файле того же размера. Для загрузки того же файла текстовому браузеру lynx
в системе Solaris потребовалась всего лишь 1 мин, и он спокойно позволял просматривать содержимое файла. Netscape 4.51 под Linux 2.2 с 256 Мбайт памяти и процессором на частоте 500 МГц загрузил половину файла за 5 мин при загрузке процессора около 15%, но к этому моменту размер браузера в памяти достиг 200 Мбайт и компьютер начал интенсивно использовать виртуальную память, что сделало работу невозможной. Тем не менее, пока браузер работал, он обеспечивал пропускную способность около 230 Кбайт/с. Вы можете предположить, что браузеры хранят кэшированные документы в обработанном формате, чтобы их можно было быстрее вывести на экран после загрузки из кэша, но изучение содержимого кэша показывает, что на самом деле это не так. Можно было бы просматривать HTML и на сервере, после чего сохранять и отправлять его в обработанном формате. Не существует стандартного формата хранения обработанного HTML, поэтому выигрыш в производительности браузера был бы достигнут за счет переносимости и удобочитаемости (исходных страниц). В любом случае для Интернета нехарактерно возвращение чрезмерно большого количества данных в ответ на запросы HTTP. Это означает, что при планировании мощностей не следует ориентироваться на производительность как на главный критерий в выборе браузеров, хотя с развитием инфраструктуры Интернета ситуация может измениться. Веб-браузерам нет смысла делать запросы HTTP чаще, чем пользователи (люди) способны прочитать и понять ответы. Браузеры обычно могут обеспечить около 20 соединений по HTTP в секунду. Даже самый быстрый на руку пользователь не смог бы щелкнуть на 20 ссылках за 1 с, но многопоточный браузер, в принципе, может достичь этого предельного значения, просматривая HTML-страницы со множеством изображений или апплетов. Даже 20 запросов в секунду, полученные с одного браузера, не составят проблемы для большинства серверов. Обычная частота поступления запросов от браузера составляет менее одной операции HTTP в секунду. Советы по настройке браузеров Браузер может и не являться «узким местом», но вы, вероятно, хотите выжать максимум производительности из тех средств, что у вас имеются. Вот несколько предложений, относящихся как ко всем браузерам, так и к некоторым из них. Общие рекомендации В последующих разделах приведены общие рекомендации по достижению максимальной производительности браузеров. Обновление Попробуйте установить последнюю версию своего браузера (не тестовую!). Новые версии обычно включают поддержку новых функций, таких как постоян-
ные соединения HTTP 1.1, а эти функции позволяют повысить производительность. Следует сказать кое-что и в защиту старых версий. Во-первых, бета-версии новых браузеров обычно характеризуются множеством ошибок и проблем с производительностью, тогда как старые нетестовые версии более стабильны. Особенно медленно работает виртуальная машина Java в браузере Netscape 4.0 beta, но эта ошибка была исправлена в официально выпущенной версии. Есть смысл подождать официального выпуска, прежде чем испытывать новую версию. Во-вторых, браузеры очень быстро растут в размерах. Netscape 3 для Linux берет при первом запуске около 5 Мбайт памяти, Netscape 4 поглощает около 8 Мбайт, а последние версии браузеров могут одним махом захватывать 20 Мбайт и более. В процессе работы они растут в размерах благодаря утечкам памяти и загрузке всяческих модулей. Если вы чувствуете, что памяти у вас маловато, старая версия браузера позволит вам достичь более высокой производительности, чем новая. Особенно сильно заметна разница, если одна из версий приводит к активному свопингу, а другая нет. Делайте меньше Вы можете изменить параметры настройки браузера таким образом, чтобы он делал лишь самое необходимое для загрузки и отображения страницы. О Отключите автоматическую загрузку изображений, поскольку именно на них расходуется большая часть пропускной способности вашего подключения к Интернету и на каждое изображение требуется отдельное соединение, если только сервер и браузер неспособны поддерживать постоянные соединения. Вы будете видеть, где должны были располагаться незагруженные изображения, и сможете щелкать по ним, чтобы те появлялись по мере надобности. Кроме того, вы можете щелкнуть одну кнопку и загрузить все изображения разом, если решите, что эта страница вас интересует целиком. О Аналогичным образом нужно отключить и поддержку Java, если у вас недостаточно высока пропускная способность подключения или не хватает памяти. О Чтобы браузер запускался чуточку быстрее, сделайте так, чтобы он загружал только пустую страницу. О Загружайте минимально возможное количество подключаемых модулей, поскольку они снижают быстроту запуска программы. О В системах Macintosh используйте меньшее количество шрифтов. О Чтобы предотвратить доступ к Сети при наличии страницы в кэше, установите параметр, управляющий проверкой актуальности страниц, в положение «никогда». При этом вы рискуете тем, что иногда будете просматривать устаревший материал, но для тех страниц, которые будут обнаруживаться в кэше, производительность значительно возрастет. О Вы можете слегка повысить производительность, если очистите журнал, но после этого ссылки, по которым вы уже переходили, больше не будут отобра-
жаться другим цветом. В Netscape 4.0 журнал очищается кнопкой Edit ► Preferences ► Navigator ► Clear History. Если это покажется вам полезным, вы можете отключить ведение журнала совсем, чтобы компьютер не тратил время на выделение просмотренных ссылок. Это никак не влияет на кэш браузера. О Отключение файлов cookie даст вам еще один небольшой выигрыш в производительности и большой выигрыш в конфиденциальности, но при этом вы можете потерять возможность работать с некоторыми сайтами, которые подготавливают свое содержимое специально для вас, основываясь именно на файлах cookie. О Сохраняйте часто используемые страницы, такие как домашние страницы поисковых серверов, на свой жесткий диск с помощью команды File ► Save As, отмечая в своих закладках эти файлы. В следующий раз вам не потребуется передавать по Сети какие-либо данные, чтобы выйти на эти страницы. Вам может потребоваться изменить код HTML сохраненных файлов, чтобы сделать ссылки абсолютными (то есть содержащими имя сервера), поскольку относительные ссылки будут указывать на файлы из вашей файловой системы, а не на документы из файловой системы веб-сервера. Проще всего сделать это с помощью тега <BASE>: <html> <head> <base href-"http://www.search.engine.com/"> </head> О Можно удалить из сохраненных страниц рекламные баннеры, чтобы они вам не мешали. Вот программа на Perl, удаляющая из HTML-страницы все изображения: % perl -pi.bak -e 's/<img*?>//gi' index.html О Возможно, вам потребуется отредактировать страницу еще больше, удалив из нее, например, ссылки на таблицы стилей. Как только вы загрузите ту же страницу с исходного сервера, вы сразу же увидите на экране все то, что перед этим удалили со своей сохраненной страницы. О Аналогичным образом можно сохранять в кэше целые сайты, просто указывая новый каталог кэширования в настройках Netscape, с последующим просмотром содержимого сайта, который вы хотите кэшировать. В новом кэше появятся все файлы сайта, после чего вы сможете вернуть кэш на прежнее место, а сайт оставить себе. В Netscape Navigator 4 размещение кэша указывается в поле Edit ► Preferences ► Advanced ► Change Cache Folder. О Пользуйтесь кнопкой Stop. Останавливайте загрузку, как только поймете, что вам не нужно все остальное. Отключайте анимацию, если вам не хватает ресурсов процессора. Анимация в виде GIF легко может потребить около 10% мощности процессора и будет продолжать это делать, пока вы ее не остановите. Это может быть важно, если вы работаете не только с браузером, но и с какими-либо вычислительноемкими приложениями одновременно. Некоторые Java-апплеты могут потреблять ресурсы процессора даже тогда, когда
вы с ними не работаете, и даже после того, как вы уйдете с веб-страницы. Это может произойти, если программист забудет переопределить метод stop(). Апплеты нельзя отключить с помощью кнопки Stop, но можно просто выключить поддержку Java. В Netscape 4 это делается с помощью флажка Edit ► Preferences ► Advanced ► Enable Java. Используйте «горячие» клавиши Активное использование сочетаний клавиш и прочих средств ускорения ввода позволяет повысить производительность системы «пользователь+браузер» (пусть даже не повышая производительности собственно браузера). О Прежде всего помните, что вводить адреса целиком совершенно необязательно. Большинство браузеров способно дополнить URL необходимыми элементами типа http://www. и .com, если вы укажете только имя домена. Таким образом, вы можете, к примеру, ввести только слово sun, если вам надо попасть на http://www.sun.com/. Однако учтите, что в некоторых случаях это ухудшает производительность или вовсе не сработает. Например, если вы работаете в организации Patrick Net, Inc., которая настроила свои серверы имен в предположении, что неполные адреса URL заканчиваются доменным именем вашей организации (pat- rick.net), то, введя слово sun в браузере, вы, по сути, попытаетесь обратиться к http://sun.patrick.net. Если такого компьютера в сети не окажется, сервер имен может перенаправить вас на http://www.sun.com/, но может и не сделать этого (в зависимости от настроек DNS). Если имя веб-сервера отлично от www, вы все равно можете не указывать протокол http://. Если в сети patrick.net есть сервер web, то в браузере можно ввести web.patrick.net вместо http://web.patrick.net. О Используйте сочетания клавиш везде, где они доступны. Например, вместо кнопки Stop можно нажимать клавишу Escape. В ОС Linux сочетание клавиш Alt+влево означает переход на предыдущую страницу, Alt+вправо — на следующую, a Alt+r приводит к перезагрузке текущей страницы. Сочетания клавиш нажимать гораздо быстрее, чем искать кнопки и щелкать их мышью. После того как вы к ним привыкнете, вы никогда уже не вернетесь к мыши. По этой причине опытные пользователи Unix не любят графические интерфейсы: гораздо быстрее набрать команду на клавиатуре, чем щелкать мышью. Если вам приходится работать с графическим меню или кнопками, помните, что клавиши Tab и Alt+Tab позволяют перейти от выбранного пункта или кнопки к следующему; но, вообще говоря, во многих ситуациях быстрее пользоваться мышью, чем перебирать элементы графического интерфейса с помощью клавиши Tab. О Вместо того чтобы несколько раз нажимать кнопку Back, выберите нужную вам страницу из просмотренных ранее в меню Go. Это намного быстрее. В Internet Explorer есть замечательная функция Автозаполнение, которая позволяет не вводить целиком адреса недавно просмотренных страниц.
Увеличьте объемы кэшей Увеличьте объем кэшей в памяти и на диске, если вы способны себе это позволить. Очистка памяти браузера и дискового кэша поможет, если вы собираетесь работать с новыми сайтами, поскольку при этом браузеру не придется проверять наличие страниц в кэше, но эта же очистка очень сильно ухудшит производительность при обращении к старым сайтам, поскольку все данные придется загружать снова. Кэш должен быть настолько большим, насколько это позволит ваш компьютер. Перезагружайтесь Печально, но факт: и Netscape, и Internet Explorer имеют тенденцию брать память и не отдавать ее обратно. Это может быть связано и с утечками памяти, и с накоплением загружаемых модулей. Если вы обнаружите, что браузер работает гораздо быстрее после его перезапуска или даже после перезапуска компьютера целиком, это будет ясным указанием на то, что ваш браузер «поедает» память. В этом случае нельзя придумать ничего лучше регулярных перезапусков и отключения функций типа виртуальной машины Java и почтового клиента. Работайте многозадачно Если страница долго не загружается, откройте новое окно браузера и продолжайте работу в этом окне, пока в старом не появится загруженная страница. В Netscape выберите пункт меню File ► New ► Navigator Window или нажмите сочетание клавиш Alt+N. Останавливайте загрузку Кнопка Stop вполне может ускорить работу. Нажатие этой кнопки приводит к остановке загрузки страницы и отображению уже загруженных данных. Возможно, этих данных вам будет вполне достаточно. Если вы нажали Stop и обнаружили, что на экране ничего нет, щелкните Reload. Может оказаться, что на второй раз сервер ответит гораздо быстрее. Пакет с вашим запросом мог просто потеряться где-то в Интернете. Браузеры, к сожалению, не дают пользователю возможности остановить Java после начала загрузки апплета, причем вы не можете заняться ничем другим до тех пор, пока инициализация виртуальной машины не будет полностью завершена. Используйте подключаемый модуль Java Существуют специальный управляющий элемент ActiveX и подключаемый - модуль Activator для Netscape, которые загружают и устанавливают последнюю виртуальную машину от JavaSoft. Этот модуль не только гарантирует наличие последней и самой мощной виртуальной машины, но и решает некоторые проблемы с производительностью, имеющиеся у других реализаций виртуальных машин. Netscape загружал и конкретизировал классы Java в несколько раз медленнее, чем IE, но эта проблема была устранена модулем Activator (http://www.javasoft.com/products/activator/).
Открывайте новые окна Щелчок на ссылке двумя кнопками мыши одновременно (либо средней кнопкой, если у вас их три) позволяет открыть ссылку в новом окне. Вместо того чтобы нажимать кнопку Back, вы сможете просто переключиться в старое окно, если оно вам понадобится. Это гораздо быстрее, чем нажимать Back, поскольку при этом отпадает необходимость заново обрабатывать HTML-код страницы. Многие веб-страницы не допускают кэширования ни при каких условиях, поэтому каждый раз при нажатии кнопки Back происходит обращение к серверу. Всего этого можно избежать, открывая ссылки в новые окна. Советы для Internet Explorer В последующих разделах приведены советы, относящиеся только к Microsoft Internet Explorer. Отключите плавную прокрутку Если у вашего компьютера недостаточно ресурсов для плавной прокрутки страниц с изображениями, эту функцию можно отключить в меню Tools ► Internet Options ► Advanced ► Use smooth scrolling. Вам не придется ждать, пока ваш компьютер догонит вашу мышь, а прокрутка будет осуществляться очень быстро. Создавайте новые процессы Если при нажатии кнопки Back возникают длительные задержки, причем страница всегда загружается по модему (даже если вы установили режим загрузки только из кэша), попробуйте установить флажок Tools ► Internet Explorer ► Advanced ► Browse in a new process. При этом запускаемые экземпляры IE не будут иметь общих ресурсов с уже работающими. Помимо изоляции экземпляров друг от дру- ia на случай сбоя это может (по неизвестной причине) заставить кнопку Back работать быстрее. Можно также удостовериться, что переключатель на вкладке Tools ► Internet Options ► Settings не установлен в положение Every visit to page. Советы для Netscape Последующие разделы относятся только к браузеру Netscape Navigator. Запускайте Java заранее Вместо того чтобы при первом обращении к апплету ждать, пока запустится виртуальная машина, попробуйте попросить Communicator инициализировать ее вместе с браузером с помощью ключа командной строки netscape.exe -startJava. Этот ключ недоступен в версиях Netscape для Unix. Используйте меньшее количество цветов Если вам не нужно, чтобы цвета, отображаемые Netscape, были абсолютно точными, вы можете переключиться в режим грубого соответствия, дающий за-
метный выигрыш в скорости. В Communicator 3.0 выберите General Preferences ► Images ► Substitute colors. В Communicator 4 выберите Edit ► Preferences ► Appearance ► Colors и установите флажок Always use my colors. Это не сработает в системах Macintosh или Unix. Уменьшите размер кнопок Вы можете сэкономить место на экране, отображая на кнопках только надписи. В Netscape это делается с помощью пункта меню Edit ► Preferences ► Appearance ► Show Toolbars as Text-Only. Можно и вовсе убрать панель инструментов, если вы знаете все необходимые сочетания клавиш. Прочие веб-клиенты Благодаря простоте программирования базовых функций веб-клиентов очень удобно писать собственные программы для прикладных целей. На данный момент наиболее популярными веб-клиентами помимо браузеров являются роботы, индексирующие веб-страницы для поисковых серверов, и программы проверки ссылок, находящие некорректные ссылки, но вариантов таких клиентов можно придумать великое множество. Вот пример сценария интерпретатора из одной строчки. Я регулярно использую его для захвата веб-страниц из других сценариев: % (/usr/bin/echo "GET /index.html HTTP/1.0\r\n\rH; sleep 5) | telnet patnck.net 80 В этом сценарии используется один неочевидный трюк: нужно подождать 5 с, чтобы получить ответ по telnet. Если не вызывать функцию sleep, то запрос будет передан в telnet, после чего программа telnet завершается, поскольку закрывается ее входной канал. Она закрывается так быстро, что никогда не успевает отобразить результат. Еще один трюк здесь в том, что команда echo сама по себе добавляет символ перевода строки. Разные версии echo поступают по-разному, поэтому вам, возможно, придется почитать документацию вашей системы. Например, в Linux команде echo нужно указывать ключ -е, чтобы она могла интерпретировать символы \г и \п. Аналогичный способ получения веб-страницы без браузера заключается в использовании утилиты Стивенса sock: % echo -ne "GET /index.html HTTP/1.0\r\n\r\n" | sock -h patnck.net 80 Вызов sock -h не сработает, если система не поддерживает неполное закрытие соединений. Еще одним способом захвата веб-страницы или даже выполнения операции HTTP POST из сценария является использование примеров команд GET и POST, устанавливаемых в каталог /usr/local/bin при установке пакета LWP. Если у вас установлены библиотеки SSL, эти программы будут автоматически их использовать: % /usr/local/bin/GET http://patrick.net/
Еще имеется программа на языке С, называемая curl. Она загружает веб-страницы и способна работать с SSL. Ищите ее по адресу: http://curl.haxx.se/. % curl http://patrick.net Наконец, вы можете работать и с программой Netcat, которой не нужно указывать никакого тайм-аута. Эта программа сама будет поддерживать соединение и открытом состоянии до тех пор, пока результат запроса не будет получен целиком. Копию Netcat можно найти по адресу: http://patrick.net/software/. Если вы хотите удалить все теги HTML из полученной веб-страницы, вот одна строка на языке PERL, которая может это сделать. Удаляются теги, содержащиеся в переменной $_. Учтите, что благодаря использованию символа ? мы не удаляем открывающую скобку первого тега и все до конца последнего тега, как поступил бы Perl по умолчанию: s/<.*?>//: Программа appletviewer, поставляемая с пакетом разработчика Java Development Kit фирмы Sun, загружает апплеты гораздо быстрее, чем Netscape и все прочие браузеры, — вероятно, потому, что ей не приходится проверять наличие уже загруженных классов в кэше. Appletviewer отлично работает с архивами jar. Gnutella и одноранговые сети Веб-клиенты, использующие протокол gnutella, являются одновременно клиентами и серверами веб, поскольку gnutella использует протокол HTTP для получения файлов. При работе с этой программой вы можете связываться с другими пользователями, у которых установлена та же программа. Когда вы запрашиваете какой-то файл, запрос отправляется вашим ближайшим соседям, а от них — к их соседям и так далее. Как только файл обнаруживается, вы можете нагрузить его, после чего станете сервером для других клиентов, которые ищут тот же файл. Возможность поиска обеспечивается протоколом, поэтому не нужно никаких поисковых серверов, индексирующих сайты. «Сайты» в данном случае быстро меняются, появляются и исчезают, поэтому индексировать их все равно не было бы смысла. Это отличная концепция, которую назвали концепцией одноранговых сетей (peer-to-peer networking). Она не вытесняет, но дополняет веб, причем эти новые сети не будут контролироваться корпорациями и правительствами. Большая часть советов этой книги (например, относящихся к операционным системам и сетевым протоколам) применима и к передаче файлов по протоколу gnutella, а не только к обычным веб-сайтам. Еще одна интересная стратегия заключается в обмене содержимым кэша между браузерами, чтобы исключить обращение к серверам. Компания cMikolo и настоящий момент испытывает эту технологию. Sun также продвигает свое программное обеспечение для одноранговой сети JXTA.
Основные рекомендации О Сделайте так, чтобы браузер проверял актуальность кэша один раз за сеанс или вообще никогда не делал этого самостоятельно. О Увеличьте размеры кэш-памяти и дискового кэша. О Используйте последние версии браузеров, поддерживающие HTTP 1.1, и другие усовершенствования. Включите загрузку пустой страницы при запуске браузера.
IO Операционная *ш система клиента Нельзя сказать, что браузер существует в вакууме. У операционной системы, п которой он работает, могут быть свои недостатки, отрицательно влияющие на производительность браузера. Об оптимизации настольных систем написаны целые тома умных мыслей, поэтому я затрону лишь несколько важных моментов, непосредственно относящихся к удобству и быстроте работы в веб. Хорошим источником более подробных сведений о производительности клиентов является сайт http://www.speedguide.net/. Microsoft Windows Самый эффективный способ повысить быстродействие компьютера, на котором установлена операционная система Windows, — это стереть Windows и установить какую-нибудь версию Unix для процессоров Intel — например, Linux, Solaris х86, FreeBSD, BSDI или SCO Unix. К сожалению, для большинства людей этот вариант не подходит из-за сложности установки операционных систем и необходимости работать с приложениями, которые могут быть запущены только под Windows. Если уж вы обречены на жизнь с Windows, кое-что все равно можно сделать для улучшения производительности браузеров. Устраните беспорядок в системе Создайте резервные копии системных файлов, после чего удалите утилиты, которыми вы не пользуетесь, из файлов win.ini и system.ini. Оставшиеся утилиты будут работать быстрее — это как в системе Macintosh после удаления неиспользуемых расширений.
Специальные драйверы экрана Драйвер, написанный специально для вашего видеоадаптера, скорее, обеспечит вам большее быстродействие и стабильность, чем стандартный драйвер VGA. Ниже приведены примеры ситуаций, в которых рекомендуется установить другой (более совершенный) драйвер видеоадаптера: О изменение параметров Экрана в Панели управления приводит к сбою системы при некоторых размерах экрана или количестве цветов (но не при всех); О установка движка Панель управления ► Система ► Быстродействие ► Графика ► Аппаратное ускорение в положение Полное приводит к сбою системы; О браузер постоянно зависает на некоторых веб-сайтах. Это может быть связано и с ошибками в системе безопасности Windows или JavaScript. Обычно вы всегда можете загрузить подходящий драйвер для своего видеоадаптера с веб-сайта производителя этого видеоадаптера или с веб-сайта производителя чипа, на котором построен адаптер. Новые версии драйверов устройств обычно позволяют достичь большей производительности по сравнению со старыми версиями. Проверьте, все ли выпущенные пакеты обновлений Windows и стека TCP/IP (Winsock) у вас установлены. Кроме того, нужно регулярно (хотя бы раз в два года) обновлять прошивку BIOS; но, скорее всего, ваш компьютер за два года успеет устареть. Память и диски Схема кэширования дисков, используемая в Windows, способна как помочь вам, так и навредить. С одной стороны, благодаря кэшированию большая часть операций записи на диск кажется быстрее, чем без кэширования, поскольку данные не записываются сразу же после выдачи команды на запись, а вместо этого помещаются в очередь, с тем чтобы быть записанными позднее. Данная схема известна как кэширование записи (write-behind caching). Так работала программа smartdrv.exe, запускавшаяся из AUTOEXEC.BAT. Кэширование тоже предусматривает упреждающее чтение данных с диска в расчете на то, что пользователю потребуется больше данных, чем он запрашивает в данный момент. Это называется кэшированием чтения (read-ahead caching); в Windows 98 оно включается следующим образом: Панель управления ► Система ► Быстродействие ► Файловая система ► Оптимизация упреждающего чтения ► Полная. С другой стороны, некоторые драйверы старых жестких дисков задерживают обработку низкоприоритетных прерываний на время синхронизации дискового кэша. Это не вызывало бы проблем, если бы низкоприоритетные прерывания последовательных (СОМ) портов не требовали бы обработки до того, как переполнится буфер UART. Если из-за диска СОМ-порт будет заблокирован и данные из буфера утеряны, эти данные придется передавать заново, что снизит эффективную производительность сети. Лучшее решение — скачать обновленный драйвер диска, но можно и просто отключить кэширование на некоторое время,
чтобы достичь максимальной производительности сети за счет быстродействия диска. Недостаток места на диске снизит производительность Netscape, поскольку браузеру придется искать свободное место для записи кэшируемых страниц и рабочих файлов. Регулярная дефрагментация диска с помощью утилиты defrag избавит вас от постепенного снижения скорости работы с ним. В Windows 98 и NT дефрагментатор вызывается так: Мой компьютер ► Жесткий диск ► Свойства ► Сервис ► Дефрагментировать. В Windows NT объем используемой памяти можно узнать, запустив диспетчер задач нажатием клавиш Ctrl+Alt+Del. Системный монитор В состав Windows 98 входит Системный монитор — очень полезная программа, помогающая искать слабые звенья в операционной системе и оборудовании. Запускается она так: Пуск ► Выполнить ► sysmon. На экран можно выводить множество различных графиков. Рекомендую особенно следить за перечисленными ниже. О Диспетчер памяти: занято в файле подкачки. О Диспетчер памяти: свободно памяти. О Контроллер удаленного доступа: переполнение буфера. Переполнения сетевого буфера быть не должно. Если оно есть, это означает, что вы не освобождаете буфер UART вовремя. Причиной может быть недостаток внимания к прерываниям СОМ-портов, устаревшая версия микросхемы UART (маловероятно на компьютерах, более совершенных, чем 386-й) либо недостаточный размер буфера. Размер буфера устанавливается в Windows 98 следующим образом: Панель управления ► Система ► Диспетчер устройств ► Порт, к которому подключен модем ► Параметры (емкость приемного буфера задается движком). Что касается свободной памяти, то она просто должна быть, а файл подкачки должен использоваться по минимуму. Проверить качество телефонной линии с помощью Системного монитора можно следующим образом: Пуск ► Выполнить ► sysmon ► Правка ► Добавить счетчик ► Контроллер удаленного доступа ► Ошибки контрольной суммы. На хорошей линии никаких ошибок быть, естественно, не должно. Если по показаниям счетчиков ваш процессор перегружен, нужно либо купить более быстрый процессор и установить его, либо уменьшить количество одновременно работающих приложений. Сетевые утилиты Некоторые сетевые утилиты Unix имеют версии для Windows. Windows 98 и NT содержат в комплекте поставки программы ping и traceroute. Чтобы запустить программу ping, выберите Пуск ► Выполнить и введите ping www.server.com. Программа traceroute в Windows называется tracert; запускается она точно так же, как
и ping. Существует версия traceroute для Windows, написанная третьей фирмой (Starfish Internet Utilities, http://www.starfishsoftware.com/) и называющаяся Quick- Route. В Macintosh для тех же целей используется программа whatroute. MTU На многих сайтах можно найти программы, позволяющие изменять размер максимального блока передачи (Maximum Transmission Unit — MTU), — попробуйте, например, поискать такую утилиту по адресу: http://www.speedguide.net/Cable_ modems/cable_registry.html. Оптимальный размер MTU соответствует максимальному размеру блока, который может быть отправлен провайдеру без получения от него ответа, гласящего, что пакет слишком велик и должен быть фрагментирован. Чтобы определить этот размер в Windows, откройте окно Командной строки и введите команду: С\> ping -f -l 1500 www.myISP.com Указать нужно, разумеется, адрес вашего собственного провайдера. Скорее всего, при размере пакета 1500 байт будет получено сообщение об ошибке типа «Packet needs to be fragmented, but DF set» (необходима фрагментация пакета, но установлен флаг «не фрагментировать»). Уменьшайте значение до тех пор, пока сообщение об ошибке не перестанет появляться. Так вы узнаете оптимальное значение размера максимального передаваемого блока. Если вы работаете в локальной сети, оставьте значение MTU равным 1500 байт. Если же вы подключаетесь к Интернету по телефонной линии, попробуйте установить значение MTU равным 576 байт. Благодаря уменьшению фрагментации производительность может возрасти. Подробнее о настройке MTU в Windows читайте по адресу: http://www.sysopt.com/maxmtu.html. Macintosh У операционной системы Macintosh есть свои «тараканы», с которыми и приходится бороться пользователям. Эмуляция 68К Переход фирмы Apple с процессоров Motorola 68000 на PowerPC, с одной стороны, разумеется, увеличил производительность компьютеров, а с другой — несколько ухудшил ее. Производительность возросла, поскольку PowerPC — это современный быстрый процессор. Однако большая часть программ под Мае была написана для процессоров 68К и работает на PowerPC лишь в режиме эмуляции. Не только приложения, но даже части операционной системы Мае OS страдают этим. Определенные меры позволяют снизить вредное воздействие эмуляции на производительность системы.
О Всегда старайтесь найти версию браузера для PowerMac, а не для 68К. О Попробуйте заменить поставляемый с ОС эмулятор на программу Speed Doub- 1ег от Connectix (http://www.connectix.com/). Эта же фирма производит пользующуюся хорошей репутацией программу RAM Doubler. О Наконец, обновите систему до Mac OS X, в которой больше кода ориентировано на PowerPC, а реализация набора TCP/IP работает быстрее и надежнее. Сеть Чтобы достичь максимальной производительности сети в системе Macintosh, убедитесь, что вы работаете с последней версией стека протоколов, которая называется Open Transport TCP/IP. Советы по этому поводу вы найдете по адресу: http://www.go2mac.com/. Программы Macintosh, использующие протокол РРР, обычно настроены на автоматическое подключение к сети. Это несколько упрощает жизнь пользователю. Монитор Mac TCP Monitor позволяет отслеживать пакеты, которые теряются по тайм-ауту и передаются снова. Повторная передача может происходить довольно часто, если вы используете медленное подключение к сети или если в принимаемых данных есть ошибки. Если монитор TCP показывает, что некоторые пакеты передаются повторно, следует увеличить тайм-аут повторной передачи и посмотреть, поможет ли это. Если повторная передача вызвана ошибками, а не большим временем ожидания данного соединения, увеличение тайм- аута приведет к снижению производительности. Еще один параметр, который можно изменять, — это размер максимального передаваемого блока (Maximum Transmission Unit — MTU), то есть максимальный размер IP-пакета, который отправляется вашим компьютером. Этот размер должен быть достаточно мал, чтобы ни один из промежуточных маршрутизаторов не испытывал «желания» фрагментировать ваши пакеты, путешествующие от браузера к веб-серверу и обратно. Фрагментация замедляет пакеты. Попробуйте сменить MTU в параметрах РРР с 1500 на 576. Для последнего значения гарантируется то, что пакеты фрагментироваться не будут. Сравните производительность системы до и после внесения изменений, поскольку, если проблема была не в фрагментации, быстродействие обязательно снизится. У сетевой библиотеки Mac OS определенно имеются некоторые проблемы с многопоточностью, из-за чего система может зависнуть при попытке браузера использовать постоянные соединения протокола HTTP 1.1. Кроме того, версии Netscape 3.04 и 3.05 могут зависать сами по себе (не из-за ошибок сетевой библиотеки). Это очень печально, поскольку некоторые сайты отключают поддержку постоянных соединений, чтобы не «вешать» браузеры пользователей, проигрывая при этом в производительности. Память и диск Если вы работали с Netscape в Windows или Unix, а потом перешли на Мае, вы могли заметить, что в версии Мае нет возможности настраивать кэширование
в памяти. На самом деле кэширование в памяти все равно есть, но оно не настраивается из пользовательского меню. Вместо этого оно управляется из Панели управления как обычный дисковый кэш, позволяющий кэшировать данны^ в памяти, не записывая их на жесткий диск. Дисковый кэш должен быть достаточно велик, чтобы компьютеру не приходилось часто обращаться к дискам, но не настолько, чтобы другим приложениям не хватало памяти, в результате чего их производительность стала бы падать. Помните простое правило: 32 Кбайта кэша на каждый мегабайт ОЗУ. Чтобы изменить параметры кэша, войдите в меню Control Panel ► Memory ► Disk Cache. В системе System 9 приложения Macintosh не могут динамически запрашивать память по мере надобности в отличие от других операционных систем. Выделять эту память вам придется самому. Чтобы узнать, сколько памяти выделено Netscape, и при необходимости выделить больше, запустите браузер, выделите значок Netscape и щелкните пункт меню File ► Get info. Вы увидите два значения — минимальный объем (необходимый Netscape для работы) и желательный объем (доступный Netscape максимум). Вы не можете ничего сделать с минимальным объемом, но если вы укажете больший желательный объем, Netscape может начать работать несколько быстрее. Для Netscape 4.0 разумно указать значение 16 Мбайт. Лучше всего обновить систему до Mac OS X, если вы этого еще не сделали, потому что она быстрее и надежнее. Расширения Расширения поглощают системные ресурсы, поэтому удаление всех ненужных расширений улучшит общую производительность и сократит время загрузки. Вы можете отключить все расширения, держа клавишу во время загрузки Macintosh, но это отключит действительно все расширения, в том числе повышающие производительность, такие как компилятор Symantec JIT. Когда вы просматриваете страницы с Java в Netscape, виртуальная машина Java будет запускаться быстрее, если вы переместите Symantec JIT (который называется «Java accelerator for the Power PC») из папки Netscape в папку Extensions. Таким образом вы гарантируете загрузку этой программы в процессе запуска системы. Убедитесь, что вы именно переместили программу, а не скопировали ее. Unix На любой рабочей станции Unix можно запустить веб-клиент, но все-таки нерационально работать в веб с рабочей станции, когда для этого вполне можно использовать персональные компьютеры Macintosh или Intel. Для ПК на базе Intel наиболее популярна версия Unix под названием Linux — отчасти потому, что она бесплатно распространяется с исходным кодом. Если быть точным, Linux — это не вполне Unix. С одинаковым оборудованием производительность в операционной системе Linux будет гораздо больше, чем в Windows, но до недавнего времени слишком
мало коммерческих программ имели версии для Linux, поскольку последний образовался, скорее, как развлечение, чем как источник прибыли. Тем не менее под Linux имеется достаточно программного обеспечения, в том числе и веб-клиентов: существуют версии Netscape для Linux и хорошая виртуальная машина Java, а также стандартные средства Unix, позволяющие со всеми удобствами следить за состоянием системы и сети: top, vmstat, strace, traceroute, ping и другие. Linux — это просто подарок для всех, кто интересуется разными операционными системами. Перечислим кое-какие средства, позволяющие узнать, чем занимается ваш веб-клиент для Linux. О Запустите top и с помощью клавиши М отсортируйте все процессы по использованию памяти. Не выходите из программы. Скорее всего, вы увидите, что Netscape стоит на первом месте по использованию памяти и что эта программа растет в размере, когда вы используете какую-то новую функцию. О Запустите netstat -с и не завершайте ее. Вы увидите, как Netscape открывает соединения при запросе веб-страниц. Соединение считается открытым, когда netstat выводит в столбце состояния слово ESTABLISHED. Все соединения должны закрываться, за исключением соединения с почтовым сервером POP, опрашиваемым на предмет поступления новой почты. О Вы можете запустить Netscape командой strace, чтобы отслеживать все выполняемые системные вызовы и таким образом лучше представлять, что именно делает Netscape. Производительность Netscape от трассировки, скорее всего, несколько ухудшится, зато вы получите ценные сведения. Исходный код Netscape можно скачать по адресу: http://www.mozilla.org/, если вы решите изменить браузер самостоятельно, чтобы повысить его производительность. О С помощью программы ping вы можете узнать время ответа любого веб-сервера. Большая часть их отвечает на запросы этой программы. Если вы вызовете ping localhost и время ожидания окажется значительно превышающим 1 мс, это означает, что вы пользуетесь плохой реализацией протокола IP. Веб-сервер в той же локальнбй сети должен давать время ожидания менее 10 мс. В противном случае это означает, что ваша сеть перегружена или у вас на компьютере установлена несовершенная реализация IP. Для веб-серверов Интернета нормальной считается задержка менее 200 мс, а хорошей — менее 50 мс. Время ожидания больше 1 с означает, что связь с сервером у вас очень плохая. Команда traceroute позволяет уточнить, какой именно маршрутизатор тормозит передачу. Это очень полезно для сравнения провайдеров. Если сервер вообще не отвечает, попробуйте запустить программу nslookup. Возможно, вы просто не можете определить адрес сервера по его имени, а сам сервер прекрасно работает. Служба DNS, как и многие другие службы Интернета, полностью перестает работать, когда нагрузка превышает некоторую величину. С помощью nslookup вы можете подключиться к DNS-серверу вне вашей организации, найти IP-адрес нужного вам сайта, а затем обратиться к нему. Вы даже можете переключиться на другой DNS-сервер на постоянной основе, если нас не устраивает его производительность, но это в некотором смысле непри-
лично делать, если только у вас нет явной договоренности с владельцем этого самого другого сервера. Попробуйте запустить DNS-сервер на своем собственном компьютере. Он будет кэшировать ваши запросы и обеспечит для них гораздо меньшее время ответа. Установите последнее ядро Linux, чтобы воспользоваться преимуществами современных реализаций TCP/IP. Не стоит, впрочем, обновлять систему чаще, чем пару раз в год. Подключайте только те драйверы, которые вам нужны. Например, вам не нужна эмуляция математического сопроцессора, поскольку в большинстве современных процессоров он и так есть. Поставьте интервал повторной передачи TCP равным 1 с, если он еще ей не равен. Удалите все лишние демоны из файлов /etc/red/*. Приведенная ниже команда позволяет изменить MTU в системе Linux: # /sbin/ifconfig ethO mtu 1500 Основные рекомендации О Используйте средства операционной системы для контроля наличия свободной памяти, повторной передачи пакетов, а также доступности сервера. О Увеличьте размер приемного буфера, если это возможно. О Используйте последние и самые лучшие реализации драйверов и протоколов стека TCP/IP.
1«~ Аппаратное •у обеспечение клиента Веб-клиентами в наши дни являются самые обычные персональные компьютеры. Хотя для путешествия по Сети частенько используются «Макинтоши», сотовые телефоны и карманные компьютеры типа Palm Pilot, первое место по числу пользователей Интернета все равно остается за ПК. В этой главе я сосредоточу внимание на компонентах оборудования персонального компьютера, поскольку компьютеры как целое отличаются друг от друга именно своими компонентами. На этом уровне компоненты остаются взаимозаменяемыми благодаря стандартизации, что делает возможным конкуренцию производителей, а пользователям предлагается выбор между ценой и производительностью. Процессор Самое важное, что следует помнить о процессорах веб-клиентов, — это то, что они играют не слишком важную роль. Просмотр содержимого веб-сайтов всегда связан в первую очередь с вводом-выводом, а не с вычислениями. В любом случае процессоры персональных компьютеров чаще всего работают быстрее, чем их шины, то есть очень быстрому процессору обычно приходится ждать, пока шина «догонит» его. Тем не менее компьютеры продаются в первую очередь как имеющие определенную тактовую частоту и модель процессора, поэтому производителям приходится устанавливать самые быстрые процессоры последних моделей, даже несмотря на то, что большинству людей вполне хватило бы процессоров предыдущих поколений. Скорость доступа к сети гораздо больше зависит от жесткого диска и сетевого адаптера (или модема), чем от процессора и даже скорости шины.
Несмотря на все сказанное, существуют достаточно веские аргументы и в пользу того, чтобы выбрать для своего клиента процессор получше. Во-первых, для обработки HTML и изображений требуется заметная вычислительная мощность. С помощью монитора производительности вы можете убедиться, что нагрузка на процессор значительно возрастает, когда браузер обрабатывает вебстраницу. Чтобы доказать себе, что эта нагрузка создается именно обработкой страницы, а не обращением к Сети или чем-нибудь другим, нажмите кнопку Back, и вы увидите, что процессор снова окажется сильно загружен, хотя страница будет считана из кэша, размещенного в памяти, а не скачана заново. С другой стороны, большая часть веб-страниц имеет обычно небольшой размер, поэтому вы, скорее всего, даже не заметите времени, потраченного на обработку таких страниц. Более серьезная причина, по которой есть смысл покупать клиентский компьютер с быстрым процессором, — потребность выполнять эмулируемые программы с максимально возможной скоростью. Ценность компьютера зависит от того, сколько полезных программ на нем можно выполнять. В принципе, любой компьютер может эмулировать любой другой компьютер, но эмуляция стоит дорого с точки зрения операций процессора, поскольку между системными вызовами операционных систем, как и между элементарными операциями процессоров, редко можно провести взаимнооднозначное соответствие. Если у вас есть компьютер Sparcstation, а вы хотите работать с Microsoft Office, вам придется запустить эмулятор (например, SoftPC) — но это значительно замедлит работу. Вы можете запускать программы для Мае на компьютере с Linux с помощью пакета Executor. И вспомните, что Macintosh с PowerPC эмулирует процессор 68К для выполнения всех старых программ. По мере того как мощность процессоров возрастает, эмуляция начинает становиться более реальной альтернативой приложениям, привязанным к конкретной платформе. Для веб-клиентов в этом отношении важнее всего эмуляция виртуальной машины Java. По самой своей природе Java не дает «родного» исполняемого кода ни для одного из существующих видов процессоров, поэтому для работы программ, написанных на этом языке, обязательна эмуляция. Потребность в эмуляции, которая может возникнуть в будущем, является достаточно веским аргументом в пользу покупки быстрого процессора, даже если существующим приложениям, написанным под этот процессор, лишняя вычислительная мощность уже не требуется. Наконец, быстрота процессора означает быстроту графики. Особенно ресурсоемким является обработка языка моделирования виртуальной реальности — VRML. Два главных признака, подсказывающих, что пора покупать процессор побыстрее, — это «молчаливое торможение» компьютера (когда не слышно движения головок жесткого диска) и постоянно высокие показания монитора активности процессора. Есть кое-какие моменты, которые полезно держать в голове, выбирая новый чип в «черепушку» своего компьютера. О Чем больше объем кэша, размещенного непосредственно на процессоре (кэш первого уровня — LI cache), тем лучше, поскольку у него самое лучшее время доступа.
О Чем больше тактовая частота процессора, тем лучше — в пределах одного поколения, но это может быть и не так, если сравниваются процессоры разных поколений или производителей. Например, Pentium II с тактовой частотой 800 МГц однозначно будет работать быстрее, чем Pentium II с частотой 600 МГц, но невозможно утверждать заранее, что он будет лучше любого процессора любого производителя, работающего на тактовой частоте 600 МГц. О Конвейерная обработка (pipelining), означающая, что процессор одновременно выполняет несколько команд, каждая из которых при этом находится на своем этапе, может повышать производительность, поскольку большую часть времени команды считываются из памяти подряд. Последовательное выполнение, таким образом, производится быстрее, чем ветвление, нарушающее последовательность. Некоторые процессоры могут пытаться предугадывать ветвление (branch prediction), чтобы не останавливать конвейер. О Для веб-клиентов наличие математического сопроцессора (Floating-Point Unit — FPU) не слишком существенно; впрочем, производители в наши дни интегрируют FPU непосредственно в процессоры. О Процессоры с сокращенным набором команд (Reduced Instruction Set Chip — RISC), такие ка*к Power PC и SPARC, обычно работают быстрее, чем процессоры с расширенным набором команд (Complex Instruction Set Chip — CISC), такие как Intel x86, поскольку могут выполнять меньшее количество команд строго регламентированной (одинаковой) длины. Однако на то, чтобы заменить одну инструкцию CISC, требуется несколько инструкций RISC, поэтому исполняемые файлы для процессоров с RISC-архитектурой обычно имеют больший размер, а приложения требуют несколько больше памяти. Совсем не обязательно 64-разрядный процессор повысит вашу производительность, если все ваши программы оптимизированы для 32-разрядных процессоров; «64-разрядность» может относиться к нескольким параметрам: размеру регистров процессора, ширине шины, адресному пространству. Для программистов на языке С скажу, что разрядность адресного пространства означает размер указателя. Процессоры с 64-разрядными регистрами могут выполнять арифметические операции непосредственно с 64-разрядными операндами. Низковольтовые процессоры, использующиеся, например, в портативных компьютерах, работают медленнее, чем процессоры тех же моделей, рассчитанные на более высокое напряжение. Это связано с тем, что каждый транзистор процессора обладает определенной емкостью, связанной с размерами соединений между элементами. При более высоком напряжении провода «наполняются электричеством» быстрее и быстрее меняют состояние транзистора, точно так же, как шланг для поливки газона быстрее наполняется водой, если вы сильнее открываете кран. Возможно, вы слышали словосочетание «субмикронные технологии», относящееся именно к размерам элементов процессора и соединений между ними. При одном и том же напряжении маленький процессор с тонкими соединениями будет работать быстрее: во-первых, расстояния меньше, а во-вторых, меньше емкость. В портативных компьютерах часто используются те же
процессоры, что и в обычных настольных, но на них подаются пониженное напряжение и пониженная тактовая частота. Это позволяет экономить энергию. То же самое относится и ко всем другим микросхемам — например, к памяти. Важно помнить одно: экономия энергии в рамках одного поколения микросхем осуществляется за счет производительности. Необычайный успех полупроводниковой электроники связан с тем, что одинаковое количество транзисторов в каждом следующем поколении чипов размещается на меньшей площади и при этом тратит меньше энергии и работает быстрее — именно благодаря увеличению плотности. Кроме того, цена в расчете на один транзистор постоянно падает, поскольку все большее количество транзисторов помещается на одной кремниевой подложке. ОЗУ Почти всегда увеличение объема памяти повышает производительность. Если у вас много оперативной памяти, вы можете увеличить размер кэша и без проблем пользоваться всеми новыми функциями браузеров. Однако увеличение объема памяти не поможет улучшить быстродействие, если проблема вызвана чем-то другим. С помощью средств контроля производительности системы вы всегда сможете сказать, вся ли оперативная память в системе израсходована. Пытаясь просмотреть очень большую веб-страницу на компьютере с небольшим объемом ОЗУ, вы почти наверняка добьетесь сбоя браузера. Особенно легко этого достичь на старых компьютерах с 16 Мбайт памяти и Windows 3.1 в качестве операционной системы. Оперативная память в персональных компьютерах обычно подключается к быстрой системной шине, которая напрямую связывает ее с процессором, а не к шинам EISA или PCI. Оперативная память объединяется в банки, количество чипов в которых определяется количеством линий для передачи данных, имеющихся в шине. Когда данные считываются из памяти, все чипы одного банка одновременно выдают по одному биту, каждый в свою линию. Два принципиально различных вида ОЗУ (Random Access Memory — RAM) называются динамическим и статическим (DRAM, SRAM), причем наиболее широко распространена именно динамическая память. DRAM требует постоянного обновления, поскольку каждая ячейка такой памяти представляет собой, по сути, миниатюрный конденсатор, который постоянно разряжается. SRAM не требует постоянного обновления с помощью какого-либо внешнего устройства, поскольку ячейки статической памяти представляют собой самообновляющийся набор из пяти или более транзисторов, называемый триггером (flip-flop). DRAM проще, а потому дешевле и обладает большей плотностью (в расчете на квадратный сантиметр чипа). SRAM стоит дороже, но работает гораздо быстрее. Микросхемы DRAM мультиплексируют адреса строк и столбцов в один и тот же набор проводов, поэтому адреса ячеек передаются в два этапа: сначала строка, затем столбец. Адрес ячейки SRAM передается за один этап, и это одна из причин, по которой SRAM быстрее.
Существуют различные разновидности DRAM. Помимо собственно микросхем памяти на чипах DRAM могут находиться достаточно сложные логические элементы. Рекламируемая скорость RAM соответствует быстроте подачи битов но внутренние логические схемы контроллера чипа. На обработку нового адреса внутри схемы уходит столько же времени, сколько на передачу битов, и еще столько же уходит на подготовку к новому циклу доступа. Вывод отсюда один: рекламируемая скорость может вовсе не соответствовать реальной. Каждый бит памяти задается адресами строки и столбца. Память с быстрым доступом (Fast Rage RAM) разрешает контроллеру начинать обработку нового адреса строки до окончания текущего цикла обращения к памяти. Память с расширенным выводом (Extended Data Output) позволяет делать то же самое и для нового адреса столбца, а не только строки. Не все материнские платы способны работать с любыми типами памяти. Кое-какие сведения по этому поводу вы можете найти по адресу: http://www.dataram.com/bytes/edo.htm. Синхронная динамическая память (Synchronous DRAM — SDRAM) синхронизируется с шиной памяти, работает быстрее, чем EDO RAM, и на данный момент является наиболее распространенным (и дешевым) видом памяти. Кэш Обратите внимание: современные микросхемы памяти обычно работают с периодом обращения 70 не и могут выдавать данные на частоте около 30 МГц C3 не), в то время как все новые процессоры работают на гораздо большей частоте. Кэш второго уровня (L2 cache), устанавливаемый, в отличие от кэша первого уровня, не на самом процессоре, используется для того, чтобы нивелиро- пать это различие в частотах. Эффективность использования кэша второго уровня падает при работе в многозадачном режиме (типичном для серверов Unix), поскольку обращение производится к различным областям памяти, что приводит к необходимости чтения данных, отсутствующих в кэше. Кэш второго уровня обычно реализуется на микросхемах SRAM, работающих гораздо быстрее C-8 не), но эти микросхемы имеют больший размер, сильнее нагреваются и стоят дороже, чем DRAM. Шина Изначально память в персональных компьютерах подключалась к той же шине, что и все остальные устройства, но на всех современных компьютерах для памяти отведена отдельная шина, обеспечивающая повышенную скорость обращения к данным. В рабочих станциях и старших моделях ПК для ввода-вывода также часто устанавливаются отдельные шины. Шина памяти, называемая также внешней шиной процессора, работала бы и идеальном случае за два этапа: передача адреса; чтение или запись данных. К сожалению, память обычно медленнее шины, поэтому в цикл вставляется не-
сколько тактов ожидания (wait states), дающих памяти время на то, чтобы добраться до данных. Обычное значение — пять тактов ожидания. Частоту системной шины ISA или EISA, как правило, можно увеличить в настройке CMOS или BIOS (называют их по-разному), установив ее равной какой-либо доле A/8 или 1/10, к примеру) тактовой частоты процессора. Если сделать частоту системной шины слишком высокой, данные будут передаваться с ошибками и система работать не сможет, но небольшое увеличение этой частоты позволяет повысить производительность всех карт расширения, подключенных к шине, таких как контроллеры дисков, видеоадаптеры и сетевые карты. Стандартной шиной в современных персональных компьютерах является шина PCI. Она отличается очень высокой пропускной способностью, а сам стандарт распространен довольно широко: он поддерживается Apple, SGI, Sun и DEC, что значительно увеличивает рынок карт расширения. Шина PCI может работать на частотах 66 и 132 МГц и быть как 32-, так и 64-разрядной. На материнские платы, поддерживающие стандарт PCI, часто устанавливаются и старые шины EISA, что дает вам возможность пользоваться купленными ранее адаптерами и дальше. Подробнее об этом рассказывается в главе 16. Если вы работаете с веб-сайтом, находящимся в локальной сети, самым «узким местом» может быть и шина. Если же вы вышли в Интернет, именно он будет этим «узким местом». Диск Двумя самыми важными для клиентов параметрами дисков являются максимальное время поиска (seek time) и скорость вращения (rotation speed). Максимальное время поиска затрачивается головками диска на перемещение с одного края его поверхности до другого. Эта величина дает нам верхнюю границу для времени считывания данных. Хорошим считается максимальное время поиска порядка 12 мс. Не путайте максимальное время поиска со средним или каким- нибудь другим — производители стараются указывать в первую очередь те цифры, которые им выгодны. Другим важным параметром является скорость вращения. Типичная скорость вращения диска IDE составляет 5400 и 7200 об/мин, а для дисков SCSI эта величина выше — 7200 и 10 000 об/мин. Максимальное время поиска более важно при беспорядочном обращении к данным, тогда как скорость вращения положительно влияет на производительность при последовательном считывании или записи больших объемов данных. IDE Интерфейс встроенной электроники жесткого диска (Integrated Drive Electronics — IDE) является также стандартом, определяющим способ соединения жесткого диска с системной шиной. Другое его название — стандарт подключения к шине AT (AT bus Attachment standard — ATA). Ширина интерфейса (ко-
личество параллельных проводов) — 16 разрядов, поскольку изначально он был ориентирован на шину EISA. В настоящее время существуют адаптеры, позволяющие подключать диски IDE через шину PCI. Диски IDE сейчас являются наиболее дешевыми и широко распространенными. Скорость передачи данных для таких дисков на момент написания книги лежит в диапазоне 1—20 Мбайт/с, а размер может достигать 60 Гбайт. Хотя в стандарте IDE электроника должна находиться на самом диске, внешний контроллер IDE все равно необходим. Один контроллер может работать с одним или двумя дисками, но если дисков два, они не могут работать независимо: когда работает один, другой вынужден простаивать. Если для повышения производительности вы планируете подключить несколько дисков IDE параллельно, нужно установить несколько контроллеров, хотя полезнее вообще перейти на интерфейс SCSI. С течением времени появляются расширения стандарта IDE, такие как EIDE и Ultra ATA. Стандарт Ultra ATA был предложен совместно Intel и Quantum; он задает более высокую скорость вращения диска и более быструю передачу данных между диском и памятью (по сравнению с EIDE). SCSI Упрощенный интерфейс компьютерных систем (Small Computer System Interface — SCSI) представляет собой универсальный стандарт для подключения внешних устройств к компьютеру. Диски, использующие стандарт SCSI, стоят дороже и обеспечивают более высокую производительность, чем диски IDE. Последние достаточно дешевы и быстры для большинства клиентов, но для серверов действительно необходимы диски SCSI. В главе 16 об этом интерфейсе рассказано подробнее. Фрагментация Когда диск заполняется почти целиком, операционной системе приходится записывать новые файлы в оставшееся свободное пространство. При этом файлы часто разбиваются на фрагменты, располагающиеся в разных местах диска, что замедляет доступ к таким файлам — ведь при их чтении производится несколько операций поиска. Утилиты-дефрагментаторы размещают файлы на дисках таким образом, чтобы уменьшить фрагментацию, что повышает скорость обращения к данным. Видео Монитор влияет на производительность системы в меньшей степени, чем видеоадаптер. Экраны портативных компьютеров обладают более низким быстродействием, чем электронно-лучевые, но и те и другие все равно работают быстрее, чем адаптеры, которые выдают на них сигнал. На видеоадаптере должно быть
достаточно видеопамяти (VRAM) для размещения всего экрана с максимальной глубиной цвета. Производительность возрастает только до этих пор. Для работы с веб-сайтами обычно достаточно 2 Мбайт видеопамяти, но вы можете увеличить объем ее до 32 Мбайт (например, с целью обеспечения повышенного разрешения экрана, ускорения работы видеоподсистемы с помощью буферизации и т. п. — Прим. ред.). Почувствовать производительность графической подсистемы можно на простом эксперименте: попробуйте пролистать содержимое окна за движок или с помощью ролика мыши либо переключиться между несколькими открытыми окнами. Современные видеоадаптеры подключаются к ускоренному графическому порту (Accelerated Graphics Port — AGP). На некоторых материнских платах устанавливаются встроенные видеоадаптеры, что несколько снижает общую стоимость компьютера, но затрудняет его обновление. ммх Расширенный набор команд ММХ был разработан фирмой Intel для своих процессоров. Его использование действительно повышает производительность графики и звука в тех приложениях, которые рассчитаны на его использование, но такие программы не переносимы на другие процессоры (за исключением процессоров фирмы AMD). Основным преимуществом, обеспечивающим высокую производительность ММХ, является наличие на процессоре 16 Кбайт кэша для графики. Хороший видеоадаптер даст вам такую же или даже заметно большую производительность. Цвета и разрешение Разработчики видеоадаптеров любят хвастаться тем, что их карты могут отображать миллионы цветов, но они забывают, что человеческий глаз не может различить такое их множество, а расчеты, требуемые для формирования сложной цветовой картины, снижают общую производительность. Глубины цвета в 8 бит B56 цветов) вполне достаточно для обычных путешествий по веб, но не для фотографий. Для хорошего отображения фотографий вам придется перейти в 16- или 24-разрядный цветовой режим. Одновременный запуск множества приложений при работе в 8-разрядном режиме может привести к тому, что буфер, отведенный на карты цветов, закончится, и некоторые приложения начнут работать в неоптимальном цветовом режиме либо отдавать право установки цветов другим приложениям, что вызовет эффект мерцания. Разрешение — количество пикселов на экране — важнее, чем количество цветов. Разрешение экранов компьютеров пока не достигает разрешения, обеспечиваемого человеческим глазом, и даже не приближается к нему, поэтому все улучшения очень хорошо заметны. С низким разрешением производительность может быть и выше, но скорость не так важна, как качество изображений, которое резко ухудшается с понижением разрешения. Для веб стандартом-минимумом является разрешение экрана 800x600.
Производители часто указывают длину диагонали экрана в дюймах, а не разрешение его в пикселах. Это может ввести покупателя в заблуждение, но огромный размер некрасивого изображения с крупными пикселами сделает его лишь еще более некрасивым. Количество цветов и разрешение экрана часто можно установить программно. Иногда это может потребовать перестановки перемычек (джамперов — jumpers) на материнской плате. Перемычки представляют собой маленькие соединения между контактами. Перестановка перемычек позволяет настраивать аппаратное обеспечение компьютера. Драйверы Драйверы всех устройств вашего компьютера должны быть самыми современными. Некоторые видеоадаптеры фирмы S3 и других производителей могут использовать процессор в то время, когда он не занят другими программами, и таким образом выдавать более высокое быстродействие графики. Однако это может помешать процессору обслуживать прерывания других устройств, в частности СОМ-портов, из-за чего будут переполняться буферы, теряться пакеты и падать производительность сети. Хорошие драйверы видеоадаптеров, например созданные фирмой Number Nine, позволяют отключать использование тактов процессора. 3D и видеоклипы Аппаратный ускоритель двух- или трехмерной графики не является обязательным аксессуаром путешествующего по веб. Исключение составляют любители интерактивных игр по сети, фанаты VRML и люди, устраивающие видеоконференции. Это может измениться, когда пропускная способность Интернета возрастет настолько, что передача видеоизображения станет реальной. Видеоадаптеры стандарта AGP лучше подходят для таких приложений благодаря высокой пропускной способности шины. Тесты для видеоадаптеров Лля видеоадаптеров имеются специальные тесты. В первую очередь нужно назвать Cbench, Wintach 1.2, VidSpeed 4.0, SpeedMark и Xbench для Xfree86. Программа Cbench (сокращение от ChrisBench) предназначена для измерения производительности видеоадаптера в играх для DOS. Ввод-вывод Возможности аппаратуры ввода-вывода персональных компьютеров значительно уступают оборудованию серверов, но вполне достаточны для путешествия по Сети. Когда браузер отправляет в веб свой запрос, он просто обращается к опе- |>ационной системе, предлагая ей переслать запрос на удаленный сервер. Подсис-
тема связи операционной системы (Winsock или другая реализация стека TCP/IP), в свою очередь, обращается к последовательному порту (если вы используете модем) или сетевому адаптеру. Микросхема, управляющая последовательным портом, называется универсальным асинхронным приемником и передатчиком (Universal Asynchronous Receiver and Transmitter — UART). UART UART представляет собой буфер с логическими элементами, обеспечивающий взаимодействие модема (обычно подключающегося по интерфейсу RS-232) и системной шины. Чтобы передать запрос к веб-серверу дальше, операционная система командует UART принять данные из шины, после чего пересылает сами данные. UART считывает их и сообщает модему о появлении данных для отправки. Модем принимает данные и через некоторое время получает ответ вебсервера. Модем начинает запись в буфер UART, а тот генерирует запрос на прерывание (IRQ), сообщая операционной системе о том, что она должна получить данные. Все было бы хорошо, но есть одна проблема. На некоторых старых компьютерах установлены UART типа 8250 или 16450, которые принимают от модема лишь 1 байт, после чего обращаются к операционной системе посредством прерывания. Процессор может быть занят более приоритетным прерыванием, а модем будет продолжать помещать данные в буфер с той скоростью, которая задана в настройках последовательного порта. В результате буфер UART будет переполнен до того, как процессор сможет считать из него данные. Сетевые подпрограммы операционной системы обнаружат, что контрольная сумма данных на канальном уровне (протокол РРР или SLIP) не соответствует ожидаемой, и потребуют повторной передачи данных. Это замедляет реальную скорость работы с сетью. Однобайтовый UART способен работать на скорости линии ISDN, если операционная система не занята ничем другим, но пользователь на компьютере с Windows в реальности будет работать со скоростью модема на 14 400 бит/с или еще более низкой. Одним из решений проблемы переполнения буфера последовательного порта является снижение скорости передачи данных через этот порт. Это позволю вам избавиться от повторных передач, но мы-то стремимся к максимально быстрому доступу в сеть. Поэтому более правильным решением будет перейти на компьютер с более современным UART, например 16550А. Такой UART может хранить в буфере от 8 до 16 байт, что дает операционной системе больше времени на обработку прерывания. Персональный компьютер с таким UART может обработать данные, передаваемые со скоростью 500 кбит/с, если код операционной системы достаточно эффективен. Заменить чип UART на материнской плате достаточно сложно, поскольку обычно он припаивается намертво, но вы мо жете легко достичь подъема производительности, купив внутренний модем, поскольку на таких модемах устанавливаются свои собственные чипы UART
Аппаратное сжатие может приводить к переполнениям Помните, что аппаратное сжатие на модемах обычно включено по умолчанию. Модем может считать, что он помогает вам, но если у вас установлен старый UART, то он может не справиться с потоком данных: ведь на каждый байт сжатых данных, принятый модемом, этот чип должен будет принять два или три байта распакованных данных. Это может вызвать замешательство пользователя, установившего низкую скорость передачи данных и рассчитывающего на то, что генерь-то UART должен справиться с их потоком. Лучшее решение — обновить UART или компьютер целиком. BIOS Вазовая система ввода-вывода (Basic Input Output System — BIOS) представляет собой самый низкий уровень программного обеспечения компьютера. Иногда BIOS неправильно называют CMOS/ поскольку настройки BIOS хранятся в микросхеме памяти CMOS (Complementary Metal Oxide Semiconductor — комплементарный транзистор типа металл—окись—полупроводник). Именно BIOS начинает работать в первую очередь, когда вы включаете свой компьютер. Действует он в три этапа: сначала выполняется тестирование компьютера (Power-On Self Test — POST), затем устанавливаются обработчики прерываний, после чего настраиваются параметры системы. Тестирование выполняется сразу же после включения компьютера. BIOS проверяет, может ли процессор обратиться к памяти и видеоадаптеру, жестким дискам и другим компонентам, которые должны быть установлены правильно. После этого устанавливаются основные обработчики прерываний — например, для клавиатуры. При нажатии должной комбинации клавиш BIOS запускает программу, позволяющую менять параметры системы. Эта комбинация различна для разных типов BIOS. На своем портативном компьютере я захожу в настройки Phoenix BIOS нажатием специально предназначенной для этого клавиши. В AMI BIOS нужно но время загрузки компьютера нажать клавишу Delete, а в других BIOS для той же цели может использоваться комбинация Ctrl+Alt+Insert. Подробнее об этом читайте в документации своего компьютера, а также на веб-сайте производителя BIOS. Правильная настройка BIOS позволяет повысить производительность компьютера. Установите переключатель скорости процессора (CPU speed) в положение fast, если ваш BIOS позволяет это сделать. Включите математический сопроцессор (FPU) и кэши всех уровней. Попробуйте уменьшить количество пустых циклов для памяти и шины. Возможно, вас удивит, почему всем этим параметрам не присвоены оптимальные, с точки зрения производительности, шачения по умолчанию. Ответ прост: для обеспечения стабильности. Если вы разгоните свой компьютер до предела, он будет чаще выдавать сообщения об ошибках, поскольку вы превысите физические пределы его производительно-
сти. Поскольку все эти параметры хранятся в BIOS, вам нужно иметь гарантию, что вы сможете загрузиться в программу его настройки, чтобы изменить их обратно, если возникнут проблемы. Если у вашего BIOS не слишком много параметров, вы можете установить утилиты, которые дадут вам больше власти над своим ПК. Попробуйте изучить сайт http://www.sysopt.com/bios.html. Полезной возможностью BIOS является спящий режим, который особенно эффективен на портативных компьютерах. В данном режиме содержимое операционной памяти обычно сохраняется на жесткий диск, а при выходе из этого режима считывается обратно, что позволяет значительно сэкономить время загрузки. С помощью BIOS вы можете включить автоматическое отключение жестких дисков после определенного периода бездействия, что продлит время работы компьютера от батарей, но приведет к возникновению задержек, связанных с необходимостью раскрутки дисков. На портативных компьютерах Macintosh многие параметры могут задаваться через панели управления. Например, установка Control Panels ► Powerbook ► Better Performance удлинит время ожидания до остановки жестких дисков. Основные рекомендации О Не пытайтесь купить самый современный процессор. О Покупайте материнскую плату с шиной PCI, а не ISA или EISA. О Купите достаточно оперативной памяти, чтобы компьютеру не нужно было обращаться к файлу подкачки. О Диски SCSI лучше, чем IDE. О UART компьютера или модема должен быть 16550А или лучше.
^ ш ЛИНИИ СВЯЗИ | 4 и оконечные устройства В этой главе я расскажу о линиях связи и терминаторах, представляющих собой ;женья цепи, соединяющей клиента с сервером, указывая, где высокоскоростные соединения могут повысить общее быстродействие, и давая общие рекомендации по повышению производительности соединений. Линией называется соединение между двумя точками. Любой сегмент соединения Интернета состоит из физической линии связи, сделанной из металла, оптоволокна или даже просто воздушного пространства, а также пары концевых устройств. Физические свойства линии устанавливают теоретические ограничения на ее производительность, а концевые устройства определяют низкоуровневый протокол этой линии и в конечном счете — то, насколько близко вы можете подойти к теоретической производительности линии. Медная телефонная линия, используемая большинством пользователей для подключения к своим провайдерам (ISP), подключается своими концами к двум модемам (хотя на ней присутствуют и коммутаторы телефонной компании). На стороне провайдера наверняка установлены две карты Ethernet, соединяющих банк модемов с маршрутизатором. Маршрутизатор подключен к линии Т1, концевыми устройствами которой являются CSU/DSU. И так далее. Миллионы пользователей веб проклинают свои местные телефонные компании и модемы, обвиняя их в низком быстродействии сети, но их гнев часто окалывается направлен не по адресу. Даже при бесконечно быстрой связи с локальным провайдером путешествие но веб все равно не было бы слишком быстрым. «Узким местом» просто стала бы точка подключения провайдера, а если бы вы каким-то образом устранили и ее, «узкое место» переместилось бы на ближайшую точку доступа к сети (Network Access Point — NAP), где провайдеры обмениваются пакетами. Интернет в целом обеспечивает среднюю пропускную способность около 50 Кбайт/с. Помните, что большинство серверов подключено не
к базовой сети, а к своим провайдерам, то есть находится на несколько ступеней ниже в иерархии подключений. Вы можете увидеть закон сокращения доходов в действии, перейдя с модема B8,8 кбит/с) на ISDN, а затем на кабельный модем. Увеличение скорости при переходе с 28,8 на 128 кбит/с (ISDN) производит сильное впечатление, а вот при переходе на 500 кбит/с (кабельный модем) оно далеко не так заметно, хотя в абсолютных единицах повышение пропускной способности линии гораздо больше. Пересылка и время ожидания Время ожидания для любой физической линии не может быть нулевым из-за конечности скорости света, но значительная доля времени ожидания Интернета создается оконечными устройствами и точками соединений, такими как маршрутизаторы. Чем меньше на линии концевых точек и разветвлений, тем меньше время ожидания. В особенности следует стремиться к уменьшению числа точек соединения различных носителей с различными скоростями передачи. Интерфейсы между линиями с различными скоростями или протоколами являются своего рода валунами, мешающими плавному течению реки данных. Пакет из медленной линии не может быть мгновенно переправлен бит за битом в быструю линию, поскольку биты в пакетах должны следовать друг за другом подряд, без временных промежутков. Пакет должен быть принят целиком, прежде чем его можно будет отослать по быстрой линии. Это увеличивает время ожидания. То же самое верно и в отношении преобразования протоколов (например, с Ethernet на Token Ring). Мораль проста: количество соединений должно быть минимальным, — так же как, и количество различных протоколов. Самым низким временем ожидания обладает прямое соединение между браузером и сервером, но такое редко оказывается возможным. Модем — выезд на информационную магистраль Аналоговые модемы преобразуют поток цифровых данных в аналоговый формат — модулированную звуковую волну, которая может быть нередана по коммутируемой телефонной линии (Plain Old Telephone Service — POTS, как ее называют в США) на другой аналоговый модем. Рост производительности модемов за последние несколько лет был связан с тем, что исследователи научились бороться с трудностями, возникающими при передаче цифровых данных по зашумленным аналоговым линиям. Телефонная линия предназначалась для передачи голоса. Фильтры в телефонной линии усиливают часть спектра, лучше всего слышимую человеческим ухом (от 300 до 3300 Гц), за счет других частот. Другие фильтры предназначены для подавления эха. Качество многих линий оставляет желать лучшего. В сме-
шанных линиях аналоговые сигналы преобразуются в цифровые с пропускной способностью линии 64 кбит/с, после чего пересылаются в таком виде на другой коммутатор, где они преобразуются обратно в аналоговые (рис. 14.1). Все эти свойства линий, связанные с их ориентированностью на передачу голоса, создают проблемы для производителей модемов, но тем не менее с выходом последнего поколения модемов на 56 кбит/с им почти удалось достигнуть теоретического ограничения в 64 кбит/с, устанавливаемого коммутаторами. Для достижения более высоких скоростей сигнал должен каким-то образом избегать преобразования из аналогового вида в цифровой и обратно либо вовсе не передаваться через коммутаторы. Именно так и работает стандарт DSL. Рис. 14.1. Преобразование сигналов при работе с модемом Модемы передают данные, модулируя несущую волну с определенной частотой. Модулироваться может как фаза, так и амплитуда несущей волны. Реальная скорость передачи состояний (baud rate) по сравнению с ранними поколениями модемов возросла не слишком сильно, но изощренные схемы кодирования увеличили количество возможных состояний для передачи большего количества битов в одном боде. Например, модемы, работающие по протоколу V.32, могут передавать одно из 64 возможных состояний, то есть каждый бод кодирует 6 бит Bе = 64). Модемы V.32 работают на скорости 2400 бод, то есть они могут пересылать 2400 х 6 ж 14 400 бит/с. Модемы V.34 работают на скорости 3200 бод и отправляют одно из 512 состояний, поэтому каждое состояние передает 9 бит Bе = 512). Следовательно, скорость передачи данных для таких модемов составляет 3200 х 9 - 28 800 бит/с. Боды часто путают с битами в секунду, поскольку в старых модемах они означали одно и то же. Эти модемы передавали лишь одно из двух состояний за раз, поэтому 2400 бод означало 2400 бит/с. Время ожидания и пропускная способность от модема к модему Нремя ожидания модема относительно велико по сравнению с чисто цифровым и единением по Интернету, даже если это соединение установлено через несколько маршрутизаторов. Чтобы подтвердить это, я провел простой тест. Передача пакета ICMP туда и обратно между двумя компьютерами, соединенными по мо-
дему (в пределах одного города), с помощью программы ping, потребовала 160 мс, тогда как между двумя компьютерами, соединенными цифровой линией, но находящимися на разных побережьях США, пакет был передан за 120 мс, хотя ему и пришлось пройти через восемь маршрутизаторов. Время ожидания создается телефонной службой, кодированием и самим модемом, но важно помнить одно: использование модема всегда связанного с небольшой, но заметной прибавку ко времени ожидания. Убедитесь, что пропускная способность вашего модема не уступает пропускной способности модемов вашего провайдера. Большинство модемов может взаимодействовать с более слабыми, поэтому вы можете купить самый современный модем, и вам не придется его менять, когда ваш провайдер обновит свое оборудование. К сожалению, модемы на 56 кбит/с не всегда совместимы друг с другом, поэтому вы можете не обнаружить улучшения пропускной способности при переходе на такой модем. Даже если модем полностью совместим с оборудованием провайдера, реальная скорость все равно может никогда не подниматься выше 45 кбит/с из-за плохого качества линии. Модемы на 33,6 кбит/с работают на номинальной скорости гораздо надежнее. Синхронизация Полоса пропускания модема ограничена не только протоколами и качеством линии, но также из-за асинхронности соединения, поскольку передача может начинаться в любой момент, как только появляются данные для отправки. Чтобы уведомить сторону-получателя о начале отправки полезных данных, модемы добавляют два лишних бита к каждому байту, обозначая его начало и конец, поэтому на каждый байт полезных данных по линии передается 10 бит. Следовательно, максимальная пропускная способность модема на 14 400 бит/с составляет 1400 байт в секунду, а не 1800, как можно было бы ожидать. Аналогичным образом модем на 28,8 кбит/с обладает пропускной способностью 2800 байт и секунду и так далее. Этой 20%-ой нагрузки можно избежать, используя процедуру доступа к каналу для модемов (Link Access Procedure for Modems — LAP-M) или один из сетевых протоколов Microcom (Microcom Network Protocol — MNP). Согласно этим протоколам, кадры РРР отправляются целиком, без начальных и конечных битов в каждом байте. Разумеется, оба модема должны «договориться» о том, какой протокол они будут использовать. Обратите внимание, что эти протоколы реализуются модемом, поэтому последовательный порт должен работать на скорости модема без 20%-ой нагрузки. Это означает, что включение одного из протоколов увеличивает нагрузку на последовательный порт и может привести к переполнению буферов UART, если раньше компьютер уже с трудом справлялся с обслуживанием модема. Аппаратное сжатие Широко распространены модемы с поддержкой аппаратного сжатия данных. Это сжатие осуществляется оборудованием модема, а не программами вашего
компьютера. Аппаратное сжатие особенно эффективно при передаче больших объемов данных и при передаче текста, который очень хорошо сжимается. 11омните, что не все файлы хорошо сжимаются, поэтому не факт, что включение аппаратного сжатия приведет к повышению производительности. Аппаратное сжатие поддерживается, в частности, протоколами MNP. Коррекция ошибок Современные модемы достаточно умны, чтобы справляться с шумом, возникающим в телефонных линиях, понижая скорость передач или упрощая кодирование, а не многократно запрашивая повторную пересылку поврежденного блока или разрывая линию. Они также способны увеличивать скорость передачи, когда качество линии улучшается. Помните, что модемы знают лишь о том, что передают друг другу блоки неструктурированных данных. Модем ничего не знает о том, что вы передаете HTTP-запрос, упакованный в TCP-сегмент, который, в свою очередь, упакован it IP-пакет, а тот, наконец, разбит на РРР-кадры. Кадры РРР проверяются на наличие ошибок, когда данные поступают на вход сокета IP, но на это уходит до- нольно много времени, а протокол РРР в случае ошибки может лишь запросить повторную передачу пакета. Система работает гораздо быстрее, когда модем исправляет те ошибки, которые может, самостоятельно. Модемы V.42 обладают встроенной коррекцией ошибок, которую не нужно ныключать. Если вы ее выключите, то будете получать больше сообщений об ошибках кадров РРР. На хорошей линии вы можете и не заметить, что коррекция выключена, но на плохой — модем может просто повесить трубку. Отключите программное управление потоком (Хоп/Xoff), поскольку оно подразумевает отправку специальных символов в потоке данных, управляющих игредачей. Из-за этого передача может останавливаться безо всяких видимых причин, когда в потоке двоичных данных появляется символ, управляющий по- ижом. Включите управление потоком RTS/CTS (аппаратное), если ваш про- иамдер его поддерживает. Оно работает быстрее и не создает подобных неоднозначных ситуаций. Качество линии Иногда можно определить, есть ли у вас проблемы с качеством линии, послушан «тишину» в трубке. Если эта «тишина» никак не может быть названа тако- иой, можете считать, что у вас проблемы. Можно попробовать пожаловаться на н»лефонном узле, но эффект от этого совершенно не гарантирован. Локальные и'лефонные компании пока что являются монополистами. Проблема может быть вызвана и состоянием провода в вашем доме, за замену которого платить придется вам. Часто качество связи можно улучшить, повесив трубку и перезвонив, то есть выполнив своего рода «перезагрузку» телефона. Устанавливая соединение с помощью модема на 28,8 кбит/с, вы можете уви- дгть сообщение CONNECT 14400. Это тоже может быть связано с шумами в линии. Скорость передачи данных меняется, когда модем адаптируется к шумам.
Программа управления модемом должна позволять получать сведения о реальной пропускной способности и количестве ошибок контрольных сумм (CRC errors). Если ошибок много значит, линия зашумлена. Если скорость передачи данных меньше той, на которой вы обычно работаете, это может означать, что модем снизил ее, чтобы скомпенсировать шум, но может быть и так, что вы просто подключились к более медленному модему. Внешние модемы подключаются к компьютеру по кабелю RS-232. Кабели модемов бывают разные. Внутренняя емкость делает некоторые кабели менее пригодными для работы с высокоскоростными модемами. Если ваш модем способен работать на скоростях от 14 000 бит/с и выше, то вам нужен высокоскоростной кабель; в противном случае вы будете страдать от ошибок и повторных передач. Внутренние модемы быстрее Внутренний модем может порадовать вас некоторыми преимуществами по сравнению с внешним, особенно если вам не лень открывать корпус компьютера, чтобы установить его. Такой модем не использует кабель RS-232, поэтому вы не можете ошибиться в выборе этого кабеля. У модема есть свой собственный чип UART — либо обеспечивается его эмуляция, так что вам не нужно беспокоиться об устаревших контроллерах на материнской плате. Наконец, внутренние модемы подключаются непосредственно к шине, поэтому время ожидания при пере даче битов между модемом и компьютером оказывается меньше. Существуют модемы, подключаемые к параллельному порту (тому же, что и принтер). Для работы с ними необходима установка специального драйвера, но они также обладают меньшим временем ожидания по сравнению с внешним модемом, подключаемым к последовательному порту. Переполнение буферов UART Чип UART, управляющий последовательным портом вашего компьютера, содержит встроенный буфер, работающий по принципу очереди (FIFO). Этот буфер должен быть освобожден прежде, чем UART сможет принять новую порцию данных. Если ваш компьютер не будет освобождать буфер UART вовремя, данные будут перезаписываться и теряться, а затем передаваться повторно. Схемы коррекции ошибок модема здесь не помогут — они и так уже выполняют свою работу, передавая данные UART. Причиной переполнения буфера UART является неспособность компьютера считать данные из этого буфера вовремя. Сколько же времени отводится на это? UART объединяет прибывающие биты в байт, после чего помещает это1 байт в буфер FIFO. Пусть ваш модем работает на скорости 28 800 бит/с. На прием одного байта уходит, таким образом, 1 с / 28 800 бит х 8 бит = 0,28 мс Это кажется весьма малым промежутком времени, но вспомните, что шина с часто той 33 МГц может за это время выполнить 33 х 106 х 0,28 х 10~'л = 9240 циклон считывания, а на перемещение байта из буфера в шину нужен всего лишь один цикл. Если буфер был пуст, то у компьютера будет в восемь раз больше времс-
ни B,2 мс) на то, чтобы скачать из этого буфера хотя бы один байт, пока он не переполнился. Поэтому у слабозагруженного компьютера не должно возникать проблем со считыванием данных из буфера UART. Основным источником переполнений буфера UART является поступление запросов на прерывание от плохо написанного драйвера диска или видеоадаптера, который полностью захватывает ресурсы процессора. Самое главное — отличать шумы в линии от переполнений буфера, вызванных вашими же собственными ошибками. Если проблема в драйвере, установите новый. К счастью, сам UART узнает о переполнении буфера, поскольку может обнаруживать момент считывания данных. В случае переполнения в регистре состояния UART устанавливается соответствующий бит, который, в свою очередь, может быть считан библиотекой Winsock или аналогичной ей. Сетевая библиотека должна каким- то образом уведомить вас о возникновении переполнений буфера. Если вы видите сообщение об ошибке РРР, но не видите сообщений о переполнениях, то причина, скорее всего, в шуме на линии. Если же ошибка РРР возникает одновременно с переполнением, источником проблем наверняка является плохой драйвер устройства или даже код сетевой библиотеки, а это может быть исправлено лишь переустановкой драйвера или операционной системы. Команды AT и время набора номера Если вы купили Hayes-совместимый модем, попробуйте поставить значение регистра S11 ниже исходных 70 мс. Часто вполне достаточно 35 мс, что вдвое сократит время набора номера. Для того чтобы изменить значение регистра, выполните команду ATS11=35 в каком-либо терминале. Кроме того, вы можете снизить время ожидания сигнала в линии с 2 до 1 с. Для этого используется команда ATS6=1. Впрочем, я не даю никаких гарантий, что это сработает именно с вашим модемом и с вашей телефонной линией. Объединение каналов Устранить внутренние задержки модемов нельзя, но можно повысить пропускную способность, используя несколько аналоговых линий параллельно. Это называется объединением каналов и требует поддержки одинакового протокола обеими сторонами. Фирма Diamond Multimedia (http://www.diamondmm.com/) продает программу Shotgun, объединяющую два модема на 56 кбит/с для получения пропускной способности в 112 кбит/с. Программа WebRamp M3t фирмы Ramp Networks позволяет мультиплексировать три модема. Разумеется, вам понадобится три телефонных линии, но такая конфигурация все равно может окапаться дешевле и надежнее, чем ISDN. ISDN Универсальная цифровая сеть (Integrated Service Digital Network — ISDN) обеспечивает полностью цифровое соединение вашего компьютера с коммутатором
телефонного узла, исключающее потерю данных при преобразовании их из аналогового формата в цифровой. Это позволяет достичь порогового значения в 64 кбит/с, определяемого внутренними параметрами телефонных сетей, предназначенных для передачи голоса. Модем для ISDN выглядит и работает приблизительно так же, как и аналоговый модем, но он очень быстро набирает номер и подключается к сети (часто быстрее, чем за 1 с), да и не издает никаких звуков. Вы можете подключить свой веб-сервер к Интернету по ISDN и экономить на подключении, договорившись с провайдером о том, что он сам будет звонить вам и устанавливать соединение с вашим веб-сервером, когда пользователи будут обращаться к веб-страницам по вашему IP-адресу. Пользователи будут при этом страдать от дополнительных задержек, да и настроить такую конфигурацию будет непросто. ISDN иногда поставляется как два канала по 64 кбит/с, которые могут быть объединены в один канал на 128 кбит/с. Никаких потерь на начальные и конечные биты в ISDN нет, поскольку соединение является синхронным, поэтому реальная пропускная способность может составлять 16 000 байт в секунду. Некоторые телефонные компании предоставляют каналы с пропускной способностью 56 кбит/с, потому что один из восьми битов используется для коррекции ошибок и синхронизации. Прямое соединение из дома к локальной сети вашего офиса по ISDN обеспечивает пропускную способность, достаточную для того, чтобы вы чувствовали себя гораздо лучше, чем с любым аналоговым модемом. Видеоконференции, к примеру, гораздо приятнее проводить по ISDN, чем по аналоговому модему. Если вы можете подключиться по ISDN к тому же провайдеру, что и ваш работодатель, а компания предоставляет доступ через Интернет к своей локальной сети (пусть даже с использованием пароля), вы можете получить довольно высокую пропускную способность и хорошее время ожидания, поскольку пакеты не будут выходить из внутренней сети провайдера. Для этого придется немного поэкспериментировать. Выяснить провайдера своей организации можно с помощью traceroute. Номер телефона этого провайдера можно узнать на его веб-странице. Существенным недостатком ISDN является ее пока не повсеместная распространенность и недостаточная поддержка. Даже если ваша телефонная компания предлагает данную услугу, ее представители могут ничего не знать об этом. Именно с такой ситуацией мне пришлось столкнуться самому. Я позвонил в одну фирму и спросил, есть ли у них служба ISDN. Там никогда не слышали об ISDN и попросили меня повторить по буквам. Х-м-м... Я повторил. Затем меня спросили, что означает эта аббревиатура. Я ответил: «I Still Don't kNovv» (я все еще не знаю). Представителя фирмы это удовлетворило, и он попросил меня подождать некоторое время, пока он найдет кого-нибудь, кто слышал об этой службе. Вскоре мне перезвонили и сообщили, что компания действительно предоставляет услуги ISDN. Установка может быть очень сложной, поскольку лишь отдельные виды модемов ISDN способны работать с конкретными коммутаторами, установленными в офисах телефонных компаний. Более того, даже когда вы выясните тип коммутатора вашей компании (например, 5ESS) и найдете модем, который дол-
жен быть с ним совместим, вам придется потратить еще много времени на настройку параметров этого модема. Что еще хуже, телефонной компании тоже придется настраивать свой коммутатор, и для этого потребуются услуги специалиста. После того как все настройки были благополучно завершены, линия ISDN начала работать прекрасно, но я не рекомендовал бы использовать ISDN тем, у кого есть другие способы подключаться к Интернету по высокоскоростной линии. Кабельные модемы Высокоскоростной доступ в Интернет по тому же коаксиальному кабелю, по которому вы подключены к кабельному телевидению, представляет собой хорошую альтернативу ISDN. Установка, как правило, чрезвычайно проста: поставщик кабельного телевидения обычно продает вам кабельный модем, и он же его и устанавливает. Модем представляет собой коробочку, у которой с одной стороны имеется разъем для коаксиального кабеля, а с другой — разъем Ethernet. У него нет никаких настроек. Большинство модемов построены на одном и том же чипсете Rockwell, поэтому, купив один, вы сможете использовать его и после переезда на новое место жительства. Вам останется только настроить свой компьютер на использование IP-адреса, предоставленного вам провайдером, но jto, вообще говоря, приходится делать независимо от способа подключения. Скорость входящего потока данных обычно превышает 384 кбит/с, что звучит очень неплохо и особенно приятно при работе с близко расположенными серверами, когда данным не приходится проходить через множество маршрутизаторов. Скорость вашего соединения будет превышать среднюю скорость Интернета. Вам все равно придется страдать от «узких мест», но теперь эти «узкие места» будут где угодно, только не на вашей линии связи с провайдером. Скорость отправки данных будет порядка 100 кбит/с, что вполне достаточно для небольшого веб-сервера. Вам не придется платить за время работы в Интернете, а на модеме даже не будет выключателя. Вы всегда будете подключены к сети. Недостаток в том, что вам придется делить свое соединение с соседями. Многочисленные пользователи в одном районе могут мешать друг другу; притом ничто не сможет помешать вашим соседям подслушивать ваши IP-пакеты, если они этого захотят, поскольку, по сути дела, вы все будете находиться в одной локальной сети. Наконец, на момент написания этой книги кабельные модемы устанавливаются далеко не повсеместно, хотя службы типа ©Ноте (http://www.home.com/) быстро расширяют сферы влияния. Стоимость услуги пока еще непостоянна. В разных местах за одно и то же можно заплатить от 30 до 100 долларов США в месяц. xDSL Не физическими характеристиками медных телефонных проводов, идущих к вашему дому, ограничиваются скорости аналоговых модемов. Ограничивающим «[шктором является преобразование в 64-килобитиый цифровой поток на ком-
мутаторе телефонной компании. Что если бы вам удалось обойти преобразование на коммутаторе и подключиться непосредственно к цифровой линии на АТС? ISDN подразумевает именно это, но подключение осуществляется к линии на 64 кбит/с, что не слишком ускоряет работу по сравнению с модемами на 56 кбит/с. Прямое подключение через цифровую линию к интернету непосредственно по медным проводам, идущим от вашего дома, называется асимметричной цифровой абонентской линией (Asymmetric Digital Subscriber Line - ADSL), а производные от этой технологии получили общее название xDSL. Скорости подключений xDSL варьируются в широких пределах, а типичные значения составляют 1,5 Мбит/с входящего потока и 128 кбит/с исходящего. Это больше, чем могут выдать кабельные модемы. Технология xDSL сейчас распространена довольно широко. Вам может потребоваться две учетных записи, чтобы работать с линией DSL. Одна учетная запись должна быть получена у телефонной станции и еще одна — у провайдера, имеющего соглашение с этой телефонной станцией о размещении оборудования xDSL на ее узле. Определить реальную полосу пропускания вашей линии DSL вы можете с помощью специальных тестов, находящихся по адресу: http://www.dslreports. com/stest. Еще более скоростные линии Приведу короткий обзор высокоскоростных линий, используемых для подключения веб-серверов. Для каждой из этих линий нужны свой тип маршрутизато ра или коммутатора и свое концевое обрудование. Для веб-клиента это уже чересчур. 56К, T1 и ТЗ Прямое цифровое соединение между своей квартирой (или организацией) и про вайдером можно получить, воспользовавшись специальными услугами, предостан ляемыми местной телефонной компанией. Эти прямые цифровые линии обыч но имеют стандартную пропускную способность: 56 кбит/с, Т1 A,544 Мбит/с) и ТЗ D5 Мбит/с). Вы можете купить не целую линию Т1 или ТЗ, а только часть полосы пропускания, сохраняя за собой возможность повысить качество соеди нения в будущем. Выделенная цифровая линия на 56 кбит/с может показаться чем-то никому не нужным, раз есть аналоговые модемы на 56 кбит/с, но учтите, что выделен ная линия надежнее, меньше подвержена шумам и работает в синхронном режи ме, то есть с меньшими побочными затратами. Т1и ТЗ — синхронные последовательные линии, поэтому дополнительные затраты на начальные и конечные биты для этих линий отсутствуют. Реальная пропускная способность может быть очень высокой — порядка 90% номиналь ной мощности линии, а время ожидания для таких линий очень мало. Недоста ток у них один: эти линии очень дороги. Подключение по линии Т1 к провайде
ру, расположенному в том же городе, может стоить 1000 долларов США в месяц. Линии, проложенные на более далекое расстояние, стоят еще дороже. Frame Relay Frame Relay (ретрансляция кадров) — это сетевой протокол с коммутацией пакетов, предназначенный для больших сетей. Он позволяет устанавливать виртуальные соединения типа «точка—точка», которые называются постоянными виртуальными каналами (permanent virtual circuit — PVC). Сеть Frame Relay экономически гораздо более эффективна при связи на больших расстояниях, чем линия Т1, поскольку при подключении по этому протоколу кабели и оборудование используются большим количеством потребителей совместно, хотя они видят только свои собственные пакеты. Иными словами, у потребителей имеются свои личные виртуальные каналы. Протокол Frame Relay является ненадежным, то есть он не дает гарантии, что пакеты прибудут вовремя или что они вообще куда-то прибудут. Повторная передача утерянных пакетов должна обеспечиваться верхними уровнями программного обеспечения. Если у провайдеров все хорошо настроено, пользователи могут не беспокоиться на этот счет. Протокол Frame Relay обладает встроенной схемой обработки приоритетов для пакетов с заданной скоростью передачи (Committed Information Rate — CIR). Соотношение «цена—качество» для сетей такого рода является достаточно хорошим, но во многом это связано с низкой загруженностью линий. Когда линии заполняются пакетами «под завязку», их производительность падает. Выбирать и оценивать качество Frame Relay следует по количеству утерянных пакетов вне зависимости от CIR, поскольку большое количество повторных передач сделает использование CIR бесполезным. ATM Асинхронным режимом передачи (Asynchronous Transfer Mode — ATM) называется еще один протокол коммутации пакетов, отличающийся от Frame Relay наличием гарантированного качества обслуживания (QoS). Вообще говоря, ATM обеспечивает коммутацию не собственно пакетов, а, скорее, ячеек фиксированной длины E3 байта). Маршрутизирующему оборудованию ATM не приходится вычислять длину ячейки, и эти ячейки имеют весьма небольшие размеры. Оба эти фактора весьма положительно сказываются на времени ожидания ATM. Голос и видеоизображение могут передаваться по линиям ATM без опасности утери или задержки данных на непредсказуемые промежутки времени. ATM часто реализуется на базе медных проводов с пропускной способностью 16 Мбит/с, а также на базе оптоволокна. Оптическое волокно также обладает характерными скоростями. Например, Optical Carrier 3 (ОСЗ) передает данные со скоростью 155 Мбит/с, а ОС12 — 622 Мбит/с. Эти линии стоят дорого, но вы можете купить нужную вам виртуальную линию с конкретной пропускной способностью, а впоследствии быстро увеличить ее пропускную способность за дополнительную плату, если такая необходимость возникнет. Вам
не придется ждать, пока будут проложены новые провода. Прокладка линии Т1 часто занимает несколько недель, а увеличение пропускной способности на ту же величину при использовании провайдера ATM может быть выполнено буквально через несколько минут после вашего заказа. Спутники Спутники связи предоставляют множество различных услуг. Для запроса страниц веб-клиенты могут использовать обычное подключение по модему, а ответы на эти запросы отправляются клиентам через спутник со скоростью 1 Мбит/с и выше. Симметричные линии стоят гораздо дороже, но это может быть дешевле, чем связываться с государственной телефонной службой-монополистом в бедном государстве. Связь через спутник часто обладает довольно большим временем ожидания, хотя бы из-за больших расстояний, но спутники с низкими орбитами могут обеспечивать время ожидания, в десять раз лучшее, нежели находящиеся на геостационарных орбитах. Недостатком низколетящих спутников является их обыкновение выходить из зоны приема, что вызывает необходимость устанавливать какие-то средства для переключения на другие спутники той же группы. Геостационарные спутники висят над одной и той же точкой Земли. Подробнее о симметричных спутниковых системах связи читайте по адресу: http://www. intelsatint/. Интрасети Интрасетью называется корпоративная сеть, использующая протокол TCP/IP. Архитекторы интрасетей имеют гораздо больше возможностей выбора сетевого оборудования и клиентского программного обеспечения, чем можно иметь п Интернете (где вы можете выбирать только своего собственного провайдера). Это позволяет гарантировать более высокое качество обслуживания и добиться более эффективного использования пропускной способности, чтобы приложения, для которых важна быстрота связи (например, потоковое видео и аудио), работали нормально. Сегментирование Интрасеть не может расширяться случайным образом без того, чтобы какие-нибудь ее части оказались перегружены. В какой-то момент вам придется заняться внесением в вашу сеть иерархической структуры. Общее правило таково: компьютеры должны чаще «разговаривать» с ближайшими соседями, лучше всего — из одной физической подсети, где связь будет самой быстрой. Выбирая размещение веб-сервера в своей интрасети, подумайте, нужно ли будет к нему обращаться из внешнего мира или только изнутри вашей организации и каким пользователям (внутренним или внешним) следует отдать прио-
ритет. Если у вас есть два отдельных варианта веб-содержимого для внешних и внутренних пользователей, есть смысл установить два веб-сервера, пусть даже .но будут два виртуальных сервера на одном компьютере. Веб-серверы, рассчитанные на обслуживание пользователей из Интернета, должны обеспечивать для них лучшее качество связи, чем для внутренних пользователей, но если внутренние пользователи будут использовать то же подключение к Интернету для отправки своей электронной почты и сообщений Usenet, то пользователи из Интернета могут начать жаловаться на недостаток пропускной способности вашего веб-сервера. Двустороннее соединение с провайдером может несколько смягчить эту проблему, так как внешние пользователи будут создавать в основном исходящий трафик. Если же вы ожидаете, что у вас будет много внутренних пользователей Интернета, или собираетесь установить на своем веб-сервере какую-то важную для всего сообщества Интернета службу, для веб-сервера следует создать отдельное соединение, не загружая его никаким другим трафиком, и пусть оно даже будет обладать меньшей пропускной способностью, чем ваше основное соединение с Интернетом. Установите свой вебсервер за брандмауэром и постарайтесь минимизировать трафик (например, обращения к базам данных) через этот брандмауэр. Два шлюза в Интернет часто работают лучше, чем один с вдвое большей пропускной способностью. Если вам приходится делить соединение важного веб-сервера с другим трафиком или если внешние пользователи вашего веб-сервера загружают внутреннюю локальную сеть, проблему помогут решить четыре слова на букву П: политика, приоритеты, прокси-серверы и перегородки (сегментирование) (policy, prioritization, proxies, partitioning). О Указывайте пользователям, какой тип трафика (HTTP, FTP, SMTP) считается приемлемым, с помощью политик. О С помощью одного из перечисленных ниже средств для управления трафиком задавайте приоритет пакетов, чтобы самые важные доставлялись в первую очередь. О Установите прокси-сервер для вашего подключения к Интернету. О Поместите внутренний веб-сервер в сегменте сети, не загруженном широковещательным трафиком и трафиком NFS. Оборудование для сегментирования Оборудование, сегментирующее вашу локальную сеть и обеспечивающее централизованное подключение к Интернету, увеличивает время ожидания для исех пакетов, поэтому используйте его осмотрительно. Ниже приведена короткая справка на эту тему. Повторители Повторители (repeaters) увеличивают допустимую длину кабеля, не разделяя при этом сеть на сегменты. Они повторяют поступающий на вход сигнал, выделяя и усиливая отдельные биты.
Мосты Мосты (bridges) хранят в своей памяти таблицу локальных МАС-адресов (таких, как адреса сетевых карт Ethernet) и пересылают пакеты, не адресованные ни одному из локальных компьютеров, дальше, во внешнюю сеть. Это обеспечивает удобство сегментирования Ethernet, но мосты не подходят для сетей большого масштаба, потому что для динамического обновления конфигурации они используют широковещательную передачу. Крупная сеть была бы просто переполнена пакетами, передающими информацию о конфигурации от одного моста к другому. Концентраторы Концентраторы (hubs) также являются повторителями, но они передают повторенный сигнал нескольким компьютерам. Получающаяся структура сети напоминает втулку колеса со спицами. Сетевая карта, подключенная кабелем к концентратору, будет получать весь сетевой трафик. Это может представлять угрозу безопасности, поскольку любой узел, подключенный к концентратору, может перехватывать трафик других узлов. Внутреннее устройство концентратором обеспечивает лишь одностороннюю передачу: они не могут одновременно принимать и передавать информацию. Коммутаторы Коммутаторы (switches) работают аналогично концентраторам, но устанавливают соединения только между парами компьютеров. Соединения могут одновременно устанавливаться между множеством пар компьютеров, что обеспечиваем гораздо большую пропускную способность. Коммутаторы повышают безопасность системы, поскольку компьютеры не могут перехватывать чужие разговоры. Наконец, коммутаторы сложнее, чем концентраторы, и часто работают пол управлением операционной системы IOS фирмы Cisco, тогда как концентраторы обычно не требуют операционных систем и не выдают никакой статистики. Коммутаторы, допускающие удаленное управление и сбор статистики, называются «управляемыми» (manageable switches). Коммутаторы могут быть двусторонними, обеспечивая прием и передачу данных одновременно. Маршрутизаторы Маршрутизаторы (routers) позволяют сегментировать сети по IP-адресу подсети, то есть на следующем уровне протоколов. Вы можете установить в компьютер несколько сетевых адаптеров и сделать из него маршрутизатор, установим соответствующее программное обеспечение, но аппаратные маршрутизаторы обычно обладают более высокой пропускной способностью и лучшим временем ожидания. Мы расскажем о маршрутизаторах подробнее далее в тексте главы, но подробный анализ производительности всех сетевых устройств выходит за рамки этой книги.
Одним из самых важных требований, предъявляемых к сетевым устройствам, является соответствие размеров максимального передаваемого блока (Maximum Transmission Unit — MTU) между протоколами. Например, если вы обеспечиваете маршрутизацию пакетов из Ethernet в Token ring, FDDI или ATM, передача макетов будет производиться более эффективно, если их не придется фрагмен- тировать, то есть если максимальные размеры блоков будут совпадать. У протокола FDDI MTU по умолчанию больше, чем в Ethernet D500 байт против 1500), поэтому пакеты из сети FDDI могут фрагментироваться при попадании и Ethernet. На любое преобразование протоколов приходится затрачивать те или иные ресурсы, поэтому следует избегать лишних преобразований везде, где ;>то возможно. Подробнее об MTU читайте в главе 15 (раздел «Протокол Интернета»). Ethernet Ethernet является на данный момент наиболее распространенным типом локальных сетей. Чаще всего встречается lOBaseT Ethernet, работающий на скорости 10 Мбит/с, но 100-мегебитный Ethernet довольно быстро захватывает рынок. Стандартная команда Unix ifconfig -а обозначает 10 Мбит/с Ethernet как 1е0, а 100 Мбит/с Ethernet — как hmeO или ЬеО. В Windows NT для получения тех же сведений можно использовать команду ipconfig. Карты Ethernet сейчас выпускаются массово и стоят очень дешево, а сеть Ethernet легко настроить, но у нее есть один серьезный недостаток. Поскольку носитель Ethernet является общим для нескольких компьютеров, они могут одновременно пытаться передавать данные, из-за чего возникают так называемые коллизии. Повторная передача, согласно алгоритмам Ethernet, осуществляется после неопределенной задержки, причем при нескольких коллизиях эта задержка экспоненциально увеличивается, оставаясь, впрочем, при этом случайной. При небольшой загрузке эта схема работает хорошо, но при возрастании загрузки линии свыше 70% пропускная способность резко падает (рис. 14.2), поэтому можно считать, что реальная пропускная способность линии на 10 Мбит/с составляет всего лишь 7 Мбит/с. Коллизии Ethernet в Linux, Solaris и некоторых других версиях Unix можно отслеживать с помощью команды netstat -i. Минимальная длина пакета (или, точнее, длина кадра) в сети Ethernet составляет 72 байта, поэтому при сеансах интерактивной работы возникают огромные накладные расходы: ведь отдельные символы, вводимые пользователем, пе- |>есылаются по одному в пакете, что составляет 71 байт накладных расходов на каждый байт полезных данных. Такой проблемы не возникает при передаче данных для веб, поскольку возвращаемые данные передаются относительно крупными порциями, которые легко перекрывают установленный по умолчанию размер кадра в 1500 байт. С другой стороны, кадры Ethernet всегда имеют длину 1500 байт. Любые данные, отправляемые веб-сервером в Ethernet, будут упакованы в 1500-байто-
вый кадр. Если вы получаете данные от пользователей Ethernet, они также будут упаковываться в такие же кадры. Этим Ethernet отличается от протокола РРР, предназначенного для связи с помощью модема, в котором нижнее ограничение на размер кадра составляет 1 байт. Рис. 14.2. Время ожидания и пропускная способность Ethernet Фиксированный размер кадра Ethernet позволяет с легкостью определить и вычислить процент использования полосы пропускания вашей сети. Если не учитывать промежуток между отдельными кадрами, максимальное количество кадров в секунду для сети на 10 Мбит/с может составлять 833. Для Ethernet на 100 Мбит/с это составляет 8,333 пакета в секунду. Обратите внимание, что Ethernet на 10 Мбит/с обычно работает в одностороннем режиме, то есть данные в любой момент времени могут передаваться только в одном направлении. Карты на 100 Мбит/с могут автоматически определять скорость карты на другом конце соединения и переходить на любой режим работы — от одностороннего на 10 Мбит/с до двустороннего на 100 Мбит/с. Типичная ситуация: одна сторона соединения по Ethernet настроена на односторонний режим, а другая — на двусторонний. В результате получаем низкую производительность, хотя соединение работает. Большая часть карт Ethernet на 100 Мбит/с по умолчанию работает в одностороннем режиме. Чтобы включить двусторонний режим Ethernet в /etc/system в Solaris, нужно ввести в этот файл приведенные ниже строки, после чего перезапустить систему: set hme:hme_adv_100fdx_cap«l set hme:hme_adv_100hdx_cap»0
Перехват пакетов Карта Ethernet по умолчанию игнорирует пакеты, если адрес их получателя не совпадает с ее глобально уникальным МАС-адресом. Однако карта может работать в смешанном режиме (promiscuous mode), в котором никакие пакеты не сбрасываются. Система Solaris поставляется с программой snoop, которая дает возможность легко перевести карту Ethernet в смешанный режим и развернуть пакеты, упакованные в несколько протоколов, до самого верхнего уровня. Для работы со snoop необходимо являться привилегированным пользователем. Эта программа позволяет увидеть своими глазами, что протокол Ethernet передает пакет протокола IP, в котором содержится сегмент TCP, и даже может показать вам содержимое полезной части пакета. Вот пример перехваченного запроса браузера, направляемого на прокси-сервер: # snoop -v -х О ETHER: — Ether Header — ETHER: ETHER: Packet 4 arrived at 11:33:12.22 ETHER: Packet size - 337 bytes ETHER: Destination - 0:60:5c:f3:71:57. ETHER: Source - 8:0:20:7b:87:4c. Sun ETHER: Ethertype - 0800 (IP) ETHER: IP: — IP Header — IP: IP: Version « 4 IP: Header length - 20 bytes IP: Type of service = 0x00 IP: xxx - 0 (precedence) IP: ...0 - normal delay IP: .... 0... - normal throughput IP: 0.. = normal reliability IP: Total length - 323 bytes IP: Identification * 27865 IP: Flags - 0x4 IP: .1 - do not fragment IP: ..0 «last fragment IP: Fragment offset - 0 bytes IP: Time to live - 255 seconds/hops IP: Protocol - 6 (TCP) IP: Header checksum - 450d IP: Source address - 10.15.6.126. guest IP: Destination address - 10.15.19.32. webcache.patrick.net IP: No options IP: TCP: — TCP Header — TCP: TCP: Source port - 38685 TCP: Destination port - 8080 (HTTP (proxy)) TCP: Sequence number - 1844000715 TCP: Acknowledgement number - 1830043605 TCP: Data offset - 20 bytes
TCP: Flags = 0x18 TCP: ..0 = No urgent pointer TCP: ... 1 = Acknowledgement TCP: .... 1... = Push TCP: 0.. = No reset TCP: 0. = No Syn TCP: 0 = No Fin TCP: Window « 8760 TCP: Checksum = 0xe027 TCP: Urgent pointer = 0 TCP: No options TCP: HTTP: — Hypertext Transfer Protocol — HTTP: HTTP: GET http://patrick.net/ HTTP/1.0 HTTP: Proxy-Connection: Keep-Alive HTTP: User-Agent: Mozilla/4.02 [en] (Xll: U: SunOS 5.6 sun4u) HTTP: Pragma: no-cache HTTP: Host: patrick.net HTTP: Accept: image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. */* HTTP: Accept-Language: en HTTP: Accept-Charset: iso-8859-l.*.utf-8 HTTP: 0: 0060 5cf3 7157 0800 207b 874c 0800 4500 /\.qW.. {.L..E. 16: 0143 6cd9 4000 ff06 450d 8199 067e 8196 .CI.@...E....-.. 32: bf20 971d If90 6de9 37cb 6dl4 3fd5 5018 ra.7.m.?.P. 48: 2238 e027 0000 4745 5420 6874 7470 3a2f "8.'..GET http:/ 64: 2f70 6174 7269 636b 2e6e 6574 2f20 4854 /patrick.net/ HT 80: 5450 2f31 2e30 OdOa 5072 6f78 792d 436f TP/1.0..Proxy-Co 96: 6e6e 6563 7469 6f6e 3a20 4b65 6570 2d41 nnection: Keep-A 112: 6c69 7665 OdOa 5573 6572 2d41 6765 6e74 live..User-Agent 128: 3a20 4d6f 7a69 6c6c 612f 342e 3032 205b : Mozilla/4.02 [ 144: 656e 5d20 2858 3131 3b20 553b 2053 756e en] (Xll: U: Sun 160: 4f53 2035 2e36 2073 756e 3475 290d 0a50 OS 5.6 sun4u)..P 176: 7261 676d 613a 206e 6f2d 6361 6368 650d ragma: no-cache. 192: 0a48 6f73 743a 2070 6174 7269 636b 2e6e .Host: patnck.n 208: 6574 OdOa 4163 6365 7074 3a20 696d 6167 et..Accept: imag 224: 652f 6769 662c 2069 6d61 6765 2f78 2d78 e/gif. image/x-x 240: 6269 746d 6170 2c20 696d 6167 652f 6a70 bitmap, image/jp 256: 6567 2c20 696d 6167 652f 706a 7065 672c eg. image/pjpeg. 272: 202a 2f2a OdOa 4163 6365 7074 2d4c 616e */*..Accept-Lan 288: 6775 6167 653a 2065 6e0d 0a41 6363 6570 guage: en..Accep 304: 742d 4368 6172 7365 743a 2069 736f 2d38 t-Charset: iso-8 320: 3835 392d 312c 2a2c 7574 662d 380d OaOd 859-1.*.utf-8... 336: 0a Это достаточно интересно и позволяет обнаружить в локальной сети совершенно неожиданные данные, но вы можете и направить вывод этой программы на устройство /dev/audio (сначала приглушите звук), чтобы постоянно иметь представление о загруженности локальной сети. Это можно сделать с помощью ключа snoop -а, а можно и просто перенаправить вывод snoop на устройство /dev/audio с помощью средств интерпретатора. Забавно бывает оставить про-
грамму работать в таком виде и слышать разные звуки, соответствующие передаваемым данным. Программу snoop хорошо использовать для просмотра, захвата или прослушивания идущих по сети пакетов, но она может просто завалить вас данными. Эта утилита неспособна собирать статистику или характеризовать тип вашего графика каким-либо образом (например, «слишком много повторных передач»). Для подобного анализа необходимо использовать подслушивающее оборудование (торговой марки Sniffer фирмы Network General) или один из множества пакетов для анализа локальных сетей — например, программу traffic фирмы Sun. Команда netstat -s в операционной системе Solaris выдает обобщенные данные. Особое внимание следует уделять отношению количества повторно переданных байтов к общему количеству переданных байтов. Средства, работающие по протоколу SNMP, также способны характеризовать сетевой трафик. Не пытайтесь подслушивать с машины, которая, в свою очередь, подслуши- нается кем-то другим, иначе вы затопите друг друга данными, поскольку системы начнут работать рекурсивно, перехватывая чужие сообщения о перехвате собственных данных о перехвате чужих сообщений... Бесплатная программа tcpdump способна на многое из того, чем занимается программа snoop, но она не распаковывает пакеты. Буферы сетевых адаптеров Как и контроллеры последовательных портов, сетевые адаптеры Ethernet (Network Interface Card — NIC) обладают буферами конечного размера. Несомненно, у карт Ethernet буферы намного объемнее, поскольку они накапливают данные с гораздо большей скоростью: у 8-разрядных карт буферы обычно по К Кбайт, а у 16-разрядных — по 16 Кбайт. Ethernet является последовательным интерфейсом, поэтому биты помещаются в буфер один за другим, а не по нескольку одновременно. Разрядность карты определяет, сколько битов эта карта может переместить из буфера в системную шину за один цикл последней. Данный параметр менее важен, чем размер буфера, поскольку шина может опустошать буфер сетевой карты очень быстро. На скорости 10 Мбит/с Ethernet может заполнить буфер объемом 8 Кбайт за A с / 10x10е бит) х 8 х 1024 х 8 бит/байт = 6,6 мс. Это чуть больше, чем 2,2 мс, ia которые, по нашим расчетам, заполняется 8-байтовый буфер модемом на 28,8 кбит/с. Помните, что по умолчанию пакеты Ethernet имеют размер 1500 байт, поэтому в буфер объемом 8 Кбайт может поместиться только пять полных пакетов. Ваша операционная система может зарезервировать часть буфера сетевого .адаптера для исходящих данных; тогда реальный объем приемного буфера, ра- ■умеется, станет меньше. Как и при работе с модемом, проблемы возникают из- ш того, что компьютер может не успеть считать данные из буфера карты до «ого, как та получит новые, и в итоге потребуется повторная передача. Чтобы устранить проблемы подобного рода, нужно аккуратно подбирать драйверы устройств, найти компьютер побыстрее, установить на него хорошую реализацию стека TCP/IP или просто сетевую карту с большим объемом буферов.
Подробнее о размерах буферов сетевых карт можно прочесть по адресу: http://www.spade.com/. Быстрый Ethernet Быстрый Ethernet основан на той же технологии, что и «просто» Ethernet, только он в 10 раз быстрее, то есть данные в подобной сети передаются со скоростью 100 Мбит/с. Одно это уже уменьшает количество коллизий и улучшает производительность на больших нагрузках. Гигабитный Ethernet (Gigabit Ethernet), работающий на скорости 1 Гбит/с, то есть в 10 раз быстрее, чем быстрый Ethernet, появился не так давно (см. http://www.yago.com/). Альтернативный вариант — сеть FDDI — обладает приблизительно той же производительностью, что и быстрый Ethernet. Веб-сервер, вызывающий, согласно статистике, более 20% коллизий Ethernet, должен быть подключен к маршрутизатору, соединенному с Интернетом, с помощью быстрого Ethernet. Недостатком быстрого и гигабитного Ethernet является их стоимость. Обновлять придется не только сетевые карты, но и концентраторы. Коммутируемый Ethernet Коммутатор Ethernet работает во многом подобно концентратору, но только лучше (и потому он дороже). В коммутируемой сети Ethernet все пакеты хранятся в буфере коммутатора до тех пор, пока ему не удастся установить соединение с адресатом. Время ожидания обычно очень мало, а выигрыш из-за отсутствия коллизий по сравнению с этим временем велик. Адресат может попытаться отправить пакет коммутатору в тот же момент, когда коммутатор будет высылать пакет адресату, — тогда, конечно же, произойдет коллизия, но, по крайней мере, есть гарантия, что ни у одного адресата не будет коллизий входящих пакетов. По этой причине коммутируемый Ethernet дает гораздо большую производительность, чем обычный сегментированный Ethernet, в котором используются концентраторы. Дополнительным источником повышения производительности является то, что компьютеры из одного сегмента могут одновременно обмениваться друг с другом данными, что невозможно при использовании концентратора. Пусть накладные расходы на упаковку одного протокола в другой составляют 20%, и пусть с каждой передачей мы отправляем 10 Кбайт. Считая время ожидания коммутатора равным нулю, получим, что для коммутируемого соединения по Ethernet между клиентом и веб-сервером теоретическая пропускная способность составит 0,8 х 1 передача НТТР/10 240 байт х 1 250 000 байт/с = -100 передач HTTP в секунду. Проблема может возникнуть, если несколько клиентов, относящихся к одному коммутатору, будут обращаться к одному и тому же веб-серверу. Если вебсервер будет находиться в том же сегменте, что и клиенты, пытающиеся обратиться к нему, преимущества коммутатора будут сведены на нет. В такой ситуации лучше поместить веб-сервер в 100-мегабитный сегмент (если все клиенты
находятся в сегменте с 10 Мбит/с Ethernet). Многие модели коммутаторов позволяют подключать сегменты с разными скоростями. Коммутация в Ethernet часто называется коммутацией второго уровня (layer 2 switching), поскольку Ethernet находится на втором уровне сетевой модели OSI. Коммутация на третьем уровне — это маршрутизация на уровне IP, где часто используется специальное оборудование для поиска. Подробнее обо всем этом можно прочесть в книге Эндрю Таненбаума «Компьютерные сети». Кабели Ethernet Всегда помните, что электрические провода способны передавать сигналы без существенных потерь лишь на определенное расстояние — из-за распределенной емкости, которая, по сути, связана со скоростью, с которой «кабель заполняется электричеством». Если кабель будет слишком длинным, высокочастотные сигналы окажутся смазанными, и вы потеряете пакеты. Для того чтобы обойти ограничение на длину кабеля, можно использовать повторители. В Ethernet между любыми двумя узлами можно поместить не более четырех повторителей, иначе время передачи будет превышать максимальное время жизни пакета. Неэкранированная витая пара пятой категории (Unshielded Twisted Pair — UTP, Category 5 — Cat 5) отлично работает до скоростей быстрого Ethernet A00BaseT). У кабеля категории 5 на один фут будет больше витков, чем у кабеля категории 3. Производительность витой пары будет несколько лучше, если вы выберете пару, представляющую собой свитые вместе кабели для отправки и приема. Кабель Ethernet может работать как антенна и принимать или отправлять радиосигналы (хотя вовсе для этого не предназначен). Гигабитный Ethernet может и не работать с кабелем пятой категории, поскольку он использует все четыре пары проводов в кабеле, а не две, из-за чего возникает больше наводок. По этой причине в первых спецификациях для гигабитного Ethernet в качестве носителя указывалось оптоволокно. Кроме того, следует опасаться разъемов худшего качества, чем кабели, так как из-за подобного несоответствия могут возникать ошибки. Коаксиальный «толстый» Ethernet сейчас уже морально устарел. Убедитесь, что соединения Ethernet настроены соответствующим образом: например, двустороннее на 100 Мбит/с не должно быть соединено с односторонним на 10 Мбит/с. В случае несоответствия карты все равно могут функционировать, но с пониженным быстродействием. Шум Некорректная установка терминаторов на линиях Ethernet может вызвать отражение сигналов, то есть шум, который понизит пропускную способность. Другими источниками отражений являются узлы и резкие сгибы кабелей. Можно с легкостью «загубить» быстродействие локальной сети, проложив кабель Ethernet над навесным потолком вблизи ламп дневного света, которые создают довольно сильный радйошум. Если у вас есть плейер с радиоприемни-
ком, а поблизости найдется магазин с неоновой рекламой, включите свой приемник и подойдите к магазину — вы услышите громкий шум, создаваемый в эфире неоновыми лампами. Я знал одного администратора, который нечаянно прикрепил кабель Ethernet к антенне офисного радиопередатчика. Когда кто- нибудь пользовался этим передатчиком, производительность Ethernet падала до нуля. По тем же причинам следует прокладывать линии связи вдали от силовых кабелей: если изображение на вашем мониторе оказывается искаженным, когда компьютер стоит в одном углу офиса, но оно не вызывает никаких претензий, стоит только поставить компьютер в другом углу, — это может быть вызвано силовым кабелем, проходящим в стене или в колонне около компьютера. Шум не только портит нормальные пакеты, но и заставляет компьютер принимать данные, когда в сети должна быть тишина. Эти данные, разумеется, все равно сбрасываются сетевой картой. Средства моделирования сетей Программы для моделирования сетей позволяют испытывать различные варианты конфигурации интрасетей. С их помощью вы можете узнать, повлияет ли сколько-нибудь существенным образом предполагаемое размещение веб-сервера на трафик в локальной сети. Приведу список из трех программных продуктов: NETSYS фирмы Cisco (http://www.netsystech.com/), OPNET фирмы МПЗ (http://www.mil3.com/) и Optimal Application Expert фирмы Optimal Networks (http://www.optimal.com/). Интернет Интернет по самой своей природе менее предсказуем, чем хорошо описываемые частные сети, поскольку он создается разнородной группой с разными мотивами, бюджетами и техническими познаниями. Все это не означает, что невозможно оценить пропускную способность и время ожидания Интернета на основании законов физики, информации о поведении его компонентов и, наконец, жизненного опыта. Время ожидания Интернета может быть произвольно большим, но нижняя граница значения этого параметра определяется скоростью света. Минимальное время ожидания при отправке любого сигнала на расстояние 2000 миль составляет A с/186 000 миль) х 2000 миль = 10,8 мс. Поэтому даже в самых идеальных условиях, если у нас есть прямой оптоволоконный канал ATM на расстояние в 2000 миль, время ожидания будет никак не меньше 10,8 мс. Помните, что прежде чем получить ответ, вам нужно будет послать запрос, поэтому время ожидания ответа сервера будет вдвое больше указанной выше величины, даже если сервер обработает запрос мгновенно. Замечательно, что проверка связи с компьютером, находящимся на другом побережье Соединенных Штатов, покажет вам, что Интернет работает на скоростях, довольно близких к теоретическо-
му максимуму. Часто время ожидания пакета составляет в таких условиях 30 мс или около того. Если вы хотите почувствовать на себе величину времени ожидания для своего соединения, попробуйте установить сеанс Telnet с компьютером, находящимся на большом расстоянии. Убедитесь, что сервер Telnet установил сеанс в символьном режиме, а не в строчном. В символьном режиме каждое нажатие на клавишу передается по каналу отдельно, а в строчном вся строка передается целиком при нажатии клиентом клавиши Enter. Строчной режим, разумеется, гораздо приятнее, но при этом вы можете работать только со строками целиком, что лишает вас возможности воспользоваться редакторами типа vi, реагирующими на отдельные нажатия клавиш. Строчной режим более эффективен: минимальное количество избыточных данных в пакете IP составляет 42 байт, поэтому если вы будете работать в символьном режиме, то на каждый байт данных будет отправляться 41 байт служебной информации. Помимо составляющей времени ожидания, определяемой скоростью света, существует другая обязательная составляющая, вносимая маршрутизаторами, которым нужно время на прием данных в буфер до принятия решения об их отправке дальше. Чем меньше маршрутизаторов будет на пути ваших пакетов, тем лучше. Наконец, небольшие пакеты проходят с меньшей задержкой, поскольку они могут быть приняты целиком и переправлены дальше за меньшее время. Это одна из причин, по которой вся базовая сеть США работает в режиме коммутируемого ATM, использующего 53-байтовые ячейки, а не в режиме маршрутизации IP, когда передаются пакеты переменной длины. Если вы знаете, где будет расположено большинство ваших пользователей, вы сможете уменьшить количество маршрутизаторов на линии связи с ними, выбрав провайдера поближе к ним. Одна миллисекунда, сэкономленная на маршрутизаторе, стоит двухсот миль физической удаленности от пользователей. Пакеты переправляются со скоростью, обеспечиваемой самым худшим звеном на линии от сервера к клиентам. Чем меньше у вас будет звеньев, тем меньше шансов получить плохой пакет. Фирма Keynote Systems занимается тем, что измеряет реальную производительность серверов Интернета из разных мест страны. Она публикует весьма примечательные отчеты на своем веб-сайте (http://www.keynote.com/). Представители этой фирмы выяснили, что в среднем в Интернете данные передаются со скоростью 50 000 символов в секунду, или 400 000 бит в секунду по любому TCP-соединению. Помните, что это лишь средняя величина, причем вычисленная с учетом большого количества пользователей с медленными (модемными) соединениями. Перейдя на кабельный модем с пропускной способностью 500 кбит/с, вы обнаружите заметное увеличение производительности Интернета, поскольку сайты, расположенные рядом с вами или обладающие широкополосными линиями связи, будут обеспечивать гораздо большую пропускную способность по сравнению со средней D00 000 бит/с). Города, в которых инфраструктура Интернета развита хуже, обладают в среднем более медленным доступом, что неудивительно. Keynote приводит список таких городов (на ян- иарь 1998 года): Феникс, Даллас, Хьюстон, Канзас, Майами. Провайдеры CompuServe, CWIX и SAVVIS обеспечивают лучшую производительность базо-
вой сети, поскольку они являются слабозагруженными провайдерами национального масштаба. Производительность Интернета возрастает по праздникам, когда большинство людей им не пользуется. Процент утерянных пакетов для Интернета (не из-за некорректно установленного тайм-аута повторной передачи TCP) составляет около 10%. Это вы можете проверить самостоятельно с помощью программы ping, которая выводит статистику количества утерянных пакетов. Некоторые фирмы пытаются отражать состояние Интернета в целом в графической форме. Попробуйте посмотреть сведения такого рода по адресам http://www.mids.org/weather/ и http://www.internetweather.com/. На этих сайтах приводятся данные о времени ожидания для разных провайдеров. Статистика о качестве маршрутизации и времени ожидания есть и на сайте http://www.merit.edu/ip- та. Комитет IETF в данный момент работает над стандартами, которые позволяли бы измерять производительность Интернета (http://io.advanced.org/IPPM/ — хотя, как это ни смешно, сайт редко бывает доступен). Анализ статистики по производительности Интернета можно найти по адресу: http://www.merit.edu/ ipma/analysis/. В обход Интернета На примере Интернета хорошо видны все прелести и недостатки сетей с коммутацией пакетов. С одной стороны, Интернет гораздо дешевле телефонного звонка, где коммутируются линии связи. Разговаривая по телефону, вам приходится платить за каждую минуту разговора, но время ожидания и пропускная способность линии гарантируются вам поставщиком. В Интернете вам приходится делить пропускную способность линии с другими пользователями, поэтому ваши пакеты должны ждать своей очереди. Низкая стоимость и совместное использование пропускной способности неизбежно ведут к необходимости ожидания. Что происходит, когда магазин, торгующий мороженым, устраивает рекламную раздачу своего товара на улице? Собирается большущая очередь, и приходится долго-долго ждать, чтобы получить свою порцию, хоть она и бесплатная. Интернет не может идеально подходить всем, кому нужна связь. Если неопределенность и задержки, связанные с использованием Интернета, для вас неприемлемы и в ваших руках оба конца соединения, вы можете арендовать выделенную линию или просто позвонить. Во многих случаях можно соединиться с офисной сетью по модему на 56 кбит/с. Вы можете купить даже линию связи по протоколу TCP/IP на большое расстояние, но это стоит дорого. Точки доступа к сети Точка доступа к сети (Network Access Point — NAP) — это место, где крупные провайдеры обмениваются потоками информации. Название было подобрано не слишком удачно, поскольку «доступ к сети» подразумевает, что провайдеры в этой точке получают доступ к чему-то большему, когда на самом деле в точке доступа они всего лишь обмениваются данными с равными партнерами (хотя некоторые из них действительно «более равные, чем другие», то есть обладают
лучшими линиями связи). Именно точкам доступа к сети слово «Интернет» обязано приставкой интер: без обмена трафиком между частными сетями провайдеров вместо Интернета у нас был бы просто набор частных сетей. Помните, что все базовые линии связи и маршрутизаторы Интернета принадлежат конкретным провайдерам. Точки доступа к сети соединяют этих провайдеров друг с другом высокоскоростными линиями Ethernet и FDDI, а также обеспечивают обмен информацией о маршрутизации. У точек NAP есть и другие трехбуквенные названия: МАЕ (Metropolitan Area Exchange — обмен между городскими районами) и FIX (Federal Internet Exchange — Обмен между сетями федерального масштаба). Все точки МАЕ принадлежат фирме Worldcom, которая недавно слилась с UUNet. Вот самые крупные точки доступа: О CIX — Commercial Internet Exchange; О FIX West (NASA Ames Research Center в Mountain View). Напрямую соединен с МАЕ West; О NAP в Аризоне (провайдер Genuity); О МАЕ Чикаго; О МАЕ Далласа; О МАЕ Лос-Анджелеса; О МАЕ Нью-Йорка; О МАЕ East в Вашингтоне (обрабатывает входящие соединения из Европы); О МАЕ West в Сан-Хосе (обрабатывает входящие соединения Тихоокеанской сети Pacific Rim); О NAP в Сан-Франциско фирмы PacBell; О NAP в Пеннсаукене фирмы Sprint. Откуда взялись точки доступа к сети? В начале 90-х годов WorldCom и несколько других провайдеров типа Metropolitan Fiber Systems (MFS) договорились о взаимовыгодном обмене трафиком. В 1993 году Национальный научный фонд (National Science Foundation) заплатил за подключение своей сети NSFNet к концентратору в Вашингтоне. Так появилась точка МАЕ East. Поскольку точки доступа к сети всегда передают огромное количество информации, именно на них чаще всего теряются пакеты и происходят задержки. В часы пиковой нагрузки на этих точках, по некоторым оценкам, теряется до трети всех пакетов. Это одна из причин, по которым связь внутри сети одного провайдера обычно существенно быстрее, чем связь между провайдерами, даже если они находятся в одном городе. Не провайдеры определяют, какое оборудо- иание и программное обеспечение установлено на точках доступа, но им приходится платить большие деньги за взаимодействие с другими провайдерами. Большая часть трафика может проходить через точки доступа к сети, но нет никакого закона, который делал бы это обязательным. Каждый провайдер может заключить соглашение с любым другим провайдером, установить необходимое оборудование и соединиться с ним или вообще с любой частной сетью. Если все наши пользователи подключены к AOL, установите прямое соединение с этим провайдером. Некоторые провайдеры, такие как InterNex, стремятся к созданию
множества связей между провайдерами. На момент написания этой книги Inter- Nex был подключен к 6 крупным и 90 обыкновенным провайдерам. Провайдеры Правильный выбор провайдера может весьма сильно повлиять на производительность. Учитывать нужно размещение провайдера и некоторые другие факторы, определяющие производительность. Размещение Если вы создаете свой веб-сайт, то именно вы решаете, где именно в Интернете будут размещаться ваши серверы. К размещению сервера предъявляется два требования: он должен располагаться близко (топологически и физически) к будущим потребителям, и быть подключен к линии с большой полосой пропускания. Топологическая близость к потребителям означает, что пакетам не приходится совершать много прыжков через маршрутизаторы. Помните, что Интернет похож на дерево: между вами и пользователями должно быть как можно меньше точек ветвления, чтобы время ожидания было минимальным. Если к вашему серверу потребители обращаются через Интернет, лучше всего, чтобы они были подключены к тому же провайдеру, что и вы. Если у вашего провайдера нет точек доступа около ваших пользователей, лучше всего найти им такого провайдера, который будет подключаться к тому же провайдеру верхнего уровня или к той же точке доступа, что и ваш провайдер. Или вы можете просто переместить свой сервер, подключившись к их провайдеру. С помощью программы traceroute вы можете узнать, сколько маршрутизаторов находится между любыми двумя точками Интернета и какую задержку вносят эти маршрутизаторы. Если ваши пользователи разбросаны по разным странам, лучше всего подключиться к провайдеру национального масштаба типа Netcom, MCI или Sprint. Списки провайдеров, подключенных к различным точкам NAP, вы можете найти на сайте http://nitrous.digex.net/. На рис. 14.3 приведена карта провайдеров и их соединений с базовой сетью Интернета. Рис. 14.3. Карта подключения провайдеров к базовой сети Интернета
Подключая свой сервер через того же провайдера, к которому подключены ваши пользователи, вы подвергаете себя новой опасности. Если ваш провайдер перегружен, то самый быстрый маршрут будет идти вокруг, через маршрутизаторы другого провайдера, — это все равно что объехать пробку по тихим боковым улочкам. К сожалению, ручная маршрутизация пакетов, или маршрутизация от отправителя, запрещена в целях безопасности, а оборудование провайдера никогда не отправит ваши пакеты во внешнюю сеть, если увидит, что и отправитель и получатель находятся в одной и той же внутренней сети. Это означает, что иногда ваши пакеты будут застревать и идти коротким, но медленным путем. Так обстоят дела на данный момент. Производительность провайдеров Экономика Интернета, поставщики доступа к которому покупают линии и доступ высокого уровня за фиксированную цену, а затем продают доступ также за фиксированную цену, побуждает провайдеров продавать свои услуги большему количеству пользователей, чем они реально могут обслужить, — до тех пор, пока пользователи не начинают уходить к другим провайдерам. Особенно плохим может быть качество доступа в часы пик. Прежде чем обвинять своих провайдеров во всех смертных грехах, подумайте о том, что провайдеры вынуждены продавать сверх имеющегося, иначе они не могли бы конкурировать в стоимости услуг с другими провайдерами, которые также продают сверх имеющегося. По тем же причинам авиакомпании часто заказывают внеплановые рейсы. Более того, провайдер может продать довольно значительную часть пропускной способности сверх имеющейся, прежде чем пользователи начнут что-то замечать. У провайдера может быть одна линия связи типа Tic его собственным провайдером, а он продаст пользователям около 15 линий Т1, и они будут иметь удовлетворительное качество доступа. Это происходит потому, что пользователям доступ в Интернет нужен обычно на довольно короткое время, причем их обращения к сети распределяются по времени дня случайным образом. Провайдер занимается тем, что объединяет пакеты и отправляет их своему провайдеру. Вы получите гораздо большую пропускную способность, совместно используя линию Т1, подключенную к крупной линии базовой сети, чем если купите выделенную линию с одной пятнадцатой частью полосы пропускания линии Т1. Если вам действительно нужна гарантированная производительность, за это придется платить. Провайдер может гарантировать только производительность собственной сети, но этого может быть вполне достаточно, если большая часть ваших пользователей подключена к тому же провайдеру, что и вы. Если производительность действительно заботит вас и у вас очень много денег — купите прямое выделенное соединение с крупным провайдером или даже с точкой доступа к сети. Не существует хорошей сравнительной статистики производительности про- иайдеров. Имеются лишь отдельные сведения, публикуемые обычными пользо- нателями. Даже если бы сравнительная статистика и существовала где-то как гдиное целое, ее нужно было бы постоянно обновлять, поскольку пользователи меняются, а провайдеры обновляют оборудование и линии связи.
Выбор провайдера Так как же выбрать провайдера? Есть множество факторов, на которые следует обратить внимание. Прежде всего спросите провайдеров, как идут дела у их фирмы. Этот вопрос даст им понять, что вас это волнует, — а у них должна быть возможность снабдить вас данными такого рода. Насколько хорош канал связи этого провайдера? Сколько у него пользователей, и во сколько раз провайдер превысил имеющуюся полосу пропускания линии связи с провайдером верхнего уровня? Какая конкретно у них установлена линия связи с провайдером или точкой доступа к сети? Можете ли вы получить сведения от провайдера верхнего уровня? Сколько пакетов теряется их маршрутизаторами, и каков их процент от общего числа? Ваши вопросы должны касаться как входящей, так и исходящей связи. Кроме того, следует обратить внимание на статистику отказов (см. приложение в этой книге). Лучше всего, если вы подключитесь к провайдеру первого уровня, базовая сеть которого реализована на ATM и у которого имеется множество избыточных точек подключения к сети. Учтите, что, когда провайдер хвастается наличием линии FDDI, связывающей его с локальной точкой доступа к сети, это еще не означает, что его базовые сети обеспечивают такую же пропускную способность. Провайдер второго уровня должен иметь соглашения о связи с другими провайдерами того же уровня или несколько соединений с провайдерами первого уровня. Хороший кэш прокси-сервера также весьма полезен, поскольку он уменьшает нагрузку на ваш сервер. (Прокси-серверы AOL кэшируют часто запрашиваемые страницы и дают им более высокий приоритет по сравнению со страницами, которых нет в кэше. Это ускоряет доступ к популярным страницам, но ухудшает качество связи с редкими сайтами. Вы можете повысить приоритет своего сайта на таком прокси-сервере, получив учетную запись на AOL и запросив по нескольку раз все страницы со своего сервера.) Определить производительность вашего провайдера можно, поглядев на статистику повторных передач вашего модема или библиотеки TCP/IP. Если вы видите множество сообщений о тайм-аутах, да еще и Netscape часто выдает вам сообщение о том, что закончилось время ожидания, — значит, дело плохо. Одним из сомнительных методов экономии денег провайдерами является следующий. Провайдеры покупают множество входящих точек подключения (Point of Presence — РоР), которые на самом деле представляют собой лишь линии пересылки данных, позволяющие избежать оплаты за междугородние разговоры путем разбиения одной длинной линии связи на множество коротких. В результате вашим пакетам придется пройти через множество коммутатором телефонной линии, прежде чем они попадут на компьютер, действительно подключенный к Интернету. Это увеличит время ожидания и ухудшит качество линии, а следовательно — и ее пропускную способность. Производительность других провайдеров может влиять на ваш сервер, даже если вы никак с ними не связаны. Если почтовая система AOL выйдет из строя, на серверах вашего провайдера может скопиться столько сообщений для пользователей AOL, что они тоже выйдут из строя и отрежут вас от остального мира.
Дублирование Многие компании предоставляют услуги по размещению серверов. Цена может быть достаточно высокой, но и выигрыш тоже может быть немалым. У вас больше не будет болеть голова насчет работоспособности сервера и его соединения; вы сможете сосредоточиться на веб-содержимом. Такие компании обычно имеют отличное качество связи с местными точками доступа к сетям, избыточные соединения и резервные источники питания, а также позволяют дублировать серверы в других частях страны и мира. Например, компания GlobalCenter (http://www.globalcenter.net/) является владельцем соединения с точкой доступа в Сан-Хосе на 100 Мбит/с и дублирующих серверов на Восточном побережье и в Лондоне. На ее серверах размещены сайты Yahoo!, Playboy и часть сайта Netscape. Все это реализовано на базе серверов Sun и SGI. В качестве резервного источника питания используется дизельный генератор. Маршрутизаторы Все маршрутизаторы увеличивают время ожидания пакетов, поскольку пакет должен быть принят целиком, а затем должен быть проверен адрес назначения — прежде чем пакет сможет быть отправлен дальше. Быстрые маршрутизаторы справляются с этой задачей за 1-2 мс, но медленные могут увеличивать время ожидания на 10 мс и более. Составляющая времени ожидания, связанная с большим количеством маршрутизаторов, может оказаться больше, чем составляющая, связанная с большим расстоянием. Если в качестве маршрутизаторов используются старые рабочие станции, у них может быть отличная полоса пропускания, но гораздо худшее время ожидания по сравнению со специальными маршрутизаторами. Нужно не просто покупать специальные аппаратные маршрутизаторы, но и из них выбирать самые быстрые, какие вы только можете себе позволить. Аппаратным маршрутизаторам не приходится заниматься тем, чем занимаются обычные операционные системы, — обслуживать множество пользователей или заданий, поэтому они оптимизируются так, чтобы хорошо делать свое дело. Аппаратные маршрутизаторы обладают лучшей буферизацией, более эффективно обрабатывают преры- нания, а их шины делаются специально в расчете на передачу данных с одного интерфейса на другой. Для большинства маршрутизаторов «узким местом» является не мощность процессора, а пропускная способность шины, по которой передаются данные. Хотя аппаратные маршрутизаторы дороги, как и любое оборудование, в расчете на один порт они могут быть достаточно дешевыми, если мы выберете маршрутизатор со множеством портов. Вы можете устанавливать приоритеты различных видов трафика на уровне маршрутизаторов. Это позволяет осуществлять управление трафиком таким же образом, как это делается специальными устройствами, описанными в разделе «Управление трафиком IP» приложения. Операционная система фирмы Cisco Systems IOS 1.11, устанавливаемая на маршрутизаторы этой фирмы, дает возможность помечать некоторые IP-пакеты как имеющие приоритет перед всеми
остальными, что позволяет обеспечивать более высокое качество обслуживания для некоторых сеансов, а всем остальным отводить оставшуюся часть пропускной способности. Некоторые маршрутизаторы позволяют вести трассировку, а впоследствии оптимизировать их использование на основании результатов этой трассировки. Коммутация на уровне IP в последнее время стала довольно популярной. Название может ввести вас в заблуждение: коммутация на уровне IP на самом деле не является коммутацией в смысле установки выделенного временного соединения. В результате этой коммутации все равно получаются пакеты, которые соревнуются с другими пакетами за общую линию связи. Коммутация на уровне IP — это просто поиск по таблице маршрутизации, осуществляемый специальными микросхемами, а не программами. Коммутаторы IP работают в 2-3 раза быстрее, чем обычные маршрутизаторы. Подробнее об этом можно прочитать на сайте http://www.ipsilon.com/. Сжатие на канальном уровне, осуществляемое маршрутизаторами, не обязательно повышает производительность, поскольку сжатие обычно осуществляется программно, что замедляет работу процессора маршрутизатора. Для загруженных маршрутизаторов это может ухудшить производительность сильнее, чем ее повышает сжатие. Вам придется поэкспериментировать самостоятельно, чтобы решить, подходит ли это для вас. Размер пакета очень сильно влияет на затраты ресурсов процессора на маршрутизацию. Например, персональный компьютер на базе i486 может обеспечить маршрутизацию 1 Гбит/с пакетов размером 1 Кбайт, но он не сможет обслужить ту же полосу пропускания, если пакеты будут иметь размер 128 байт. Это происходит потому, что процессор занят решением задачи об отправке пакета, а не самой отправкой. Чем больше пакетов, тем больше нагрузка на процессор при том же объеме передаваемых данных. Попробуйте поработать с бесплатной программой Multi Router Traffic Grapher, написанной Тобиасом Оэтикером (http://www.mrtg.org/). Она использует протокол SNMP и бесплатную программу построения графиков для отображения в реальном времени сведений о трафике маршрутизаторов. Кто виноват? В принципе, можно выяснить, кто виноват в низкой производительности внешней сети. Если производительность сети меняется в зависимости от времени суток, винить следует всех пользователей Интернета, которые активно пользуются сетью в течение дня. Помните, что в разных частях США и мира инфраструктура устроена по-разному, поэтому производительность будет различной в зависимости от того, где вы находитесь. Подробнее об этом можно прочесть по адресу: http://www.keynote.com/measures/business/business40.html. Небольшой трюк поможет выяснить, связана ли проблема с вашим провайдером или с провайдером удаленного сервера. Предположим, скорость загрузки файла с сервера кажется вам недостаточной. Попробуйте одновременно открыть еще один экземпляр браузера и загрузить в нем файл с другого сайта. Если программа, с помощью которой вы следите за модемом или сетью, говорит вам, что
суммарная скорость приема данных возросла, когда вы подключились к другому серверу, ясно: ваш провайдер может отправлять вам пакеты с большей скоростью, чем это было вначале, — и, следовательно, «узким местом» является провайдер сервера или какой-то из промежуточных маршрутизаторов. Если же скорость приема данных при обращении к другому серверу не меняется, виноват ваш провайдер — и вам нужно пожаловаться (либо же вы достигли максимума возможностей вашего подключения, и тогда жаловаться не нужно). Обязательно начинайте эксперимент с пустыми кэшами браузеров. Если программы traceroute у вас нет, команда ping -sRv имя узла в Solaris (или ping -Rv имя узла в Linux) дает возможность определить маршрут пакетов до интересующего вас компьютера. Будущее Интернета В настоящее время создается по меньшей мере два альтернативных Интернета, призванных исправить недостатки существующей системы. На сайте Merit (http://www.merit.edu/) вы найдете множество сведений по этому поводу. Internet2 Internet2 — это консорциум образовательных учреждений, занимающихся проектированием сети с измеримым и строго определенным качеством. Эта сеть должна будет отвечать конкретным требованиям к времени ожидания и его колебаниям, возможностям получения и резервирования пропускной способности, а также гарантиям доставки пакетов. Подробнее об этом можно узнать на сайте http://www.internet2.edu/. NGI Создаваемый правительством США Интернет следующего поколения (Next Generation Internet) также будет отвечать конкретным целям и потребностям в качестве обслуживания. NGI будет связывать исследовательские институты высокоскоростными сетями, которые будут в сотни и тысячи раз быстрее современного Интернета. птт В некоторых странах телефонная компания является монополистом национального масштаба, скрывающимся под аббревиатурой ПТТ (Почта, Телефон, Телеграф). Не стоит ожидать от ПТТ слишком многого. Связываться с ПТТ, в какой бы стране вы ни находились, богатой ли, бедной, — это все равно, что предпринимать путешествие назад во времени. Ваш телефонный узел может поддерживать только импульсный набор или вообще состоять из одного телефониста, переключающего соединительные шнуры. Получение обычного телефонного номера может занимать месяцы и годы — и скорее всего, это будет стоить дороже, чем в США. Невероятно, но факт: купить высокопроизводительный компьютер
можно в любом уголке Земли, но больше половины населения этой Земли никогда не звонили по телефону. Мир меняется, операторы сотовой связи появляются даже в бедных странах, потому что это дешевле и проще, чем тянуть провода под землей. Основные рекомендации О Купите модем того же уровня, что и у вашего провайдера. О Если вы работаете в локальной сети Ethernet, купите карту с буферами по 16 Кбайт или больше. О Выбирайте провайдера поближе (в смысле количества прыжков) к вашим любимым сайтам. О Подключитесь к тому же провайдеру, что и ваша фирма, если вам придется часто работать с ее веб-сайтом, или подключайтесь к локальной сети по модему напрямую. О Купите нормальный маршрутизатор, вместо того чтобы пытаться выжать все возможное из старой рабочей станции. О Отведите своему серверу отдельное соединение с Интернетом. Не используйте это соединение для путешествий по сети, передачи системных или управляющих данных. О Помните, что цельность данных позволяет повысить пропускную способность.
15 Сетевые протоколы Власть и протоколы Отвлечемся на минуту, чтобы рассмотреть политическую жизнь протоколов, поскольку именно политика, а не производительность определяет, какие протоколы используются в реальности, а какие остаются только на бумаге. Ценность протоколов пропорциональна количеству пользователей: широко распространенный протокол дает вам желанную возможность общаться с большим количеством собеседников. Поэтому, когда каким-то протоколом пользуется достаточно большое число людей, он начинает привлекать новых пользователей одним этим своим качеством. Протоколы ведут себя подобно снежному кому, который, катясь по склону горы, может превратиться в лавину. При этом совершенно неважно, обладает ли протокол достаточной производительностью. Ценность одной лишь возможности общаться с большим количеством людей очень велика. Хорошим примером является протокол HTTP: он не является особенно эффективным, но стал крайне ценным благодаря своей повсеместной распространенности. Открытые протоколы лежат в основе Интернета и веб. TCP/IP, HTTP, HTML, Java и CORBA — все эти протоколы являются открытыми. Существует множество определений «открытости» протоколов, придуманных для удобства тех, кому это выгодно. Я называю протокол открытым, если полная его спецификация доступна всем желающим для бесплатного использования или реализации этого протокола. Открытые протоколы распространяются быстрее, чем «закрытые», поскольку их использование не повышает стоимости программного обеспечения. Благодаря открытым протоколам было разработано бесплатное программное обеспечение для Интернета, которое послужило развитию веб. Даже небольшая цена всегда является барьером для приобретения программного обеспечения.
Открытые протоколы дают конечному пользователю больше, чем закрытые, поскольку обычно возникает несколько совместимых реализаций протокола, которые соревнуются в качестве, производительности и стоимости. Например, поскольку никто не является владельцем протокола HTTP, существует множество различных веб-серверов и веб-клиентов, которые отличаются друг от друга как стоимостью, так и производительностью. Эффективность существующих реализаций постоянно повышается. Другим важным фактором, послужившим успеху HTTP, стала его простота. Наиболее типичной причиной «гибели» открытых протоколов является их надуманность и сложность. Все открытые протоколы, за исключением CORBA, относительно просты, и им прочат великое будущее. Если открытые протоколы хороши для пользователей, почему все еще существуют закрытые протоколы? Одна из причин в том, что бизнес ориентируется не на удовольствие пользователей, а на деньги. Огромные прибыли сулит удачная реализация закрытого протокола, единственным владельцем которого будет ваша фирма, а извлечь деньги из создания открытого протокола гораздо тяжелее, хотя и не невозможно. Многие открытые протоколы появились как плоды трудов государственных исследовательских проектов, поскольку эти проекты обычно не ориентируются на получение прибыли. Соблазн оставить протокол закрытым возникает потому, что закрытый протокол может обрасти пользователями как снежный ком — и стать мировым стандартом де-факто. Когда это произойдет, одна только повсеместная распространенность протокола будет вынуждать пользователей покупать его реализацию, чтобы общаться друг с другом, что будет еще больше усиливать лидерство фирмы на рынке. В результате всем придется покупать реализацию этой фирмы вне зависимости от ее качества. Это плохо для пользователей, но замечательно для бизнеса. Закрытые протоколы плохи не во всем: централизованное управление гарантирует, что протокол не распадется на несовместимые «диалекты». Если считать интерфейсы программирования приложений (API) операционных систем протоколами взаимодействия этих систем и приложений, то можно прийти к выводу, что Unix пострадал именно из-за такой фрагментации. Unix обладает лучшей производительностью по сравнению с Windows, но производители Unix пытались обратить на себя внимание пользователей, добавляя в систему свои собственные элементы, что сделало невозможным работу приложений в других версиях той же операционной системы. Ситуация несколько улучшилась после широкого распространения стандарта Posix. Windows обязана своим успехом тем, что в этой системе всегда был только один протокол (API), хотя к настоящему моменту ситуация изменилась с появлением различных видов Windows. (В Windows XP компания Microsoft пытается устранить это разделение, объединяя ветви Windows 2000 и Windows 95/98/Ме. — Примеч. ред.) Интересную стратегию применили создатели языка Java. Спецификация Java (за исключением J2EE) бесплатно доступна всем желающим, и эти желающие могут создавать свои реализации по этой спецификации, которая остается тем не менее собственностью компании Sun Microsystems. У покупателей есть гарантия, что спецификация Java не разделится впоследствии на множество диа лектов, но им не нужно беспокоиться о том, что они будут привязаны к одной
реализации этого языка. С другой стороны, компания Sun сохранила довольно большую власть над этим языком, поскольку она может расширять спецификацию так, как ей будет выгодно. Это хороший компромисс между открытыми и закрытыми протоколами. Вообще говоря, история с протоколами взаимодействия не является чем-то новым. Английский язык — пример того, что открытый протокол может быть выгоден своим создателям. Англия сделала английский язык официальным в своих колониях по всему миру. Теперь он стал самым широко распространенным языком делового общения и продолжает распространяться все шире и шире, поскольку его знание необходимо для общения. Англия и Америка все еще получают с этого прибыли, так как граждане этих стран могут путешествовать и заключать сделки по всему миру, не изучая никаких других языков. Новым в Интернете является возможная скорость распространения протоколов. Факторы, влияющие на производительность сетевых протоколов Сетевые протоколы обладают набором свойств, влияющих на их производительность. Большая часть этих свойств подробно разбирается в книге А. Танен- баума «Компьютерные сети» (издательство «Питер», 2002), а мы вкратце поговорим о них в последующих разделах. Пакеты, кадры и ячейки переменного и фиксированного размеров Для пакетов фиксированной длины, обычно называемых ячейками, можно разработать более эффективное оборудование, поскольку заранее известен, например, точный размер буфера, который будет обеспечивать заданную производительность. Кроме того, можно использовать крайне эффективный коммутатор, соединяющий каждый вход с каждым выходом напрямую. Совмещенная отправка Некоторые протоколы позволяют отправлять подтверждение приема предыдущего пакета в текущем отправляемом пакете, что повышает эффективность использования линии. TCP поддерживает совмещенную отправку (piggy-backing) v задержкой сегмента АСК, то есть подтверждение приема откладывается до тех мор, пока подтверждающее приложение не подготовит данные для отправки их имеете с сегментом АСК. Подробнее см. в документе RFC 1122 «Требования к Интернет-хостам — коммуникационный уровень» (Requirements for Internet hosts — communication layers).
Конвейер и подтверждение отдельных пакетов Окном называется количество пакетов, которые могут быть отправлены до того, как придет подтверждение приема первого из них. Оптимальный размер окна зависит от длины кабеля в битах, то есть от максимального количества битов, которые могут находиться «в пути» в любой конкретный момент времени. Для длинных или надежных кабелей нужно устанавливать больший размер окна. Подробнее об этом читайте в книге Таненбаума. Односторонние и двусторонние протоколы Двусторонние протоколы поддерживают одновременную передачу данных в обоих направлениях. Односторонние протоколы также поддерживают передачу данных в обе стороны, но не одновременно. Ошибки Оптимальный размер пакета зависит от количества ошибок. Если ошибки маловероятны, пакеты лучше делать большими, чтобы скомпенсировать затраты на передачу их заголовков и обработку прерывания от сетевого адаптера. Если же ошибки весьма вероятны, небольшой размер пакетов снижает затраты на повторную передачу. Количество прыжков Если пакетам нужно сделать большое количество прыжков в пути между вами и конкретным адресатом, вы можете выиграть, отправляя небольшие пакеты. Данные не могут быть отправлены с одного маршрутизатора на другой, пока пакет не будет принят целиком; поэтому, если пакеты имеют большой размер, биты дольше ждут на маршрутизаторах. Если же пакеты имеют небольшой размер, большее их количество может одновременно находиться в пути между разными маршрутизаторами. Это все равно что перевозить грузы в больших фургонах или маленьких микроавтобусах: на шоссе фуры эффективнее, но в городе, где много светофоров и пробок, маленькие автомобили будут разгоняться быстрее, чем грузовики, и потому эффективнее окажутся именно они, несмотря на то, что накладные расходы у микроавтобусов больше. Уровни Помните, что работа в сети основывается на протоколах различных уровней. HTTP работает поверх TCP, a TCP поверх IP, который обычно реализуется в сетях Ethernet. Оптимизация на высоком уровне ничего не даст, если проблема возникла на нижних уровнях. Начинайте с физического уровня и ищите малоэффективные решения, продвигаясь по уровням вверх.
Протоколы веб В последующих разделах приведено описание самых важных сетевых протоколов, используемых в веб, а также информация о производительности каждого из них. Начнем с самых нижних уровней. ARP Протокол разрешения адресов (Address Resolution Protocol — ARP) преобразует IP-адреса в адреса сетевых адаптеров Ethernet, которые называются адресами управления доступом к линии связи (Media Access Control — MAC address). Узел, которому нужно отправить IP-пакет адресату, находящемуся в той же локальной сети, отправляет широковещательный запрос по протоколу ARP, выясняя, не знает ли кто-нибудь МАС-адрес, соответствующий требуемому IP-адресу. На запрос должен ответить сам будущий адресат IP-пакета. Ответы ARP кэшируются на определенный срок, и в целом этот протокол работает достаточно эффективно. Однако на определение адреса требуется некоторое время, поэтому слабозагруженные веб-серверы после долгого бездействия могут отвечать с некоторой задержкой. ARP может вызвать проблемы, если он будет использоваться вместо нормальной маршрутизации. Клиенты должны быть настроены на отправку пакетов непосредственно локальному маршрутизатору, если в локальной сети никто не соглашается их принимать. Может показаться разумным сделать так, чтобы маршрутизатор отвечал на все запросы но протоколу ARP (прокси-сервер ARP), а не только па те, которые соответствуют адресатам, отсутствующим в данной локальной подсети; но это создаст слишком большую нагрузку на маршрутизатор и сеть, поскольку все пакеты должны будут проходить через маршру- шзатор. ррр 1'РР — это протокол канального уровня, предназначенный для передачи пакетов 'нобого протокола сетевого уровня, в отличие от SLIP, который может переда- мать только пакеты протокола IP. Если вы подключаетесь к Интернету напрямую по модему — скорее всего, вы используете именно этот протокол. Для определения ошибок передачи в кадрах РРР передаются контрольные суммы. Кадры с ошибками передаются повторно, что снижает реальную скорость передачи информации. Эти кадры часто имеют размер 1500 байт, поскольку такой размер позволяет передать в кадре один пакет Ethernet, но, вообще говоря, раз- мгр кадра обговаривается собеседниками во время установления соединения. 1МФ обычно разрывает соединение, если возникает слишком много ошибок кон- цюльныхсумм.
Протоколы маршрутизации Рассмотрение протоколов маршрутизации, таких как RIP, OSPF и BGP, лежит за рамками данной книги. (Эти вопросы освещены во 2-м издании книги В. и Н. Олифер «Компьютерные сети. Принципы, технологии, протоколы» издательство «Питер» 2003. — Примеч. ред.) Протокол Интернета Протокол Интернета (Internet Protocol — IP) — это протокол сетевого уровня, используемый в Интернете. HTTP работает поверх TCP, а тот — поверх IP. Подробное описание протокола IP приведено в книге «TCP/IP Illustrated». Для оптимизации производительности достаточно знать, что именам DNS ставятся в соответствие четырехбайтовые IP-адреса, а IP-пакеты находят своих адресатов с помощью маршрутизаторов, которые принимают решения о дальнейшем направлении движения пакета в точках ветвления Интернета. И DNS и маршрутизаторы являются источниками задержек, поскольку для каждого HTTP-запроса необходимо выполнять преобразование имени в адрес, а также принимать решения по пути пакетов к адресату. Несмотря на все разговоры о том, что Интернет устраняет расстояния, длина линии связи (особенно измеренная в количестве прыжков) все еще имеет большое значение для производительности, поскольку каждый прыжок увеличивает время ожидания. По этой причине полезно бывает определить распределение ваших пользователей по провайдерам на основании записей в журналах и попытаться разместить сервер поближе к своим потребителям. Помните, что IP был реализован в расчете на динамическую маршрутизацию, которая позволяет обходить медленные или отказавшие маршрутизаторы, поэтому маршрут между любыми двумя узлами Интернета может меняться с течением времени. Отправитель может попросить, чтобы его пакеты были доставлены адресату определенным путем. Это называется адресацией от отправителя и работает только в том случае, если все маршрутизаторы на пути пакетом поддерживают упомянутый режим. Обычно они его не поддерживают из соображений безопасности: с помощью этого режима пользователи могли бы сделать так, чтобы пакеты казались пришедшими из другого места. В интрасети, где вы сами настраиваете маршрутизаторы, вместо динамического обновления таблиц создаются статические таблицы маршрутизации. Это может стать угрозой про изводительности, поскольку ошибка в таблице маршрутизации приведет к тому, что для каждого пакета, направленного не на тот шлюз, будет генерироваться дорогостоящее в смысле ресурсов и времени сообщение ICMP о перенапраи лении. Максимальный теоретический размер пакета IP составляет 64 Кбайт, а ми нимальный размер избыточных данных на один пакет — 42 байт, поэтому большая часть запросов HTTP легко помещается в один пакет. В реальности обычно используется максимальный передаваемый блок (Maximum Transmission Unit • MTU), который чаще всего равен 536 байт. MTU устанавливается равным ми нимальному из двух значений. Первое задается при настройке интерфейса, а вто
рое сообщается собеседником в поле MSS (максимальный размер сегмента — Maximum Segment Size). С помощью команды ifconfig -а вы можете просмотреть список интерфейсов вашего узла и значения их MTU. Если удаленный узел не задает значение MSS, по умолчанию используется значение 536 байт. IP-пакеты подлежат фрагментации на пакеты меньшего размера, если маршрутизаторы на их пути работают с меньшим значением MTU. Заголовки IP и TCP имеют в длину 20 байт, поэтому максимальный размер сегмента данных TCP (MSS) может быть равен (без фрагментации) только MTU — 40 байт. Фрагментация замедляет передачу, поскольку протоколу TCP приходится собирать фрагменты в единое целое. Хорошая интрасеть должна работать с одним и тем же значением MTU на всем своем протяжении, но по отношению к Интернету в целом у вас нет никакой власти. Параметр MRU вашего сетевого интерфейса задает максимальный размер IP-пакета, который может быть принят из сети. Это значение должно быть установлено равным MTU вашего провайдера, поскольку пакет большего размера вы никогда не получите. Делать это значение меньше смысла нет, так как о фрагментации пакета беспокоиться нечего, раз уж он дошел до вас. MRU и MTU обычно совпадают. Если вы работаете по протоколу РРР, значение MTU по умолчанию будет равным 1500 байт. Это вполне приемлемое значение, поскольку оно равно максимальному размеру пакета Ethernet, а большинство провайдеров используют для своих внутренних нужд именно Ethernet. Когда размер пакета превышает MTU какого-нибудь маршрутизатора на его пути, этот пакет приходится разбивать на куски. Пакет может быть разбит до отправки его маршрутизатору, который не может принять пакет целиком, после чего собран адресатом (либо, если в заголовке IP установлен бит «не фрагмен- тировать» (DF), весь пакет будет сброшен, а в ответ отправителю будет передано сообщение ICMP о том, что необходима фрагментация пакета. Это сообщение используется механизмом определения максимального MTU маршрута — P&th MTU Discovery). Я не уверен, что накладные расходы, связанные с Path MTU Discovery, окупаются выгодами использования оптимального значения этого параметра, поскольку HTTP-соединения живут очень недолго. Выключить этот механизм можно, установив параметр ndd ip_path_mtu_discovery в 0. В листинге 15.1 приведен небольшой сценарий, который я написал для определения MTU маршрутизатора моего провайдера с помощью пакетов ICMP различной величины. Данные сохраняются в формате, совместимом с gnuplot. Листинг 15.1. Определение MTU маршрутизатора #!/usr/local/bin/perl -w $| - 1: # Отключаем буферизацию, чтобы не терялись данные open(OUT. ">out"): print OUT "# Latency vs ICMP ping packet size.\n": LOOP: for ($i-64: $i<4000: $i++) { $_ - 4ping -cl -n -s$i 1.2.3.44: m!100S packet loss! && next LOOP: m!(\d+) data bytes.*- (.*)/(.*)/(.*) ms!s: print OUT "$1 $3\n": }
На рис. 15.1 приведены результаты. Максимальный передаваемый блок моего компьютера имел размер 1500 байт, но, возможно, максимальный размер принимаемого блока был меньше этого значения, из-за чего разрыв несколько сместился. Накладные расходы на заголовок IP составляют не менее 20 байт, на ICMP — 8 байт, а структура timeval должна представлять собой два целых числа по 4 байт каждое. Поэтому накладные расходы не могут быть «виновны» в том, что фрагментация начинается с величин около 1250 байт. Рис 15.1. Фрагментация пакетов Вы можете скачать исходный код версии traceroute, которая позволяет определять MTU всех промежуточных маршрутизаторов. В Интернете эту программу можно найти по адресу: http://ftp.uu.net/pubished/books/stevens/tcpipvl.tar.Z. В операционных системах Solaris 2.x механизм обнаружения MTU включен в ядро. Стандартный способ определения MTU описан в документе RFC 1191. Компьютер отправляет IP-пакет большого размера со включенным битом DF в заголовке IP Когда пакет доходит до маршрутизатора или моста, который не может его пропустить, этот объект генерирует сообщение ICMP «can't fragment». Отправитель уменьшает размер пакета и пробует все снова. Это продолжается до тех пор, пока не будет найдено значение MTU, позволяющее передавать пакет без фрагментации. DNS и TFTP используют пакеты размером не более 512 байт, поскольку для пакетов размером менее 576 байт гарантируется то, что они не будут фрагмен-
тированы. Можно считать, что 576 байт — это минимальный передаваемый блок. В локальных сетях Ethernet MTU обычно устанавливается равным 1500 байт, и это значение выбирается по умолчанию большинством клиентов (например, Windows). Однако при работе в Интернете иногда лучше установить MTU равным 576. С помощью упомянутой выше программы вы можете определить MTU между вами и вашими любимыми сайтами. IP позволяет передавать сообщения, управляющие самим этим протоколом. Данные сообщения называются пакетами протокола управляющих сообщений Интернета (Internet Control Message Protocol — ICMP). Вот некоторые возможные сообщения: пакет не может быть отправлен, пакет превысил допустимое количество прыжков, пакет был направлен не на тот шлюз, удаленный узел доступен. Последнее сообщение используется утилитой Unix под названием ping, которая позволяет проверять доступность удаленных узлов. Поддержка ping отключена у множества провайдеров, поскольку эта программа часто используется злоумышленниками в дурных целях. С ее помощью легко можно отправить столько сообщений, что производительность серверов провайдера упадет ниже критической отметки. Того же можно достичь и с помощью пакетов TCP SYN, являющихся запросами о соединении. Такие вещи называются ping flooding и SYN flooding и являются примерами атак типа «отказ в обслуживании». Можно отследить того, кто проводит эти атаки, — для этого есть бесплатная программа от MCI, которая называется DoS Tracker. Скачать ее можно по адресу: http://ftp.mci.net/outgoing/dostrack742812.tar. Команда traceroute также использует протокол ICMP для определения времени ожидания промежуточных маршрутизаторов, а у протокола ICMP приоритет самый низкий из возможных, поэтому результаты, выдаваемые traceroute, будут хуже, чем для нормального трафика, приоритет у которого выше. Пакеты сетевого протокола синхронизации времени (Network Time Protocol — NTP) имеют самый высокий приоритет, что разумно, поскольку они используются для настройки часов. В главе 3 о многоадресной передаче рассказывается более подробно. Это эффективный способ экономии полосы пропускания при передаче информации одновременно множеству пользователей — например, при радиопередачах в Интернете. Помните, что реализации TCP/IP отличаются друг от друга по эффективности. Время ожидания реализации TCP/IP пропорционально объему буферизации, выполняемой до того, как пользовательский процесс сможет получить входящие данные, а также времени обработки каждого сегмента процессором. Большой IP-пакет захватит линию целиком до тех пор, пока он не пройдет, блокируя эти маленькие, но более важные пакеты (например, пакеты звуковых данных реального времени). Алгоритм сжатия Ван Якобсона уменьшает размер заголовка IP на основании того факта, что заголовки в группе последовательных IP-пакетов во многом подобны друг другу. Этот алгоритм применяется только к заголовкам, а не к пе- |>едаваемым данным и особенно полезен при передаче больших объемов информации.
TCP Протокол управления передачей (Transmission Control Protocol — TCP) был разработан для установки надежного соединения по ненадежному носителю. Поток данных разбивается на IP-пакеты, которым присваиваются номера, причем не подтвержденные в течение определенного времени пакеты передаются повторно. Пакеты могут прибывать в произвольном порядке: протокол автоматически учитывает это и упорядочивает их так, как положено. TCP разрабатывался с учетом некоторых предположений — например, что соединения будут устанавливаться сравнительно редко, объемы передаваемых данных будут относительно велики, а правильность и полнота передачи гораздо важнее, чем производительность. Эти предположения верны для протокола передачи файлов FTP, но не для HTTP, который обычно требует установки множества короткоживущих соединений подряд, одного за другим, причем по каждому из этих соединений передается всего несколько килобайт. Важность абсолютной правильности и полноты для передач HTTP остается под вопросом. Для установки и закрытия соединения TCP требуется несколько обменов пакетами между клиентом и сервером, что дает заметную прибавку к обычному переносу данных по HTTP, составляющему всего около 10 Кбайт. Поскольку для установки соединения требуется отправка и получение в общей сложности трех пакетов, для отправки запроса и получения ответа требуется по меньшей мере два пакета и еще два пакета осуществляют завершение соединения TCP, даже на самый маленький запрос уходит целых семь IP-пакетов. Используйте последние версии TCP Вы никак не можете повлиять на то, что веб-серверы используют протокол HTTP, но как можно устранить падение производительности, связанное с использованием TCP? Поскольку реализации HTTP и TCP все больше учитывают существование друг друга, самые последние реализации протоколов должны использоваться как на стороне сервера, так и на стороне клиента. TCP встроен в ядро Unix и обновляется с помощью заплат (patches) — пакетов обновления. Рекомендуем установить все пакеты для протокола TCP Версии Solaris старше 2.6 уже учитывают нужды HTTP. Что же касается самого HTTP, то выбирать следует веб-сервер, способный работать по протоколу HTTP 1.1, который может использовать одно соединение TCP для передачи нескольких файлов, — такое соединение называется постоянным. В главе 18 вы узнаете, какие серверы используют HTTP 1.1. Некоторые особенности TCP ограничивают его производительность, но это не должно останавливать. Одно из препятствий связано с тем, что последовательный номер пакета может превысить максимально возможный, после чего отсчет вновь начнется с нуля. Это возможно в очень быстрых соединениях, но современные реализации включают защиту от превышения последовательного номера (Protection Against Wrapped Sequence Numbers — PAWS). Другое потенциальное ограничение связано с тем, что в любой момент времени в сети может находиться лишь одно полное окно данных. Это окно традиционно было ограничено в размерах и не могло превышать 64 Кбайт, но в последних реализациях
TCP с включением параметра масштабирования окна размер его может быть увеличен до 1 Гбайт. Пусть между двумя точками сети, находящимися на расстоянии в тысячу миль, время путешествия пакета составляет 20 мс. Максимальная пропускная способность для такого соединения составит 109 байт / 20xl0_:l с = - 200 Гбайт/с, а такой пропускной способности наверняка хватит для любого применения Интернета, которое я могу представить на сегодняшний день. Параметры TCP У TCP есть много параметров, настройка которых может влиять на производительность сети. Прежде всего следует бороться с повторной передачей пакетов, которые принимаются адресатом безо всяких проблем, но задерживаются из-за внутренних особенностей Интернета. Параметры, установленные по умолчанию, приемлемы для локальной сети с малым временем ожидания, но при работе в Интернете они могут приводить к ненужным повторным передачам. В Solaris многие параметры могут быть изменены без перезагрузки компьютера с помощью команды ndd. Это большой шаг вперед по сравнению с другими версиями Unix, требующими перезагрузки ядра. Все параметры измеряются командой ndd в миллисекундах. Вывести значения этих параметров можно, даже не являясь администратором системы. Для этого нужно выполнить команду ndd /dev/tcp \?. Изменить же параметры TCP/IP можно, лишь обладая правами привилегированного пользователя. Сделанные вами изменения иногда могут быть перекрыты приложениями, явно устанавливающими значения параметров TCP/IP при создании сокета. Сложности обычно возникают при попытке сравнить параметры TCP на двух разных компьютерах, например тестовом и рабочем. В листинге 15.2 приведен сценарий, распечатывающий настраиваемые параметры TCP в системе Solaris. Этот сценарий нужно запустить на обоих компьютерах, после чего сравнить получившиеся файлы командой diff. Скачать сценарий можно по адресу: http://patrick.net/software/dumpndd.sh. Листинг 15.2. Вывод настраиваемых параметров TCP #!/bin/sh for parm in "ndd /dev/tcp \? | cut -fl -d" " | grep -v _hash | grep -v status | grep -v \?* do /usr/ucb/echo -n Sparm /usr/ucb/echo -n " " ndd /dev/tcp $parm done Очереди прослушиваемых сокетов Когда говорят об очередях прослушиваемых сокетов, обычно сравнивают их с центром обслуживания потребителей, где вас, когда вы туда звоните, помещают в режим ожидания, пока не освободится кто-нибудь из представителей компании. Люди, находящиеся в режиме ожидания, соответствуют соединениям, находящимся в очереди прослушиваемых сокетов TCP. Ваш вызов принят, но никто ничего не делает, чтобы обслужить вас.
В действительности имеется две очереди прослушивания. Ядро устанавливает соединение TCP в два этапа, вначале помещая запросы в очередь незавершенных соединений, а затем, после благополучной установки соединения, помещая их в очередь установленных соединений. Нахождение в очереди незавершенных соединений аналогично ситуации, когда в службе поддержки уже снята телефонная трубка, но вас еще не поместили в режим ожидания. Две очереди предназначены для защиты от атак сегментами SYN, когда на сервер направляется множество пакетов SYN, чтобы он перестал обслуживать нормальных потребителей. (Как уже отмечалось, эта атака относится к группе атак типа «отказ в обслуживании» — DoS.) Очереди создаются для каждого процесса на сервере, ожидающего поступления входящих соединений. Когда очередь установленных соединений переполняется, клиенты перестают получать хоть какие-нибудь ответы, то есть сервер производит впечатление отказавшего. При этом клиенты обычно выходят по тайм-ауту и повторно отправляют сегмент SYN, хотя пользователь не получает никаких сообщений. Когда пользователю удается попасть в очередь установленных соединений, браузер выдает сообщение типа «Site contacted, waiting for reply...». После установки соединения netstat будет выводить для него состояние ESTABLISHED вне зависимости от того, было ли соединение принято приложением. С этого момента браузер может отправлять запрос, который должен быть буферизован сокетом, даже если приложение еще не приняло соединение. Длина очереди установленных соединений задается в качестве одного из параметров системного вызова listen(), на сервере, но не может превышать максимума, определяемого операционной системой. В системе Solaris максимальный размер очереди может быть задан с помощью команды ndd. Длина очереди, запрашиваемая сервером в вызове listen() либо может быть задана жестко в тексте программы (и тогда изменить ее будет нельзя, если только вам не удастся добыть исходный код и перекомпилировать его), либо может считываться из конфигурационного файла веб-сервера. Стивене показывает, что очереди завершенных соединений обычно бывают пусты, поэтому тратить на них память смысла нет, если только ваш сервер не относится к числу действительно загруженных. Очередь неустановленных соединений должна быть несколько больше. Очередь неустановленных соединений не использует дескрипторы файлов, поэтому ее можно сделать достаточно большой для защиты от атак типа SYN — например, так: # /usr/sbin/ndd -set /dev/tcp tcpconnreqjnaxqO 10000 Длина очереди установленных соединений (задаваемая операционной системой) должна быть, по крайней мере, не меньше, чем длина очереди, запрашиваемая веб-сервером, но помните, что большая очередь будет занимать больше памяти. Нет смысла делать длину очереди установленных соединений большей, чем количество дескрипторов файлов, доступных одному процессу, поскольку сервер не сможет установить больше соединений, чем у него будет дескрипторов. Сервер Netscape Commerce по умолчанию запрашивает очередь размером в 128 элементов, поэтому на уровне операционной системы размер очереди также должен быть установлен равным 128. Я предпочитаю устанавливать пара-
метр listenQ в файле конфигурации Netscape magnus.conf равным 1024, хотя такая большая очередь редко может быть задействована целиком. Изменить очередь установленных соединений в системе Solaris можно следующим образом: # /usr/sbin/ndd -set /dev/tcp tcpconnreqjnaxq 1024 А следить за очередями прослушиваемых сокетов в Solaris можно так: # /usr/sbin/ndd -get /dev/tcp tcpj i stenhash С помощью netstat -s можно вывести на экран количество соединений, сброшенных из-за недостаточного размера очереди установленных соединений. Этот параметр называется tcpListenDrop. В системе Linux 2.0 изменить размер очереди прослушивания можно с помощью параметра SOMAXCONN в файле /include/linux/socket.h, причем требуется компиляция ядра. В системе BSD размер очереди неустановленных соединений хранится в константе so_q0len, а установленных — в константе so_qlen. Для их изменения необходимо перекомпилировать ядро. Тайм-аут повторной передачи Если TCP не получает уведомления о получении сегмента в течение определенного промежутка времени, он считает сегмент утерянным и отправляет его еще раз. При первой отправке пакета для него используется фиксированный тайм- аут, устанавливаемый при создании соединения, а затем величина периода ожидания вычисляется динамически на основании данных о производительности этого соединения. Можно ускорить работу протокола TCP, установив начальное значение тайм-аута в соответствии с вашими знаниями о своих клиентах. Проблема в том, что слишком большое время ожидания сделает работу в сети, где возможно большое количество ошибок, крайне медленной, поскольку придется дольше ждать повторной отправки утерянных пакетов. Слишком маленькое время ожидания приведет к тому, что множество пакетов будет отправляться повторно, несмотря на то, что они не потерялись, а просто находились в пути чуть дольше, чем следовало. Отслеживать количество повторных передач в системе Solaris можно с помощью команды % netstat -s Анализируя выводимые результаты, нужно сравнивать tcpOutDataSegs с tcpRet- ransSegs, a tcpOutDataBytes — с tcpRetransBytes. Если вам приходится повторно передавать более 20% сегментов или байтов, попробуйте увеличить время ожидания до повторной передачи и проанализировать вывод netstat снова. С клиентской стороны на компьютерах Macintosh можно использовать средство Мае TCP Monitor, а в Windows величина тайм-аута хранится в перемен ной RTOmax. Время ожидания до первой повторной передачи для данного соединения устанавливается в системе Solaris с помощью параметра tcp_rexmitjnterval_initial. Этот начальный тайм-аут по умолчанию составляет 200 мс, что подходит для локальной сети, но абсолютно недостаточно в Интернете. Для Интернета нужно установить значение тайм-аута равным 1 с A000 мс): # /usr/sbin/ndd -set /dev/tcp tcp_rexrait_interval initial 1000
Вы можете также установить ограничения на возможные значения времени ожидания тоже в миллисекундах: # /usr/sbin/ndd -set /dev/tcp tcp_rexmit_interva1_min 1000 # /usr/sbin/ndd -set /dev/tcp tcprexmitintervaljnax 10000 Алгоритм повторной передачи будет изменять время ожидания между его максимальным и минимальным значениями в зависимости от того, какова в целом производительность этого соединения. Большая часть соединений но протоколу HTTP существует недолго, поэтому нет смысла делать интервалы повторной передачи большими. Пользователь, скорее всего, просто уйдет на другой сайт, если ему придется прождать десять секунд или больше. TIME_WAIT Интервал TIME_WAIT определяет, сколько времени после закрытия сокета должно пройти, прежде чем он может быть использован другим клиентом. Если сделать этот параметр слишком малым, вы можете повторно открыть сокет и получить сбой в потоке данных, если сегмент TCP, относящийся к предыдущему соединению, прибудет слишком поздно. Если же этот параметр сделать слишком большим, у вас могут закончиться соединения TCP, поскольку все они будут находиться в состоянии TIME_WAIT. В идеальном варианте нужно ждать ровно столько, чтобы не было уже никакой возможности получить задержавшиеся сегменты TCP с прошлого сеанса связи. Вполне приемлемое начальное значение для этого параметра — 60 с, и именно оно используется по умолчанию в системе BSD: # /usr/sbin/ndd -set /dev/tcp tcp_c1ose_wait_interval 60000 Период завершения Период завершения определяет количество повторных передач до разрыва соединения. После того как отправитель решает разорвать соединение, он отправляет завершающий сегмент RST По умолчанию значение этого параметра в системе Solaris установлено равным 7 200 000 мс, или 2 ч, в соответствии с рекомендациями документа RFC 1122. Для загруженных веб-серверов это слишком много, поскольку клиенты могут часто исчезать без уведомления, а вам невыгодно оставлять за ними неиспользуемые ресурсы. Для таких систем гораздо больше подойдет значение 60 000 мс A мин): # /usr/sbin/ndd -set /dev/tcp tcp_ip_abort_interval 60000 Время жизни сегмента и скорость обработки соединений Еще один параметр TCP, называемый максимальным временем жизни сегмента (Maximum Segment Lifetime — MSL), ограничивает количество новых соединений, которые могут быть установлены сервером за 1 с. Например, при MSL, равном 120 с, мы не можем создать новое соединение между одними и теми же сервером и клиентом (которые задаются IP-адресами и номерами портов), прежде чем с момента завершения предыдущего соединения пройдут 120 с. Всего существует 65 536 портов, но 1024 зарезервированы за привилегированным пользо-
вателем. Это означает, что максимальное количество новых соединений в секунду составляет F5 536 - 1024) / 120 с = 538, если сервер закрывает соединения со своей стороны. Какой это тон? Нота «ля» первой октавы соответствует частоте 440 Гц, так что 538 Гц — это, наверное, что-то вроде «до диез». Однако можно поднять частоту установки новых соединений до 64 512 в секунду Интервал проверки жизнеспособности Протокол TCP поддерживает параметр проверки жизнеспособности соединения, не имеющий никакого отношения к постоянным соединениям HTTP 1.1 (оба понятия объединяет общее название keepalive). Соединения TCP не передают никаких данных, пока одной из сторон не потребуется что-либо передать другой стороне, поэтому «молчащее» соединение не использует сетевых ресурсов. То есть одна из сторон может отключиться, а вторая не узнает об этом до тех пор, пока не попробует что-нибудь отправить. Для веб-клиентов подобный тип соединения не создает проблем, но для серверов, продолжающих выделять ресурсы под буферы для соединений, которые не существуют, это серьезная проблема. Клиенты часто отключаются от сети без всякого предупреждения, поскольку пользователь может просто выключить модем или компьютер, и сервер элементарно выйдет из строя из-за недостатка памяти, если будет ждать поступления данных от этих пользователей. В принципе, за проверку жизнеспособности соединений может отвечать вебсервер, но в большинстве реализаций TCP есть специальный параметр, обеспечивающий автоматическую проверку доступности собеседника через регулярные промежутки времени. Интервал по умолчанию составляет от двух до восьми часов, но для загруженного веб-сервера он должен быть уменьшен до максимального промежутка времени, в течение которого пользователь но каким-то причинам может поддерживать открытым неиспользуемое соединение. Если сделать это значение слишком маленьким, оно может затруднить управление системами по протоколу Telnet, потому что сеансы связи будут закрываться даже при небольших паузах. Если netstat показывает, что большое количество соединений находится в состоянии FIN_WAIT_2, — значит, клиенты некорректно завершают свои соединения. Попробуйте уменьшить период проверки жизнеспособности, чтобы справиться с этим. Обсуждение вопросов, связанных с FIN_WAIT_2, вы можете найти на сайте http://www.apache.org/. Судя по всему, клиенты, отключающиеся по тайм- ауту HTTP 1.1 KeepAliveTimeout, могут не закрывать соединение корректно. Пять минут — вполне разумное значение периода проверки жизнеспособности для загруженного веб-сервера: # /usr/sbin/ndd -set /dev/tcp tcpkeepaliveinterval 300000 Окно приема Окно приема TCP известно также под названиями RW1N (Receive WINdow) и Rx Window. Окно приема — это количество данных, которые могут находиться в пути без подтверждения приема. Размер окна сообщается получателем отправителю. Он ограничивает количество сегментов TCP, которые могут быть от-
правлены в любой конкретный момент времени, и, следовательно, ограничивает пропускную способность линии размером окна, деленным на время путешествия пакета от одного компьютера к другому и обратно (RTT). Увеличить пропускную способность можно, увеличив размер окна или уменьшив время передачи пакетов. Стандартное значение размера окна приема составляет 32 Кбайт, поэтому сервер не может отправить более 32 Кбайт данных без получения уведомления о приеме хотя бы части этих данных. Таким образом, медленный приемник TCP (веб-клиент) может взаимодействовать с быстрым отправителем TCP (веб-сервером). Это, по сути, механизм управления потоком. С каждым уведомлением получатель отправляет количество данных, которые могут быть приняты на данный момент. Эта величина называется предлагаемым окном, и оно на величину окна приемника меньше, чем количество данных, которые должны быть считаны приемником из буфера его сокета. Размер предлагаемого окна всегда меньше либо равен размеру окна приемника. Приемный буфер сокета будет равен по величине размеру окна приемника, поэтому клиент всегда сможет принять данные, находящиеся в пути, сколько бы их там ни было, даже если приложение будет занято и не сможет считать данные из приемного буфера. Окно приемника должно быть достаточно большим, чтобы в пути находилось ровно столько данных, сколько может быть обработано приемником. Полный объем линии передачи легко вычислить как произведение пропускной способности на время ожидания. Например, если время передачи пакета туда и обратно для вашего модема на 56 кбит/с составляет 200 мс, то объем линии составляет E6000 бит/с /10 бит на байт с учетом накладных расходов) х 200 мс = * 1120 байт. Поэтому окно приемника должно быть равно 1120 байт. Если время ожидания для вашего Ethernet на 10 Мбит/с составляет 5 мс, то объем линии составит 6250 байт, и таким же должно быть сделано окно приемника. Слишком большое окно ухудшает производительность. Провайдеры могут выделить на своих маршрутизаторах для каждого входящего подключения буфер фиксированного размера. Если ваше окно превысит размер такого буфера, отправитель может переполнить его прежде, чем вы опустошите этот буфер через свой модем. Все лишние данные будут утеряны, и их придется передавать повторно. Разумно устанавливать размер окна приемника кратным максимальному размеру сегмента TCP (Maximum Segment Size — MSS), чтобы большие потоки данных могли удобно помещаться в буфер без фрагментации. Попробуйте сделать окно приемника в 4 или 8 раз большим, чем максимальный размер сегмента. Размер окна приемника ограничен размером приемного буфера сокета. Приложения могут запрашивать увеличение буфера сокета у операционной системы вызовом setsockopt(), но нет никаких гарантий, что операционная система пойдет на это увеличение. В операционной системе размер буфера сокета может быть задан жестко. Если вы работаете в основном с сайтами, подключенными к одному и тому же провайдеру, используйте значение максимального передаваемого блока этого провайдера для максимальной эффективности.
У протокола TCP есть интересный недостаток. При достаточно долгом и быстром соединении 31-разрядные последовательные номера пакетов могут достичь максимального значения и вернуться к нулю, прежде чем адресат уведомит о получении первого сегмента. После этого все подтверждения станут неоднозначными, так как они могут относиться не только к первому, но и ко второму сегменту с тем же порядковым номером. Проблема решается применением алгоритма PAWS (Protection Against Wrapped Sequence Numbers), но не все реализации TCP используют этот алгоритм. Отложенное подтверждение Некоторые реализации TCP специально задерживают отправку подтверждения, потому что такая задержка дает приложению шанс подготовить и выслать ответ на запрос собеседника вместе с сегментом АСК. Например, подтверждение получения запроса HTTP может быть отложено до тех пор, пока веб-сервер не отправит свой ответ на этот запрос. Тогда сегмент АСК будет отправлен в том же пакете, что и ответ веб-сервера. Это уменьшает количество пакетов, отправляемых сервером, но может замедлить его ответ. Я оставляю время ожидания равным 50 мс, — значению, предлагаемому системой Solaris по умолчанию. Соответствующий параметр ndd называется tcp_defered_ackjnterval. Медленный старт Некоторые рекомендуют отключать алгоритм медленного старта, используемый в процессе управления потоком на стороне отправителя. Согласно алгоритму медленного начала, отправитель посылает только один сегмент TCP (и, следовательно, только один IP-пакет) и ждет его подтверждения получателем. Если первый сегмент будет благополучно подтвержден, отправитель пошлет два сегмента и будет ждать теперь уже их подтверждения. После этого будут отправлены четыре сегмента и так далее — до тех пор, пока не будет достигнут размер окна отправителя, указывающий, сколько данных может быть отправлено до получения подтверждения. Таким образом, количество данных в сети гарантированно не превышает возможностей приемника по их обработке. Подробнее об этом алгоритме рассказывается в документе RFC 2001. Одна из проблем, связанных с использованием алгоритма медленного начала при работе с веб, заключается в том, что соединения TCP с веб-серверами устанавливаются часто и существуют недолго. Алгоритм медленного старта приводит к потере времени, пока компьютер пытается определить оптимальную скорость передачи для соединения, которое все равно будет закрыто очень скоро, хотя этот алгоритм, в принципе, может быть полезен при передаче больших объемов информации по медленным каналам. Более серьезный недостаток алгоритма медленного старта связан с тем, что стек TCP/IP-клиентов, работающих под управлением Windows, предполагает, что сервер, согласно алгоритму медленного начала, вышлет два пакета, а не один. Это не вполне корректное поведение, но большая часть серверов Unix адаптировались к нему, за исключением Solaris 2.6, который по умолчанию высылал один пакет и ждал его подтверждения. Клиенты Windows, обращавшиеся к таким серверам, получали первый пакет и молча ждали второго, который ни-
когда не приходил. У клиента заканчивалось время ожидания, и он отправлял АСК-сегмент для первого пакета, из-за чего в конфигурации по умолчанию возникала значительная задержка. Эта задержка имела место для каждого ТСР-со- единения, то есть для каждого изображения или любого другого компонента веб-страницы, если только не использовались постоянные соединения HTTP 1.1. Постоянные паузы могут более чем удвоить время загрузки страницы. Выход состоит в том, чтобы сказать системе Solaris 2.6 (или Solaris 2.5.1 с установленными пакетами обновления TCP), чтобы та начинала передачу по TCP с двух пакетов, а не с одного: # /usr/sbin/ndd -set /dev/tcp tcpslowstartinitial 2 Серверы BSD и Windows по умолчанию отправляют два пакета без получения уведомлений, поэтому для них не требуется никаких изменений в конфигурации. Solaris 2.7 и более поздние его версии также начинают с двух пакетов, да и спецификация TCP уже изменилась и разрешает отправку двух пакетов. Еще одна проблема алгоритма медленного старта связана с тем, что окно отправки в большинстве реализаций TCP ограничено значением 64 Кбайт. Его очень легко превысить на Ethernet со 100 Мбит/с. Если у такой линии время ожидания составляет 10 мс, то в пути могло бы находиться 125 Кбайт данных. Документ RFC 1323 TCP Large Window Extensions (увеличенный размер окна TCP) позволяет увеличить окно отправки при работе с клиентами, и это новшество было реализовано в Solaris 2.6. Установить максимальный размер окна отправителя в системе Solaris можно командой # /usr/sbin/ndd -set /dev/tcp tcpcwndjnax 100000 Максимальный размер сегмента Максимальным размером сегмента (Maximum Segment Size — MSS) называется величина самого большого сегмента TCP, который может быть передан по определенному соединению. Он объявляется стороной, запрашивающей об установлении соединения. Отправитель может посылать сегменты произвольного размера, не превышающего, однако, величины MSS. Этот параметр должен быть достаточно маленьким, чтобы избежать фрагментации на уровне IP, и в то же время достаточно большим, чтобы накладные расходы на передачу заголовков были малы по сравнению с размером полезных данных (IP-пакета). Во многих реализациях TCP по умолчанию величина MSS составляет 536 байт, что вполне приемлемо для веб-серверов. В системе Solaris по умолчанию используется алгоритм определения максимального передаваемого блока для каждого из маршрутов. Узнать установленное по умолчанию значение можно с помощью приведенной ниже команды: # ndd -get /dev/tcp tcpjnssdef Вы можете выводить и изменять значения параметров tcpjnssjnax и tcp_mss_min. Гораздо более подробно параметры TCP в системе Solaris разобраны на замечательной веб-странице Йенса С. Веклера по адресу: http://www.rvs.uni-hanno- ver.de/people/voeckler/tune/EN/tune.html.
Контроль TCP О контроле состояния сетей было написано множество книг, поэтому я не буду пытаться воспроизвести здесь их содержимое. Вне зависимости от того, какие именно средства вы используете для контроля TCP, всегда нужно следить за несколькими важными параметрами. Ошибки входящих пакетов могут быть вызваны множеством причин. Например, дело может быть в том, что ваш кабель слишком длинный, что он поврежден или просто неправильного типа. Может быть, просто разъем на сетевом адаптере плохо воткнут. Ошибки могут быть связаны с проблемами сетевого характера, а могут быть вызваны лишь переполнением буфера драйвера сетевого адаптера. Ошибки исходящих пакетов могут быть связаны с повреждением разъема сетевой карты либо с отсутствием ответов из сети. Вы можете определить, часто ли вам приходится повторно передавать пакеты из-за истечения времени ожидания. Сравните количество отправленных сегментов с количеством повторно переданных сегментов или количество отправленных байтов с количеством повторно переданных байтов. Если вам постоянно приходится передавать данные повторно, попробуйте увеличить интервал повторной передачи TCP. Если вы не будете вовремя отвечать серверу, он станет отправлять сегменты в вашу сторону повторно, что приведет к возникновению непринятых сегментов TCP или пауз для ресинхронизации. Следите за количеством сброшенных пакетов. Большое их количество свидетельствует о том, что у вас регулярно случаются переполнения буферов, которых можно избежать, увеличив размеры этих буферов. Ниже перечислено несколько хорошо известных программ для контроля состояния сети. О netstat — это стандартная программа Unix, используемая для контроля сетевых соединений. Команда man netstat снабдит вас подробными сведениями об этой программе, netstat обычно доступна всем пользователям, а не только привилегированным, netstat -а показывает информацию обо всех текущих соединениях вашего компьютера, netstat выводит статистику производительности сети, такую как количество переполнений буферов и число сброшенных пакетов. В Linux та же информация содержится в каталоге /proc/net/dev. В Windows NT есть своя версия программы netstat с тем же именем. О snoop — это утилита, доступная в системе Solaris. Она переводит карту Ethernet в смешанный режим, после чего та начинает перехватывать все пакеты, передаваемые в данном сегменте Ethernet. Чтобы использовать эту программу, нужно обладать правами привилегированного пользователя. Она очень полезна для изучения содержимого передаваемых по сети пакетов, но по умолчанию выводит слишком много данных. У команды snoop есть множество параметров, обеспечивающих фильтрацию и вывод данных. В главе 14 приведен пример результатов работы программы snoop. О tcpdump — еще одна программа для Unix, использующая смешанный режим работы карт Ethernet, но в отличие от snoop она не выводит содержимое каждого пакета. Программа tcpdump входит в комплект поставки Red Hat Linux (/usr/sbin/tcpdump), но отсутствует в системе Solaris. Кроме того, имеется возможность изучить ее исходный код.
Ниже приведен пример слегка измененного вывода команды tcpdump. Я обратился к веб-странице, которая уже находилась в кэше браузера, и сервер ответил, что страница со времени моего последнего посещения не изменялась. # tcpdump Kernel filter, protocol ALL. datagram packet socket tcpdump: listening on all devices 08:36:12.195549 browser.1026 > server.www: S 3311753430:3311753430@) win 31072 <mss 3884.sackOK.timestamp 2712118 O.nop.wscale 0> (DF) 08:36:12.195681 browser.www > server.1026: S 3305435973:3305435973@) ack 3311753431 win 31072 <mss 3884.sackOK.timestamp 2712118 2712118.nop.wscale 0> ( DF) 08:36:12.195738 browser.1026 > server.www: . 1:1@) ack 1 win 31072 <nop.nop.tim estamp 2712118 2712118> (DF) 08:36:12.217507 browser.1026 > server.www: P 1:342C41) ack 1 win 31072 <nop.nop .timestamp 2712120 2712118> (DF) 08:36:12.217604 browser.www > server.1026: . 1:1@) ack 342 win 30731 <nop.nop.t imestamp 2712120 2712120> (DF) 08:36:12.220354 browser.www > server.1026: P 1:198A97) ack 342 win 31072 <nop.n op.timestamp 2712120 2712120> (DF) 08:36:12.220431 browser.1026 > server.www: . 342:342@) ack 198 win 30875 <nop.n op.timestamp 2712120 2712120> (DF) 08:36:28.893523 browser.www > server.1026: F 198:198@) ack 342 win 31072 <nop.n op.timestamp 2713788 2712120> (DF) 08:36:28.893637 browser.1026 > server.www: . 342:342@) ack 199 win 31072 <nop.n op.timestamp 2713788 2713788> (DF) Кое на что здесь следует обратить особое внимание. В начале каждой строки выводится отметка времени. Заметьте, что браузер использует большое случайное число в качестве номера порта для подключения к стандартному порту сервера (80 — www here). Ясно виден процесс установки соединения TCP (трех- этапное рукопожатие), а также 16-секундная задержка перед закрытием постоянного соединения HTTP 1.1. Существуют аналогичные бесплатные средства, такие как aps — расширенный перехватчик пакетов, разработанный для системы Linux и предназначенный для отображения содержимого передаваемых по сети пакетов. Т/ТСР В будущем может возрасти пропускная способность, но время ожидания не улучшится, поскольку скорость света увеличить невозможно. Мы уже практически добрались до минимально возможного времени ожидания. Вы можете убедиться в этом самостоятельно, проверив время обращения к серверу, расположенному далеко от вас, и сравнив результат со временем, которое потребовалось бы световому лучу на путешествие туда и обратно. Поскольку время ожидания на больших расстояниях уменьшено быть не может, важно попытаться уменьшить количество передач пакетов в процессе установки соединения TCP Именно этой цели служит протокол TCP для транзакций (Transaction TCP — Т/ТСР). Установка соединения и отправка первого сегмента данных выполняются, согласно этому протоколу, одним пакетом. Реально это может значительно ускорить получение веб-страницы клиентом.
Проблема в том, что далеко не все серверы и еще меньшая доля клиентов понимают протокол Т/ТСР. Некоторые клиенты могут быть «сбиты с толку», получив данные и сегменты, устанавливающие соединение, в одном пакете. Это может даже вывести их из строя. Кроме того, серверы, поддерживающие протокол Т/ТСР, не смогут эффективно защищаться от атак типа «отказ в обслуживании». Судя по всему, серверы http://www.yahoo.com/ поддерживают Т/ТСР, но у меня еще не было возможности это проверить. Пробная реализация Т/ТСР включена в BSD Unix. UDP Протокол пользовательских дейтаграмм (User Datagram Protocol — UDP) — это протокол транспортного уровня, работающий поверх IP аналогично TCP, но в отличие от него не устанавливающий надежных соединений. UDP, однако, обладает более высокой производительностью по сравнению с TCP, поскольку не «перетруждает» себя ненужной работой. Он очень полезен в тех случаях, когда надежность может обеспечиваться приложением (то есть приложение само может потребовать повторную передачу недостающих пакетов), либо в тех, где надежность не так важна, как скорость, — например, при передаче аудио- и видеопотоков в Интернете. Службы DNS, NFS и протокол RealAudio основаны именно на UDP. DNS Служба доменных имен (Domain Name Service — DNS) использует протокол UDP. Она преобразует полные доменные имена (fully qualified domain name — FQDN), такие как www.umich.edu., в IP-адреса A41.211.144.53). Эта служба совершенно необходима для веб, поскольку обращение к большинству сайтов осуществляется именно по их именам — как при вводе этих имен с клавиатуры, так и при указании ссылок на веб-страницах. Малоизвестно, что корневой домен содержит в своем названии одну точку (.), поэтому технически все полные доменные имена должны заканчиваться точкой. На практике эту точку подразумевают, но не пишут нигде, за исключением конфигурационных файлов DNS. Главный совет по повышению производительности DNS таков: использовать службу не обязательно. Если служба DNS кажется вам слишком медленной, используйте в своих HTML-страницах IP-адреса вместо доменных имен, чтобы браузеру не приходилось тратить время на поиск IP-адресов. Пользователи могут несколько смутиться, увидев в поле Location своего браузера IP-адрес, а не привычное доменное имя узла, но заголовок веб-страницы должен помочь им сориентироваться. Вспомните также, что пользователи вовсе не видят URL изображений, разве что при просмотре исходного кода HTML-страниц. Опасность использования IP-адресов заключается в том, что файлы cookie обычно связываются с конкретным доменом и не будут отсылаться браузером серверу, если последний не будет принадлежать к этому домену. При использовании IP-адресов вместо имен DNS файлы cookie могут вовсе перестать работать.
Система DNS представляет собой иерархическую распределенную базу данных. Если ваш местный DNS-сервер не знает адреса, который вы ищете, он запрашивает следующий сервер в иерархии этой службы. Поиск редко используемого имени иногда занимает несколько секунд, поскольку запрос может передаваться вверх и вниз по иерархической лестнице несколько раз. Пользователи могут пользоваться полными доменными именами без сервера DNS, используя старый и примитивный метод установки соответствия между доменными именами и адресами — файлы hosts (/etc/hosts или WINDOWS/hosts). Это делает поиск очень быстрым, но лишает вас возможности пользоваться динамическим обновлением и считается дурным тоном среди системных администраторов. Пользоваться файлом /etc/hosts можно только в отношении тех адресов, которым вы доверяете. Вот пример файла /etc/hosts с компьютера, работающего под управлением Linux: # hosts This file describes a number of hostname-to-address # mappings for the TCP/IP subsystem. It is mostly # used at boot time, when no name servers are running. # On small systems, this file can be used instead of a # "named" name server. Just add the names, addresses # and any aliases to this file... 127.0.0.1 localhost 141.211.144.53 www.umich.edu Пользователи Unix легко могут установить на своих компьютерах-клиентах собственные DNS-серверы. Преимущество такого подхода в том, что серверы будут кэшировать ответы на сделанные запросы, что значительно ускорит обработку последующих запросов. Программа Netscape Navigator DNS helper также обеспечивает автоматическое кэширование записей DNS. Хотя DNS-серверы обычно не бывают сильно загружены, убедитесь, что ваш DNS-сервер и веб-сервер не соревнуются за пропускную способность подключения к Интернету. Для этого можно попробовать поместить DNS-сервер внутри вашей организации, а не полагаться на сервер вашего провайдера. Учтите, что производительность DNS-серверов, как и большинства других типов серверов Интернета, надает нелинейно, то есть становится практически нулевой при превышении определенной нагрузки. Клиенты под управлением Unix и Windows взаимодействуют с круговой системой DNS существенно различным образом. Unix обращается к DNS каждый раз, a DOS и Windows делают один запрос и кэшируют ответ на него (один IP-адрес). Это означает, что результаты тестирования могут различаться для разных клиентов, если один из двух веб-серверов, входящих в круговую систему DNS, выйдет из строя. Клиенты под управлением Windows могут создать у вас ошибочное впечатление, что оба сервера не работают или оба в порядке, тогда как клиенты под управлением Unix будут соединяться с серверами случайным образом. В системе Solaris имеется универсальный демон кэширования имен (Name Service Cache Daemon). Статистику его использования можно вывести с помощью команды nscd -д. Вы можете управлять временем жизни (Time To Live) каждого из его кэшей, а также вовсе отключить кэширование.
NFS Сетевая файловая система (Network File System — NFS), предложенная компанией Sun Microsystems, — это средство, позволяющее работать с файлами удаленной системы так, как если бы они были расположены на локальном жестком диске. Удаленная система может располагаться в любой части света, но NFS чаще используется в локальных сетях, поскольку производительность NFS в глобальных сетях обычно недостаточна. NFS является протоколом без сохранения информации о состоянии. NFS версии 2 работает поверх UDP, а версии 3 — поверх TCP (по умолчанию, хотя все еще сохраняется возможность перейти на UDP). Хорошо настроенный сервер NFS может обеспечивать гораздо большую пропускную способность, чем большинство веб-серверов с тем же аппаратным обеспечением. Поэтому сервер NFS используется для масштабирования веб-серверов, особенно тех, которые поставляют в основном статическое содержимое. Вы можете настроить несколько веб-серверов и подключить их к одному централизованному серверу NFS, чтобы не заботиться о синхронизации между ними. Для NFS существует механизм кэширования, который называется cachefs. Этот механизм сохраняет локальную копию файлов, запрашиваемых по NFS, и тем самым значительно увеличивает быстроту чтения при повторных запросах. Производительность записи в системе NFS гораздо ниже, поскольку, в соответствии с протоколом, запись обязательно должна производиться на энергонезависимый носитель, такой как жесткий диск. Учтите, что получение списка каталогов требует обращения к NFS, поэтому поиск по большому дереву каталогов требует много времени. Большое количество обращений к NFS может заметно ухудшить производительность веб-сервера. Не следует, к примеру, размещать журнал вашего вебсервера в системе NFS, поскольку журнал будет считываться с сервера NFS, дополняться и записываться обратно каждый раз при обращении пользователей к серверу. Мне лично пришлось столкнуться с аналогичной проблемой при записи сообщений в мой почтовый ящик (файл mbox), расположенный на сервере NFS. Я обнаружил, что по мере роста почтового ящика скорость добавления сообщений постоянно уменьшалась. С помощью snoop я выяснил, что большая часть почтового ящика копировалась на мой компьютер, изменялась на нем и копировалась обратно. Решение (в данном случае не единственное) заключалось в том, что я превратил файл mbox в своем домашнем каталоге в символьную ссылку на /opt/mbox, который располагался уже на моем жестком диске. Проблемы с производительностью исчезли, но почтовый ящик, расположенный на локальном жестком диске, больше не архивировался по расписанию администратором системы. HTTP Протокол передачи гипертекста (HyperText Transfer Protocol — HTTP) лежит и самой основе веб. Он был создан в Швейцарском исследовательском институ-
те CERN человеком по имени Тим Бернерс-Ли и изначально был предназначен для обмена научными документами. Протокол был создан простым и модифицируемым, но предназначался для доставки статического содержимого, что является одной из причин его недостаточной эффективности в качестве протокола для обработки транзакций. Протокол HTTP действительно прост: клиент запрашивает документ, сервер возвращает его, после чего соединение закрывается. Изначально этим все и ограничивалось. Хотя установка соединения и разрыв его создавали значительные накладные расходы, в те времена это не стало проблемой, поскольку большинство веб-серверов не были достаточно загружены, чтобы веб-мастеры начали волноваться о производительности. HTTP работал хорошо. Протокол HTTP разрабатывался для передачи страниц языка разметки гипертекста (HyperText Markup Language — HTML), но ничто в спецификации HTTP не ограничивало тип передаваемых данных. Этот протокол может использоваться для передачи документов любого типа. Позднее в заголовки, создаваемые веб-серверами, была добавлена типизация MIME, позволявшая клиенту принимать решения о том, как именно ему следует обработать данный документ. Протоколу HTTP был довольно быстро присвоен хорошо известный порт 80, что избавило пользователей от необходимости указывать номер порта в URL-адресах и зарезервировало для протокола HTTP место в файлах /etc/services на Unix-серверах по всему миру. Следует различать просмотр страницы в браузере и обращение к серверу по протоколу HTTP (хит). С точки зрения пользователя, он просто загружает страницу, скачивая текст, изображения и, возможно, апплет или аудиоклип. Процесс загрузки кажется единым. С точки зрения сервера, никто не запрашивает «страницу целиком»: вместо этого на сервер поступает последовательность запросом на текст HTML-страницы, на изображения, на апплет и на клип. Сервер «но знает» о том, что в первом запрошенном файле (HTML-странице) были ссылки на те файлы, которые были загружены позже. Обслуживая множество клиентом одновременно, он имеет дело с перекрывающимися во времени запросами. Операция отправки клиенту файла в ответ на его запрос называется HTTP-операцией или просто хитом. Без соединения и сохранения состояния Протокол HTTP не сохраняет информацию о состоянии, то есть не предусматривает наличия какой-либо памяти о том, что клиент и сервер делали в про« шлом. Не существует набора возможных состояний для клиента и сервера HTTP также называют протоколом, не ориентированным на установку соединения, поскольку между клиентом и сервером не устанавливается постоянного со единения (по крайней мере, не устанавливалось до появления HTTP 1.1). С точки зрения сервера, запрос пользователя всегда выглядит так, как если бы это! пользователь обращался к серверу впервые. Сервер устанавливает новое соеди нение и возвращает запрошенную страницу. Эта особенность позволяет избе
жать усложнения протокола HTTP, а простота протокола ведет к быстрой его реализации на всех компьютерах, поддерживающих стек TCP/IP. Протоколы без сохранения информации о состоянии не подходят к традиционной архитектуре «клиент—сервер», где клиент открывает соединение с базой данных (двухъярусная схема) или сервером приложений (трехъярусная схема), а сервер поддерживает соединение открытым до тех пор, пока клиент не произведет явного отключения. Пользователь в архитектуре «клиент—сервер» может находиться в различных состояниях: вошел в систему, прошел проверку, редактирует документ и так далее. Сохранение информации о состоянии является обязательным для множества сложных операций, таких как проверка подлинности и обработка транзакций. Хотя сам протокол HTTP и не поддерживает сохранения информации о состоянии, эта функциональность вместе с постоянными соединениями (как, впрочем, и без них) может обеспечиваться дополнительным программным обеспечением, написанным с использованием CGI, Java или CORBA. Механизм сохранения информации о состоянии может быть основан на передаче файлов cookie между браузером и сервером, ведении журналов на сервере и индексации по IP-адресу и cookie клиента — либо же на прямых соединениях через сокеты или других технологиях. Несохранение информации о состоянии имеет положительный побочный эффект, заключающийся в том, что HTTP проще масштабировать, чем систему с архитектурой «клиент—сервер». Когда клиент отключен (а с точки зрения сервера, он отключен практически всегда), серверу не нужно отводить этому клиенту никаких сетевых ресурсов. Это означает, что один сервер HTTP может обслуживать гораздо больше клиентов, чем сервер, поддерживающий со своими клиентами длительные соединения. Несмотря на то, что сам протокол HTTP не ориентирован на установку соединения, отдельные операции HTTP производятся поверх протокола TCP, который поддерживает сохранение информации о состоянии, чтобы обеспечить доставку и корректную сборку в единое целое всех передаваемых пакетов. Установка соединения TCP, называемая трехэтапным рукопожатием, создает серьезные накладные расходы для операции HTTP (как, впрочем, и разрыв соединения TCP). Подробное описание протокола TCP и его производительности вы найдете в одном из предыдущих разделов этой главы, который называется «TCP». Этот протокол действительно может снижать общую производительность системы из-за того, что рукопожатие приходится осуществлять для каждого передаваемого файла: для самой HTML-страницы, для всех изображений с :>той страницы, а также для апплетов и прочих файлов. Возможно, разумнее Г»ыло в качестве основы для HTTP использовать протокол UDP, который не требует никакой инициализации соединения, а проверку правильности приема пакетов переложить на плечи приложения, но история пошла другим путем. Асимметричный Стоит обратить внимание на резкую асимметричность трансферов HTTP. В одну сторону передается очень маленький запрос (десятки или сотни байт),
а в другую — ответ, имеющий обычно гораздо большие размеры. Поэтому отправка данных сервером имеет значительно больше шансов стать «узким местом», чем их прием. Несмотря на то, что данных в одном направлении передается намного больше, чем в другом, количество пакетов, идущих в обе стороны, одинаково, потому что клиенту требуется подтверждать все принимаемые пакеты сегментами TCP ACK. Основан на тексте Протокол HTTP основан на передаче текстовых команд, поэтому вы можете взаимодействовать с веб-сервером, подключившись к порту сервера по протоколу Telnet и вводя команды HTTP с клавиатуры: % telnet www.umich.edu 80 Trying 141.211.144.53... Connected to www.umich.edu. Escape character is ,A]' GET / HTTP/1.0 HTTP/1.1 200 OK Date: Sun. 08 Feb 1998 18:35:25 GMT Server: Apache/1.2.5 Connection: close Content-Type: text/html <html> Посмотреть аналогичным образом, что будет передавать браузер, несколько сложнее, поскольку именно браузер должен сделать первый ход. Вы не можете просто подключиться к браузеру какого-то пользователя и начать отдавать ему команды. Однако вы в состоянии написать небольшую программу-сервер, которая будет принимать запросы браузера и пересылать их ему обратно. Это позволит вам подробно изучить отправляемую браузером информацию. В листинге 15.3 приведена программа-сервер, написанная на языке Java. Листинг 15.3. Эхо-сервер HTTP, написанный на языке Java // прослушиваемый порт задается в качестве // аргумента командной строки, например: Java EchoServer 8080 import java.io.*; import java.net.*: class EchoServer { public static void main(String[] args) { try { byte buf[] - new byte[1024]: int Ten: Socket s; String replyHeader - "HTTP/1.0 200 0K\r\n" + "Content-type: text/p1ain\r\n\r\n": ServerSocket ss - new ServerSocket(new lnteger(args[0]).intValue( )):
while (true) { s * ss.accept( ); BufferedlnputStream bis - new BufferedInputStream(s.getInputStream( )): BufferedOutputStream bos * new Bu fferedOutputStream(s.getOutputStream( )): len = bis.read(buf): // получение запроса bos.write(replyHeader.getBytes(). 0. replyHeader.length( )); bos.write(buf. 0. len): bos.close( ): bis.close( ): } } catch (Exception e) { System.out.println(e): } } } Скомпилируем эту программу и запустим ее: % javac EchoServer.java % java EchoServer 8888 Теперь попробуйте с помощью Netscape получить документ с веб-сервера по адресу: http://localhost:8888/ — и увидите, как ваш собственный запрос будет направлен обратно браузеру: GET / HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.51 [en] (Xll: I: Linux 2.2.5-15 1686) Host: local host:8888 Accept: image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. image/png. */* Accept-Encoding: gzip Accept-Language: en Accept-Charset: iso-8859-l.*.utf-8 Тот же самый запрос, сделанный с помощью Internet Explorer, будет выглядеть следующим образом: GET / HTTP/1.1 Accept: application/vnd.ms-excel. application/msword. application/vnd.ms-powerpoint. image/gif. image/x-xbitmap. image/jpeg. image/pjpeg. */* Accept-Language: en-us Accept-Encoding: gzip. deflate User-Agent: Mozilla/4.0 (compatible: MSIE 4.01: Windows NT) Host: local host:8888 Connection: Keep-Alive Изучив этот запрос, вы увидите несколько пар «имя—значение», отправляемых браузером. Обратите также внимание на заголовок Connection: Keep-Alive, ко- горый позволяет сохранить соединение TCP открытым для получения не только самой страницы, но и всех встроенных изображений и прочих объектов.
Сохранение соединения подразумевается в HTTP 1.1 по умолчанию, а в HTTP 1.0 оно требует использования заголовка Connection: Keep-Alive. Обратите внимание, наконец, на тот факт, что браузер Netscape 4.51 способен принимать файлы, сжатые gzip, a Netscape 4.04 — нет. Сжатие Одной из интересных, с точки зрения производительности, пар «имя—значение», отправляемых браузером, является пара, определяющая используемый тип сжатия. На данный момент не существует никакого общепринятого стандарта, определяющего формат сжатия веб-документов, но большая часть веб-серверов способна добавить в заголовок пару «имя—значение» Content-encoding: gzip, указывающую браузерам на то, что документы отправляются в gzip-сжатом формате, а браузеры, в свою очередь, умеют декодировать документы, сжатые gzip. Помните, что не все файлы хорошо сжимаются (иначе вы могли бы сжать любой файл до размера в 1 бит), поэтому иногда не следует тратить ресурсы на сжатие и распаковку веб-страницы. Кабельное управление Еще одна пара «имя—значение», которая может повысить производительность, — это заголовок if-modified-since, указывающий серверу, что он должен возвращать документ только в том случае, если последний был изменен с момента, отмеченного в заголовке. Аналогичного эффекта можно достичь с помощью команды HTTP HEAD, но она может потребовать установки двух соединений с сервером — одного для получения заголовка документа и еще одного для загрузки собственно документа, если копия, хранящаяся в кэше, устареет. Заголовок if-modified-since подразумевает отправку ответа по тому же соединению, через которое был послан запрос с этим заголовком. Он автоматически добавляется в запросы браузера на получение всех документов, присутствующих в кэше. Сервер может отсылать в ответ заголовок expires, означающий, что страница будет автоматически сочтена устаревшей по истечении определенного срока. Для страниц с котировками акций применение этого заголовка разумно и оправданно, но многие используют его для того, чтобы получить побольше хитов на свои страницы с рекламой (за счет общественных сетей), поскольку невозможно учесть количество просмотров рекламных баннеров из кэшей браузеров. Завершающий слэш Адрес URL, указывающий на каталог, технически должен оканчиваться симво лом / (слэш), который говорит серверу о том, что этот URL указывает на ката лог, а не на файл. Тем не менее большинство пользователей не вводит этот слэш, заставляя сервер самостоятельно выяснять, что пользователю нужен файл, а не каталог. Серверы способны справиться с этой задачей, но им приходится тра тить время на поиск несуществующего файла, что замедляет их работу. Сервс ры могли бы отправлять клиенту список файлов в запрошенном каталоге, но вместо этого на практике клиенту отправляется страница с перенаправлением, что увеличивает сетевой трафик и задерживает получение нужной страницы
Серверу будет лучше, если пользователи будут вводить адреса вместе с завершающим символом /, поэтому если вы где-либо указываете адреса URL или включаете в свою страницу ссылки, делайте это в соответствии с требованиями синтаксиса: http://patrick.net/dir/. Например, сервер Apache 1.2.4 отвечает на запрос без символа / операцией перенаправления, отправляя клиенту введенный им адрес URL, но с добавленным символом /. Предположим, мы запросили с сервера patrick.net каталог dir, забыв добавить к его имени символ /. Вот что будет передано по сети: % telnet patrick.net 80 Trying 127.0.0.1... Connected to patrick.net. Escape character is ,A]". GET /dir HTTP/1.0 HTTP/1.1 301 Moved Permanently Date: Thu. 14 May 1998 03:41:58 GMT Server: Apache/1.2.4 Location: http://patnck.net/dir/ Connection: close Content-Type: text/html <HTML><HEAD> <T1TLE>301 Moved Permanently</TITLE> </HEAD><B0DY> <Hl>Moved Permanently</Hl> The document has moved <A HREF»"http://patrick.net/dir/">here</A>.<P> </B0DY></HTML> Connection closed by foreign host. Усовершенствования HTTP 1.1 Консорциум Всемирной Сети (World Wide Web Consortium — W3C) учел недостатки HTTP 1.0 ii опубликовал спецификацию HTTP 1.1 со множеством изменений, призванных повысить производительность этого протокола. Спецификация HTTP 1.1 доступна по адресу: http://www.jcs.ud.edu/pub/ietf/http/rfc2068.txt. Самым важным нововведением является поддержка постоянных соединений — использование одного соединения TCP для получения нескольких документов. Это позволяет экономить сетевые ресурсы, так как накладные расходы на установку и разрыв соединения TCP разделяются на несколько документов. Изучив строки заголовка запроса, отправленного браузером Netscape версии 1.0, вы лучше поймете принцип постоянных соединений, хотя эти соединения не записываются в журналах сервера как операции по протоколу HTTP 1.1. Тайм-аут постоянного соединения становится важным параметром оптимизации веб, особенно если множество ваших клиентов подключаются по медленным линиям, поскольку на каждое открытое соединение расходуются память и другие ресурсы. Когда значительное количество клиентов с медленными модемами подключается к серверу по протоколу HTTP 1.1, они одновременно создают такую большую нагрузку, что у вас может возникнуть желание сократить иремя до разрыва соединения при отсутствии активности. Узнать количество
открытых в данный момент соединений можно с помощью команды netstat, обработав ее вывод с помощью grep (на предмет наличия в строке слова ESTABLISHED), а затем подсчитав количество строк в выводе grep с помощью программы wc. Итак, команда для определения количества установленных соединений будет выглядеть следующим образом: netstat | grep ESTABLISHED | wc -1 Постоянные соединения работают только со статическим содержимым, но не со страницами, генерируемыми шлюзами CGI или серверным API. Протокол HTTP 1.1 допускает одновременную отправку клиентом нескольких запросов, то есть клиент может отправлять следующий запрос, не дожидаясь получения ответа на предыдущий. Это называется конвейерной обработкой. Протокол HTTP 1.0 требовал, чтобы очередной запрос по соединению TCP отправлялся только после завершения приема ответа на предыдущий. Браузеры обходили это ограничение, открывая несколько одновременных ТСР-соедине- ний с сервером, но больше им не придется этого делать. Новым протоколом разрешена загрузка диапазона байтов документа (раньше документы должны были загружаться только целиком). Загрузка диапазона байтов позволяет пользователям загрузить часть документа и решить, хотят ли они получить все остальное, а затем продолжить загрузку с того места, где она была прервана, без необходимости заново принимать начальную часть. Эта возможность оказывается очень полезной в тех случаях, когда передача прерывается из-за отказа сети. Наконец, HTTP 1.1 допускает проверку подлинности MD5, что позволяет проверять пароль на стороне клиента (а последнее не только оказывается быстрее, чем отправлять этот пароль для проверки на сервер, но и увеличивает степень защищенности пользователя, поскольку его пароли не пересылаются по сети открытым текстом). Короче говоря, если можете, переходите на HTTP 1.1. Он уже поддерживается серверами Apache и Netscape Enterprise Server 3.0. Internet Explorer 4.0 декларирует поддержку HTTP 1.1. Netscape Navigator 4.0 иг пользует HTTP 1.0, но с поддержкой некоторых функций HTTP 1.1, таких как постоянные соединения. Формат запросов к прокси-серверу HTTP Прокси-серверы HTTP принимают запросы в несколько ином формате. Поско льку браузер соединяется с прокси-сервером, а не с самим веб-сервером, он дол жен сообщить прокси-серверу, к какому веб-серверу нужно подключиться Поэтому вместо команды GET ... / НТТР/1.0 браузер выдает команду GET / http://server/index.html, а добавление строки с типом протокола оставляет прокси серверу. Загрузка диапазона байтов HTTP и HTML были созданы в институте CERN Тимом Бернерсом-Ли для об мена научными статьями. Никому и в голову не приходило, что можно запро сить несколько байтов из середины статьи, поэтому в изначальной специфика ции не было никакого механизма, позволявшего запрашивать и передавать
лишь часть веб-страницы, а браузеры не умели вставлять обновленные куски вкэшированные данные. Вы либо получали всю страницу целиком, либо не получали ничего. Эта схема работала достаточно хорошо, но довольно быстро стало ясно, что можно сэкономить значительную часть пропускной способности, добавив в HTTP механизм запроса конкретного диапазона байтов. В особенности это относится к динамическому содержимому. Обычно лишь часть динамической страницы изменяется в промежутке между двумя последовательными обращениями к ней. Например, изменяются данные, но не их оформление — как на странице с котировками акций. Пользователю важны числа, а не окружающие их картинки. Если бы вы могли загружать только данные, то вы порадовали бы пользователя возросшей быстротой отклика сервера и сэкономили бы пропускную способность своей и его линий. Существует несколько способов загрузить часть веб-страницы, но все они довольно неуклюжи и обладают серьезными недостатками. Например, можно заключить данные в небольшой фрейм, а затем регулярно обновлять этот фрейм с помощью тега HTML МЕТА refresh, однако при нажатии кнопки браузера Reload страница все равно будет загружаться целиком. Другой вариант — написать небольшой аинлет, который будет загружать данные, но тогда вам придется запускать виртуальную машину Java, на что уходит много времени, и все равно страница будет загружаться целиком при нажатии на кнопку браузера Reload. Умные люди в W3C (http://www.w3c.org/) знали об этой проблеме, поэтому они включили в HTTP 1.1 возможность загрузки части веб-страницы. Частичная загрузка называется также загрузкой диапазона байтов (byterange request). Серверы Apache поддерживают загрузку диапазона байтов, как и веб-серверы Netscape. Серверы, принимающие такие запросы, выдают в ответ заголовок Ас- cept-ranges: bytes, поэтому вы можете с помощью telnet и некоторых познаний в HTTP проверить, принимает ли ваш сервер такие заголовки. В приведенном ниже примере я вручную подключился к серверу Apache на моем собственном компьютере и запросил заголовок корневой веб-страницы: vahe* telnet local host 80 Trying 127.0.0.1... Connected to local host. Escape character is *"]'. HEAD / HTTP/1.1 Host: vahe HTTP/1.1 200 OK Date: Wed. 01 Aug 2001 17:17:23 GMT Server: Apache/1.3.9 (Unix) (Red Hat/Linux) Last-Modified: Mon. 30 Jul 2001 05:41:56 GMT ETag: 4802-86d-3b64f3a4" Accept-Ranges: bytes Content-Length: 2157 Content-Type: text/html Connection closed by foreign host.
Узнав, что частичная загрузка поддерживается, давайте попробуем проверить эту функцию и запросить несколько байтов из середины веб-страницы. Для этого в запрос добавляется заголовок Range: vahe* telnet local host 80 Trying 127.0.0.1... Connected to local host. Escape character is ,A]\ GET / HTTP/1.1 Host: vahe Range: bytes-1000-1008 HTTP/1.1 206 Partial Content Date: Tue. 31 Jul 2001 17:36:37 GMT Server: Apache/1.3.9 (Unix) (Red Hat/Linux) Last-Modified: Mon. 30 Jul 2001 05:41:56 GMT ETag: M54802-86d-3b64f3a4" Accept-Ranges: bytes Content-Length: 9 Content-Range: bytes 1000-1008/2157 Content-Type: text/html TTOM></a>Connection closed by foreign host. Мы запросили байты с 1000-го по 1008-й (то есть 9 байт, поскольку мы начали с нуля); их мы и получили: «ТТОМ></а>». Так что все работает отлично. А здорово получилось! Наш сервер может корректно обработать запрос на частичную загрузку страницы! Теперь попробуем выполнить аналогичный запрос из браузера. Х-м-м..! Браузеры такого делать пока не умеют. Можно написать апплет на Java, который будет выполнять соответствующий запрос, но этот запрос не будет интегрирован в HTML-страницу. В действительности у браузером сохранились кое-какие остаточные способности, но их недостаточно. Судя по всему, функции были добавлены много лет назад, но остались малоизвестными и не использовались. После долгих поисков и экспериментов мне удалось составить URL, который сработал в Netscape 4.61 в ОС Linux (обратите внимание на обязательный пробел перед точкой с запятой): http://1 оса1host/index.html :bytes«1000-1008 К сожалению, в браузере отобразились только эти байты. На самом деле я хотел получить кэшированную страницу, в которую были бы добавлены обном- ленные данные. После недолгих мучений мне удалось заставить сервер Apache отправить Netscape сообщение 206 Partial Content в ответ на корректный запрос браузера на получение диапазона байтов, но браузер все равно отобразил только эти байты. IE вовсе игнорирует сообщение 4206 Partial Content», если у нет в кэше уже есть веб-страница целиком, и не интерпретирует URL со словом «bytes*». Как видите, у нас имеются кое-какие возможности отправки запроса на диа пазон байтов, но мы все равно не можем интегрировать ответ сервера в кэширо ванную копию веб-страницы. Может быть, когда-нибудь появится простой стан дартный способ заставить браузер обновлять лишь небольшой диапазон байтом,
но на сегодняшний день такого способа нет. (А вот у тех, кто работает с документами PDF, соответствующая возможность имеется.) Хотя запрос на диапазон байтов не поддерживается браузерами непосредственно, есть одно новшество, позволяющее интегрировать часть страницы в уже имеющийся документ. Объектная модель документа (Document Object Model — DOM) — это стандартный способ представления внутренней иерархической структуры документа HTML и работы с ним. Корнем дерева является исходная HTML-страница, его ветвями — изображения и фреймы — и так далее. Интерфейс JavaScript API позволяет работать с этим деревом и изменять его. Загвоздка в том, что объектная модель документа поддерживается только IE 5.0 и NS 6.0, причем у каждого из этих браузеров она своя. HTTP и файловые системы В принципе, можно считать веб одной большой файловой системой. Тот факт, что большая часть файлов представляет собой HTML-страницы или изображения, дела не меняет. Теоретически возможно написать драйвер файловой системы, который подключал бы всю сеть в один каталог, а все ваши программы могли бы с этим каталогом работать. Запускаемые на выполнение файлы загружались бы с веб-сервера и выполнялись; открываемые документы с электронными таблицами тоже загружались бы и открывались в соответствующем приложении на пашем компьютере. В системе Unix вы могли бы вести поиск прямо по веб-страницам с помощью grep. Например, если бы драйвер файловой системы HTTP подключал веб в каталог /web, поиск мог бы осуществляться командой такого |юда: % grep "sales rank" /web/www.amazon.com/exec/obidos/ASIN/1565923790 Все остальные команды Unix работали бы точно так же, за исключением команды dir (Is), которая не выводила бы содержимое каталога без разрешения удаленного сервера. Большая часть данных была бы доступна только для чтения. Веб воспринималась бы точно так же, как компакт-диск, вставляемый в компьютер и подключаемый к файловой системе. Еще один проект, требующий реализации, — подключение таблиц баз данных в виде файлов, чтобы с ними можно было работать как с обычными файлами, а запросы на сохранение преобразовывались бы в команду SQL insert. FTP Протокол передачи файлов (File Transfer Protocol — FTP) — «старший брат» HTTP. Протокол FTP во многом похож на HTTP: например, успешность соединения передается с помощью числового кода, а для передачи каждого файла устанавливается соединение TCP. FTP отличается от HTTP тем, что после установки соединения TCP оно не разрывается до тех пор, пока клиент не пожелает отключиться от сервера. Самое важное, что нужно знать об FTP в связи с работой в веб, — это то, что большая часть браузеров поддерживает протокол FTP и корректно обрабатывает адреса URL, начинающиеся с ftp://. Загрузка по протоколу FTP идет быстрее,
чем по HTTP, — возможно, из-за меньшего объема накладных расходов, а также из-за того, что HTTP разбивает большие файлы на отдельные куски. Браузеры умеют анонимно подключаться к тем FTP-серверам, которые это допускают. FTP отвечает целям создания TCP: большой объем передаваемых данных и редкая установка соединений. NNTP Сетевой протокол передачи новостей (Network News Transport Protocol — NNTP) обычно используется только для передачи статей, помещаемых в группы новостей Usenet, но в принципе он может использоваться и для распространения веб-содержимого, распространяя веб-сайт по всему миру. К тому же он сильно затруднит проверку веб-сайта цензурой. CORBA Стандартная архитектура посредника в запросах объектов (Common Object Request Broker Architecture — CORBA) — это спецификация взаимодействия программных объектов между различными платформами. CORBA находится в разработке уже много лет, и этот стандарт получил некоторое распространение, поскольку он работает с Java, но сейчас дела обстоят так, что он может быть заменен пакетом Enterprise JavaBeans (EJB). Этот пакет позволяет обращаться к устаревшим приложениям из любой части веб, упаковывая приложения в объектно-ориентированный интерфейс, который пишется на языке определения интерфейсов (Interface Definition Language — IDL). Компонент, называемый по средником в запросах объектов, направляет запросы на обслуживание тем, кому следует. Посредники Java ORB могут быть загружены из сети, что делает серве ры CORBA доступными любому веб-клиенту, который способен работать с Java Netscape включает поддержку ORB фирмы Visigenic. Есть и другие ORB для Java — от фирм Iona, Orbix и Expersoft. Существуют также общедоступные ORH для Java, например JacORB. О производительности CORBA практически нет доступных данных. Оснон ным фактором, определяющим производительность CORBA, является количс ство операций копирования данных между буферами, требуемое для выполне ния запроса. Перевод параметров в последовательный формат для выполнении удаленных вызовов потребляет очень много ресурсов. Каждый параметр должен быть преобразован в формат, допускающий его передачу по сети, причем вместе с ним должны быть переданы и все объекты, от которых он зависит, если этих объектов нет на стороне получателя. Тем не менее CORBA обладает определен ным преимуществом перед CGI, которое заключается в том, что вы можете за пускать методы и службы по сети без необходимости порождать отдельный про цесс для обработки каждого вызова. CORBA хорошо масштабируется в теории, но на практике я не встречал успешных крупномасштабных реализаций CORBA, а вот с неудачными мж столкнуться пришлось. Объекты могут выполняться на произвольном количс стве серверов, а посредники будут направлять запросы туда, куда нужно, или
даже создавать новые объекты при необходимости. Недостаток CORBA — в избыточной сложности, а также в отсутствии возможности корректно обработать ошибку при создании экземпляра удаленного объекта. Поиск именованных объектов в принципе не может выполняться быстро, хотя возможности у него довольно большие. Интересно сравнить CORBA с простым веб-сервером, на котором выполняется CGI или сервлет. Поиск имени сервера в DNS аналогичен поиску именованного объекта в CORBA. Огромное отличие заключается в том, что веб-формы предназначены для людей, а вызовы CORBA — только для компьютеров. Помните, что порождение удаленного объекта выполняется в миллионы раз медленнее, чем порождение локального, а нормальных механизмов обработки ошибок при порождении не существует. Распределенные объекты хорошо работают в тех случаях, когда большая часть работы осуществляется локально, а передача данных по сети осуществляется лишь изредка, но они не слишком успешно справляются с задачей, если для ее решения требуется постоянное сетевое взаимодействие. Пакет Voyager фирмы Object Space (http://www.objectspace.com/) обладает более высокой производительностью, чем CORBA (по крайней мере, в тех простых тестах, которые я выполнял), и он более строен и прост в использовании. Это свободно доступная распределенная система объектов для Java, но она пока не включает спецификацию взаимодействия с устаревшими приложениями, в отличие от CORBA. Совместимость с CORBA, несомненно, когда-нибудь будет включена в этот пакет. х Удаленная работа с системой X Window может забить любую линию, которая будет под нее отведена. Каждое мерцание курсора, «звездочки» с логотипа Netscape — любое изменение на экране будет порождать сетевой трафик. Самое ужасное — это передаваемая по сети заставка для сохранения экрана неработающего компьютера. Не стоит помещать свой веб-сервер в сети, где передается такой трафик. Основные рекомендации О Установите тайм-аут повторной передачи по протоколу TCP побольше, поскольку Интернет медленнее, чем локальная сеть. О Увеличьте размер очереди прослушивания TCP, если вы знаете, что она переполняется. О Не давайте неиспользуемым соединениям занимать ваши ресурсы более получаса (и уж тем более восемь часов, согласно спецификации TCP). Используйте веб-сервер и браузер, совместимые с HTTP 1.1.
1Г Аппаратное q обеспечение сервера В этой главе мы вновь займемся изучением оборудования компьютеров, на сей раз — с точки зрения сервера. Хотя каждый клиент принимает ровно столько байтов, сколько отправляет ему сервер, оборудование сервера должно быть более мощным, чем клиентское, поскольку серверы должны быть способны одновременно обслуживать нескольких клиентов, а также порождать динамическое содержимое. С другой стороны, владельцы небольших веб-сайтов обычно завышают требования к своим серверам. Если вашему серверу приходится обрабатывать одного клиента раз в несколько секунд, вам будет вполне достаточно того оборудования, которое устанавливается на приличном веб-клиенте. Для большинства веб-сайтов «узким местом* бывает сетевое соединение, а не аппаратура сервере. Коробка с проводом Веб-сервер, по сути, представляет собой удаленное хранилище информации, ко пирующее данные из памяти или с диска на интерфейс сетевого соединения но запросу клиента. Это может быть и не просто копирование, поскольку серверы часто генерируют динамическое содержимое или обращаются к базам данных, но с точки зрения пользователя, веб-сервер представляет собой всего лишь ещг одно глобальное устройство хранения данных. Есть ли у жесткого диска собственный оконный интерфейс? Нет. Так boi, вашему веб-серверу он тоже не нужен, как не нужны видеоадаптер, монитор и даже клавиатура! Оконный интерфейс занимает много оперативной памяти и потребляет ресурсы центрального процессора, поэтому он снижает производи тельность сервера. У вас нет выбора, если ваш веб-сервер установлен в операцп
онной системе Windows или Mac, но в системах Unix вы можете просто отключить сервер X Window. Есть еще одна причина, по которой не следует использовать оконный интерфейс: текущее окно обычно обладает более высоким приоритетом по сравнению с прочими процессами. Например, в системе Solaris процессы, относящиеся к выбранному в данный момент окну, вызываются с приоритетом в 10 единиц (примерно из 100 возможных). Если вы будете работать с оконным интерфейсом недостаточно аккуратно, вы можете снизить производительность веб-сервера одним движением мыши. Лучше заниматься администрированием веб-сервера удаленно, подключаясь к нему с помощью telnet. Веб-серверы без мониторов называются безголовыми серверами. Хорошая подсистема ввода-вывода Главной отличительной особенностью сервера является высокая производительность подсистемы ввода-вывода. Оборудование обычных персональных компьютеров ограничено возможностями устаревшей подсистемы ввода-вы- нода, а оборудование серверов разрабатывается с учетом требований к этой подсистеме и может в 10 и более раз превосходить по производительности стандартные ПК. Несколько шин В серверах обычно устанавливаются отдельные шины для кэша второго уровня, ниода-вывода, ОЗУ и периферийных устройств. Это уменьшает борьбу за ресурсы и позволяет выбирать для каждой из шин подходящее оборудование. Шины серверов могут работать в режиме коммутации пакетов в том смысле, что по шине отправляется запрос, после чего шина освобождается до тех пор, пока не будет готов ответ. В это время по шине может быть отправлен еще один запрос (или ответ на один из предыдущих запросов), что увеличивает пропускную способность. Пропускная способность шины является критическим фактором для серверов, поскольку большая часть работы сервера заключается в копировании данных между сетевыми интерфейсами и запоминающими устройствами. Быстрые диски На сервере должны быть установлены отдельные высокоскоростные жесткие лиски стандарта SCSI для содержимого и для журналов. Диски стандарта IDE традиционно для серверов не использовались, однако стандарт этот эволюционировал, и теперь некоторые диски IDE соревнуются в производительности г дисками SCSI. Чередующиеся массивы дисков очень полезны для повышения И|юизводительности, поскольку они позволяют распараллелить поиск данных.
Много памяти На серверах должно быть очень много памяти, чтобы уменьшить необходимость обращения к диску. Памяти, согласно простому правилу, должно быть столько, чтобы в нее поместилась операционная система и та часть данных, обращение к которой производится чаще всего. На серверах обычно устанавливают большие кэши первого и второго уровней, причем допустимо разделение на кэш команд и кэш данных, поскольку доступ к данным и командам осуществляется по-разному. Быстрее кэша первого уровня могут быть только регистры процессора. Иметь несколько мегабайт кэша второго уровня уже стало обычным делом, но физическое расстояние между этим кэшем и процессором (даже в один дюйм) заметно снижает эффективность этого кэша. К сожалению, эффективность кэширования на сервере снижается из-за переключения контекста, которое происходит при каждом сетевом прерывании. Инструкции демона httpd и подпрограмм работы с сетью поочередно вытесняют друг друга из кэшей. Драйверы устройств занимают память ядра, а память эта не может быть выгружена в файл подкачки. Поэтому ненужные драйверы уменьшают эффективный объем ОЗУ. Ненужные драйверы устройств устанавливать не следует. Масштабируемость Сервер должен быть масштабируемым, чтобы вы могли с легкостью отвечать на возрастающий спрос потребителей. Рабочие станции Unix обладают гораздо большей масштабируемостью по сравнению с персональными компьютерами: в них может быть установлено до 64 или даже до 128 процессоров, тогда как оборудование персональных компьютеров обычно неспособно выдержать конкуренцию между более чем четырьмя процессорами (по крайней мере, так было на момент написания книги). Рабочие станции обладают большей пропускной способностью подсистемы ввода-вывода и большими возможностями по расширению объема памяти. Сетевой адаптер Сетевой адаптер (Network Interface Card — NIC) соединяет кабель с шиной сер вера. Адаптеры заполняют концептуально простую нишу на рынке оборудона ния, но разнообразие существующих адаптеров отражает разнообразие комбинаций кабелей, протоколов и шин. Адаптер считывает последовательный поток битов из кабеля и выдает параллельный поток битов в шину (и наоборот). До недавних пор можно было считать пропускную способность сети много мет» шей, чем пропускная способность процессора и шины, но пропускная способность локальных сетей возрастает быстрее, чем пропускная способность процессора и шины, поэтому теперь уже нельзя надеяться, что ваши процессор и шиш» смогут справиться с любым сетевым адаптером. Тем не менее, если ваш сервер
связан с Интернетом, вы можете смело рассчитывать на то, что сервер больше всего будет ограничен пропускной способностью Интернета. На сетевых адаптерах имеются собственные буферы, причем большие буферы всегда лучше, потому что они оставляют вам больше возможностей для маневра. Буфер исторически был важен для отправки данных по сети, но ситуация меняется, и в будущем буферы станут использоваться для хранения данных до тех пор, пока операционная система не сможет их обработать. В любом случае большой буфер уменьшает вероятность потери данных из-за его переполнения. Потерянные пакеты TCP/IP просто передаются заново, что увеличивает накладные расходы. У 8-разрядных карт Ethernet буферы обычно имеют объем 8 Кбайт, а у 16-разрядных — 16 Кбайт. Когда сетевой адаптер получает пакет целиком и готов переслать его по шине компьютера, он порождает аппаратное прерывание, заставляющее процессор сохранить свое текущее состояние и запустить обработчик прерывания сетевого адаптера, который считывает данные из буфера и заполняет соответствующую структуру данных в памяти. Критическим фактором производительности является, таким образом, количество прерываний в секунду, вызываемых сетевым адаптером, которое может быть обработано процессором, памятью и шиной. Еще одной важной характеристикой сервера является его способность быстро передавать данные из оперативной памяти или с жесткого диска на сетевой интерфейс. Эта операция обязательно включает в себя копирование данных из одного участка памяти в другой — из памяти сервера в память сетевого адаптера. Исходящий пакет Ethernet объемом в 1500 байт копируется операционной системой по 4 байта за раз, поэтому на операцию копирования уходит 375 циклов шины. Для данной операции часто используются библиотечные вызовы memcpy и Ьсору, поэтому для сервера весьма важна эффективность их реализации. Здесь также оказывается важной эффективность реализации стека TCP/IP в ядре операционной системы. Плохая реализация может допускать значительные задержки между поступлением прерывания от сетевого адаптера и считыванием пакета из его буфера, поэтому новые пакеты, прибывающие на сетевой интерфейс, могут не поместиться в буферную память и будут сброшены либо перезапишут данные, уже находящиеся в буфере. Все это приведет к дорогостоящей повторной передаче утерянного пакета. Лучшая производительность обеспечивается самыми современными сетевыми адаптерами. Многие из них могут обновляться путем загрузки нового кода в их флэш-память (ППЗУ). Самым быстрым будет, скорее всего, последний официальный вариант этого кода, не предназначенный для бета-тестирования. Использование процессора в операции считывания данных из буфера сетевого адаптера в память вовсе не обязательно. Сетевые адаптеры, способные самостоятельно передавать данные по шине в память, называются «сетевыми адаптерами с захватом шины» (busmastering NIC). У таких адаптеров имеется существенное преимущество в производительности перед неспособными на такие трюки устаревшими адаптерами, но они и стоят дороже, поскольку требуют установки большего количества контроллеров. Фирма Intel опубликовала спе-
цификацию метода, позволяющего записывать данные с сетевого интерфейса непосредственно на жесткий диск персонального компьютера. Эта спецификация называется 120, и для ее использования требуется поддержка операционной системы. К тому времени, когда вы будете читать эту книгу, спецификация Intel, скорее всего, распространится уже достаточно широко. Шина Шина (bus) представляет собой набор параллельных проводов (обычно их 32, 64, 128 или 256 плюс отдельные каналы для обработки ошибок и отправки служебных данных протокола), проложенных в материнской плате компьютера. Шина — это то, что соединяет между собой все остальные компоненты системного блока: процессор, память, жесткий диск и сетевые карты. В компьютере может быть несколько шин. У персональных компьютером шина обычно одна, и к ней подключены все устройства, тогда как у серверов чаще всего бывает по меньшей мере две отдельные шины: высокоскоростная шина соединяет процессор с оперативной памятью, а более медленная — с устройствами ввода-вывода. Системные шины заметно отстают по пропускной способности от процессора, поэтому ему часто приходится пропускать множество циклов, ожидая поступления данных по шине. С другой стороны, шины обычно оказываются быстрее, чем сетевые интерфейсы. Как уже отмечалось, ситуация меняется. Быстрый Ethernet имеет пропускную способность 100 Мбит/с, что превышает возможности шин ISA и EISA. Гигабитный Ethernet с пропускной способностью 1000 Мбит/с может перегрузить и более современную шину. На таких скоростях «узким местом» становятся шина сервера и даже процессор, особенно если последний пытается одновременно обращаться к базе данных или выполнять приложения CGI. Шестидесятичетырехразрядная шина PCI, работающая на частоте 66 МГц, технически может обеспечить пропускную способность 4224 Мбит/с, но реальная пропускная способность наверняка будет гораздо ниже из-за борьбы устройств за ресурсы шины, накладных расходов на сетевые пакеты, недостатков реализации операционной системы и множества других факторов. Для персонального компьютера хорошей пропускной способностью по протоколу TCP/IP можно считать 10 Мбит/с. Компьютер Sun Ultra 1 должен значительно превышать 40 Мбит/с. (Учтите, что в рекламе обычно приводятся теоретические значения пропускной способности, которые во много раз выше.) Шина PCI, работающая на частоте 66 МГц, обгоняет в скорости доступа к данным даже память, поэтому последняя может становиться «узким местом». Параллельные шины PCI, устанавливаемые на некоторых персональных компьютерах фирмы Compaq, могут обеспечивать одновременный доступ к нескольким периферийным устройствам. Фирма Sun производит свои шины SBus в соответствии со стандартом IEEE 1496, но начинает переходить на шины РС1, поэтому, достав соответствующие драйверы, вы сможете использовать широкодоступные сетевые адаптеры PCI. Sun устанавливает на своих компьютерах
64-разрядную шину PCI, работающую на частоте 66 МГц. Эта шина способна обеспечить пропускную способность, достаточную для работы с линиями ATM, гигабитным Ethernet и оптоволокном. Оперативная память Трудно преувеличить различие между скоростями доступа к оперативной памяти и к жесткому диску. Хотя с человеческой точки зрения, ощутимого различия между обращением к памяти, занимающим 100 не, и обращением к диску, занимающим 100 мс, нет, на самом деле отношение этих промежутков времени равно миллиону, что можно сравнить с разницей между секундой и десятью днями. Разница в скорости ощущается при многократном повторном обращении, и тогда сразу становится понятной необходимость покупки достаточного количества памяти. Характеристики ОЗУ Первое место по количеству продаваемых микросхем в настоящее время занимает динамическая оперативная память (Dynamic Random Access Memory — DRAM). Random Access (произвольный доступ) означает, что время обращения ко всем участкам памяти одинаково. «Динамичность» памяти означает, что ее постоянно приходится обновлять, потому что транзисторы, представляющие собой ячейки памяти, постоянно теряют заряд. Память DRAM была изобретена в 80-е годы, когда обнаружилось, что плотность ячеек памяти можно значительно увеличить, храня один бит в одном транзисторе, а не в наборе из нескольких транзисторов. Правда, такая схема требовала постоянного обновления данных из-за утечки заряда. Существовавшие ранее микросхемы памяти, не требующие постоянного обновления, получили название статического ОЗУ (Static RAM — SRAM). В микросхемах SRAM используются триггеры, состоящие из 4-5 транзисторов, которые не теряют заряд, поскольку постоянно обновляют друг друга. Память SRAM стоит дороже, чем DRAM, и обладает меньшей плотностью записи, зато обеспечивает гораздо более быстрый доступ B0 не против 80 для DRAM). Сейчас микросхемы SRAM используются для кэша второго уровня. Хотя микросхемы памяти очень быстры по сравнению с жесткими дисками, их пропускная способность не бесконечна, а время ожидания существенно больше нуля. У современных микросхем памяти время доступа обычно меньше 100 не. Сравните это с процессором, работающим на частоте 1000 МГц. Один такт процессора занимает 1 не. Большая часть инструкций процессоров Intel занимает 3-5 тактов и может потребовать дополнительных обращений к памяти для считывания операндов. Даже если инструкция будет выполнена за 5 тактов, процессору все равно придется ждать еще 45 тактов до считывания из памяти следующей инструкции. Этот пример сильно упрощен, в нем не учитываются существование шины, конвейерная обработка команд и существование супер-
скалярных процессоров (исполняющих одновременно несколько инструкций), но в целом вы видите, что процессоры работают заметно быстрее, чем память, их обслуживающая. Быстродействие памяти по отношению к конкретному процессору может оцениваться в пустых циклах последнего (wait states). Каждый цикл, пропущенный процессором в ожидании поступления данных из памяти, считается пустым, поэтому самой лучшей памятью для вашего процессора будет такая, для которой количество пустых циклов будет нулевым. Из-за того, что на практике число пустых циклов существенно отличается от нуля, для процессоров предусматривается кэш-память, которая устанавливается как на самом процессоре (кэш первого уровня — L1), так и на материнской плате в непосредственной близости от процессора (кэш второго уровня — L2). Обращение к кэш-памяти может осуществляться на тактовой частоте процессора. Благодаря этому несколько сглаживается разница в скоростях между процессором и оперативной памятью с шиной данных. Часто используемые данные и инструкции размещаются в кэшах поближе к процессору. Учтите, что у некоторых микросхем памяти бывают встроенные кэши; именно их наличием отличаются друг от друга стандарты EDO, BEDO и SDRAM. Номинальные скорости, указываемые для микросхем памяти, являются лишь теоретическими, поскольку в реальности оперативной памяти присущи внутренние задержки между операциями задания номеров строк и столбцов. Наличие нескольких контроллеров памяти позволяет одновременно передавать несколько адресов, по которым будут запрашиваться или записываться данные, что увеличивает общую пропускную способность. Процессор Взгляните на любую рекламу продажи компьютеров. Первое же указываемое число — это скорость процессора, потому что люди, которые покупают персональные компьютеры, любят, когда у них есть возможность сравнивать числа, а это число удобно использовать для сравнения. К сожалению, из-за этого большинство персональных компьютеров оказывается несбалансированным: мот ный процессор большую часть времени простаивает из-за шины и жесткого диска. (С другой стороны, нельзя сказать, что процессор, с точки зрения производителя, пропадает даром, если именно он заставляет вас купить этот ком пьютер.) Даже низкопроизводительный процессор Intel Pentium, работающий на частоте 500 МГц, будет постоянно ждать поступления данных от шины EISA и дисков IDE. На самом деле вам нужны быстрая шина, быстрый диск и много памяти. Системы, продаваемые в качестве серверов, обычно сбалансированы лучше, поскольку их оценивают по реальной пропускной способности. Иногда вы все-таки можете попасть в ситуацию 100%-ной загрузки процессора, и тогда покупка нового чипа очень поможет вам. Поиски в базах данных, расчеты, генерация графики и выполнение серверных приложений Java загрузя1 ваш процессор по максимуму. Отслеживать использование процессора можно
с помощью доступных в любой системе Unix программных средств. Запустите vmstat 1 и последите за последними тремя столбцами, в которых указывается время, проведенное процессором в пользовательском, системном и свободном (незагруженном) режимах. Если свободного времени у процессора практически нет (скажем, менее 5%), вам действительно нужен более быстрый процессор. То же самое можно определить с помощью программ top и perfmeter. Потребность в мощности процессора зависит и от скоростей соединения клиентов, размеров передаваемых ими файлов, а также от количества клиентов. Предположим, вы передаете большой файл A00 Кбайт) сотне клиентов одновременно. Если все клиенты подключаются по высокоскоростным линиям, вы, может быть, успеете передать им весь файл до переключения процесса. В системе Solaris процессы могут переключаться каждые 10 мс, но этот параметр системы можно изменить. Успеете ли вы передать файл за то количество квантов времени, которое будет вам отведено, зависит от производительности подсистемы ввода-вывода. Если клиенты подключаются по медленным линиям, большая часть времени будет потрачена на переключение между процессами, и тогда мощность процессора окажется важнее, чем пропускная способность подсистемы ввода-вывода. Важно помнить, что в моменты наибольшей загруженности Интернета даже самые быстрые клиенты становятся медленными. Требования к серверу могут меняться в течение дня: ночью ваш сервер должен иметь максимальную пропускную способность подсистемы ввода-вывода, а днем — как можно более быстрый процессор и много ОЗУ, чтобы поддерживать множество одновременных соединений. (Спасибо Джиму Баррику из Keynote за этот совет.) Архитектура процессора Рассмотрим устройство процессора с точки зрения производительности. В самом простом варианте картина его работы такова: после включения питания или перезагрузки компьютера процессор считывает инструкцию, расположенную в памяти по фиксированному адресу (обычно это ненулевой адрес), выполняет ее, увеличивает внутренний счетчик команд на единицу, считывает следующую инструкцию, выполняет ее и так далее. Картина несколько упрощенная, но лишь совсем чуть-чуть. Инструкции могут быть переменной длины, поэтому очередная инструкция может располагаться не непосредственно после предыдущей, и, кроме того, процессору может понадобиться загрузить из памяти операнды для выполнения с ними некоторой операции, предписываемой инструкцией. Велика вероятность того, что процессор перейдет к инструкции, расположенной не непосредственно после предыдущей, причем адрес перехода зависит от результата выполнения этой предыдущей инструкции, но общая картина выполнения всегда одинакова: инструкция считывается и выполняется, после чего увеличивается счетчик команд. Если бы вся память была заполнена холостыми операциями (NOP — no operation), процессор просто просмотрел бы всю память подряд, не пропуская ни одного адреса. (Это заняло бы не слишком много времени: приблизительно такие действия выполняются при проверке
памяти во время загрузки компьютера.) Достигнув конца памяти, процессор завершает работу и ждет возникновения сигналов о прерываниях. Для ускорения основного процесса (считать, декодировать, выполнить операцию) применяются различные методы оптимизации. Например, современные процессоры поддерживают конвейерную обработку: инструкции считываются по нескольку за раз, помещаются в очередь, после чего выполняются по частям, то есть в каждый момент времени несколько инструкций находятся в различных состояниях выполнения. Это уменьшает затраты на доступ к памяти и ускоряет выполнение программы, но часто возникают ситуации, когда очередная инструкция оказывается записана в памяти не вслед за предыдущей, и тогда конвейер останавливается, а процессору приходится осуществлять дополнительное обращение к памяти. Некоторые процессоры анализируют выполняемый код и используют алгоритмы предсказания ветвления (branch prediction), чтобы заранее считывать те команды, которые с наибольшей вероятностью будут выполнены следующими. Разные составные части процессоров работают на разной тактовой частоте. У процессора Pentium имеется одна 64-разрядная шина, связывающая его с внешним миром (называется она frontside bus). Эта шина работает на тактовой частоте PCI F6 МГц). Скорости же обращения к внутреннему кэшу процессора и выполнения инструкций могут быть выше (например, 100 МГц). Внешняя шина процессоров Sun Ultra является 128-разрядной, она работает на частоте 83 или 100 МГц. Когда процессор называют 32- или 64-разрядным, это не значит, что он стоит 4 или 8 долларов соответственно. Данное высказывание относится к используемой в этом процессоре адресации. С другой стороны, 2-разрядный процессор стоил бы, наверное, около 25 центов. Итак, количество разрядов определяет размер указателя и, таким образом, ограничивает максимальный размер адресного пространства памяти. 32-разрядные компьютеры имеют 4 Гбайт адресного пространства. Что же касается размера адресного пространства 64-разрядных компьютеров, то я даже не знаю, как его описать, — настолько он огромен. Все процессоры Pentium являются 32-разрядными; процессоры UltraSPARC и Alpha — 64-разрядными. На данный момент существует не так уж много программ для 64-разрядных процессоров, но если вы пишете программы сами и вам нужно большое адресное пространство и высокая производительность, то 64-разрядный процессор может быть вам полезен. Поисковый сервер AltaVista использует 64-разрядное программное обеспечение, и не по простой прихоти его создателей: на всех компьютерах этого сервера установлено более 4 Гбайт памяти. На 64-разрядной версии того же процессора будут работать и 32-разрядные программы, но производительность совершенно не обязана при этом повыситься. Программы, в принципе, могут выполняться не на тех процессорах, для которых они были оптимизированы. Это верно, к примеру, для серии процессором SPARC. Любой выполняемый файл для процессора SPARC будет выполняться на любом процессоре этого семейства, но его производительность не будет мак-
симальной, если он не был скомпилирован специально для данного процессора. Хороший компилятор (например, дсс) позволяет указывать семейство процессоров с помощью множества параметров, что дает вам возможность пользоваться преимуществами усовершенствования процессоров последнего поколения. Чтобы получить более подробные сведения об этом компиляторе, выполните команду man gcc. Компилятор языка С, написанный фирмой Sun, позволяет указывать конкретный процессор SPARC с помощью ключа командной строки -xchip. Какую пропускную способность может обеспечить данный процессор? Согласно Брайану Вонгу, процессор Sparc 5 способен «забить» информацией линию на 50 Мбит/с (приблизительно ТЗ), но при этом будут израсходованы практически все ресурсы данного процессора. Процессоры Sun Ultra и Pentium Pro могут полностью загрузить линию ATM на 155 Мбит/с. Инструкции процессоров CISC имеют разные размеры, и их больше, чем инструкций для процессоров RISC. Оптимизировать процессор RISC-архитектуры для достижения максимального быстродействия проще, но ведь на каждую CISC-инструкцию нужно несколько RISC-инструкций, поэтому размер исполняемого кода становится больше. В итоге вы тратите больше памяти на то, чтобы иметь более производительный процессор. Процессоры Intel обладают CISC-архитектурой и поддерживают обратную совместимость с процессором 8088, но у современных моделей внутреннее ядро представляет собой процессор с RISC-архитектурой. На большинстве теперешних процессоров устанавливается встроенный математический сопроцессор (FPU), очень сильно ускоряющий выполнение операций с плавающей точкой, но на веб-сайтах, вообще говоря, очень редко используются вычисления с плавающей точкой. Помните, что любой алгоритм, реализованный программно, можно реализовать и аппаратно (и наоборот). Производительность реализаций будет существенно разной: аппаратные решения могут быть в тысячи раз быстрее. Виртуальная машина Java (]VM) представляет собой, по сути, программно реализованный процессор. Логично предположить, что если ее реализовать аппаратно, то производительность сразу же возрастет. Первые процессоры для Java уже появились на рынке, но не стоит ожидать резкого возрастания быстроты программ. Исполнение программы на Java не сводится к одному лишь выполнению инструкций байт-кода, но в основном состоит из более сложных действий — таких, как создание объектов. Эти операции обеспечиваются виртуальной машиной, но современные аппаратные реализации на такое неспособны. Несомненно, со временем появятся более совершенные процессоры, и тогда программы на Java будут выполняться так же быстро или даже быстрее, чем «родные» программы для других платформ. Сервер HTTP тоже можно было бы целиком реализовать аппаратно. Специальные процессоры HTTP упростили бы встраивание этого протокола в пользовательские устройства, чтобы вы могли обращаться к своему радиоприемнику или видеомагнитофону из веб-браузера и управлять им. Разумеется, процессоры обновлять гораздо сложнее, чем программное обеспечение, но вспомните: когда вы и последний раз «обновляли» свой видеомагнитофон?
Многопроцессорные компьютеры Приложениям корпоративного уровня часто требуются вычислительные мощности, превышающие возможности любого однопроцессорного компьютера. Переделать приложение таким образом, чтобы оно эффективно использовало несколько процессоров, не всегда легко. Если вам повезет, окажется, что ваше приложение может выполняться на нескольких однопроцессорных компьютерах. Веб-серверы масштабируются именно таким образом. Однако многие приложения — такие, как базы данных, — могут выполняться только на одном компьютере. В такой ситуации, когда приложение обязательно должно выполняться на одной машине, вам придется установить на этот компьютер несколько процессоров для повышения его вычислительных возможностей. Одна из стратегий использования мощности нескольких процессоров заключается в выполнении нескольких процессов, взаимодействующих посредством различных форм межпроцессного взаимодействия, таких как семафоры и разделяемая память. Операционная система будет автоматически распределять процессы между процессорами. Однако технологии межпроцессного взаимодействия различны на разных платформах. Библиотеки многопоточного программирования обычно позволяют использовать несколько процессоров потокам (threads) одного процесса и являются в достаточной степени переносимыми, но программирование с их использованием не слишком просто. Сравнительно с собственными библиотеками потоков программирование потоков на Java является относительно простым. Многопоточные программы, написанные на Java, хорошо переносятся между платформами, а реклама утверждает, что в многопроцессорных системах такие программы еще и хорошо масштабируются. Как мы увидим впоследствии, для существующих на данный момент версий этого языка последнее утверждение является не вполне верным, однако кое-какие несложные методы позволяют повысить производительность многопоточных приложений Java в многопроцессорных системах. Сотрудничество нескольких процессоров одного компьютера называется симметричной многопроцессорной обработкой (Symmetric Multiprocessing SMP). Компьютер с одним процессором называется однопроцессорным. Много процессорные компьютеры обычно содержат специальные процессорные модули, подключаемые к шине. Теоретически мощность такого компьютера повышается путем покупки новых процессоров и подключения их к модулю. К сожалению, из-за проблем с координацией действий процессоров, а также из-за того, что большая часть приложений тратит время на ожидание завершения операции ввода-вывода, а не на сложные вычисления, пропускная способность с добавлс нием второго процессора к первому не обязательно возрастет вдвое. Более того, реально производительность может даже ухудшиться. Если программа не была разработана специально для многопроцессорной среды, добавление второго про цессора сможет повысить быстродействие не более чем на 30%. Вычислительно- емкие программы, разработанные с учетом возможностей SMP, могут ускорить
свою работу на 80-90%. Многое зависит от того, чем именно занимается данное приложение. Вычислительноемкие программы, которые могут выполняться в параллельных процессах или потоках, естественно, выигрывают при добавлении процессоров больше, чем программы, работающие в основном с сетью или жестким диском. Потоки программы, написанной на Java, могут выполняться на разных процессорах, но не будут этого делать до тех пор, пока вы не перейдете на собственную библиотеку потоков, которая планирует выполнение потоков операционной системой в отличие от «зеленого» пакета потоков, который планирует выполнение потоков внутри виртуальной машины Java, представляющей собой единственный процесс. Обычно для включения собственной библиотеки используется переменная окружения или параметр командной строки. Даже после подключения этой библиотеки Java не всегда будет использовать все доступные процессоры: это зависит от того, как именно написана данная виртуальная машина. В вопросах многопроцессорной обработки Unix значительно опережает Windows NT. Максимальное количество процессоров, с которыми может работать NT, на данный момент равно восьми. Даже если у компьютера, работающего под управлением NT, есть место для установки более чем четырех процессоров, делать этого все равно не следует, поскольку производительность может уменьшиться. Операционная система Windows NT плохо распределяет работу между более чем четырьмя процессорами. Воспринимайте скептически рекламные акции, на которых производитель ставит рядом несколько компьютеров и говорит о хорошей масштабируемости, не упоминая о том, что большую часть корпоративных приложений трудно разделить между несколькими компьютерами. Системы Solaris на данный момент поддерживают установку 64 процессоров, причем производительность возрастает при установке каждого последующего процессора. Это значит, что вы можете купить низкопроизводитсльный компьютер Solaris, а впоследствии добавлять в него процессоры, но мере того как они будут требоваться для вашей работы. При этом вам не придется переходить на другие приложения или заново планировать архитектуру — при одном обязательном условии: ваши приложения должны быть рассчитаны на использование SMP. Тестирование масштабируемости Sun SMP Я решил провести несколько тестов, чтобы доказать самому себе, что добавление процессора к большому компьютеру фирмы Sun увеличит его производительность. Отчет об исследовании масштабируемости SMP в Linux, написанный Камероном Маккинноном, я скачал по адресу: http://www.phy.duke.edu/brahma/ benchmarks.smp. В этом отчете Камерон рассказывает о том, как он тестировал масштабируемость SMP с помощью множества процессов, перебиравших числа от нуля до миллиарда. Такое тестирование действительно должно нагружать только процессоры, и ничто иное. При этом не происходит обращений к диску или памяти, а в принципе не должен использоваться даже кэш процессора. Пример программы на языке С, которая должна до предела загрузить ваш процессор приведен в листинге 16.1.:
Листинг 16.1. Считаем от 0 до 1 000 000 000 (язык С) main( ) { unsigned long i: for (i=0; i<1000000000: i++): } Я скомпилировал данную программу с максимальной оптимизацией, вызвав для этого команду дсс -03 -о loop loop.c, и запустил получившийся исполняемый файл на персональном компьютере Dell Optiplex GX1 (шина PCI, частота процессора 500 МГц, 512 Кбайт кэша, ОС Linux 2.2). Программа выполнилась примерно за 4 с: % time loop 4.02user O.OOsystem 0:04.02elapsed 99SCPU Некоторые строки я удалил для большей ясности. Процессор, работающий на частоте 500 МГц, за 2 с выполняет миллиард элементарных операций. Наша программа работала 4 с; следовательно, увеличение переменной i на единицу выполнялось за 2 такта. Что будет, если мы запустим 2 экземпляра этой программы «одновременно» на однопроцессорном компьютере под управлением Linux? Разумеется, о строгой одновременности выполнения программ говорить не приходится, поскольку в любой момент времени лишь один процесс может выполняться процессором. Ядро будет планировать выполнение процессов, поэтому пользователю будет казаться, что они выполняются одновременно, но работать эти процессы должны в 2 раза дольше. Реальное время работы должно быть прямо пропорциональным количеству процессов. Я запустил 24 процесса с помощью приведенного в листинге 16.2 сценария на языке Perl, не загружая компьютер ничем другим, кроме этих процессов. Листинг 16.2. Одновременный запуск 24 процессов #!/usr7local/bin/perl $| = 1: $\ - "\П"; for ($procs = 1: Sprocs <» 24; $procs++) { for ($i - 1: $i <- Sprocs: $i++) { if (Spid - fork) {} elsif (defined $pid) { exec 'loop*; } else { die "cannot fork: $!\n"; } } Sstart - time( ); for ($i =1; $i <- Sprocs: $i++) { wait: } Send = time( ): Slatency = Send - Sstart:
print "Sprocs Slatency": } Результаты получились такие: 1 4 2 9 3 12 4 16 5 20 6 24 7 28 8 32 9 37 10 38 11 44 12 48 13 53 14 56 15 61 16 64 17 69 18 71 19 76 20 80 21 83 22 89 23 89 24 93 Я построил график этих значений с помощью gnuplot и получил картинку, показанную на рис. 16.1. Чем больше процессов вы запустите одновременно, тем дольше они будут работать. Именно такого поведения и следует ожидать от вычислительноемких процессов на однопроцессорном компьютере. Я поставил аналогичный эксперимент на компьютере фирмы Sun, отключив все процессоры, кроме одного, и получил ту же линейную зависимость, только с другой начальной точкой. Время выполнения одного экземпляра программы loop.c на компьютере Sun E450 с одним процессором на 250 МГцсоставило около 67 с. Здесь вы, наверное, воскликнете: «Подождите-ка! Ведь компьютеры Sun стоят дороже персоналок, так почему же программа работает медленнее?» Действительно, данном конкретном случае тест действительно выполнялся медленнее, но не следует делать из этого слишком далеко идущие выводы. Компьютеры Sun рассчитаны на масштабирование путем установки нескольких процессоров, а персональные компьютеры — нет. Это создает некоторые накладные расходы. Процессор Sparc работал на тактовой частоте, вдвое меньшей, чем процессор Intel, и он использует совершенно другой набор инструкций. Процессор Sparc основан на архитектуре RISC, a Intel — на CISC. Чтобы убедиться в том, что на результаты одного эксперимента полагаться нельзя, можете просто изменить порядок перебора чисел в программе loop.c и считать от миллиарда к нулю, а не от нуля к миллиарду, как раньше. При этом компьютеру Sun потребуется вдвое ме-
ньше времени C,35 с), чем раньше, тогда как ПК выполнит работу за то же самое время, что и в первый раз D,02 с). Теперь Sun кажется более быстрым. В чем дело? Рис 16.1. Время работы процессов пропорционально их количеству Компилятор дсс генерирует меньше инструкций процессора Sparc при вычитании, чем при сложении, а для платформы Intel количество операций всегда оказывается одинаковым. Помните, что эти процессоры используют абсолютно разные наборы команд. Компилятор дсс просто нашел более эффективный способ обратного отсчета на Sparc. Вы можете вывести и изучить промежуточный код на языке ассемблера с помощью параметра командной строки gcc -S. Оптимизация, выполняемая компилятором, может приводить к весьма парадоксальным результатам. Попробуем изменить нижнюю границу вычислений. Например, если считать от миллиарда вниз к числу 4095 (на том же компьютере Sun), времени будет тратиться приблизительно столько же, сколько при счете до нуля. Но если увеличить нижнюю границу до 4096 или до большего значения, время выполнения удвоится. Вы, конечно, помните, что 4096 = 212. Когда нижняя граница равна 4095, компилятор генерирует одну команду на операцию сравнения, но когда эта граница равна 4096 и более, команд требуется две. Если подумать, действительно «умный» компилятор должен был бы сразу устанавливать значение счетчика равным конечному и полностью выбрасывать цикл, поскольку цикл пустой и компилятор это видит. Тогда тест выполнялся бы мгновенно, и толку от него не было бы никакого. (Более современные версии
компиляторов именно так и поступают. См. Бентли Дж. Жемчужины программирования. — СПб.: Питер, 2002. — Прямей, ред.). Мы отметили, что оборудование Sun разрабатывается с расчетом на использование нескольких процессоров. Действительно ли все эти процессоры используются эффективно? Это важный вопрос, поскольку стоят процессоры недешево. Начнем с процессов. Если мы запустим нашу программу в количестве 1, 2, 3 и так далее до 24 экземпляров на компьютере Sun с 12 процессорами, время выполнения не будет увеличиваться до тех пор, пока количество процессов не превысит 12. После этого время работы будет возрастать с добавлением каждого следующего процесса, поскольку у нас не будет хватать процессоров на все процессы. Увеличение времени на каждый дополнительный процесс составит около 1/12 времени выполнения одного процесса. Это увеличение показывает, что процессоры используются всеми процессами в одинаковой степени. Если бы работа по выполнению 13-го процесса не распределялась поровну между процессорами, полное время выполнения возросло бы более чем на 1/12, поскольку, по крайней мере, один из процессоров делал бы больше работы, чем остальные. В системе Solaris можно распределить процессы между процессорами явно, чтобы операционная система не тратила время на выбор процессора, но я эту функцию в данном тесте не использовал. На рис. 16.2 приведены результаты. (Время выполнения значительно выше, чем в первом случае, поскольку я забыл указать ключ -03, включающий у компилятора дес оптимизацию.) Рис. 16.2. Время выполнения начинает увеличиваться при количестве процессов, превышающем 12
Что если мы отключим несколько процессоров и запустим тест снова? Можно ожидать, что подъем на графике будет начинаться раньше. Именно это мы и увидим. Один за другим были отключены 11 из 12 процессоров, и в результате получилась сетка результатов 12 х 24. Вот сценарий на Perl, с помощью которого я выполнял этот тест (листинг 16.3). Листинг 16.3. Отключение процессоров и запуск нескольких экземпляров программы #!/usr71ocal/bin/peHS| - 1:$\ - "\п": if ($<) { # Мы не в привилегированном режиме. die "Need to run as root to execute psradm. Terminating"; } # Номера процессоров не обязательно идут последовательно. @cpu_array - @. 1. 3. 5. 8. 9. 12. 14. 16. 19. 20): for ($cpu - 0; $cpu < 11; Scpu++) { for ($procs - 1: $procs <- 24; $procs++) { for ($i - 1; $i <- $procs: Si++) { if ($pid - fork) {} elsif (defined $pid) { exec 'loop'; } else { die "cannot fork: $!\n": } } Sstart - time( ): for ($i - 1; $i <- $procs: Si++) {wait: } Send - time( ); Slatency - Send - Sstart: $cpus_running - 12 - Scpu; print "Scpus_running Sprocs Slatency"; } print; 'psradm -f Scpu_array[Scpu]v: } На рис. 16.3 приведен график результатов. Видно, что в левой части график идет горизонтально: процессов меньше, чем процессоров. Время выполнения не меняется. Однако когда процессов становится больше, чем процессоров, время выполнения начинает расти. Это замечательная кривая. Она показывает, что для процессов, осуществляющих исключительно вычисления и не использующих память, жесткий диск или сеть, оборудование Sun работает со 100%-ной отдачей — по крайней мере, если процессоров не больше 12. Посмотрим, что будет с потоками Java. Будут ли они так же эффективно нагружать процессоры Sun, как и обычные процессы? Перепишем программу loop.c на Java (листинг 16.4).
Рис 16.3. Время начинает увеличиваться раньше при уменьшении количества процессоров Листинг 16.4. Считаем от 0 до 1 000 000 000 на Java class Loop implements Runnable { public static void main(String[] args) { for (int t - 0: t < Integer.parselnt(args[0]); t++) new Thread(new Loop()).start( ); } public void run( ) { for (int i - 0: i < 1000000000: 1++): } } Скомпилировав и запустив однопоточную программу в виртуальной машине Sun Java 1.1.7 на 4-процессорном компьютере Sun, мы обнаружим, что время выполнения составит 13 с: % javac Loop.Java % time Java Loop 1 Скомпилировав эту же программу и запустив один поток в виртуальной машине Blackdown Java 1.1.6v5 на, ПК под управлением Intel, мы получим время выполнения 76 с. Оно оказывается намного больше из-за того, что в комплект Blackdown JDK 1.1 не входит компилятор JIT (Just-In-Time — компиляция «на лету» по мере необходимости), а в Sun JDK он входит. Именно на простейших циклах вроде этого лучше всего проявляются преимущества JIT-компиляции.
Существуют J IT-компиляторы для Blackdown JDK, распространяемые свободно, но я не пробовал их подключать. Вернувшись к компьютеру Sun, попробуем увеличить количество потоков Java и посмотрим, как будет меняться время работы. Я изменял количество потоков от 1 до 24 на компьютере с 12 процессорами. Предполагалось получить график, аналогичный приведенному на рис. 16.3: горизонтальная линия при количестве процессов меньше 12, а затем линейный рост. Но результат оказался совсем иным (рис. 16.4). Рис. 16.4. Нелинейный рост времени выполнения с использованием потоков Java Что здесь происходит? Прежде всего, вероятно, используются по меньшей мере два процессора, так как для одного и двух потоков время выполнения одно и то же. Похоже, что двумя процессорами дело и ограничивается, поскольку время выполнения возрастает, хотя и ступенчато. Оно удваивается при увеличении количества потоков до трех и остается приблизительно таким же при запуске четырех потоков. Все это очень странно! Посмотреть, какие же процессоры реально используются, мы можем с помощью программы mpstat: % jre Loop 3 & mpstat 1 [1] 17745 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 22 0 683 10 322 233 3 14 0 428 2 1 1 97 1 23 0 597 301 100 307 223 4 17 0 464 2 1 1 96 4 24 0 962 10 231 149 3 15 0 351 1 1 1 97 5 23 0 622 10 356 257 4 17 0 480 2 1 1 96
8 23 0 1212 1 0 350 284 3 14 0 461 2 1 1 96 9 21 0 855 10 221 122 4 18 0 350 1 1 1 97 12 21 0 1816 2 1 196 123 3 15 0 309 1 1 1 97 13 20 0 896 10 323 234 4 16 0 432 2 1 1 97 16 19 0 1448 3 2 343 258 3 14 0 428 1 1 1 96 17 17 0 1182 13 11 212 108 3 17 0 322 1 1 1 97 20 20 0 1212 15 12 340 190 6 27 0 491 2 1 1 96 24 23 0 846 26 24 461 324 6 25 0 608 3 1 1 96 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 0 0 0 2 1 142 1 5 7 0 478 0 0 0 100 1 0 0 88 301 101 142 0 4 6 0 67 0 0 0 100 4 0 0 0 0 0 15 0 4 5 0 56 0 0 0 100 5 0 0 0 0 0 27 0 2 8 0 39 0 0 0 100 8 390 0 405 4 0 65 4 3 16 0 1136 60 15 0 25 9 561 0 431 2 0 61 2 17 6 0 809 18 8 0 74 12 0 0 0 3 1 26 2 4 6 0 46 33 0 0 67 13 0 0 0 3 2 91 1 4 17 0 234 0 0 0 100 16 000 4242210 0 16 00 84 17 0 0 0 2 2 90 0 8 8 0 778 0 3 0 97 20 0 0 0 5 3 191 2 6 22 0 310 0 0 0 100 24 3 0 0 5 4 246 1 5 47 0 376 0 0 0 100 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 0 0 0 4 0 196 4 4 7 0 667 0 0 0 100 1 0 0 88 300 100 14 0 1 4 0 4 0 0 0 100 4 0 0 0 0 0 18 0 1 6 0 82 0 0 0 100 5 0 0 0 1 1 29 0 2 7 0 46 0 0 0 100 8 0 0 0 0 0 26 0 6 5 0 101 0 0 0 100 9 0 0 0 6 0 7 6 12 0 0 100 0 0 0 12 0 0 37103 1 0 45 1 3 16 0 120 0 20 0 80 13 0 0 0 4 2 50 1 1 15 0 52 0 0 0 100 16 000 8276120 0 100 000 17 0 0 44 8 8 41 0 5 11 0 62 0 0 0 100 20 0 0 0 3 2 417 0 9 85 0 650 0 0 0 100 24 0 0 0 19 18 212 0 5 14 0 122 0 0 0 100 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 0 0 0 0 0 9 0 1 2 0 11 0 0 0 100 1 0 0 88 300 100 7 0 1 4 0 0 0 0 0 100 4 0 0 0 0 0 17 0 0 8 0 66 0 0 0 100 5 0 0 0 2 2 27 0 1 6 0 28 0 0 0 100 8 0 0 0 1 0 280 0 3 28 0 427 0 0 0 100 9000 7087120 0 100 000 12 0 0 0 1 0 212 1 4 63 0 738 0 0 0 100 13 0 0 0 2 2 27 0 6 4 0 52 0 0 0 100 16 0 0 0 8 2 7 6 12 0 0 100 0 0 0 17 0 0 0 2 2 25 0 4 7 0 56 0 0 0 100 20 0 0 0 3 2 156 1 13 10 0 292 0 0 0 100 24 0 0 0 4 3 217 0 4 11 0 110 0 0 0 100 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 0 0 0 0 0 19 0 3 2 0 44 0 0 0 100 1 0 0 88 300 100 9 0 5 6 0 14 0 0 0 100 4 0 0 0 0 0 15 0 1 4 0 56 0 0 0 100 5 0 0 0 0 0 25 0 1 8 0 30 0 0 0 100 8 0 0 0 1 0 406 1 4 50 0 624 0 0 0 100 9000 8098120 0 100 000 12 0 0 0 0 0 208 0 1 51 0 739 0 0 0 100 13 00 0 0080240 0000 100 16 0 0 0 9 2 8 7 12 0 0 100 0 0 0
17 0 0 0 2 2 8 О 1 3 0 19 О О О 100 20 О О 0 4 4 37 0 13 4 0 112 0 0 0 100 24 0 0 0 6 6 222 0 8 8 0 108 0 0 0 100 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0000 0030140 0000 100 1 0 0 88 300 100 23 0 6 2 0 76 0 0 0 100 4000 00 18 0190 40 000 100 5 00 0 2 2 36 0 3 6 0 40 0 0 0 100 8 0 0 0 1 0 403 0 4 56 0 627 0 0 0 100 9000 7097140 0 100 000 12 0 0 0 0 0 209 0 0 42 0 732 0 0 0 100 13 0 0 0 0 0 7 0 14 0 3 0 0 0 100 16 0 0 0 8 18 7 12 0 0 100 0 0 0 17 0 0 0 2 2 9 0 2 4 0 30 0 0 0 100 20 0 0 0 3 3 22 0 3 5 0 63 0 0 0 100 24 0 0 0 16 14 222 1 6 8 0 107 0 0 0 100 Я не стал приводить весь текст, поскольку это ни к чему. Итак, для трех потоков mpstat показывает, что в любую конкретную секунду используются либо два процессора, либо один. Похоже, что jre 1.1.7 неспособна эффективно распределять работу между двумя процессорами. Третий поток назначается одному из двух процессоров, а все остальные процессоры вообще не используются. Попробуем, как раньше, отключать процессоры один за другим и выполнять на них от 1 до 24 потоков. На рис. 16.5 приведен график результатов. Рис 16.5. Добавление процессоров оказывается неэффективным, если вы пишете многопоточную программу на Java
Видно, что два процессора иметь гораздо лучше, чем один, но большее количество процессоров ситуацию никак не улучшает. (На графике виден провал, связанный с тем, что кто-то другой подключился к компьютеру и запустил свой тест.) Таким образом, можно утверждать, что jre 1.1.7 не обеспечивает хорошей масштабируемости на многопроцессорном оборудовании фирмы Sun. Пообщавшись по электронной почте с представителем фирмы Sun, я получил подтверждение, что при отображении потоков Java на легковесные процессы или потоки ядра (Light Weight Process — LWP), судя по всему, создавалось не более двух потоков. Именно LWP реально выполняются процессорами, поэтому наша программа и не могла задействовать более двух процессоров. Все наши пользовательские потоки превращались в эквивалентное количество внутренних потоков Java, которые, в свою очередь, отображались на два потока ядра. Существует три способа устранения этой проблемы с масштабируемостью. 1. Вы можете продолжать работать с Java 1.1.7 и написать метод, обращающийся к интерфейсу thr_setconcurrency (для получения более подробных сведений об этом методе введите команду man thr_setconcurrency), который позволяет указать библиотеке потоков Sun на необходимость создания большего количества потоков ядра. Однако при этом ваша программа утратит переносимость. 2. Вы можете обновить операционную систему до Solaris 8 и работать с одноуровневой библиотекой потоков, которая отображает потоки пользовательского уровня непосредственно в потоки ядра. Эта библиотека подключается к программам путем настройки значения переменной LD_LIBRARY_PATH. 3. Вы можете обновить виртуальную машину до Java 1.2.2, которая автоматически вызывает thr_setconcurrency, устанавливая количество потоков ядра равным количеству процессоров в компьютере. Работа с Java 1.2.2 требует установки заплат в ядро Solaris 2.6. Я выбрал третий способ: запустил предыдущий тест в Java 1.2.2 в системе Solaris 2.6 с соответствующими заплатами и получил результат, показанный на рис. 16.6. Теперь график выглядит гораздо лучше! Мы видим знакомую горизонтальную линию в левой части и не видим больше никаких ступенек. Похоже, что все наши процессоры аккуратно распределяются между потоками Java, причем загружаются полностью. Таким образом, выяснилось, что Java 1.2.2 решит проблему масштабируемости, имеющуюся у Java 1.1.7. К сожалению, в том месте, где я работаю, достаточно сложно производить глобальные изменения типа установки заплат в операционную систему и задания нового значения переменной jres. Поэтому мы не смогли применить предложенное выше решение к своей проблеме, а вместо этого создали больше процессов Java 1.1.7 и распределили нагрузку между ними. Это позволило более эффективно использовать процессоры, хотя каждый из процессов продолжал выполняться лишь на двух из них.
seaUatJi I i ty of jav* 1.2. Z threads ,rflf seconds to completion .jdflll^^^^^^^' j | | ■ ; ! gj^^ -:: i' д^у^ЁДЙ? /" / б nuwber of cpus number of threads Рис 16.6. Установка Java 1.2.2 исправляет проблему с масштабируемостью Мне удалось найти сервлет, который создавал более реалистичную для вебсайта нагрузку, чем счетчик. Этот сервлет выполнял сложную работу со строками и генерировал большой объем HTML. Я добавил в него цикл, чтобы обработка строк выполнялась 100 раз вместо одного, а затем выбросил операции вывода HTML, вставив вместо них одну команду, возвращавшую несколько байтов, указывавших на успешное завершение сценария. Цель была в том, чтобы оценить производительность процессора, а не сетевого интерфейса. Кроме того, я специально исключил доступ к базам данных и диску, чтобы эти операции не стали «узким местом» программы. Я запустил сервлет в системе Weblo- gic 4.5.1 на виртуальной машине Java 1.1.7 в операционной системе Solaris 2.6. Количество потоков выполнения Weblogic было установлено равным 15. Поскольку сервлет должен был обращаться к обычной памяти, а не только к кэшу процессора, я не рассчитывал получить результаты, которые бы свидетельствовали о хорошей масштабируемости. И я действительно не получил таких результатов, но тем не менее остался доволен (рис. 16.7). Заметьте, что это график пропускной способности, а не времени работы программы, поэтому чем больше числа, тем лучше. Пиковое значение достигается при 12 процессорах и 12 виртуальных машинах Ore). С одной виртуальной машиной увеличение количества процессоров свыше двух не приводит к повышению пропускной способности. Этого и следует ожидать, учитывая, что одна виртуальная машина jre 1.1.7 может использовать только два процессора. При
увеличении количества виртуальных машин увеличивается и выигрыш, достигаемый добавлением процессоров. С другой стороны, учет времени ожидания при обращениях к диску и сети увеличивает количество виртуальных машин, которые могут быть запущены одновременно, потому что заблокированные виртуальные машины не будут тратить время процессоров, которые смогут заниматься выполнением других jre. Рис. 16.7. Балансировка нагрузки между несколькими потоками Java 1.1.7 Для еще большей реалистичности я запустил аналогичный тест для страницы, формирование которой требовало обработки сложных запросов к базе данных. Поскольку мы добавляем в систему новое слабое звено — базу данных, выигрыш от увеличения количества виртуальных машин и процессоров становится менее значительным. После увеличения количества машин до двух или количества процессоров до четырех производительность выходит на уровень насыщения и остается неизменной, а значение ее определяется базой данных (рис. 16.8). Резюме: виртуальная машина Sun 1.1.7 не может использовать более двух процессоров в системе Solaris 2.6 на компьютерах Sun. Это можно исправить тремя способами: добавив вызов метода (действующего только в Solaris), обновив операционную систему или виртуальную машину. Можно и обойти проблему, запустив несколько виртуальных машин. Оборудование Sun действительно обеспечивает высокую масштабируемость, но расширение мощностей может потребовать некоторых усилий, из которых большая часть будет затрачена на тестирование.
seal ability о* page gene-rated by riat-abase access d ■: '■' ■ hits per second throughput ^rWf$h-¥'^'H ■' ■ л"' пил ег о j es ^ 0 Рис. 16.8. База данных накладывает новое ограничение на масштабируемость Жесткий диск Вторым по степени влияния на реальную производительность сервера параметром после пропускной способности подключения к Интернету является быстродействие его жестких дисков. Если вам кажется, что все сделано как надо, но производительности все равно не хватает, проблема может заключаться в жестких дисках сервера. Вы помните, во сколько раз обращение к жесткому диску медленнее по сравнению с обращением к ОЗУ? Соотношение между сотней наносекунд, затрачиваемых на доступ к памяти, и десятком миллисекунд, затрачиваемых на доступ к диску, такое же, как между 1 секундой и 28 часами A00 000 раз). И это еще довольно быстрый диск! По указанной причине следует избегать обращения к жестким дискам везде, где это возможно. Если же нам приходится работать с диском, то пусть он будет быстрым. Архитектура и параметры дисков Своим названием жесткие диски определяются полностью: это жесткие «тарелки», покрытые магнитным материалом, способным хранить информацию. В одном жестком диске обычно бывает несколько (и даже множество) таких пластин. Блок пластин называется шпинделем. У каждой пластины имеется своя считывающая головка, размещенная на консоли или приводе, который можп
перемещаться по дуге, достаточно широкой, чтобы головка могла расположиться над любой точкой радиуса пластины. Диски обычно раскручиваются сразу после включения питания компьютера и вращаются до тех пор, пока вы не выключите питание. Портативные компьютеры и другие «озабоченные» состоянием батарей приборы могут останавливать диски после некоторого периода бездействия, но на веб-серверах все подобные функции следует отключить, потому что раскрутки диска, как правило, приходится ждать несколько секунд. Жесткие диски обычно вращаются со скоростями 7200-10 000 об/мин. Поскольку у дисков имеются движущиеся части — пластины и консоли, этот компонент вашего оборудования имеет больше всего шансов сломаться. Чтобы не волноваться из-за отказов дисков, нужно организовать из них избыточный массив. Об одном из стандартов таких массивов мы в скором времени поговорим. Он называется RAID. Самым важным для сервера параметром жесткого диска является максимальное время поиска, затрачиваемое головкой диска на перемещение к самой дальней дорожке. Головки дисков подвергаются действию сил инерции, и именно эта инерция, а также конечная скорость перемещения ограничивают производительность диска. Когда головка останавливается над дорожкой, она еще некоторое время колеблется, и диску приходится ждать, пока она остановится, прежде чем можно будет начать чтение или запись данных. Время ожидания для дисков определяется как максимальное время, затрачиваемое на то, чтобы любой сектор дорожки мог достичь головки, после того как та зафиксируется в нужном положении. Время ожидания обратно пропорционально скорости вращения диска. Время поиска обычно оказывается намного больше скорости вращения, поэтому именно оно является «узким местом». Время поиска — более важный параметр, чем пропускная способность, потому что диски большую часть времени тратят на поиск, а не на передачу данных. Для уменьшения среднего времени поиска диски часто пытаются накапливать запросы, а затем выполняют их в таком порядке, чтобы минимизировать перемещение головки. Конкретный используемый алгоритм зависит от контроллера диска, но обычно применяется алгоритм лифта (elevator), согласно которому головки движутся в одном направлении до тех пор, пока в очереди попадаются запросы, выполнение которых связано с движением в этом направлении. Как только такие запросы заканчиваются, направление движения головок изменяется на противоположное. Лучшая производительность в среднем достигается между шпинделем и внешним цилиндром, поскольку до этой дорожки головкам приходится проходить самое меньшее среднее расстояние. Некоторого повышения производительности можно достичь, разместив наиболее часто используемую файловую систему вблизи середины диска. У дисков имеется собственная кэш-память, используемая в основном для ускорения операций записи на диск. Эффективность использования кэш-памяти зависит от того, какова доля операций записи в общем количестве обращений к диску. Веб-серверам обычно приходится считывать значительные объемы данных, а заносят они лишь небольшие по объему записи в журналы, поэтому полезность больших объемов кэша сомнительна.
Локальные диски, размещенные на том же компьютере, обеспечивают большую производительность, чем сетевые; но высокоскоростные соединения, например оптоволоконные, постепенно устраняют это различие. На веб-сервере должно быть по меньшей мере два диска: один для содержимого и еще один для журналов веб-сервера. Если вы можете себе это позволить, то нужно купить еще один диск для самой операционной системы, которой тоже нужны ресурсы жестких дисков. Для содержимого следует отводить самый быстрый диск, потому что отправка содержимого требует больше ресурсов, чем ведение журнала, и непосредственно связана с реальной производительностью. Пользователям безразлично, что у вас там творится с журналами; это важно только для вас. Вы можете еще больше повысить производительность, отведя еще один диск для виртуальной памяти. Балансируйте нагрузку между дисками, чтобы каждый из них выдавал все, на что способен. Установка отдельного контроллера для каждого жесткого диска уменьшит состязание за ресурсы. Если же у вас один контроллер обслуживает несколько дисков, убедитесь, что его пропускная способность равна суммарной пропускной способности всех дисков, подключенных к нему или превышает ее. Сейчас на рынке появляются твердотельные диски. Такие диски основаны на энергонезависимой памяти, либо на флеш-картах, либо на ОЗУ с батареями, а подключаются по интерфейсу SCSI или аналогичному, то есть системе такие диски кажутся самыми обычными. В них нет движущихся частей, поэтому они редко ломаются — в отличие от обычных дисков. Время доступа у них в тысячи раз меньше, чем у вращающихся жестких дисков. Главным недостатком твердотельных дисков является их стоимость, которая сравнима (в долларах за мегабайт) со стоимостью обычной памяти. Еще один недостаток состоит в том, что системная память быстрее, чем такие диски, поэтому если у вас есть деньги, то лучше их потратить именно на системную память — это даст больший прирост производительности. Тем не менее, если вы до предела заполнили свой вебсервер микросхемами памяти, установка твердотельного жесткого диска может быть экономически более эффективна, чем обновление веб-сервера целиком. IDE Диски, устанавливаемые на персональных компьютерах, как правило, изготавливаются в соответствии со стандартом IDE (Integrated Device Electronics). Это обычные диски для широкого потребительского рынка, не слишком дорогие, но и не слишком быстрые, надежные или масштабируемые. Диски IDE можно приспособить для ведения журнала веб-сервера, но они не подходят в качестве высокопроизводительных дисков с файлами содержимого или базой данных. EIDE Стандарт EIDE представляет собой расширенную версию стандарта IDE. Он не был разработан с нуля, поэтому ему присущи некоторые недостатки IDE. On не обеспечивает достаточной масштабируемости, но обеспечивает большую производительность, чем IDE.
SCSI Высокопроизводительные диски производятся в соответствии со стандартом сокращенного программного интерфейса с компьютером (Small Computer Software Interface — SCSI). SCSI — это тип интерфейса, используемого дисками для взаимодействия с компьютером, а не тип самих дисков, но так уж повелось, что диски, подключаемые через такой интерфейс, называются SCSI-дисками. SCSI- диски разработаны для использования как в одиночку, так и в составе больших массивов. Контроллеры SCSI могут иметь собственную кэш-память, а также поочередно направлять запросы на разные диски для повышения пропускной способности. Если вы работаете в режиме распределения запросов, наивысшая производительность будет достигнута в случае балансировки нагрузки между равноценными дисками. Вы можете координировать работу нескольких контроллеров SCSI. С помощью iostat или sar в системе Solaris можно отслеживать загрузку дисков, проверяя, что нагрузка действительно сбалансирована. В последовательную цепочку может быть выстроено до 7 дисков SCSI 1 или 15 дисков SCSI 2; каждый из дисков может быть размером не более 6 Гбайт. Обычный стандарт SCSI обеспечивает пропускную способность от 5 до 10 Мбайт/с. Интерфейс Wide UltraSCSI обладает пропускной способностью 40 Мбайт/с C20 Мбит/с), и на данный момент это наиболее распространенная разновидность SCSI. Диски с таким интерфейсом обычно вращаются со скоростью 10 000 об/мин и обладают очень малым временем поиска и ожидания. Интерфейс Narrow UltraSCSI передает данные с пропускной способность 20 Мбайт/с A60 Мбит/с). И широкий и узкий интерфейсы UltraSCSI разрешают протягивать кабели дайной до 3 м, что только кажется достаточным, но на самом деле может быть и маловато для больших систем. Разностный (Differential) интерфейс SCSI позволяет увеличить длину кабеля до 25 м, а в остальном не отличается от Wide и Narrow. Стандарт SCSI развивается, и сейчас можно найти диски UltraSCSI 2 (80 Мбайт/с) с длиной кабеля до 12 м. SCSI-диски стоят дороже, чем EIDE-, но они окупаются. Все ваше содержимое должно быть размещено именно на таких дисках. Fibre Channel Вы можете заменить интерфейс SCSI на Fibre Channel, обеспечивающий более высокую производительность. Fibre Channel — стандарт последовательного соединения, широко используемый в серверах Unix, но редко встречающийся в более дешевых системах. Его главное преимущество заключается в том, что он позволяет соединять периферийные устройства с сервером, а сам сервер — с другими серверами. Теоретическое ограничение на расстояние составляет 10 км. Это в тысячу раз больше, чем у интерфейса SCSI, ограниченного длиной 10 м.
На данный момент Fibre Channel позволяет достичь пропускной способности 100 Мбайт/с B00 Мбайт/с в двустороннем режиме). Стандарт Fibre Channel был разработан для использования с оптическим волокном, но при желании вы можете использовать и коаксиальный кабель, и витую пару. Стандарт этот дает возможность нескольким серверам совместно работать с одним диском (в отличие от SCSI), и он допускает работу как в коммутируемом, так и в коллективном режиме (как Ethernet). Поскольку названный стандарт позволяет работать с диском напрямую, вы можете устранить часть задержки, возникающей в результате необходимости преобразовывать данные из формата Ethernet в формат SCSI и обратно. Fibre Channel предназначается для серверов. Пропускная способность кабеля пропадала бы зря, если бы к нему был подключен персональный компьютер, неспособный обработать такой объем данных. Будущее стандарта неясно, потому что с ним соревнуются стандарты Ethernet и SCSI, которые постоянно обновляются, a Fibre Channel не слишком хорошо интегрируется с ними. RAID Избыточный массив недорогих дисков (Redundant Array of Inexpensive Disks — RAID) является примером того, как из относительно низкопроизводительных компонентов можно собрать нечто обладающее высокой производительностью. Идея массива RAID состоит в использовании нескольких дисков, с тем чтобы каждый бит информации хранился по меньшей мере на двух дисках и отказ одного из них не приводил к отказу системы целиком. Благодаря этому вы можете покупать более дешевые диски, которые менее надежны. Быстродействие систем RAID оказывается выше — потому, что система может обслуживать несколько запросов параллельно, и еще потому, что у маленьких дисков время поиска может быть меньше, так как их физические размеры тоже меньше, чем у больших дисков. Например, четыре диска по 2 Гбайт обычно дают большую производительность, чем один диск на 2 Гбайт. Массивы RAID обычно продаются как пакеты, которые воспринимаются компьютером как один большой диск. Аналогичная концепция чередования записи заключается в том, что блоки данных распределяются по нескольким дискам, что увеличивает параллельность доступа и уменьшает время поиска (опять же благодаря меньшим размерам дисков). Производительность типичных дисков Современные диски обычно работают на скорости 7200 об/мин и могут выполнять до 100 операций ввода-вывода в секунду (со случайным доступом), или 500 последовательных запросов на запись или чтение в секунду. Кроме упомянутых выше на рынке присутствует множество дисков со скоростями 5400 об/мин G5 случайных операций ввода-вывода в секунду) и 10 000 об/мин (около 140 таких операций). Сто операций доступа в секунду соответствуют времени поиска в 10 мс, поскольку большая часть времени при работе с дисками тратится на поиск данных.
Диски на персональных компьютерах обеспечивают пропускную способность 8-16 Мбит/с, а такие же диски в системах Unix способны выдать 32—40 Мбит/с благодаря оптимизации доступа к диску, выполняемой этой операционной системой. Одним из недостатков файловой системы Unix является необходимость обновления узлов inode и суперблока при записи в файл, что требует выполнения множества операций поиска. Файловая система BeOS, рассчитанная на ведение журналов, не обладает этим недостатком. Чтобы оценить количество дисков, необходимое для конкретного веб-сервера при условии, что данные будут считываться не из памяти, возьмите среднее количество хитов в секунду, умножьте его на три (пиковое значение), а затем умножьте еще на два, чтобы получить пиковое количество хитов в секунду для диска. Помните, что вам нужно считать содержимое каталога, чтобы узнать о разрешении доступа к файлу (системный вызов ореп()), прежде чем вы сможете считать сам файл (системный вызов read()). Так что если у вас количество хитов веб-сервера в секунду равно 30, то ваш диск должен быть способен выдавать 180 случайных операций доступа в секунду, чтобы пользователи не замечали задержек. Чтобы достичь этой пропускной способности, вам придется купить два диска со скоростью 7200 об/мин и объединить их в массив RAID или в чередующийся массив. Мы можем, таким образом, сформулировать простое правило: диск, рассчитанный на 100 операций в секунду, может быть использован в системе, получающей в среднем 17 хитов в секунду. В реальности вы сможете «выжать» из дисков больше, потому что операционная система будет кэшировать имена каталогов и узлы inode, экономя время на поиски. Чередование дисков повышает производительность только в том случае, если у вас есть несколько контроллеров. В противном случае «узким местом» становятся сами контроллеры. Фрагментация По мере заполнения дисков операционной системе становится все труднее находить непрерывные свободные участки для записи файлов, поэтому она выбирает небольшие куски и записывает файлы в виде фрагментов. Чтение и запись фрагментированного файла требует больше времени, потому что головкам диска приходится перемещаться с одного места на другое. Фрагментация становится более серьезной проблемой, когда диски заполняются, поэтому есть смысл оставлять на всех дисках не менее 10% свободного места. Диски в системах Windows и Macintosh требуют регулярной дефрагмента- ции, поэтому в составе этих операционных систем поставляются соответствующие утилиты. Диски в системах Unix фрагментируются медленнее благодаря более совершенным алгоритмам записи, но время от времени и им требуется дефрагментация. Самым эффективным способом дефрагментации диска в системе Unix является архивация этого диска на магнитную ленту, инициализация файловой системы с помощью mkfs, а затем восстановление ее с ленты. Эта задача упростится, если вы совместите ее с регулярной процедурой резервного копирования.
Часто можно отследить процесс, который чрезмерно нагружает диск. Например, в системе Solaris для этого можно использовать команду iostat -x. Если вы найдете диск, который загружен больше всего, просмотрите символьные ссылки в каталоге /dev/sdl5*, чтобы узнать, какому контроллеру и диску соответствует этот каталог. Предположим, sdl5 отображается на cOtOdOsO (контроллер 0, объект 0, диск 0, вырезка 0). После этого с помощью команды mount вы узнаете, какая файловая система размещена на диске /dev/dsk/c0t0d0s0. Теперь с помощью команды fuser вы сможете выяснить, какие процессы в данный момент используют эту файловую систему. Программа truss позволяет определить, какие из этих процессов заняты записью на диск. Процедура сложна, но она помогает узнать, кто перегружает диск. К сожалению, все усложняется при переходе на более современные системы SparcStorage (массив дисков) и Veritas (файловая система). Активность дисков и идентификаторы процессов Активная работа с диском способна значительно снизить производительность, однако, насколько я знаю, не существует способа узнать, какой именно процесс отвечает за активность дисков в любой конкретный момент. Скорее всего, это вовсе невозможно, учитывая, что операции чтения и записи группируются, а момент их выполнения выбирается ядром, а не самими процессами. Основные рекомендации О Не беспокойтесь о процессоре, если ваш сервер доставляет клиентам в основном статическое содержимое. Главное, чтобы у вас было хорошее сетевое соединение, быстрые диски и достаточно памяти. О Купите достаточно памяти, чтобы в ней помещалось дерево документом HTML целиком. О Лучше использовать диски SCSI, а не IDE. О Храните содержимое и журналы на разных дисках. О По поводу оптимизации серверов Sun можно обратиться по адресу: http://www.sun.com/sunworldonljne/
17 Операционная / система сервера Операционная система — посредник между оборудованием и программным обеспечением веб-сервера, который отвечает на аппаратном уровне, когда веб-сервер запрашивает его о каких-либо действиях. Операционная система доставляет данные с интерфейсов устройств веб-серверу. Максимальная производительность оборудования сервера строго фиксирована — она задается его физическими спецификациями. Приблизиться к этой максимальной производительности можно, сделав конфигурацию операционной системы оптимальной. Для веб-сервера задача стоит просто: нужно настроить операционную систему так, чтобы она принимала запросы из сети, находила нужный файл для считывания или запускала нужную программу, а затем отправляла результаты на сетевой интерфейс — и все это должно делаться как можно быстрее. Данная глава будет практически целиком посвящена операционной системе Unix в различных версиях, за исключением небольшого раздела, в котором эта операционная система сравнивается с Windows NT. В самом последнем (апрель 1999 года) исследовании из тех, что мне удалось найти (http://leb.net/hzo/iosco- unt/), установлено, что около 75% всех веб-сайтов работает под управлением той или иной версии Unix, а еще 24% базируется на операционных системах компании Microsoft. Среди версий Unix 27% составляет Linux; Solaris и SunOS — 20%; BSD - 16%. Unix и рождение Сети Операционная система Unix изначально разрабатывалась для работы в сетях. Unix был создан около 1970 года; это был исследовательский проект в лабораториях Bell Labs фирмы AT&T. Ключевыми концепциями были многозадачность и многопользовательский режим. Эти концепции были взяты из правитель-
ственного исследовательского проекта 60-х годов, который назывался Multics. Поскольку AT&T не могла продавать программное обеспечение, являясь телефонной компанией-монополистом, она разрешила университетам использовать исходный код в образовательных и исследовательских целях. Университет штата Калифорния, расположенный в Беркли, продолжил работу над реализацией стека TCP/IP в ядре Unix. Исследовательская группа Беркли внесла в систему столько изменений, что это привело к делению Unix на два главных лагеря — Berkeley Unix и AT&T Unix — и это деление просуществовало примерно 10 лет. Около 1988 года произошло слияние в систему Unix System V Release 4 (SVR4), однако наследники представителей двух лагерей продолжают бороться — примером могут служить BSDI и SCO Unix. Протокол HTTP и первый веб-сервер были разработаны и реализованы на платформах Unix, естественным образом родившись из проводившихся ранее работ. HTTP унаследовал многие свои свойства от FTP, добавив к нему автоматизированные запросы. Первый широко распространенный веб-сервер httpd, созданный в университете штата Иллинойс, был классическим демоном Unix. На тот момент все операционные системы Unix поддерживали TCP/IP и FTP, поэтому технологический скачок от существовавших протоколов к протоколу Сети был весьма невелик сравнительно с его влиянием на мир. Поскольку практически все компьютеры Unix были соединены сетями, было очень легко скачать httpd из университета штата Иллинойс и запустить его на своем компьютере. Программа распространялась бесплатно — ведь она появилась как результат проекта, оплачиваемого налогоплательщиками. Технология веб распространялась со скоростью взрыва, потому что Интернет был заправлен информацией и ждал нового простого интерфейса для доступа к ней. Веб-серверы и клиенты были быстро перенесены и на другие платформы, такие как Windows, Macintosh, и даже на мейнфреймы с операционной системой AS/400, но большая часть веб-серверов продолжала работать под управлением Unix. Эта операционная система превосходила все остальные в стабильности и производительности благодаря своей долгой истории развития и открытому исходному коду. Попросту говоря, большее число людей смогло внести свой вклад в улучшение этой системы за долгие годы ее существования. Разработка частных платформ была ограничена количеством оплачиваемых сотрудников компании, a Unix пожинал плоды трудов всего научного и Интернет-сообщества. (Интересный гибрид открытого и закрытого подходов возник в результате стремления компании Netscape задействовать творческие способности сообщества Интернета и выкладывания ею в открытый доступ для изучения и улучшения исходного кода своего браузера. Скачать его можно по адресу: http://www. mozilla.org/.) Версии Unix С одной стороны, можно утверждать, что рынок операционных систем Unix выигрывает от соревнования разных производителей, но с другой стороны, верно и противоположное утверждение: этот рынок страдает от конкуренции произво-
дителей. Проблема в том, что производители создали свои собственные версии Unix, несовместимые друг с другом. Это означает, что исполняемый файл, скомпилированный для одной из версий Unix, обычно не может выполняться ни в какой другой версии, даже если оборудование компьютеров будет полностью идентичным. Эта проблема постепенно решается. Сначала на рынке стал доминировать стандарт SVR4. Есть такая старая шутка: фирме Sun удалось объединить производителей Unix, но, к сожалению, они объединились в коалицию против этой фирмы. Так или иначе, SVR4 является на данный момент стандартом де-факто. Программы, написанные в соответствии с этим стандартом, обладают переносимостью на уровне исходного кода на другие операционные системы SVR4. Это означает, что вы можете компилировать код в любой системе безо всяких изменений. Затем возросла популярность операционной системы Solaris корпорации Sun Microsystems, реализующей стандарт SVR4, и таким образом Solaris начал становиться стандартом де-факто для переносимости на уровне исполняемых файлов, а будущее прочих версий Unix, за исключением Linux (который, строго говоря, не является версией Unix), оказалось под сомнением. Наконец, по мере того как все больше приложений переносится или пишется с нуля на Java, небольшие различия между операционными системами становятся несущественными. Системам придется соревноваться в производительности и стоимости, а не в совместимости. В последующих разделах мы рассмотрим основные версии Unix, используемые для устройства веб-серверов. Solaris Операционная система Solaris представляет собой версию Unix, созданную корпорацией Sun Microsystems (http://www.sun.com/). Когда Беркли-совместимая операционная система SunOS была сделана совместимой и с SVR4, она получила новое название — Solaris. Существуют версии Solaris для процессоров SPARC фирмы Sun и для процессоров х86 фирмы Intel. Solaris для SPARC лидирует на рынке Unix по количеству продаж, поэтому вы можете быть уверены, что любое многоплатформенное программное обеспечение для Unix в первую очередь будет портировано под Solaris, под ним отлажено и, возможно, даже оптимизировано для Solaris. Это очень важно, потому что у производителей программного обеспечения не хватит сил на то, чтобы оптимизировать программы под все существующие версии Unix. Solaris лидирует на рынке операционных систем для веб-серверов отчасти благодаря производительности и надежности этой операционной системы, но также и потому, что эта система лидирует на рынке программного обеспечения для образования в области информатики. Студенты, которые учатся программировать и администрировать в системах Solaris, продолжают использовать их и дальше, в реальной работе. Одним из достоинств Solaris является эффективность алгоритмов выделения памяти, которое приходится выполнять так часто, что оно может заметно влиять на производительность системы в целом. Выделение памяти ускоряется ис-
пользованием специальных команд, доступных только операционной системе, но не пользовательским приложениям. Solaris 8 — последняя версия на момент написания книги — по умолчанию настраивается так, что веб-сервер, запущенный в этой системе, не требует особого изменения настроек. Кроме того, эта система обладает некоторыми фундаментальными улучшениями по сравнению с предыдущими версиями. Нас интересуют, конечно, улучшения, имеющие отношение к Сети: более эффективная реализация стека TCP/IP, больший объем сетевого кода в ядре, лучшая поддержка многопроцессорности. AIX Операционная система AIX от IBM завоевала репутацию простой в использовании и обладающей обширным набором вспомогательных средств. Некоторые крупные корпоративные веб-сайты работают на этой ОС, что говорит о ее достаточной стабильности и масштабируемости. Digital Unix Система Digital Unix известна исключительно высоким быстродействием подсистемы ввода-вывода, которая достигается благодаря эффективности драйвера диска и реализации TCP/IP, что делает ее подходящей для установки веб-сервера. Digital Unix выпускается в 64-разрядном варианте, опережая в этом отношении большую часть прочих версий Unix. Данная система очень хорошо масштабируется — примером является поисковый сервер AltaVista. Linux Linux — бесплатное ядро, родственное Unix. Изначально Linux был написан для процессоров архитектуры Intel, но позднее его перенесли на Alpha, Power PC и даже на SPARC. Отцом Linux считается Линус Торвальдс из Финляндии. Помните, что Linux — это только ядро, но не утилиты, обеспечивающие взаимодействие пользователя с этим ядром. Linux поставляется в виде дистрибутивов, подготавливаемых разными организациями. В состав дистрибутивов обычно входят утилиты проекта GNU — компилятор gcc и интерпретатор команд bash, а также версия X Window System, которая называется XFree86. В плане масштабируемости Linux еще нельзя считать столь же зрелой системой, как Solaris. До недавних пор количество одновременно выполняющихся процессов было ограничено 256-ю, а поддержки многопроцессорности не было вообще никакой. Тем не менее Linux так же устойчив и производителен, как многие коммерческие версии Unix, а переключение процессов осуществляется в нем значительно быстрее, чем в Solaris. Веб-страницы Linux вы можете найти по адресам http://www.li.org/ и http:// www.linux.org/. Бесплатную поддержку всегда обеспечат группы Usenet, специа лизирующиеся на этой операционной системе, а за плату вам помогут и компании типа Cygnus. После переноса на Linux базы данных Oracle эта операци-
онная система стала рассматриваться в деловом мире как серьезная платформа. Несколько крупных веб-сайтов работают на бесплатном сервере Apache под Linux. Irix Irix — это версия Unix, разработанная фирмой Silicon Graphics для своих высокопроизводительных графических рабочих станций. Данная версия может работать только на оборудовании Silicon Graphics. Оборудование это оптимизировано для работы с графикой, но многие его особенности, такие как очень быстрая память и диски, полезны и для веб-серверов. К сожалению, Irix не столь хорошо поддерживается поставщиками программного обеспечения типа Netscape, как, к примеру, Solaris, поэтому появления версий программ для Irix всегда приходится ждать некоторое время. О том, как настраивать Irix для установки вебсерверов, читайте по адресу: http://www.sgi.com/. BSD Стандартный дистрибутив Unix университета Беркли (Berkeley Standard Distribution — BSD) схож с Linux в том плане, что используется для небольших вебсайтов и работает на процессорах Intel x86. В отличие от Linux BSD включает не только ядро, но и все утилиты с документацией. Продолжателями BSD стали операционные системы BSDI (http://www.bsdi.com/) и FreeBSD (http://www. freebsd.com/). Mach OS Список версий Unix, используемых в Сети, был бы неполным, если бы мы не включили в него операционную систему Mach OS. Mach был разработан в университете Карнеги—Меллона и послужил основой для создания операционной системы NextStep, на которой Тим Бернерс-Ли (ЦЕРН, Швейцария) создал первую реализацию HTTP. Mach OS является ядром операционной системы Macintosh OS X. Это микроядро, которое не занимается ничем, кроме работы с оборудованием. Файловая система и управление процессами надстраиваются сверху. Устройство Unix Займемся теперь рассмотрением принципов работы Unix, помня о том, что больше всего нас интересует производительность. Системные и библиотечные вызовы Операционная система — это способ абстрагировать оборудование в набор вызовов, которые могут делаться из программ. Эти вызовы выполняются ядром, и только посредством вызовов программы могут работать с аппаратурой компью-
тера. Системные вызовы существенно отличаются от вызовов библиотечных функций, хотя с программной точки зрения они и могут выглядеть очень похоже. Изначально в системе Unix системных вызовов было немного: read, write, open, creat (именно так!), dose, fork, exec, wait, exit. Деннис Ритчи хорошо объяснил, что именно было сделано и почему, в статье -«Эволюция системы разделения времени Unix» (http://cm.bell4absxom/cm/cs/who/dmr/hist.html). Процессы и ядро Вся работа в Unix выполняется процессами, которые можно представлять себе как задачи, подлежащие выполнению. Каждый из процессов обладает уникальным идентификатором (обычное целое число) и владельцем, а также приоритетом и многими другими атрибутами, которые выводятся командой ps. Unix — многозадачная многопользовательская операционная система, которая, следовательно, может параллельно выполнять множество процессов множества пользователей. (NT, например, является многозадачной, но не многопользовательской операционной системой.) Конечно, процессы Unix выполняются не строго одновременно, но выглядит все именно так, потому что операционная система дает каждому из них выполняться лишь небольшой период, после чего процесс прерывается, а управление передается следующему (система, близкая к круговой). Процесс, осуществляющий планирование выполнения других процессов, выполняется в ядре и называется планировщиком. В качестве единиц времени при планировании используются кванты времени (clock ticks) — сотые доли секунды, поэтому любому процессу, если уж он был запущен, отводится никак не меньше 1/100 с. Сам планировщик отводит себе гораздо меньшее время — около 1 мс. Это время называется временем ожидания планировщика. Оно возрастает по мере увеличения количества одновременно выполняемых процессов. Ядро представляет собой некоторую область адресного пространства, а также процессы, выполняющие планирование и некоторые другие фундаментальные операции, такие как взаимодействие с оборудованием для отображения информации на экране или считывания ее с диска. Только ядро обладает прямым доступом к оборудованию, а пользовательским программам ядро доступно лишь посредством системных вызовов, являющихся интерфейсом ядра. Такая схема обладает рядом преимуществ: ядро не дает пользовательским процессам делать нехорошие вещи с оборудованием — например, считывать с диска чужие файлы. Кроме того, системные вызовы всегда одинаковы и не зависят от оборудования, что делает исходный код программы переносимым. SVR4 во многом является лишь спецификацией системных вызовов, поэтому программы, написанные с использованием только этих системных вызовов, должны компилироваться и вы- подняться в любой системе SVR4. Планирование Если быть точным, планировщик задач выделяет процессам время не строго по круговой системе. Он присваивает каждому процессу определенный приоритет,
а затем решает, какой из процессов будет запущен следующим, в соответствии с некоторым алгоритмом, который зависит от конкретной системы. Выбор процесса зависит от того, каким приоритетом он обладает, сколько он ожидал в очереди на выполнение, от состояния аппаратных прерываний и других факторов. Чем больше процессов будет выполняться, тем хуже производительность каждого из них. Переход от одного процесса пользовательского уровня к другому называется переключением контекста. Это относительно дорогостоящая операция, поскольку она требует очистки некоторых кэшей, например кэша преобразования адресов в блоке управления памятью (Memory Management Unit — MMU), а также сохранения и восстановления регистров процессора. Переход в режим ядра (системный вызов) выполняется гораздо быстрее, чем переключение между пользовательскими процессами, Но также занимает некоторое время. Последите за средней загрузкой системы с помощью программы perfmeter, если она у вас есть. Если у вас компьютер с одним процессором, и средняя загрузка примерно равна двум (то есть в среднем в любой момент ожидают выполнения два процесса), а процент загрузки процессора велик, то вы пытаетесь одновременно выполнять слишком большое количество процессов и вам стоит подумать о завершении тех из них, которые вам менее всего нужны. Перенесите часть нагрузки на другой компьютер или обновите оборудование. С другой стороны, если количество ждущих процессов велико, а загрузка процессора низка, вы, возможно, просто недостаточно хорошо настроили систему, или выполняемое приложение плохо написано, или ваша нагрузка имеет резко выраженный импульсный характер. Планировка процессов должна занимать часть ресурсов, но я не смог измерить временные расходы на планирование на своем компьютере с Linux, поскольку максимальное разрешенное количество процессов B50 или около того) было недостаточным для нагрузки процессора. По моим оценкам, время работы планировщика должно измеряться в микросекундах. Сервер, на котором выполняется единственный процесс, не будет тратить время на планировку или переключение контекста. В принципе, можно вовсе избавиться от операционной системы и выполнять одно лишь приложение. Проект Exokernel, речь о котором пойдет в конце главы, действует именно в этом направлении. Операционные системы реального времени, такие как QNX, дают пользователю точную верхнюю границу времени ожидания при выполнении какой-либо задачи. Этим они принципиально отличаются от Unix и большинства операционных систем, где время выполнения задачи заранее предсказать невозможно. На практике использование операционных систем реального времени для вебсервера нерационально, потому что Интернет сам по себе обладает достаточной неопределенностью, a Unix обычно достаточно быстр. Контекст ядра Разрешая работать с оборудованием одному только ядру, мы проигрываем в производительности. Прежде всего, чтобы получить доступ к оборудованию, нужно сначала переключиться в режим ядра. Затем время расходуется на копирование
данных из буфера устройства в ядро, а потом из буфера ядра в пользовательский процесс (либо в противоположном направлении). Все это означает, что операции с устройствами занимают в системе Unix неопределенное время. Каким бы коротким ни был этот интервал времени, вы не можете быть уверены в том, что он будет таким каждый раз, когда вы обращаетесь к оборудованию, то есть пока Unix нельзя использовать в приложениях реального времени — например, для управления боевым самолетом. Для таких целей предназначены операционные системы реального времени (real-time operating systems — RTOS). В системе Solaris можно установить процессу приоритет реального времени (около 90), и тогда он будет иметь преимущество даже перед задачами системного уровня, но программирование в реальном времени под Unix все равно должно учитывать некоторую неопределенность. Подпрограммы ядра обращаются к оборудованию (сети и дискам, например, — а именно этим и занимается веб-сервер постоянно) гораздо быстрее, но интересы разработки и обслуживания требовали создания уровней ядра и пользователя вместо одного большого ядра. В процессе перехода с SunOS на Solaris ядро стало многопоточным, а всем процессам для увеличения скорости переключения контекста стали сопоставляться потоки ядра. Unix и httpd Как владелец веб-сервера, вы должны прежде всего интересоваться тем, насколько быстро в данной операционной системе вы можете получить прерывание от сетевого адаптера, перейти в режим ядра, чтобы считать данные, а затем вернуться в пользовательский режим. С вашей точки зрения, лучше всего, если запрос и возвращаемые данные будут копироваться внутри операционной системы только один раз — из буфера драйвера устройства в ядре в пользовательский процесс (или в противоположном направлении). Хорошие реализации TCP/IP выполняют действительно лишь одно копирование, а некоторые экспериментальные системы вовсе не копируют данные, а вместо этого просто меняют владельца буфера с пользователя на ядро. Когда компьютер с веб-сервером принимает запрос по протоколу HTTP, он должен отвести некоторое количество процессорного времени на обработку запроса демоном httpd (рис. 17.1). Демон httpd выполняется как пользовательский процесс, поэтому приоритет у него ниже, чем у процессов ядра. Ему приходится ждать выполнения этих процессов, конкурируя за оставшееся время с другими пользовательскими процессами, так что чем меньше будет процессов в системе, тем лучше. Если вы можете себе это позволить, отведите своему веб-серверу один компьютер, не запуская на нем сеансов интерактивной работы, баз данных, служб NFS или DNS и так далее. Этот совет вступает в противоречие с концеп цией использования Java-апплетов для клиент-серверных приложений, потому что в основной модели безопасности Java-апплетам разрешается подключаться только к веб-серверу, с которого они были загружены. Это означает, что компьютер с веб-сервером должен не только отправить пользователю апплет, но и об
работать запросы этого апплета, который может обращаться к базам данных и т. п. Есть несколько вариантов решения этой дилеммы — например, можно добавить в апнлет электронную подпись, чтобы он мог обращаться и к другим компьютерам, или использовать appletviewer, или отключить систему сетевой безопасности браузера (только в интрасети), или же написать небольшой демон- перенаправитель, который будет копировать данные из приемного сокета вебсервера в другой сокет другого компьютера. Еще можно сопоставить IP-адресу веб-сервера несколько компьютеров с помощью одного из программных продуктов для балансировки нагрузки (см. главу 3). Рис. 17.1. ОС и веб-сервер: обработка запроса Буферы сокетов имеют размеры SO_SNDBUF и SO_RCVBUF, которые задаются веб-сервером при вызове setsockopt(). Если веб-сервер попытается записать в буфер больше, чем SO_SNDBUF байтов, выполнение его процесса будет приостановлено до тех пор, пока буфер сокета не будет опустошен ядром. Подпрограммы стека TCP/IP считывают из буфера сокета пакеты объемом MSS и менее, однако данные не удаляются из буфера до тех пор, пока их прием не подтвердится клиентом, поэтому медленные клиенты могут вызывать переполнение буфера сокета и приостановку выполнения веб-сервера. Стек TCP/IP формирует IP-пакеты размера MTU из сегментов размера MSS. Если размер сегмента + 40 байт оказывается больше MTU, сегмент разбивается на несколько IP-пакетов. IP-пакеты передаются в буфер сетевого адаптера. Если этот буфер полон, пакеты сбрасываются, а на уровень IP отправляется сообщение об ошибке, и дальше оно идет
на уровень TCP, который предпринимает новую попытку передачи через несколько секунд. Сетевой кэш и ускоритель в системе Solaris Система Solaris может хранить кэш веб-страниц в пространстве ядра, что значительно увеличивает максимально доступное компьютерам Sun количество HTTP-операций в секунду. Эта функция хорошо работает с сервером Netscape Enterprise Server, но требует некоторых модификаций при установке веб-сервера Apache. Для большинства пользователей реальная скорость веб-сервера сама по себе не создает проблем при работе с сетью, поэтому данная функция ускорения не обязательно полезна. Повышение скорости подключения клиента к Интернету, динамической генерации содержимого и базы данных, скорее всего, гораздо больше поможет клиенту. Тем не менее SNCA уменьшает требования к оборудованию для очень загруженных сайтов, а для установки этой системы достаточно всего лишь загрузить в ядро лишний модуль и выполнить некоторые другие простые действия. Linux khttpd Аналогичная функция в системе Linux обеспечивается веб-сервером уровня ядра, который называется khttpd. khttpd работает в ядре в качестве драйвера устройства и ускоряет отправку статических веб-страниц. Он передает запросы на динамически генерируемые веб-страницы веб-серверу, работающему на пользовательском уровне (например, Apache). Работа над этим демоном еще не завершена, и он еще не полностью совместим с протоколом HTTP 1.1, но тем не менее достаточно хорош, чтобы быть полезным. Подробнее об этом читайте в разделе http://www.fenrus.demon.nl/. Уменьшение нагрузки на операционную систему Если ваш веб-сервер должен обращаться к большой базе данных, рассмотрите возможность использования FastCGI или открытия сокета на другой компьютер, где будет выполняться база данных. Закрывать данный сокет не следует. Некоторые промежуточные связующие продукты могут обеспечить это соединение с базой данных без дополнительных усилий. Интерактивные сеансы кажутся достаточно «невинными», но порождают множество прерываний (каждое движение мыши вызывает даже не одно прерывание, а несколько). Вы можете увеличить приоритет процесса веб-сервера, выполнив соответствующий системный вызов. Для этого вам нужно являться привилегированным пользователем. Это может быть опасно при большой загруженности вебсервера, потому что другим важным функциям может не хватить ресурсов, что приведет к сбою сервера. Еще один трюк, позволяющий повысить производительность, заключается в увеличении квантов времени планировщика процессов. Это иногда помогает в тех случаях, когда быстродействие ограничивается процессором, поскольку система проводит меньше времени в самом планировщике задач.
Когда я писал книгу для первого издания, дойдя до этого места, я задумался над вопросом, насколько эффективно было бы поместить веб-сервер в ядро целиком, чтобы не нужно было тратить ресурсы на переключение между режимами пользователя и ядра. С тех пор появились версии Linux 2.3 и 2.4, в которых имеется веб-сервер уровня ядра khttpd, загружаемый в качестве модуля. Этот веб-сервер может работать только со статическими страницами, а запросы на динамические страницы отправляются веб-серверу пользовательского уровня. Веб-сервер khttpd настраивается через файловую систему /ргос. Я не тестировал его, но думаю, что его производительность для статических страниц очень высока; никаким другим путем достичь такой производительности в Linux невозможно. Одна из проблем, связанных с загрузкой дополнительных модулей, заключается в том, что эти модули увеличивают размер ядра, а память ядра не может быть выгружена в файл подкачки. Это уменьшает объем памяти, доступный другим приложениям. Создание процессов Создание новых процессов осуществляется в Unix при помощи системного вызова fork, который копирует память процесса и присваивает копии новый идентификатор. После вызова fork обычно следует системный вызов exec, который считывает новый исполняемый файл с диска (если тот еще не загружен в память) и запускает его в текущем адресном пространстве. Обращение к диску занимает около 50 мс, а создание процесса само по себе — около 10 мс. Созданный процесс занимает в ядре около 50 Кбайт, отводимых под различные записи, а также поглощает память в пользовательском пространстве (объем этой памяти можно узнать с помощью команды ps). Вызов функций fork и exec — не самый эффективный способ решения задач, но этот способ самый простой с точки зрения программиста. Предполагалось, что создание новых процессов будет происходить не слишком часто, поэтому не было никаких стимулов делать эту процедуру более эффективной. Именно недостаток эффективности при порождении новых процессов ограничивает масштабируемость CGI, потому что процессы-шлюзы создаются и уничтожаются при каждом обращении к веб-серверу. Причина, по которой системные вызовы fork и exec были разделены, состоит в том, что вызов fork был предназначен для использования в архитектуре «клиент—сервер», где хорошо иметь возможность порождать новую копию процесса сервера для каждого клиента. Чтобы обойти затраты на создание новых процессов, была предложена концепция многопоточного программирования. Программные потоки — это отдельные выполняемые последовательности кода в пределах одного процесса. На создание нового потока уходит гораздо меньше времени и ресурсов: выполняется оно приблизительно в 100 раз быстрее. Кроме того, переключение между потоками также выполняется очень быстро. Конечно, процессу как целому все равно приходится ждать решения планировщика, чтобы его потоки смогли запуститься, но преимущества быстроты создания потоков и переключения между ними все равно остаются весьма значительными. Если на вашем компьютере установ-
лено несколько процессоров, вы можете разделить выполнение потоков между ними и воспользоваться всеми преимуществами параллельного выполнения. Это возможно, например, в многопоточном программировании на Java, но никоим образом не гарантируется. Другое преимущество потоков заключается в том, что весь поток больше не должен блокироваться в ожидании завершения операций ввода-вывода. Эта операция выполняется одним потоком, который в ней и блокируется, в то время как все остальные продолжают выполняться. Наконец, потоки работают с общими дескрипторами файлов, но о том, достоинство это или недостаток, говорить достаточно сложно. Ценность последнего качества зависит от вашего приложения. Пользователю Unix не составит труда создать процесс, который будет вызывать fork до тех пор, пока система не выйдет из-под контроля. Создайте сценарий интерпретатора и включите в него команду, вызывающую этот же сценарий. Например, создайте файл с именем х, а в качестве содержимого файла введите единственную букву — х. Сделайте этот файл выполняемым и запустите его. Количество процессов с именем х очень быстро возрастет до такой степени, что у вас вообще закончится ресурс. Насколько быстро это будет происходить и какой именно ресурс закончится — сложный вопрос. Вот один из способов узнать, сколько именно процессов может создать данный пользователь — измените сценарий х так, чтобы он запускал не только себя самого, но и программу ps: ps -ef | wc -1 ./x Запустив эту программу, следите за максимальным достигнутым результатом. Прежде чем постоянное обращение к файлу подкачки замедлило мою систему до невозможности, мне удалось достичь числа 317 . Я изменил сценарий х, удалив из него строку ps -ef | wc -I, и стал следить за процессами с помощью программы top. Мне удалось добраться до 371 процесса, но после этого сценарий х аварийно завершился, хотя само ядро Linux продолжало работать. Тем не менее система была недоступна в то время, когда выполнялось порождение процессов, так что это можно считать простейшей атакой типа -«отказ в обслуживании» на уровне пользователя. Для такой атаки уязвимо большинство операционных систем Unix. Думаю, что в мейнфреймах действия пользователей контролируются более жестко, и это одна из причин, по которым они более надежны, чем Unix. Адриан Кокрофт отмечает, что в Solaris можно обойти эту проблему, установим значение maxuproc в файле /etq/system и перезагрузившись. Например: set maxuprc-100 Адресное пространство Когда процесс запрашивает у системы Unix больше памяти, чем имеется на компьютере, такой процесс все равно может работать, используя файл на диске в качестве виртуальной памяти. Это название возникло потому, что такая память не является настоящей оперативной памятью. Файл виртуальной памяти
называется файлом подкачки (swap file). Это может быть и не файл, а целый раздел или даже отдельный жесткий диск. Память сегментируется на страницы, поэтому помещение части адресного пространства процесса на диск называется замещением страниц (paging). Если весь процесс целиком приостанавливается и записывается на диск, говорят, что процесс был выгружен (swapped out). Простейшее правило гласит, что замещение страниц допустимо, но нежелательно, тогда как выгрузка процессов говорит о серьезных проблемах, угрожающих вашей производительности. При запуске программы замещения страниц не избежать, поскольку программа должна считываться с диска. Замещение происходит и в тех случаях, когда программы долгое время не выполняют никаких действий. В этих случаях оно не является угрожающим симптомом. Отслеживать активность подкачки нужно с помощью программы sar или vmstat, а посмотреть, как обстоят дела в данный момент, можно с помощью программы perfmeter. Если вы наблюдаете постоянное замещение страниц или активность виртуальной памяти, нужно выяснить, в чем дело, и устранить источник проблемы, и тогда производительность возрастет. Возможно, для этого придется купить больше памяти или уменьшить загрузку компьютера. Оптимизация памяти — отдельная тема. Все процессы в системе Unix выполняются в собственных адресных пространствах и «не знают» о том, что это пространство отображается на гораздо меньший объем физической памяти, установленной в компьютере. Большая часть компьютеров является 32-разрядными, и потому на них может быть установлено до 4 Гбайт ОЗУ. Многие компьютеры Unix допускают установку больших объемов памяти, но они работают под управлением 32-разрядных операционных систем. Возникает вопрос: как 32-разрядное ядро может обращаться к памяти, лежащей за пределами 4 Гбайт? Ответ в том, что виртуальная система адресации использует указатели большего размера. Например, Solaris использует 36-разрядное физическое адресное пространство. Это означает, что, хотя каждый из 32-разрядных процессов ограничен 4 Гбайт ОЗУ, таких процессов может быть много, и ядро справится с ними со всеми. В системах обычно имеется общий динамический пул памяти, совместно используемый процессами и файловой системой, причем кэш файловой системы занимает все свободное место, ненужное другим процессам. Буфер уменьшает количество выполняемых операций чтения и записи, повышая производительность, но он может создать у вас ложное впечатление недостатка памяти, когда на самом деле процессы могут еще значительно увеличить свое адресное пространство, вытеснив из памяти кэш файловой системы. В системе Solaris нужно следить не за количеством свободной памяти, а за частотой поиска свободных страниц (sr в vmstat) и количеством выгруженных и загруженных страниц. Помните, что разные программы (sar, vmstat, top) могут использовать разные определения свободной памяти. Некоторые вычитают из объема свободной памяти предположительный объем, который еще может потребоваться процессам.
Копирование областей памяти Копирование данных из одной области памяти в другую — основное «занятие» веб-серверов. Сервер считывает файл с диска в одну область памяти, затем копирует его в другую область памяти (буфер) для отправки по сети. Эффективнее было бы, если бы ядро просто стало считать некоторую область памяти буфером, не выполняя копирование. Некоторые ядра действительно способны выполнять изменение таблицы указателей на страницы вместо копирования данных, но только в том случае, если размер данных в точности равен размеру страницы. По этой причине была изобретена упаковка остаточных данных в протоколе IP (trailer encapsulation). Интересно было бы поэкспериментировать с размером веб-страниц: возможно, они загружались бы быстрее, если бы их размеры были кратны размеру страницы памяти. Освобождение памяти Когда процесс запрашивает у операционной системы новый участок памяти, операционная система записывает этот запрос и резервирует память, но не считает ее принадлежащей процессу до тех пор, пока он не попытается эту память использовать. Когда память освобождается, она немедленно возвращается операционной системе, а размер процесса в памяти уменьшается. Это часто приводит программистов и пользователей в замешательство. Вот пример, который вы можете испытать самостоятельно (листинг 17.1). Вы можете скачать эту программу по адресу: http://patrick.net/software/freetest.c. Листинг 17.1. Тестирование динамической памяти (язык С) include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <errno.h> #include <umstd.h> #include <stnng.h> mainhnt argc. char * argv[]) { void *buf: buf = (void *) mallocB0000000): pnntf("reserved\n"): sleep A0): bzero(buf. 20000000): /* память не будет считаться используемой, пока вы к ней не обратитесь */ pnntfC'in use\n"): sleep A0); free(buf):
printf("freed\n"); sleep A0); } Если вы скомпилируете ее командой % дсс -о freetest freetest.с, а затем запустите, следя за ней с помощью top (сортируйте по размеру процесса, если ваша версия top на это способна), вы увидите, что программа практически не использует память вплоть до выполнения строки с вызовом bzero, очищающим память. После этого размер процесса увеличивается. Освобождение памяти приводит к возвращению ее операционной системе. Это отличает С и Unix от Java, потому что большая часть виртуальных машин с удовольствием поглощает память, но не отдает ее операционной системе до своего завершения. Вместо этого они возвращают память в собственную кучу виртуальной машины. В листинге 17.2 приведена аналогичная программа на Java (http://patrick.net/software/freetest.java), так что можете убедиться сами. Листинг 17.2. Тестирование динамической памяти (язык Java) class freetest { public static void main(String[] args) { System.out.println("not al1ocated"): try { Thread.sleep(lOOOO): } catch (java.lang.InterruptedException ie) {} byte[] array - new byte[20000000]: System.out.println("allocated"); try { Thread.sleepA0000); } catch (java.lang.InterruptedException ie) {} arrdy - null: System.out.pri ntln("freed"): try { Thread.sleepA0000); } catch (java.lang.InterruptedException ie) {} } } Обычно чем больше памяти — тем лучше, но даже если бы вы могли установить в систему столько памяти, сколько хотите, увеличение количества процессов или потоков свыше определенного числа все равно приводило бы к замедлению работы системы вследствие затрат на переключение контекста. Кроме того, большой объем памяти может замедлить работу системы даже сам по себе из-за накладных расходов на управление им. Существует много программных средств, измеряющих используемый объем памяти, причем все они обычно дают разные результаты. По крайней мере, программа top иногда возвращает совершенно неправдоподобные значения. Есть
и коммерческие средства, которые тоже можно использовать для оценки использования памяти (например, Measureware). Также имеются программы vmstat, prtmem из пакета RMCmem (автор — Ричард Мак-Дугал), ps, memtool, файловая система /ргос и просто статистика ядра. Одной из причин, по которой все программы выдают разные результаты, является то, что они могут учитывать (или не учитывать) размеры сегмента кода, кучи, стека и неинициализированных данных (bss), общие библиотеки, виртуальную или только физическую память, буферы файловой системы и другие буферы. Файловая система В системах Unix все объекты считаются файлами (включая данные, исполняемые файлы, каталоги и устройства). Самым распространенным типом файла является обычный файл, представляющий собой просто поток байтов данных в отличие от каталога или устройства. Текстовые и двоичные файлы в Unix не различаются. Мы хотим, чтобы наш веб-сервер мог обращаться к обычным файлам с максимально возможной скоростью. Чтобы понимать, от чего эта скорость зависит, нам нужно кое-что знать о файловой системе Unix. Существуют разные виды файловых систем, но чаще всего используется унифицированная файловая система (Unified File System — UFS), произошедшая от файловой системы Беркли (Berkeley File System). Файловая система UFS состоит из узлов inode, каталогов и блоков данных. Узлы — это обычно 128-байтовые записи на дисках, описывающие файлы. В каждом узле хранится список указателей на блоки данных, формирующие дисковый файл. Если знать количество указателей в узле и размер блоков данных, можно определить объем данных, относящихся к этому узлу. Размер блоков по умолчанию устанавливается равным 512 байт или 2 Кбайт, что приемлемо, если у вас есть много небольших файлов, но слишком мало, если есть большие файлы. Размер блока в 2 Кбайт означает, что вы можете поместить миллион файлов объемом н 2 Кбайт на диске в 2 Гбайт. При наличии файлов большего размера, по крайней мере, один из указателей inode должен указывать на своего рода узел второго уровня, который называется косвенным блоком. Этот последний содержит указатели на другие блоки данных. Структура может разрастаться до дважды косвенных блоков, однако обращение к большим файлам через несколько уровней косвенной адресации связано с потерей производительности. Небольшие диски с меньшим количеством узлов работают быстрее хотя бы потому, что системе приходится искать нужную информацию в меньшем объеме. Если вы рассчитываете работать преимущественно с очень большими файлами, вы повысите производительность, увеличив размер блоков данных. При этом маленькие файлы будут занимать больше места, но что поделать? UFS позволяет увеличить размер блока до целых 64 Кбайт. Способ изменения размера блока зависит от платформы, однако выбирать нужный размер приходится в момент создания файловой системы. Суть в том, что вы можете оптимизировать свою файловую систему под конкретный размер файлов содержимого. Помните, что веб-содержимое часто имеет двухвершинное распределение по размерам - множество мелких файлов A0-20 Кбайт) с текстом и изображениями и не-
сколько больших файлов (более 1 Мбайт) программ, аудио и изображений с высоким разрешением. Одно из решений заключается в том, чтобы отвести для больших файлов отдельный сервер и оптимизировать его файловую систему, но выигрыш, достигнутый благодаря производительности файловой системы, может быть сведен на нет долгой загрузкой по сети. Если же вы имеете дело с потоковым видео, то действительно разумно отвести под него отдельный сервер со специально настроенной файловой системой. В системе Solaris используется еще один тип файловой системы для временных файлов — tempfe. Изучите содержимое файла /etc/vfstab в системе Solaris, и вы увидите, что в каталог /tmp обычно подключается система tempfe. Уникальность tempfe в том, что операционная система пытается хранить все файлы, относящиеся к этой файловой системе, в оперативной памяти. Это означает, что чтение и запись в каталог /tmp осуществляется гораздо быстрее, чем в любой другой каталог. Недостаток tempfe в том, что содержимое этой системы исчезает при перезагрузке. Кроме того, tempfe не гарантирует, что файлы будут размещены в памяти, — она лишь пытается этого достичь. Помня об этом, вы можете использовать tempfe в различных приложениях, чтобы повысить их производительность. Если ваш веб-сервер постоянно считывает какие-то данные для отправки их клиентам, есть смысл поместить эти данные в каталог /tmp. Они все равно постоянно меняются, а быстрый доступ к ним достаточно важен. Чтобы получить более подробные сведения, выполните команду man tempfe в системе Solaris. Длина имени файла Можно предположить, что короткие имена каталогов и файлов ускоряют доступ к ним, но насколько? В листинге 17.3 приведена маленькая программа на С, которая позволяет получить ответ на этот вопрос. Листинг 17.3. Определение скорости доступа к файлам #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #iinclude <errno.h> maindnt argc. char * argv[]) { int i: struct stat *buf: buf - (struct stat *) malloc(sizeof(struct stat)): for (i-O: K100000: i++) { if (stat(argv[l]. buf)) { perror(argv[l]): exit(l): } } }
Компилируется она следующим образом: % дсс -о stat stat.c Запустите ее с каталогом t в качестве аргумента командной строки, а затем с каталогом thisname, и вы увидите, что для каталога t она будет выполнена примерно за 1,37 с, а для каталога thisname — за 1,45 с: % time stat t real Oml.370s user 0m0.270s sys Oml.100s Поскольку мы обращаемся к файлу 100 000 раз, каждое обращение занимает около 1,37 / 100 000 в 0,0000137 с, или 1,4 мкс. Обращение к каталогу thisname осуществляется на 6% медленнее. Открытие каталогов происходит с меньшей разницей во времени. Тем не менее остаются, по крайней мере, две причины, по которым стоит использовать очень короткие имена файлов, — меньший объем журналов и меньшее количество байтов в запросах и ответах. Заполненная файловая система Главной и самой серьезной проблемой файловых систем является их конечная емкость. Когда заполнение файловой системы приближается к 100%, любая программа, работающая с ней, значительно замедляется. Производительность веб-серверов, серверов приложений и баз данных снижается. Если же заполнение становится равным 100%, приложения чаще всего завершаются аварийно, хотя хорошо написанные программы могут сделать это и корректно. Когда заполняется корневая файловая система, аварийно останавливается сама операционная система. Поэтому, с точки зрения производительности и надежности, очень важно следить за заполненностью основных файловых систем, а для замедления скорости заполнения следует располагать файлы журналов в отдельной файловой системе. Вы можете запустить команду df -k в любом каталоге и узнать, насколько полной является соответствующая файловая система. Вот пример: % сд /opt/apache/logs % df -k . Filesystem 1024-blocks Used Available Capacity Mounted on /dev/hda2 3857447 1224872 2432993 33* /opt Мы видим, что файловая система с журналами веб-сервера Apache заполнена всего на 33%. Каталоги Каталог (directory) — это специальный тип файла, содержащий список имен файлов и соответствующие им номера узлов inode, а также дополнительные сведения о каждом файле (разрешения доступа, время создания и т. п.). Структура каталогов Unix представляет собой связный список. Когда вы обращаетесь к файлу по его полному имени (например, /dirl/foo), ядро начинает линейный поиск по корневому каталогу. Когда обнаруживается нужный каталог (в нашем
примере — dirl), ядро считывает его номер inode и по этому номеру находит блок данных с именем dirl, после чего ищет в нем файл с именем foo. Найдя этот файл, ядро считывает его номер inode и таким образом точно узнает, где именно на диске размещен файл foo. Это достаточно сложный процесс, поэтому использование коротких путей и имен файлов обеспечивает в среднем более высокую производительность. Если вам совершенно необходимы длинные имена, старайтесь выбирать их так, чтобы они отличались префиксами, а не суффиксами. Какую бы функцию сравнения строк ни использовала операционная система, эта функция станет работать быстрее, если строки будут различаться первыми символами, а не последними. Например, вместо того чтобы называть файлы содержимого именами типа regional.daily.report. 12.3.1998, regional.daily.report. 12.4.1998 и так далее, поместите на первое место дату: 3.12.1998.regional.daily.report, 4.12.1998.regional.daily.re- port... (Дисковый кэш Netscape Navigator не следует этому принципу, но сделать тут ничего нельзя, разве что вы достаточно смелы, чтобы изменять исходный код браузера.) Однако все это не означает, что нужно помещать все файлы в корневой каталог или просто создавать каталоги с большим количеством файлов. Поиск по каталогу осуществляется линейно, поэтому большое количество файлов в каталоге значительно снизит вашу производительность. Нельзя одновременно сократить длину пути и количество файлов в каталоге, если у вас очень много файлов содержимого. К чему же лучше стремиться? Учтите, что каждый уровень вложенности пути задействует косвенную адресацию, требующую перемещения головок диска, если только содержимое каталога уже не находится в памяти, тогда как поиск в связном списке имен каталогов в памяти представляет собой последовательное сравнение строк. Сбалансированную нагрузку будут давать каталоги с количеством элементов около нескольких сотен (по моим оценкам). С другой стороны, после первичного поиска по файловой системе дерево каталогов кэшируется в памяти, поэтому при многократном обращении лучше иметь более длинный путь к файлу, чем большое количество файлов в каталоге. Вам придется специально тестировать время доступа к содержимому в различных конфигурациях, чтобы узнать, какой вариант фактически является самым лучшим, но начинать, по-видимому, следует все же с сотни файлов на каталог. В некоторых системах имеются кэши поиска имен каталогов (DNLC), которые уменьшают количество обращений к диску при поиске по каталогам. Файловая система Veritas VxFS хэширует каталоги для увеличения быстроты поиска, но это коммерческий продукт, который стоит денег. Подробнее см. http://www.veritas.com/. Ядро имеет собственную таблицу узлов inode, используемую в качестве кэша для недавно открывавшихся файлов. Ее размер определяется константой, задаваемой при компиляции ядра. Часто эта константа называется MAXUSERS, или INODE, или NINODE. Связные списки, такие как каталоги, не слишком хорошо кэ- шируются, поскольку не являются последовательными участками памяти, но увеличение размера таблицы inode должно так или иначе повышать производительность.
Длина имени файла может влиять на время его считывания, поскольку имя запрошенного файла сравнивается с именами всех файлов подряд до тех пор, пока он не будет найден. Я провел небольшой тест в системе Linux, назвав файл сначала одной буквой а, потом двумя, затем тремя и так далее до 25. Сто последовательных запросов этого файла из сервера Apache всегда выполнялись за одно и то же время — 1,8 с, а отклонения были не больше 1 мс. Судя по всему, длина имени файла не слишком влияет на работу системы, однако при большей нагрузке результаты могут оказаться несколько иными — главным образом из- за того, что записи в журналах станут длиннее. Кэширование файловой системы Когда вы считываете файл в системе Unix, файловая система помещает его в кэш, который называется буферным кэшем файловой системы, поэтому вы можете избежать обращения к диску при последующих операциях с этим файлом, если они произойдут достаточно скоро. В SVR4 под кэш отводится вся свободная на данный момент память, то есть размер кэша динамически увеличивается и уменьшается. В других версиях Unix под кэш обычно отводится специальный раздел адресного пространства процесса. Когда SVR4 отбирает память у кэша, операционная система начинает с тех файлов, которые давно не использовались. Этот метод называется вытеснением по давности использования (Least Recently Used — LRU removal). Когда вы осуществляете запись в буферный кэш, изменения не записываются на диск немедленно. Они помещаются в очередь для оптимизации записи. Это отличает Unix от Мае и Windows 95/98, которые записывают данные на диск синхронно. В Windows NT были взяты на вооружение идеи Unix. Такой подход делает системы Unix и NT более уязвимыми к внезапному отключению питания, зато более производительными — еще один компромисс. Вы легко можете почувствовать эффективность буферного кэша на себе, изменив файл, который вы давно не открывали, закрыв его, а затем открыв снова. Второй раз он откроется гораздо быстрее, потому что и редактор и файл будут находиться уже в кэше, и их не нужно будет загружать с диска. Это кэширование очень сильно помогает HTTP-серверам, потому что пользователи часто запрашивают одни и те же файлы. Кэш поиска имен каталогов Разработчики Solaris учли, что на поиск нужного каталога в дереве может уходить много времени, и потому они включили в систему специальный кэш для быстрого поиска каталогов, который называется DNLC — directory name lookup cache. Количество обращений к этому кэшу можно узнать с помощью команды vmstat -s (столбец cache hits). Процент попаданий в кэш должен быть около 90 или выше. В противном случае вам, вероятно, необходимо увеличить размер кэша. Узнать текущий размер кэша можно следующим образом (нужно обладать правами привилегированного пользователя):
Устройство Unix 369 # adb -к /dev/ksyms /dev/mem ?U ncsize AD Чтобы увеличить размер кэша, добавьте в файл /etc/system строку наподобие set ncsize=xxxx Фрагментация Размещение файлов на диске становится все более хаотичным по мере того, как вы выполняете все новые и новые операции чтения и записи, а в результате новые файлы сохраняются в виде фрагментов, разбросанных по свободным участкам диска. Это снижает производительность, поскольку чтение и запись фраг- ментированных файлов требуют лишних перемещений головок диска. Если в вашей системе выполнялось много операций записи, вы можете попробовать запустить у себя утилиту дефрагментации или просто записать всю файловую систему на магнитную ленту, переформатировать диск, а затем записать файлы обратно. Не стоит создавать образ диска на ленте с помощью dd, dcopy или аналогичных утилит, потому что этот образ будет фрагментирован. Записывайте файлы в виде файлов. В системе Windows регулярная дефрагментация обязательна, тогда как в системах Unix она не столь важна, потому что более совершенные алгоритмы обеспечивают меньшую фрагментацию файлов при записи. Unix записывает данные целыми блоками, тогда как Windows пытается оптимизировать скорость записи, потому что в Windows файлы обычно записываются на диск без задержек, чтобы избежать потерь данных при сбоях. Unix записывает файлы время от времени посредством процесса, который называется fsflush. Данные подвергаются большей угрозе в случае сбоя системы, но сбои в Unix случаются реже, так что на практике отложенная запись не создает проблем. Синхронную запись на диск вызывает помещение в буфер больших объемов данных, закрытие файла или выход из программы (также приводящий к закрытию файлов). Когда вы начнете записывать файлы с ленты обратно на диск, вы можете попытаться применить еще один трюк: записывать однотипные файлы вместе. Например, запишите на диск HTML-страницу, а следом за ней — все изображения с этой страницы. Когда вы обратитесь к файлу HTML и вам понадобятся изображения, головки дисков почти наверняка окажутся в нужном месте, что повысит быстроту считывания. Файлы, к которым вы станете обращаться часто, будут храниться в буферном кэше, поэтому трюк сработает только при первом считывании, так что этот метод лучше подходит для больших наборов редко используемых файлов. Если ваш диск будет слишком заполнен, файлы начнут быстро фрагментиро- ваться, потому что операционная система не сможет найти свободных участков нужного размера. Старайтесь не занимать более 90% объема дисков, особенно если вы не только считываете с них статическое содержимое, но и записываете на них данные. Если ваш диск заполнен почти на 100% и его производительность становится крайне низкой, можете попытаться заполнить его резервное пространство. Как обратиться к этому пространству — зависит от операционной
системы: можно, например, применить одну из простых и опасных утилит — fdisk, tunefe или fips. Я не буду вдаваться в подробности, и вообще я вам об этом не говорил (на тот случай, если с вашим диском случится что-нибудь плохое). Вы ведь создали резервную копию всех данных заранее — не првпа ли? Помните, как именно осуществляется обращение к файлу? Кроме всего прочего, разрешения файла, хранящиеся в его каталоге, применяются к идентификатору пользователя. На это тратится некоторое время, а для веб-сервера, изолированного от интрасети, такая процедура создает лишь ненужные задержки. Если вы привыкли копаться в ядре, можете изменить его и выкинуть проверку разрешений. После этого все пользователи смогут обращаться ко всем файлам компьютера, но это не так опасно, как кажется, если на вашем сервере нет ничего, кроме содержимого, которое и так должно быть выложено в общий доступ, а вход на компьютер по сети запрещен. Самую большую угрозу вашему веб-серверу создает Интернет, потому что хакеры часто захватывают чужие веб-узлы для распространения нелегальных копий программ, и вы облегчите им это, отключив разрешения. Обратите внимание, что запустить веб-сервер от имени привилегированного пользователя — это не то же самое, что отключить разрешения, хотя привилегированный пользователь и имеет доступ ко всем файлам. Проверка разрешений осуществляется даже для привилегированного пользователя. Еще одна несущественная для веб-сервера операция, выполняемая при обращении к файлу, — изменение даты доступа. Обращение к файлам выполняется постоянно, а точное время все равно записывается в журнал. Особенно важно это в том случае, если ваши HTML-страницы считываются по NFS, где запись времени обращения требует отправки лишних пакетов по сети. В главе 15 о NFS рассказано подробнее. Вам придется серьезно менять свою файловую систему, чтобы время доступа перестало обновляться. Впрочем, можно просто подключить ее в режиме «только для чтения». Не используйте символические ссылки в дереве содержимого — не только потому, что они лишь добавляют один уровень косвенности, но и потому, что требуют двух обращений к диску: одного — для чтения разрешений ссылки (помните, что ссылка, как и все прочие объекты в Unix, представляет собой файл), а другого — для чтения содержимого ссылки, которая укажет вам лишь место, где размещен нужный файл. Символическая ссылка — это текстовый файл, содержащий имя того файла, на который ссылка указывает. Файл ссылки имеет специальный атрибут, благодаря которому операционная система распознает его как ссылку, а не как обычный текстовый файл. Жесткие ссылки не создают дополнительных временных затрат, но действуют только в рамках одной файловой системы в отличие от символических. Следите за тем, чтобы значения переменных PATH и LDJJBRARY_PATH были короткими и в них указывались в первую очередь пути к библиотекам, которые действительно будут использоваться веб-сервером. В противном случае вы потеряете уйму времени в системных вызовах при выполнении CGI или запуске других процессов. В приведенном ниже примере каталог /lib должен был бы идти первым в LDJJBRARY_PATH, а он вместо этого идет последним, из-за чего программа выполняет множество вызовов open зря.
% echo $LD_LIBRARY_PATH /usr/openwin/lib:/usr/ucblib:/usr/dt/lib:/usr/lib:/usr/local/lib:/lib А вот что происходит, когда мы запускаем CGI (убедиться в этом можно с помощью трассировщика системных вызовов truss или strace): программа перебирает все имена каталогов из переменной LD_LIBRARY_PATH. Каталог /lib в нашем примере является последним, а должен был бы стать первым: open(-/usr/openwin/lib/libc.so.5". 0_RD0NLY) = -1 ENOENT (No such file or directory) open("/usr7ucblib/libc.so.5". 0_RD0NLY) - -1 ENOENT (No such file or directory) open('7usr/dt/lib/libc.so.5". 0_RD0NLY) « -1 ENOENT (No such file or directory) openC7usr71ib/libc.so.5". 0_RD0NLY) « -1 ENOENT (No such file or directory) openC7usr71ocal/lib/libc.so.5\ 0_RD0NLY) = -1 ENOENT (No such file or directory) openC71ib/libc.so.5.2.18\ 0_RD0NLY) - 3 Изменять переменную LDJJBRARY_PATH может быть опасно, потому что некоторые программы могли работать с конкретными версиями библиотек, а после изменения этой переменной им придется работать с другими. Можно считывать все содержимое с компакт-дисков. Однако поскольку компакт-диски передают данные гораздо медленнее жестких, делать это не рекомендуется из соображений производительности. Еще один способ экономии памяти и ускорения доступа к файлам заключается в отображении файлов в память с помощью системного вызова mmap. Это позволяет сознательно поместить файл с данными в ОЗУ, чтобы процессы CGI или другие, работающие с ним, могли обращаться к участку памяти, а не к диску. Считывание файла, конечно, поместит его в дисковый кэш, но эффективнее загрузить его с помощью mmap, потому что этот вызов отобразит файл непосредственно в адресное пространство пользователя, тогда как read() и write() копируют данные сначала в ядро, а затем в пользовательское пространство. После того как файл окажется в памяти, вы сможете обращаться к данным с помощью указателей, что намного быстрее, чем при использовании стандартных подпрограмм ввода-вывода. Отображение файлов в память требует программирования на С, а не на Perl или Java. Подробную информацию об этом вызове вы получите, выполнив команду mmap. Системы BSD и Solaris способны отображать файлы в память, тогда как Linux 2.0 делать этого не умеет. Наконец, следует помнить о том, что большая часть интерпретаторов команд Unix и веб-серверов «понимает» сокращения типа ~user (домашний каталог пользователя). Поэтому, когда URL вводится в форме http://server/~user/file.html, вебсерверу приходится преобразовывать символ ~ (тильду) в имя домашнего каталога пользователя. Это может выполняться различными способами — например, с помощью запроса NIS или файла /etc/passwd — но в любом случае на это уходит много времени. Классический способ — открыть файл /etc/passwd, найти пользователя, перейти в его домашний каталог — занимает слишком много времени, даже если /etc/passwd кэшируется в ОЗУ, а поиск осуществляется через хэш-таблицу. Вашему веб-серверу придется тяжело, если вы захотите раскрывать сокращения типа ~user много раз в секунду, особенно если у вас не установлена файловая система cachefs. Короче говоря, не стоит употреблять тильду в именах файлов на загруженных веб-серверах.
Оконный интерфейс Нет никакой нужды в установке оконного интерфейса на веб-сервере, связующем сервере или базе данных. Пользователи ничего не выиграют от этого, потому что они не видят экран сервера. Более того, пользователи сильно пострадают от установки оконного интерфейса, потому что он потребляет ресурсы процессора и заметную долю ОЗУ. Избавление от оконного интерфейса устранит проблемы, связанные с изменением приоритета процессов при перемещении указателя мыши. В большинстве подобных систем приоритет процессов, относящихся к выделенному окну, автоматически повышается. Веб-сервер наверняка пострадает, если за клавиатуру сядет пользователь и начнет запускать задачи с более высоким приоритетом. Можете убедиться в этом самостоятельно с помощью несложного эксперимента. Предположим, вы запустите один процесс httpd из терминала xterm в системе Solaris. Вот небольшой сценарий интерпретатора sh, который будет выводить приоритет этого демона раз в секунду (приоритет будет указан в 17-м столбце слева): while true do ps -cle | grep httpd sleep 1 done Уведите мышь из окна xterm и щелкните на каком-нибудь другом окне. Вы убедитесь, что приоритет httpd упадет на 10 единиц. Когда вы вернете мышь в окно xterm, приоритет возрастет на 10 единиц. Это не самое желательное поведение для веб-сервера. Очень легко избежать запуска X в системах Unix, управляя сервером в режиме терминала или по протоколу Telnet. Windows и Mac не дают вам возможности выбирать. Вам приходится тратить ресурсы на оконную систему, даже если ваш компьютер целиком отведен под веб-сервер. Даже в системе Unix некоторые приложения серверного класса могут требовать оконного интерфейса. Например, один мой друг дал мне сервлет, который динамически создает файлы GIF, используя класс java.awt. Пакету java.awt приходится открывать окно X для прорисовки GIF, даже если на дисплее ничего не появляется. Мы решили запускать виртуальный Х-сервер, используя программу Xvfb. Она создает Х-сервер с виртуальным буфером кадров, что устраняет необходимость установки графического устройства. Версии и заплаты Я советую вам установить последнюю официальную (не бета-) версию операционной системы со всеми заплатами, потому что способы повышения производительности обнаруживаются постоянно, и также постоянно затыкаются бреши в системе безопасности. Узнать, с какой именно версией ОС вы работаете, можно во время загрузки либо с помощью команды uname -а (работает в большинстве версий Unix). Помните, что заплаты часто добавляют в систему свои соб-
ственные ошибки, поэтому проверяйте производительность сразу после их установки. Заплата Solaris Internet Server Supplement (SISS) для системы Solaris 2.5.1 дает приблизительно 20%-ный прирост производительности служб Интернета в даной системе — как на процессорах SPARC, так и на процессорах Intel. SISS также устанавливает систему WebNFS (файловую систему для веб), а кроме того — виртуальную машину Java с поддержкой многопроцессорности. SISS 1.0 включен в Solaris 2.6. Команда showrev -p позволяет вывести список установленных заплат в системе Solaris. Настраиваемые параметры операционных систем В этом разделе мы пройдемся по списку оптимальных параметров операционной системы для запуска на ней веб-сервера. Помните, что ядро систем Unix не оптимизировано под какое-то конкретное применение — напротив, оно рассчитано на приемлемую производительность в самом общем случае. В главе 15 подробнее рассказывается о настройке протокола TCP. Узнать текущие значения параметров системы в Solaris можно, изучив содержимое файла /etc/system или вырезав из файла inetinit все строки с командой ndd с помощью утилиты grep. В принципе, система Solaris 2.6 может считаться изначально оптимизированной для работы с веб-сервером, поэтому вам не нужно ничего изменять для достижения оптимальной производительности. Однако в других системах (например, в Linux), вам придется поварьировать некоторые основные параметры. Обязательно архивируйте ядро и конфигурационные файлы перед внесением каких-либо изменений. Количество дескрипторов файлов Дескрипторы файлов — это положительные целые числа, используемые ядром для отслеживания открытых процессом файлов и сетевых соединений. Если ваш веб-сервер открывает из одного процесса множество файлов и сетевых соединений, ему может не хватить дескрипторов — а тогда вы не сможете принимать новые соединения или открывать новые файлы до тех пор, пока не завершатся имеющиеся соединения или не закроются открытые файлы. Например, вызов accept() для сетевых соединений будет возвращать ошибку. Что будет происходить после этого — зависит от вашей версии Unix. Сообщение об ошибке может быть записано в журнал системы или выведено на консоль. В старых версиях Unix количество дескрипторов файлов на процесс ограничивалось двадцатью (константа OPEN_MAX в заголовочном файле limits.h в системах SVR4), однако с тех пор данное ограничение стало значительно менее жестким. У некоторых процессов могут быть веские основания открыть одновременно тысячу файлов и сетевых соединений, а то и больше. Команды интерпретатора limit или ulimit, а также функции С позволяют изменить максимальное количество дескрипторов до некоторого жесткого предела, установленного при компиляции ядра или в процессе его загрузки. Узнать жесткое ограничение в системе Solaris можно с помощью команды sysdef (строка file descriptors). Установить это ограничение позволит команда
setrlim_fd_max = 1024 (файл /etc/system), но вам придется перезагрузить компьютер. Системы Solaris позволяют увеличить количество дескрипторов на процесс до 4096, а при больших числах стабильность системы не гарантируется. Текущее ограничение для любого выполняемого в данный момент процесса в системе Solaris можно выяснить с помощью команды /usr/proc/bin/pfiles. Чтобы узнать количество выделенных каждому процессу дескрипторов, выполните команду Isof. Копия этой утилиты для Solaris 2.6 хранится на моем веб-сайте по адресу: http://patrick.net/software/. Наконец, вы можете просто изучить содержимое файловой системы /ргос, в которой хранятся ссылки на все открытые процессами файлы. Установить предлагаемое по умолчанию «мягкое» ограничение на количество процессов можно, записав в файл /etc/system команду set rlim_fd_cur=64 и перезагрузившись. Установка rlim_fd_max более 1024 приведет к сбоям в работе библиотечного вызова select(), но сервер Netscape Enterprise Server 3.0 будет работать без перебоев, пока это значение не превысит 3000. Программы, использующие функцию poll() вместо select(), могут задействовать достаточно большое количество дескрипторов без всяких проблем, потому что poll() использует дескрипторы типа int, тогда как select() работает с типом fd_set, размер которого равен FD_SEETSIZE, а значение этой константы в системах Solaris и Linux равно 1024. Чтобы узнать количество дескрипторов, с которыми ваш веб-сервер сможет надежно работать, вам придется изучить его исходный код. Иногда можно заставить программу, написанную с использованием select, работать с большим количеством дескрипторов, изменив ее исходный код, а именно добавив определение FD_SETSIZE перед включением файла <sys/types.h>. Очень редко выбор между select и poll может быть сделан в процессе компиляции с помощью файла makefile. Определение типа FILE в библиотеке stdio позволяет работать только с 256 дескрипторами файлов, поэтому программы, написанные с использованием этого типа, могут открывать не более 256 файлов. Вот несколько способов изменения жесткого ограничения количества дескрипторов на процесс для некоторых операционных систем. О Solaris — установите rlim_fd_max в файле /etc/system и перезагрузитесь. О Irix — запустите systune -i, установите rlimit_no_file_max и rlimit_nofile_cur и перезагрузитесь. О AIX — запустите smit и проверьте значения параметров настройки ядра. О HP-UX — запустите sam и проверьте значения параметров настройки ядра. О Linux — в Linux 2.0 жесткое ограничение равно 256, а в Linux 2.1 оно составляет 1024. Чтобы изменить это, вам придется влезть в исходный код ядра, после чего перекомпилировать его. Количество процессов Максимальное количество процессов, которые могут быть запущены одним пользователем, может быть задано с помощью ulimit и при этом не должно превышать некоторого жесткого ограничения, установленного в ядре. В системе Linux может быть запущено не более 4000 процессов. В системе Solaris максимальное
количество процессов очень велико, поэтому у вас наверняка раньше закончатся другие ресурсы. Сетевые буферы Вспомните, что ответ веб-сервера записывается в сетевой буфер (буфер сокета), а не отправляется клиенту непосредственно. Это дает операционной системе возможность позаботиться об отправке данных медленным клиентам, освобождая веб-сервер от ненужной загрузки. Если сетевой буфер слишком мал, веб-серверу придется записывать свой ответ в виде отдельных блоков, размер которых должен совпадать с размером буфера. Серверу придется ждать, пока очередной блок не будет отправлен, прежде чем он сможет записать в буфер следующий блок. Операционная система должна иметь достаточное количество буферов подходящего размера, чтобы работать с вашими соединениями без затрат лишней памяти и приостановки веб-сервера до отправки очередной порции данных. Сетевые буферы, относящиеся к клиентам, не выполнившим закрытие соединения, являются основным источником затрат памяти на веб-серверах. Именно из-за этого следует сокращать интервал проверки жизнеспособности протокола TCP/IP. Размер буферов сокетов устанавливается с помощью параметров SO_SNDBUF и SO_RCVBUF или вызова setsockopt(), но он не может превышать жесткого ограничения, установленного в ядре. Мощным серверам со значительным объемом ОЗУ нужны большие буферы. Небольшой объем приемного буфера позволяет ограничить входящий поток данных. Команда man setsockopt позволит вам узнать обо всем этом подробнее. У веб-сервера Apache имеется директива Send BufferSize, позволяющая веб-мастеру управлять размерами буферов сокетов без перекомпиляции исходного кода. Большой размер буфера приводит к объявлению большего размера окна TCP/IP. Вот комментарий из исходного файла демона httpd_main.c: /* * Для отправки данных по соединениям с большой пропускной способностью и задержкой * с максимальной скоростью окно TCP/IP должно быть достаточного размера, чтобы канал * был постоянно заполнен данными. По умолчанию в большинстве систем размер окна составляет * всего 4 Кбайт. Для сайтов с хорошей связью вполне можно установить соединение на 1 Мбит/с * с задержкой 100 мс. Буфер объемом 4 Кбайт ограничивает пропускную способность * на уровне 40 Кбайт/с: * Чтобы бороться с этим, я добавил директиву SendBufferSize. позволяющею веб-мастеру * изменять размер буфера отправки: + * Недостатком больших буферов является то. что на них тратится больше памяти ядра. * Вы должны знать все о своих потребителях и своей сети. • * -Джон Хейдеманн <johnh@isi.edu> 25-0кт-96 • * Если размер не указан, используется значение, установленное в ядре по умолчанию. */
Ограничение памяти Указать максимальный объем памяти, доступной процессу, можно с помощью системного вызова ulimit или одноименной утилиты. Таким образом можно ограничить ущерб от сбойной программы CGI. К сожалению, в некоторых системах это ограничение реализовано не вполне корректно, так что процессы могут поглощать совершенно неограниченные объемы памяти. Помните, что драйверы устройств увеличивают размер ядра, а ядро не может быть вытеснено в файл подкачки, поэтому следует избавляться от всех ненужных драйверов с целью экономии памяти. Частота очистки буферов файловой системы Запись на диск в системе Unix не обязательно выполняется синхронно. Когда вы записываете данные в файл, изменения немедленно вносятся в его образ, размещенный в памяти, но они не переносятся на диск до тех пор, пока операционная система не найдет время заняться этим. Таким образом, вы достигаете более высокой производительности, потому что, с точки зрения пользователя, запись происходит мгновенно, а контроллер диска может накапливать запросы в очереди для наиболее эффективной записи впоследствии. Недостаток в том, что, когда запись на диск все-таки происходит, она выполняется столько времени, сколько нужно, а все прочие задачи на это время откладываются и пользователи могут ощущать задержку. Одним из способов обойти это является использование контроллера диска с прямым доступом к памяти (Direct Memory Access — DMA), который способен управлять передачей данных между памятью и жестким диском без участия процессора. После начала передачи информации процессор может вновь заняться обслуживанием пользователей, поэтому операции записи не влияют на время отклика системы. Если же у вас нет контроллера с DMA, тогда единственное, что вам остается, — обращаться к диску пореже за счет использования большего объема памяти. Правда, при этом операции записи могут занимать больше времени, потому что за больший срок будут накапливаться большие объемы данных, а кроме того, риск утери данных тоже увеличится. Вполне разумно установить время ожидания равным 60 с (против 30 по умолчанию в системе Linux). Чтобы сделать это, измените содержимое файла /etc/rc.d/rc.S, добавив в него строку /sbin/update 60 &. В системе Solaris нагрузка автоматически распределяется по отрезкам времени длиной 5 с. Занимается этим процесс fsflush. Приоритет Некоторые операционные системы позволяют уменьшать и увеличивать приоритет процессов с помощью команды nice, если вы обладаете достаточными правами. Программа top позволяет вызывать команду nice, а в системе Solaris имеется команда priocntl, обеспечивающая точность управления приоритетом. Вот пример использования priocntl для повышения приоритета четырех процессов до
максимально возможного в категории разделения времени (более высокие приоритеты относятся к категории реального времени. — Примеч. ред.): # priocntl -s -с TS -ш 20 -р 20 -i pid 7645 7646 7647 7648 Прерывания таймера В большинстве операционных систем семейства Unix слежение за временем осуществляется посредством специального прерывания таймера. Прерывание таймера происходит каждые 0,01 с; по этому прерыванию запускается планировщик, который решает, какой процесс будет запущен следующим, и получит следующий квант времени величиной 0,01 с. Это вполне приемлемо в большинстве случаев, однако накладывает на нас некоторые ограничения: например, программа не может быть приостановлена на время, меньшее 0,01 с. В большинстве систем таймер можно настроить. В Linux для процессоров Intel для этого достаточно изменить строку #define HZ 100 в файле /usr/include/asm/param.h. Однако помните, что изменение таймера требует перекомпиляции всех модулей! Средства контроля Unix В большинстве версий Unix измерение производительности осуществляется ядром раз в секунду, поэтому большая часть утилит контроля производительности не позволяет установить интервал измерения меньше секунды. В любом случае не стоит устанавливать слишком короткие интервалы измерений, потому что это создаст слишком большую нагрузку на измеряемые объекты. Обращайтесь к страницам документации всех перечисленных ниже программ, чтобы получить более подробные сведения о них. Последующие разделы описывают основные средства контроля производительности и содержат примеры результатов их работы на сильно загруженном веб-сервере. ps Самое простое и часто используемое средство, позволяющее получить хоть какое-то представление о том, что творится в системе, — это программа ps, которая выводит список всех процессов, а также сведения об используемых ими ресурсах процессора и памяти. Параметры командной строки для этой утилиты сильно зависят от версии операционной системы, так что за подробностями вам придется обратиться к документации. Версия программы ps для систем Беркли обладает некоторыми весьма полезными функциями, например способностью отображать процент использования процессора для каждого процесса. Она размещается в каталоге /usr/ucb/ps в системе Solaris, а ее документацию можно вызвать командой man -s lb ps. Важно помнить, что приоритеты процессов в версиях Беркли вычисляются не так, как в версиях SVR4, но ps для Беркли распространены шире. В SVR4 боль-
шее значение приоритета означает более высокий приоритет (процесс выполняется первым). Вы можете переключиться в режим вывода приоритета в стиле SVR4 с помощью ключа -с. Ниже приведен листинг, упорядоченный по приоритету и несколько отредактированный для большей ясности. % ps -cle | sort -k 7 | tail -25 F S UID PID PPID CLS PRI ADDR SZ WCHAN TTY TIME CMD 8 S 10002 24097 24060 TS 58 61518010 346 6101627e ? 0:01 xterm 8 S 10002 27452 24102 TS 58 61216cd8 1297 6101663e pts/15 0:14 xemacs 8 S 10003 10417 1 TS 58 60602668 370 60aebd36 ? 0:00 xterm 8 S 65533 21162 21161 TS 58 613d6670 346 610162a6 ? 0:00 xterm 8 S 65533 21305 21174 TS 58 612ff9a0 257 6194Ы56 pts/30 0:00 tcsh 8 S 65533 29569 27210 TS 58 612f0cd8 231 61017П6 ? 0:00 httpd 8 S 0 135 1 TS 59 605f0cc8 203 604d3c96 ? 0:00 in.named 8 S 0 312 1 TS 59 607ce020 214 607celf0 ? 0:02 nntp 8 S 0 19112 19104 TS 59 60efb998 109 60efbb68 ? 0:00 tail 8 S 10001 12530 1 TS 59 60c0a008 725 60c0ald8 ? 0:02 Java 8 S 10001 20646 1 TS 59 60b26660 726 60b26830 ? 0:01 Java 8 S 10001 29165 1 TS 59 6183ecc0 723 6183ee90 ? 0:01 Java 8 S 65533 11391 11386 TS 59 60029338 1209 60029508 ? 0:40 Java 8 S 65533 27224 27210 TS 59 61alacd8 231 60dl3el0 ? 0:00 httpd 8 S 65533 29602 27210 TS 59 618e0000 231 60dl3290 ? 0:00 httpd 8 S 6443 11302 11301 TS 60 60028cd8 240 6152e0a6 pts/18 0:00 tcsh 8 S 65533 4437 27210 TS 60 61a2e020 231 60dl3350 ? 0:00 httpd 8 S 65533 19921 27210 TS 60 60065338 231 60dl3310 ? 0:00 httpd 8 S 65533 29603 27210 TS 60 6120a668 231 60dl3190 ? 0:00 httpd 8 S 65533 29604 27210 TS 60 618eece0 231 60dl3210 ? 0:00 httpd 8 S 65533 29605 27210 TS 60 61988008 231 60dl3250 ? 0:00 httpd 8 S 65533 29606 27210 TS 60 61a0e020 231 60dl32d0 ? 0:00 httpd 19 S 0 3 0 SYS 60 60122678 0 1043el94 ? 64:08 fsflush 19 T 0 0 0 SYS 96 10416C88 0 ? 0:00 sched 19 S 0 2 0 SYS 98 60122cd8 0 10439П0 ? 0:00 pageout perfbar perfbar — бесплатная программа реального времени, предназначенная для контроля производительности систем Solaris. Она работает в системе X Window, выводя на экран индикатор занятости процессора. Замечательная вещь, если вам удастся ее найти — мне она давненько не попадалась. perfmeter perfmeter — простая программа с графическим интерфейсом, предназначенная для контроля производительности дисков, сети, процессора и так далее. Она получает данные от демона rpcstatd, который имеется в большинстве версий Unix, perfmeter поставляется вместе с системой Solaris, однако существует и бесплатная открытая версия, которую можно найти по адресам http://rstatd.sourcefor- ge.net и http://www.koeniglich.de. Выведите на экран все нужные вам показатели, и вы получите прекрасное представление о том, как одно влияет на другое и что от чего зависит. Если ваш процессор будет перегружен или если в сети вдруг
возникнет трафик, когда вы его не ждете, вы это сразу заметите. Аналогичное средство для Linux называется xload. На рис. 17.2 приведено изображение окна программы perfmeter на компьютере Sun Ultra 1 с 64 Мбайт памяти, работающем под управлением Solaris 2.5.I. Я обратился к этому компьютеру с помощью программы для создания нагрузки, которая запрашивала двоичный файл объемом 55 Кбайт 250 раз за 35 с. Таким образом, нагрузка на сервер составляла около 7 хитов в секунду, а пропускная способность — около 3 Мбит/с. Рис. 17.2. Окно программы perfmeter perfmon perfmon — это средство, позволяющее пользовательским программам обращаться к счетчикам производительности процессоров Sun Ultra и Intel PentiumPro. Использование его нетривиально, поскольку требует установки драйвера устройства на компьютере, где оно должно выполняться, а также написания программы, которая будет использовать этот драйвер. (Подробнее об этом см. по адресу: http://^лллпл/.(^e.msu.edu/~enbody/perfmon/design.html.)
rstat rstat — это клиентская программа RPC, написанная мною для получения и вывода статистики производительности с любого компьютера, на котором работает демон rstatd. (Подробнее см. главу 4.) rup Программа rup полезна, если вы хотите быстро узнать, какие компьютеры с работающим демоном rstatd относятся к вашей локальной сети и какова их средняя загрузка. hstat hstat — это фирменное средство Sun, предназначенное для профилирования процессоров Sparc. Оно поставляется только фирмой Sun и не сопровождается службой поддержки. top Отличное средство для постоянного контроля производительности — программа top, сортирующая список процессов по потреблению ими ресурсов, top работает как постоянно обновляющая вывод программа ps. Вот пример: last pid: 1867: load averages: 1.29. 1.38. 1.40 13:57:59 196 processes: 173 sleeping. 1 running. 21 zombie. 1 on cpu CPU states: 61.2% idle. 11.7% user. 24.5% kernel. 2.7% lowait. 0.0% swap Memory: 371M real. 106M free. 260M swap. 181M free swap PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND 29390 giacomo 8 0 ЮМ 10М sleep 0:02 1.51% 2.94% buildindex 27210 fred -25 0 1848K 1384K run 348:16 2.31% 2.36% httpd 2807 root 33 0 133M 117M sleep 22.8H 2.67% 1.46% dataserver 1074 patrick 33 0 1880K 1648K cpu 0:00 0.35% 0.27% top 27643 Jeffrey 33 0 12M 4824K sleep 67:00 0.15% 0.08% Java 2302 Jeffrey 33 0 5648K 5224K sleep 0:05 0.02% 0.05% Java 8450 root 33 0 2136K 1592K sleep 0:38 0.01% 0.03% sshd 99 root -3 0 904K 680K sleep 9:30 0.02% 0.01% defrouter 117 root 33 0 2120K 1176K sleep 3:02 0.00% 0.00% rpebind 315 root 33 0 2000K 1000K sleep 1:37 0.00% 0.00% Ipd 12828 root 33 0 1672K 816K sleep 1:09 0.00% 0.00% sshd 445 root 33 0 8248K 904K sleep 0:43 0.00% 0.00% backupserver 11391 aloysiu 34 0 9672K 5368K sleep 0:39 0.00% 0.00% Java 1 root 33 0 440K 192K sleep 0:36 0.00% 0.00% lmt 330 root 33 0 2904K 1888K sleep 0:30 0.00% 0.00% defcon 140 root 23 0 1760K 1184K sleep 0:21 0.00% 0.00% inetd 217 root 33 0 1504K 1144K sleep 0:20 0.00% 0.00% syslogd 346 root 33 0 1480K 736K sleep 0:20 0.00% 0.00% at 213 root 33 0 2752K 1568K sleep 0:10 0.00% 0.00% automountd
С этой программой на моем компьютере возникла неожиданная проблема: она показывала, что у меня установлено 2 Гбайт памяти, тогда как на самом деле — и я точно это знал — их было 4. Возможно, это было связано с какими-то внутренними ограничениями. У программы имеется очень удобная функция: она срабатывает один раз и завершается — если только у нее нет доступа к терминалу. Именно это вам и нужно, если вы запускаете top в качестве задания сгоп или как приложение CGI на веб-сервере. Параметр -Ь позволяет зафиксировать это поведение (однократный запуск с последующим завершением) явно. Это полезно, если вы хотите получить список всех процессов, а не нескольких главных потребителей ресурсов: укажите параметр -Ь и максимальное количество отображаемых процессов, например: top -b 200. Наконец, top может помечать вытесненные в файл подкачки процессы словом <swap>. Программа ps на такое неспособна. xload Программа xload поставляется с системой Solaris. Она выводит постоянно обновляющийся график загрузки системы. Трассировщики системных вызовов Возникало ли у вас когда-нибудь желание узнать, что происходит внутри вашего компьютера, когда он мучительно «размышляет» над, казалось бы, простым вопросом, своей тупостью сводя вас с ума? Так вот: вы можете это сделать! Вы можете вывести на экран список всех выполняемых системных вызовов вместе сих параметрами. Это делается с помощью утилит трассировки системных вызовов, таких как truss (Solaris) и strace (Linux). Есть и другие трассировщики, среди них ktrace и par. Вызовы функций из общих библиотек можно отслеживать с помощью программы sotruss (Solaris 2.6). Пример трассировки вызовов, происходящих в момент получения веб-сервером запроса, приведен в главе 9. Трассировка особенно полезна, потому что позволяет найти приложения, считывающие и записывающие данные побайтно, что крайне неэффективно. В языке Java эта проблема легко решается путем использования буферизованных считывающих и записывающих классов вместо побайтного ввода-вывода. Запустив команду truss -t read,write -s\!all -p (идентификаторы процессов), вы должны увидеть нечто подобное: readD9. " В\г\п Т R 0 8 0 6 5 9"... 8192) - 8192 readD9. " J"... 8192) - 8192 readD9. 49 В D "... 8192) - 8192 readD9. 0329.890000"... 8192) - 8192 readD9. " . О О R "... 8192) * 8192 readD9. " В\г\п Т R 0 8"... 8192) - 8192 readD9. " "... 8192) = 8192 readD9. 413249 В "... 8192) = 8192 readD9. 00245615.03"... 8192) « 8192
А вот такого быть не должно: readD9. " С". 1) =1 readD9. " С". 1) - 1 readD9. " ". 1) - 1 readD9. "О". 1) =1 readD9. " 2". 1) =1 readD9. " 3". 1) - 1 readD9. " 0". 1) - 1 readD9. " 0". 1) - 1 readD9. " 7". 1) - 1 readD9. " 5". 1) «1 readD9. " 6". 1) - 1 readD9. " ". 1) =1 readD9. " 0". 1) - 1 readD9. "\r". 1) - 1 readD9. "\n". 1) » 1 readD9. " T". 1) = 1 readD9. " R". 1) - 1 readD9. " 2". 1) - 1 readD9. " 3". 1) « 1 readD9. " 4". 1) =1 readD9. " 5". 1) - 1 readD9. " 6". 1) » 1 readD9. " 7". 1) - 1 readD9. " 8". 1) - 1 readD9. " 9". 1) - 1 readD9. " ". 1) - 1 readD9. " B". 1) - 1 readD9. " U". 1) - 1 readD9. " Y". 1) «1 readD9. " ". 1) =1 readD9. " \ 1) =1 readD9. " D". 1) =1 readD9. " L". 1) = 1 readD9. " R". 1) - 1 readD9. " S". 1) - 1 readD9. " ". 1) - 1 readD9. " ". 1) =1 readD9. " ". 1) =1 readD9. " ". 1) =1 readD9. " ". 1) - 1 readD9. " ". 1) - 1 readD9. " ". 1) - 1 readD9. " ". 1) =1 readD9. " 7". 1) =1 readD9. " 7". 1) « 1 readD9. " 7". 1) - 1 readD9. " 6". 1) - 1 readD9. " 5". 1) =1 readD9. " .". 1) =1 readD9. и 0". 1) = 1 readD9. " 0". 1) - 1 readD9. H ". 1) =1
Программы прослушивания сети Возникало ли у вас желание узнать, что происходит на вашем сетевом соединении? Утилита snoop, поставляемая с системой Solaris, будет исправно сообщать вам о том, что передается в вашем сегменте сети. Для работы с ней нужно обладать правами привилегированного пользователя, поскольку она дает возможность увидеть абсолютно все, включая содержимое пакетов. Исходный код аналогичной утилиты tcpdump можно скачать по адресу: ftp://ftp.uu.net/. Еще одна программа этого класса называется etherfind. netstat Программа netstat следит за состоянием сетевых соединений. Это очень полезно, если вы хотите узнать, какие соединения используются, а какие нет, чтобы не тратить зря большие объемы памяти на буферы для неиспользуемых соединений. В системе Linux команда netstat -с выводит обновленную информацию о состоянии сети каждую секунду. Полезно бывает выполнить несколько запросов из браузера, одновременно запустив эту команду на выполнение. Вот пример вывода программы netstat: % netstat -at Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (State) User tcp 0 0 *:700 *:* LISTEN root tcp 0 0 *:netbios-ssn *:* LISTEN root tcp 0 0 *:nntp *:* LISTEN root tcp 0 0 *:auth *:* LISTEN root tcp 0 0 *:6000 *:* LISTEN patrick tcp 0 0 *:sunrpc *:* LISTEN root tcp 0 0 *:pop3 *:* LISTEN root tcp 0 0 *:www *:* LISTEN root tcp 0 0 *:finger *:* LISTEN root tcp 1 0 cn2.cab:1584 nik.null.com:www CLOSE_WAIT patrick tcp 1 0 cn2.cab:1580 nik.null.com:www CLOSE_WAIT patrick tcp 1 0 cn2.cab:1579 mk.null.com:www CLOSE_WAIT patrick tcp 1 0 cn2.cab:1578 nik.null.com:www CLOSE_WAIT patrick tcp 1 0 cn2.cab:1577 nik.null.com:www CLOSE_WAIT patrick tcp 1 0 cn2.cab:1576 nik.null.com:www CLOSE_WAIT patrick tcp 1 0 cn2.cab:1575 nik.null.com:www CLOSE_WAIT patrick tcp 0 0 *:time *:* LISTEN root tcp 0 0 *:uucp *:* LISTEN root tcp 0 0 *:ftp *:* LISTEN root tcp 0 0 *:chargen *:* LISTEN root tcp 0 0 *:netstat *:* LISTEN root tcp 0 0 *:daytime *:* LISTEN root tcp 0 0 *:systat *:* LISTEN root tcp 0 0 *:discard *:* LISTEN root tcp 0 0 *:echo *:* LISTEN root tcp 0 0 *:printer *:* LISTEN root tcp 0 0 *:shell *:* LISTEN root tcp 0 0 *:login *:* LISTEN root tcp 0 0 *:2049 *:* LISTEN root
Программа netstat работает в системах Linux и Solaris довольно медленно. В системе Solaris есть гораздо более быстрый способ отображения информации о соединениях — программа ndd: % ndd /dev/tcp -get tcpstatus vmstat Программа vmstat выводит краткий отчет о состоянии памяти в формате ASCII, зависящем от версии Unix. Индикацией достаточного (или недостаточного) объема памяти в системе Solaris служат счетчики количества запросов на поиск свободных страниц и количества страниц вытесненных, в секунду. Показания обоих должны быть как можно меньше. Вот пример вывода программы vmstat: % vmstat l procs memory page disk faults cpu г b w swap free re mf pi po fr de sr s2 s3 s4 si in sy cs us sy id 0 0 0 352 888 0 534 18 3 7 0 0 0 1 0 1 271 1 418 3 6 91 6 0 0 192960 111528 0 2139 0 0 0 0 0 0 0 0 0 488 2780 1106 4 23 73 1 0 0 196128 112136 0 4412 0 0 0 0 0 0 0 0 0 1086 3193 2511 7 33 60 0 0 0 194016 111416 0 3419 0 0 0 0 0 0 0 0 0 689 1977 1722 2 22 76 0 0 0 193664 111296 0 4319 0 0 0 0 0 0 0 0 0 890 2597 2231 2 28 69 1 0 0 195608 111992 0 4100 0 0 0 0 0 0 0 0 0 887 2341 2210 4 23 72 0 0 0 196480 112256 0 1234 0 0 0 0 0 0 0 0 0 390 924 785 2 7 92 0 0 0 194720 111720 0 1616 0 0 0 0 0 0 0 0 0 360 1095 738 2 8 91 0 0 0 189440 110016 0 2900 0 0 0 0 0 0 0 0 0 701 1767 1732 2 20 78 1 0 0 195040 111768 0 5486 0 0 0 0 0 0 2 0 1 1046 3969 2729 10 32 58 0 0 0 194280 110808 0 4147 0 0 0 0 0 0 0 0 0 787 2368 1984 2 27 70 2 0 0 191816 110152 0 5556 0 0 0 0 0 0 31 0 0 1122 3268 2840 4 38 58 0 0 0 194368 111528 0 3784 0 0 0 0 0 0 0 0 0 750 2157 1914 4 18 78 2 0 0 194776 112064 0 4684 0 0 0 0 0 0 0 0 0 893 2607 2316 4 28 67 0 0 0 195424 111888 0 2366 0 0 0 0 0 0 1 0 0 526 1433 1240 4 16 81 0 0 0 195424 111888 0 3650 0 0 0 0 0 0 0 0 0 758 2381 1896 2 24 73 0 0 0 194368 111592 0 4166 0 0 0 0 0 0 0 0 0 830 2405 2108 3 24 73 0 0 0 194368 111528 0 3430 0 0 0 0 0 0 0 0 0 676 2116 1724 2 22 76 0 0 0 194360 112000 0 3988 0 0 0 0 0 0 0 0 0 772 2266 1896 2 26 71 sar Программа sar выводит те же сведения, что и vmstat, но она, кроме того, позволяет сохранять данные в сжатом двоичном формате, для того чтобы можно было собирать долгосрочную статистику производительности системы. Эта же программа служит интерфейсом для отображения собранной статистики, sar обеспечивает большую гибкость и полноту информации, чем vmstat. Вот пример выводимого ею текста:
% sar -с 5 5 SunOS pokey.patrick.net 5.5.1 Generic_103640-12 sun4u 02/17/98 15:03:46 scall/s sread/s swrit/s fork/s exec/s rchar/s wchar/s 15:03:51 2418 5 84 79.64 0.60 1126 537 15:03:56 1703 3 58 57.80 0.00 478 505 15:04:01 1676 10 57 51.70 0.00 640 523 15:04:06 2553 14 93 84.83 0.00 739 559 15:04:11 1807 4 60 56.80 0.60 965 556 Сколько соединений может обслужить мой веб-сервер? Интересно установить максимально возможное количество соединений со своим веб-сервером, чтобы узнать, какой ресурс будет исчерпан первым. Запустите приведенный в листинге 17.4 сценарий и следите за производительностью системы с помощью перечисленных в предыдущем разделе средств контроля. Учтите, что сценарий может привести к сбою сервера или тестового клиента, поэтому запускайте его только на тех компьютерах, сбой которых для вас вполне допустим. Возможно, вам придется запустить несколько экземпляров сценария на нескольких компьютерах, чтобы ресурсы сервера наконец исчерпались, — в таком случае вам придется сложить выведенные экземплярами сценария результаты. Мне удается установить до 3500 соединений на моем портативном компьютере Sony Vaio, который работает под управлением Linux 2.2. Судя по всему, один процесс может устанавливать гораздо больше соединений, чем это ограничивается максимальным количеством дескрипторов файлов. Программу можно скачать по адресу: http://patrick.net/software/maxconn. Листинг 17.4. Установка максимального количества соединений #!/usr/bin/perl use Socket: die "Usage: maxconn <host> <port>\n" unless $ARGV[0]: Siaddr - gethostbyname($ARGV[0]): Sproto = getprotobyname('tcp'): while A) { print "$n\n": $n++: socket (SOCK. PFJNET. SOCK_STREAM. Sproto) or fail ("socket: $!"): Spaddr = sockaddr_in($ARGV[l]. Siaddr); connect(SOCK. Spaddr) or fail("connect: $!"): }
Сколько процессов может одновременно выполняться на моем сервере? Интересно также проверить, сколько процессов может выполняться сервером и какой ресурс закончится первым. В листинге 17.5 приведена небольшая программа на С, порождающая собственную копию и ожидающая завершения дочернего процесса. Она очень быстро размножается до максимально возможного количества процессов. Эта программа тоже может привести к сбою вашего компьютера, поэтому запускайте ее только на тех компьютерах, остановка которых для вас допустима. Загрузить ее можно с сайта по адресу: http://patrick.net/ software/fork.c. Компилируется она так: дсс -о fork fork.c. Листинг 17.5. Порождение максимального количества процессов #include <unistd.h> include <stdio.h> #include <errno.h> finclude <sys/types.h> #include <sys/wait.h> main( ) { int pid; pid - fork( ): if (pid " -1) perror("failed: "); if (pid - 0) { printf("child\nH): execl(\/fork\ ""): } else printf("parent\n"): wait(NULL): } Поскольку все дочерние процессы являются новыми, мы не можем организовать счетчик с той же легкостью, с которой мы сделали это в сценарии на языке Perl (см. листинг 17.4). Количество процессов я отслеживал с помощью программы top. Мой портативный компьютер добрался приблизительно до 500 процессов, затем программа top выдала сообщение help! (помогите!), а жесткий диск в это время работал не переставая. Я убил родительский процесс нажатием Ctrl+C, и все встало на свои места, потому что дочерние процессы тоже завершились. Если вы удалите из программы вызов wait, то получится маленькая злобная программка, которую нельзя будет так просто уничтожить. Родительский процесс завершается, а дочерний порождает новый процесс и тоже завершается — и так далее. Ни один процесс не живет достаточно долго, чтобы вы могли заметить его существование с помощью ps; процессы постоянно рождаются и исчезают, не переполняя таблицы процессов, но потребляя массу ресурсов процессора. Чтобы убить этого «мутанта», нужно запустить программу, приведенную в листинге 17.5, но не выбрасывая вызов wait, чтобы она поглотила столько ресурсов,
что «плохая» версия не сможет размножаться. Как только один из дочерних процессов не сможет породить новый, цепочка будет прервана. Насколько быстро может мой сервер породить новый процесс? Маленькая зловредная программка может быть слегка изменена, чтобы сообщить нам кое-какую полезную информацию, а именно: насколько быстро могут порождаться новые процессы в нашей системе. Нам придется добавить в нее функции для измерения времени работы, а также ограничить количество порожденных дочерних процессов, и тогда мы просто воспользуемся вышедшим из моды оператором goto, чтобы каждый из дочерних процессов возвращался к оператору fork. Поскольку дочерние процессы создаются именно вызовом fork, а не execl, значение счетчика сохраняется. Программу, приведенную в листинге 17.6, вы можете скачать по адресу: http://patrick.net/software/forktime.c. Листинг 17.6. Измерение времени выполнения вызова оператора fork #include <unistd.h> #include <stdio.h> #iinclude <errno.h> #include <sys/types.h> #include <sys/wait.h> #iinclude <time.h> main( ) { int pid; int count - 0: time_t t: struct tm * tp: char timestr[20]: t - time(NULL): tp - localtime(&t): strftime(timestr. 20. "П %m %6 %H *M *S". tp); pnntf(timestr): pnntf("\n"): there: pid - fork( ); if (pid ~ -1) perrorCfailed: "): if (pid — 0) { /* дочерний процесс */ if (++count > 10000) { t - time(NULL): tp - localtime(&t): strftime(t1mestr. 20. "SY %m %6 %H SM SS\ tp): printf(timestr): printf(H\n"):
_exit@): } else { goto there: } } /* only parent can get here */ _exit@): } Запустив эту программу, я определил, что, судя по разнице во времени между моментом выполнения первого родительского процесса и десятитысячного дочернего G с), создание нового процесса на моем портативном компьютере под управлением Linux занимает около 0,7 мс. Мне не нужно было порождать процессы в цепочке от родительского к дочернему, поскольку родительский процесс не может продолжить выполнение до тех пор, пока дочерний не начнет выполняться и не получит идентификатор процесса. Я изменил программу fork, чтобы она выполняла порождение процессов конечное число раз, и заменил вызов execl вызовом _exit@), чтобы новые дочерние процессы завершались. Попытки породить таким образом 1000 процессов неизменно приводили к разного рода ошибкам, но мне удалось породить 500 процессов. Если я выводил на экран сообщение child exiting, порождение нового процесса занимало 50 мс. Когда я выводил только номер процесса, та же операция занимала 27 мс. Если же дочерний процесс вовсе ничего не выводил на экран, порождение процесса занимало всего 0,7 мс. Это показывает, что даже самые простые операции ввода-вывода занимают больше времени, чем порождение новых процессов. Unix и Windows NT в качестве ОС для веб-серверов Все сказанное не означает, что ни одна система не может конкурировать с Unix в качестве платформы для веб-сервера. Несложно установить веб-сервер на компьютере с Windows или на Macintosh и получить при этом приемлемую производительность (по крайней мере, при низкой загрузке). Однако при серьезной нагрузке единственным конкурентом Unix в качестве платформы веб-сервера остается Windows NT. Создатели NT задействовали множество концепций Unix: ядро, процессы, приоритетную многозадачность. Посмотрим, что каждая из операционных систем сможет нам предложить. Достоинства и недостатки NT NT обладает традиционными для Microsoft преимуществами хорошей интеграции с другими продуктами Microsoft, единообразия и наличия оконного интерфейса, удобного для тех, кто не любит набирать команды врущую и кому не нужно управлять системой на достаточно тонком уровне. NT позволяет выполнять некоторые устаревшие приложения для Windows. Операционная система
Windows NT может работать на дешевом оборудовании персональных компьютеров, однако на это же способны и многие версии Unix. NT обладает не слишком хорошей производительностью и масштабируемостью по отношению к веб-серверу. Еще важнее, что NT очень нестабильна по сравнению с Unix, постоянно останавливается из-за сбоев или требует перезагрузки, что является серьезным недостатком с точки зрения владельцев важных сайтов. NT поставляется без средств удаленного администрирования и не может работать в многопользовательском режиме (в Windows 2000 есть Terminal Services — аналог многопользовательского режима. — Примеч. ред.). Разместить высокопроизводительный веб-сервер на оборудовании ПК достаточно тяжело. Масштабируемость будет ограничена несовершенством архитектуры персонального компьютера, которая никогда не рассчитывалась на серьезную нагрузку. По некоторым оценкам, даже на лучших ПК невозможно обслужить одновременно более 250 пользователей в режиме обработки транзакций. Оборудование персональных компьютеров в среднем менее надежно, чем оборудование настоящих рабочих станций, потому что оно изготавливается для широкого рынка, где главным фактором является стоимость, а не надежность. Еще один сложный вопрос: можно ли доверять компании Microsoft? Демонстрируя масштабируемость, она использовала тест debit—credit, результаты которого легко исказить, — а ведь могла бы выбрать более надежные тесты для транзакций ТРС-С и TPC-D. Разработчиков компании Microsoft обвиняли в том, что они исказили возможности версии Windows NT Workstation по сравнению с NT Server. Более дешевая версия NT Workstation не могла открывать более 10 соединений одновременно, причем утверждалось, что это связано с физическими ограничениями, а пользователи должны были платить гораздо больше за более производительную (согласно рекламе) версию NT Server. Сравнение исполняемых файлов на двоичном уровне (обычной программой diff) показало, что они были полностью идентичны — за исключением нескольких байтов, которые, вероятно, представляли собой переключатель, разрешавший установку большего количества соединений. Достоинства и недостатки Unix Операционные системы класса Unix очень устойчивы. Обычно они могут работать месяцами, а иногда и годами, не нуждаясь в перезагрузке. Важно и то, что Unix обладает гораздо большей масштабируемостью по сравнению с Windows NT, что позволяет небольшому сайту расти путем добавления в компьютер новых процессоров и контроллеров ввода-вывода, а не путем размножения сервера на несколько добавочных компьютеров. Наконец, система Unix обеспечивает более высокую производительность — отчасти потому, что она обычно устанавливается на более дорогом оборудовании, чем то, которое используется в обычных персональных компьютерах. Основная часть высокопроизводительных веб-серверов работает под управлением одной из версий Unix, так что все возникающие вопросы давно уже проработаны. Профессиональная система Unix в минимальном варианте обычно стоит дороже, чем NT, даже если соотношение «цена/производительность» на
этом уровне у нее оказывается хуже. Если стоимость для вас важна, то помните, что имеется множество версий Unix, которые будут работать на том же оборудовании, что и Windows NT, и обеспечивать при этом ту же или лучшую производительность. Это Solaris x86, Linux, BSDI и FreeBSD. Стоимость операционной системы Solaris сравнима со стоимостью Windows NT. Управление системой Unix требует более высокой квалификации администраторов, несмотря на то, что для настройки этой системы имеются графические интерфейсы например, линейка продуктов фирмы Sun под названием Ne- tra, а также бесплатная программа Webmin с сайта http://www.webmin.com. Проект Exokernel Одна из исследовательских групп в Массачусетском технологическом институте разработала нечто вроде микроядра, которое занимается лишь тем, что обеспечивает доступ к оборудованию разным приложениям. Приложения могут быть и операционными системами, но это вовсе не обязательно. Можно написать веб-сервер, который будет использовать оборудование «на полную катушку», избавившись от всех накладных расходов на операционную систему. Группа Exokernel написала собственный веб-сервер Cheetah, графики некоторых впечатляющих характеристик которого приведены по адресу: http:// www.pdoc.lcs.mit.edu/exo.html. Это здорово, но, вообще говоря, скорость веб-сервера обычно не является главной проблемой. Скорости базы данных и генерации динамического содержимого обычно гораздо важнее, поэтому именно их следовало оптимизировать при помощи метода, примененного группой Exokernel. Основные рекомендации О Не записывайте время доступа к файлам. Либо подключите файловую систему в режиме только для чтения, либо измените исходный код, обслуживающий данную файловую систему, и перекомпилируйте его. О Сделайте пути короткими. О Не используйте символические ссылки. О Не запускайте на сервере оконный интерфейс — работайте в режиме терминала.
10 Программное q обеспечение сервера Веб-серверы принимают запросы и отсылают ответы. Ответом может быть статическая страница, произвольное динамическое содержимое или сообщение об ошибке. Производительность сильно зависит от нагрузки, однако обычно время работы веб-сервера между получением запроса и отправлением ответа (статической страницы) составляет около одной десятой доли секунды. Время ожидания для модемов, Интернета и даже для браузера (время обработки HTML) чаще всего превышает эту величину, поэтому при низкой нагрузке веб-сервер никогда не бывает «узким местом». Другое дело — сильно загруженный веб-сервер. Производительность веб-серверов меняется нелинейно, резко снижаясь после определенного порогового значения нагрузки. В данной главе рассказывается о том, почему это происходит, и о том, как выжать все возможное из имеющегося программного обеспечения. Эволюция веб-серверов Основная задача веб-серверов не менялась никогда, но сами они за годы своего существования претерпели значительные изменения. Серверы, порождавшиеся демоном inetd Веб-серверы первого поколения были обычными службами Unix, запускающимися при необходимости демоном inetd, который считывал файл /etc/services в момент своего запуска и прослушивал указанные в этом файле порты. Когда на один из портов демона inetd поступал запрос, он запускал программу, также указанную в этом файле, которая и должна была обрабатывать данный запрос.
Такая схема требовала двух вызовов — fork() и ехес(). Вызов fork порождал новую копию inetd, а вызов exec заменял образ процесса inetd образом нового процесса, который должен был обслуживать запрос. Этот механизм предназначался для сбережения системных ресурсов: демоны запускались только по мере необходимости, а всем прочим процессам доставалось больше ресурсов. Рассмотрим демон ftpd в качестве простого примера. Последите за списком процессов в своей системе, скажем, с помощью программы top. Когда на порт 21 поступает запрос, демон inetd запускает ftpd, который появляется в списке процессов. Когда FTP-сеанс завершается, процесс ftpd исчезает. Изначально httpd запускался таким же образом, но с порта 80. Неприятности начались, когда загрузка серверов превысила 1-2 хита в секунду. Серверы просто перестали справляться со своими обязанностями. Помните, что одна HTML-страница может включать множество изображений, поэтому 1 запрос пользователя может вызвать столько HTTP-операций, что они превысят максимальную пропускную способность сервера, запускающего httpd из inetd. Пользуясь старым механизмом, вы платите увеличением времени запуска за уменьшение средней загрузки системы, но это допустимо только при очень низкой загруженности веб-сервера. Как только загруженность возрастает, многократный запуск httpd начинает увеличивать ее еще больше, а производительность как локального пользователя, так и веб-клиента начинает падать. Не запускайте httpd из inetd. Вместо этого нужно установить автономный сервер. Файл httpd.conf веб-сервера Apache настраивается для этого следующим образом: # ServerType is either inetd. or standalone. ServerType standalone Серверы, порождающие процессы Шагом вперед но сравнению с порождением нового сервера демоном inetd при помощи вызовов fork() и ехес() является порождение процессом httpd новой копии себя самого при помощи вызова fork() (уже без exec). Вызов fork изначально предназначался именно для таких целей, и он достаточно хорошо работает в мире клиентов и серверов, но запросы HTTP поступают так часто, а обрабатываются так быстро, что порождение нового процесса часто занимает больше времени, чем собственно обработка запроса. Первые версии серверов CERN и NCSA относились именно к классу серверов с порождением процессов. Новое усовершенствование появилось в веб-сервере Apache. Серверы Apache порождают некоторое количество экземпляров себя самих заранее. Например, когда демон Apache 1.2.4 httpd запускается, он немедленно запускает еще пять копий себя, чтобы иметь возможность эффективно обрабатывать одновременные запросы одного браузера или даже нескольких клиентов. Apache увеличивает количество процессов сервера при возрастании нагрузки; такая схема работает достаточно хорошо даже для очень больших сайтов, но она требовательна к ресурсам ОЗУ и процессора.
Многопоточные серверы Чтобы соответствовать легковесной и непостоянной природе HTTP-соединений, программисты, разрабатывающие серверы, перешли к концепции потоков. Потоки — это отдельные выполняемые последовательности команд в рамках одного процесса. Создание потока или переключение контекста выполняется приблизительно в 10 раз быстрее, чем аналогичные действия с процессами. Однако после создания процесса и подготовки его к приему соединения «узким местом» становится процедура обслуживания запроса, а не управление процессами или потоками сервера, поэтому не следует ожидать десятикратного повышения производительности при переходе на многопоточный сервер. Серверы Netscape Enterprise 2.0 и более новых версий являются многопоточными и могут обслуживать несколько тысяч соединений в секунду. Apache 2.0 поддерживает многопоточный режим работы (помимо режима работы с предварительным порождением процессов) благодаря наличию специального модуля МРМ (Multi-Processing Module). Серверы с постоянными соединениями Дополнительно повышение производительности достигается поддержанием соединений TCP в открытом состоянии для передачи нескольких файлов без разрыва соединения. Это технология постоянных соединении (persistent connections), или соединений с проверкой жизнеспособности (keepalivc), которая входит в стандарт HTTP 1.1. Большая часть браузеров и серверов на данный момент понимает и поддерживает постоянные соединения, даже если они не поддерживают HTTP 1.1 полностью. Браузеры указывают на возможность установки постоянного соединения при помощи заголовка Connectionrkeepalive, отправляемого в тексте запроса. И многопоточные серверы, и серверы с предварительным порождением процессов могут работать с постоянными соединениями. Опасность постоянных соединений в том, что клиенты могут отключаться, не уведомляя об этом сервер, который будет поддерживать для них открытое соединение и тратить на это драгоценные ресурсы. Чтобы предотвратить накопление чрезмерного количества открытых соединений, большая часть реализаций постоянных соединений позволяет указать время ожидания для закрытия неиспользуемых соединений. Системные вызовы веб-сервера Ниже приведен пример трассировки системных вызовов (всех вызовов функций операционной системы, сделанных программами за время работы трассировщика) в системе Linux 2.O. Мы увидим, что именно делает веб-сервер Apache I.2.4. Чтобы вставить в книгу этот пример, я запустил веб-сервер Apache с одним дочерним процессом и включил трассировку вызовов для этого процесса, одновременно запросив из браузера веб-страницу. Обычно довольно трудно бывает понять, почему приложение решило сделать данный конкретный систем-
ный вызов, но в любом случае это очень ценная методика, позволяющая узнать, чем занимается программа и на что она тратит время. Я воспользовался аналогичной трассировкой, выполненной Дином Годе (Dean Gaudet), чтобы понять, что тут происходит, строки я пронумеровал, чтобы упростить дальнейшее обсуждение: 1 # strace -pll47 2 ассерШб. {sin_family=AF_INET. sin_port=htons( 1034). sin_addr=inet_addr(M127.0.0.1M)}. [16]) - 3 3 fcntlA8. F_SETLKW. {type=F_UNLCK. whence=SEEK_SET. start-0. len=0}) - 0 4 rt_sigaction(SIGUSRl. {SIG_IGN}. {Ox80596cO. []. SA_INTERRUPT|0x4000000}. 8) - 0 5 getsocknameC. {sin_family=AF_INET. sin_port=htons(80). sin_addr=inet_addr(27.0.0.1M)}. [16]) = 0 6 setsockoptC. IPPR0T0JCP1. [1]. 4) = 0 7 brk@x80b3000) - 0x80b3000 8 readC. "GET / HTTP/1.O\r\nlf-Modified-Sinc".... 4096) - 336 9 rt_sigaction(SIGUSRl. {SIG_IGN}. {SIGJGN}. 8) - 0 10 time(NULL) - 988240305 11 statC/home/httpd/html". {st_mode»S_IFDIR|0777. st_size=2048. ...})-0 12 1stat("/home". {st_mode-S_IFDIR|0755. st_size-1024. ...})-0 13 IstatCVhome/httpd". {st_mode=S_IFDIR|0755. st_size=1024. ...}) -0 14 lstatC/home/httpd/html". {st_mode»S_IFDIR|0777. st_size=2048. ...}) =0 15 brk@x80b6000) = 0x80b6000 16 statr/home/httpd/html/index.htmr. {st_mode«S_IFREG|0644. st_size=2488. ...}) =0 17 1stat("/home". {st_mode=S_IFDIR|0755. st_size-1024. ...}) =0 18 IstatC'/home/httpd". {st_mode*S_IFDIR|0755. st_size=1024. ...})= 0 19 lstatC/home/httpd/html". {st_mode»S_IFDIR|0777. st_size-2048. ...}) -0 20 statCVhome/httpd/html/index.html". {st_mode=S_IFREG|0644. st_size=2488. ...}) =0 21 1 state/home". {st_mode=S_IFDIR|0755. st_size=1024. ...}) = 0 22 IstatC'/home/httpd". {st_mode»S_IFDIR|0755. st_size»1024. ...}) =0 23 lstatC/home/httpd/html". {st_mode»S_IFDIR|0777. st_size=2048. ...})=0 24 openCVhome/httpd/html/index.html". 0_RD0NLY) - 4 25 openC/etc/localtime". 0_RD0NLY) = 5 26 readE. "TZif\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0".... 44) - 44 27 readE. "\236\246H\240\237\273\25\220\240\206*\240\241\232\367\220".... 920) - 920fstatE. 28 {st_mode=S_IFREG|0644. st_size»1000. ...}) =0 29 mmap@. 4096. PR0T_READ|PR0T_WRIТЕ. MAP_PRIVATE|MAP_ANONYMOUS. -1.0)- 0x40014000 30 readE. M\377\377\235\220\l\0\377\377\217\200\0\4\377\377\235\220".... 4096) =36 31 closeE) - 0 32 munmap@x40014000. 4096) - 0 33 selectD. [3]. NULL. NULL. {0. 0}) - 0 (Timeout) 34 writeC. "HTTP/1.1 304 Not Modified\r\nDate:".... 197) - 197 35 time(NULL) - 988240305 36 wnteA7. 27.0.0.1 - - [25/Apr/2001:16:ll".... 66) = 66 37 closeD) = 0 38 rt_sigaction(SIGUSRl. {Ox80596cO. []. SA_INTERRUPT|0x4000000}. {SIG_IGN}. 8) = 0 39 readC. 40 0x809eb24. 4096) - ? ERESTARTSYS (To be restarted) 41 - SIGALRM (Alarm clock) - 42 closeC) - 0 43 rt_sigprocmask(SIG_SETMASK. []. NULL. 8) - 0 44 rt_sigaction(SIGURG. {0x8058700. []. SAJNTERRUPT|0x4000000}. {0x8058700. []. SA
45 JNTERRUPT10x4000000}. 8) - 0 46 rt_sigaction(SIGALRM. {0x8058910. []. SA_INTERRUPT|0x4000000}. {0x8058910. []. S 47 AJNTERRUPT10x4000000}. 8) - 0 48 rt_sigaction(SIGUSRl. {0x80596c0. []. SAJNTERRUPT]0x4000000}. {0x80596c0. []. S 49 AJNTERRUPT]0x4000000}. 8) - 0 50 fcntlA8. F_SETLKW. {type=F_WRLCK. whence=SEEK_SET. start-0. len=0} В строке 2 вы видите системный вызов accept(), свидетельствующий о том, что сервер принял запрос на обслуживание от IP-адреса 127.0.0.1, то есть от локального компьютера. Затем идет вызов fcntl, снимающий блокировку. Это делается потому, что доступ к вызову accept осуществляется строго последовательно во избежание проблем, описанных на веб-странице http://www.apache.org/ docs/misc/perf-tuning.html. В строке 4 мы видим, что сервер пытается управлять сигналами при помощи вызова rt_sigaction(). Это делается для того, чтобы дочерние процессы завершили работу, когда родительский отправит им сигнал SIGUSR1, но только в том случае, если в момент его получения они не будут заниматься отправкой ответа на запрос клиента. В строке 5 мы получаем сведения о сокете, чтобы включить режим работы с виртуальными узлами. В строке 6 мы отключаем алгоритм Нагла (алгоритм медленного старта), потому что он снижает производительность короткоживущих соединений HTTP. В строке 8 наш запрос считывается из сети. В строке 16 мы видим один из множества вызовов stat. Функция stat используется для получения сведений о файле, которые нужны веб-серверу для того, чтобы отправлять заголовки типа Content-Length и Last-Modified, а также чтобы решить, была ли страница изменена с момента последнего ее запроса веб-клиентом. В строке 29 мы видим, что файл отображается в память при помощи вызова mmap. Веб-сервер Apache поступает так со всеми статическими файлами. В строке 34 начинается отправка ответа по сети. В строке 36 транзакция записывается в файл журнала. В строке 50 доступ к функции accept снова блокируется для обеспечения строго последовательной работы с ней. Как происходит сбой сервера Если для сервера с предварительным порождением процессов установлено ограничение на максимальное количество процессов (например, с помощью параметра MaxClients в файле httpd.conf веб-сервера Apache), то тем самым задается и максимальное количество одновременно обрабатываемых клиентов (название параметра конфигурации Apache, таким образом, не случайно). Лишние запросы не снимаются сервером с очереди прослушиваемого сокета TCP, а пользователи, пославшие эти запросы, нервничают в ожидании перед окнами своих зависших браузеров. Как только очередь прослушиваемого сокета переполняется, пользователи начинают помещаться в очередь неустановленных соединений,
и им все равно приходится ждать. Игнорируемые соединения никак не влияют на способность сервера обрабатывать принятые запросы. Аналогичная ситуация складывается, когда у многопоточного сервера исчерпываются свободные потоки (параметр MaxThreads в конфигурационном файле magnus.conf сервера Netscape Enterprise). Тогда и многопоточный сервер отказывается обслуживать новых клиентов. Хорошо было бы, если бы сервер немедленно отсылал браузеру сегмент RST, но мне не удалось этого добиться. Предположим, у нас было бы совершенно неограниченное количество процессов или потоков, и размер очереди прослушиваемого сокета тоже был бы неограниченным, а мы бы попытались перегрузить сервер, посылая на него все большее и большее количество запросов. Что произойдет в этом случае? Мало того, что за процессорное время станет соревноваться слишком большое количество клиентов, но еще больший процент этого времени будет поглощаться планировщиком. В какой-то момент процессор начнет заниматься практически только планировкой, а не реальной работой. Представьте себе график зависимости пропускной способности от количества одновременных соединений: этот график будет иметь максимум при каком-то определенном количестве соединений, а при увеличении числа соединений свыше оптимального пропускная способность будет спадать. Производительность серверов, не использующих потоки, падает быстрее, потому что на планировку и переключение процессов уходит больше ресурсов, чем на планировку и переключение потоков. Загрузка процессора растет по мере того, как количество одновременно работающих процессов возрастает. Память тоже тратится быстрее, потому что процессы создают большие накладные расходы, чем потоки. Снижение производительности идет практически линейно, потому что накладные расходы распределяются по большому количеству относительно коротких процессов. Многопоточные серверы сначала справляются с задачей лучше благодаря меньшим расходам на переключение между потоками. Их производительность медленно падает по мере того, как потоков становится все больше, — до тех пор, пока в системе не заканчивается память и компьютер не начинает обращаться к файлу подкачки. Недостаток потоковых серверов заключается в том, что вытеснение в файл подкачки огромного процесса вместе со всеми его потоками очень сильно и резко снижает производительность. По этой причине Netscape рекомендует запускать 4 процесса по 32 потока в каждом, а не 1 процесс со 128 потоками. Еще одна проблема, связанная со многопоточными серверами, состоит в том, что взаимная блокировка потоков и их зависание обычно происходят только при очень больших нагрузках, что затрудняет отладку. Медленные клиенты интенсивнее потребляют память сервера, чем быстрые, потому что для медленных клиентов, подключающихся параллельно, приходится создавать отдельные буферы. Это означает, что отказ сервера происходит раньше, если большинство клиентов используют медленные линии связи. Помните, что когда Интернет сильно загружен, все клиенты кажутся веб-серверу медленными. Быстрые клиенты выигрывают от улучшения подсистемы ввода- вывода сервера больше, чем медленные.
Утечки памяти Некоторые веб-серверы страдают медленными утечками памяти. Они выделяют память для каких-то своих нужд, а затем теряют все ссылки на нее, так что эта память больше не может быть использована или отдана обратно операционной системе. Постепенно процесс сервера становится таким большим, что его приходится перезапускать. Если перезапуск веб-сервера значительно повышает производительность, то вы, возможно, имеете дело с утечкой памяти. Если возможности достать пакет исправлений для веб-сервера нет, можно попытаться запланировать с помощью сгоп регулярный перезапуск веб-сервера или — худший вариант — регулярную перезагрузку компьютера. Размер процессов httpd отслеживается с помощью ps или top. Производители серверов могут использовать и используют специальные программные средства для поиска утечек — например, Purify (http://www.rational.com/), но жесткое расписание проектов заставляет их отказываться от аккуратного тестирования в пользу быстрого выпуска продукта. Настройка Apache и Netscape Производители серверов стараются настроить свои продукты оптимальным образом для наиболее широкого круга задач. Они действительно хотят, чтобы ваша производительность была высокой. Причина, но которой у вас может возникнуть желание что-то менять, одна: вы знаете о своих конкретных задачах больше, чем они. Вначале я приведу несколько общих рекомендаций, применимых к любому серверу. Короткие пути Чем меньше данных вы будете записывать в журнал, тем быстрее будет осуществляться запись. Короткие имена файлов содержимого записываются быстрее, поглощают меньше дискового пространства и даже отыскиваются операционной системой быстрее. Отличный пример — сервер Yahoo!. У него имена каталогов и файлов часто состоят вообще из одной буквы. Не преобразуйте время Еще один трюк: отключите любые преобразования времени в процессе записи в журнал. Веб-сервер Java Web Server — мир праху его! — по умолчанию преобразовывал время из GMT в локальное при каждом обращении к нему. Буферизуйте запись в журнал Сейчас журналы веб-серверов, связующих и других типов серверов буферизуются, то есть записи держатся в памяти до тех пор, пока их не накопится доста-
точное количество для эффективной записи на диск или пока не истечет соответствующее время. Включите буферизацию журнала, если она отключена. Это даст вам заметный выигрыш в производительности при небольших затратах памяти. Настройка Apache Веб-сервер Apache на данный момент является наиболее успешным примером веб-сервера. Он используется более чем на половине всех веб-сайтов. Его можно бесплатно скачать по адресу: http://httpd.apache.ord/. Сервер Apache «родился» из старого сервера NCSA после установки множества программных заплат (нат- чей); отсюда и его название (Apache — A patchy web-server — веб-сервер в заплатах). Одним из главных достоинств этого веб-сервера является его цена: вы можете бесплатно скачать как веб-сервер, так и его исходный код. Apache долгое время являлся веб-сервером с предварительным порождением процессов, но сейчас появилась и многопоточная версия для Unix и NT. Считается, что Apache эффективно работает с CGI-шлюзами. Поддержка осуществляется множеством групп Usenet, так что она, пожалуй, превосходит по своим возможностям службу поддержки любого коммерческого веб-сервера, оставаясь бесплатной. Apache поддерживает Java-сервлеты благодаря трудам проекта Tomcat: для него имеются средства контроля производительности реального времени. Он поддерживает специальный режим записи в журнал, позволяющий определить, сколько времени заняла каждая HTTP-операция. (Подробнее см. файл modJog_config.html в документации сервера.) Убедитесь, что веб-сервер был скомпилирован самым современным компилятором языка С с подключением библиотек для вашей платформы, либо скомпилируйте его самостоятельно. О внутренних особенностях серверов Apache, имеющих отношение к оптимизации, читайте в заметках Дина Годе по адресу: http://www.apache.org/docs/ misc/perf-tuning.html. AllowOverride Система проверки подлинности, используемая в Apache и некоторых других серверах, подразумевает поиск файла .htaccess в текущем каталоге и всех родительских каталогах (до корневого каталога системы). При обнаружении этого файла он считывается и обрабатывается. Вы можете ускорить работу Apache, отключив проверку подлинности для тех каталогов, которым она не нужна, — например, для корневого каталога системы. Для этого нужно добавить приведенные ниже строки в файл access.conf: <Directory /> AllowOverride None </Directory> <Directory /usr/local/mydocroot> AllowOverride All (или любой другой из возможных вариантов) </Directory>
Если вы не используете файлы .htaccess, лучше вообще отключить их поиск: <Directory /usr/local/mydocroot> AllowOverride None </Directory> Общая рекомендация сокращения длины пути становится особенно актуальной для веб-серверов с управлением доступом к отдельным каталогам типа Apache. Поиск по каталогу занимает время не только потому, что нужно перебирать элементы связного списка и проверять разрешения, но еще и потому, что сервер должен обработать файлы управления доступом (.htaccess для Apache), что осуществляется еще менее эффективным способом. Изучите пример трассировки системных вызовов, приведенный ранее в этой главе. BUFFEREDJ.OGS С целью повышения производительности Apache скомпилируйте его с ключом -DBUFFEREDJ.OGS, чтобы запись в журнал откладывалась до накопления определенного количества байтов. Это количество задается системной константой POSIX, которая называется PIPEJ3UF. MaxClients Ваша производительность станет гораздо лучше, если количество процессов сервера будет таким, чтобы все они могли уместиться в оперативной памяти. Если процессов будет слишком много, система начнет обращаться к файлу подкачки, и производительность всех процессов упадет. Сколько же их может быть? Определить оптимальное количество достаточно сложно, потому что некоторые области памяти всех процессов httpd являются общими, однако простое правило гласит, что один процесс Apache занимает 1 Мбайт. Если у вас всего 128 Мбайт памяти, не пытайтесь запустить более 128 процессов, даже когда количество одновременно работающих пользователей превышает 128. В любом случае при увеличении количества процессов до 128 в дело вступят другие ограничивающие факторы. Количество процессов httpd в Apache настраивается директивой MaxClients. Слишком урезать его не стоит, потому что надо заботиться о быстрых клиентах, для которых всегда должны иметься свободные процессы. Постоянные соединения Включите постоянные соединения (KeepAlive On в файле httpd.conf) и установите максимальное количество запросов на соединение побольше (MaxKeepAliveRequ- ests 100), чтобы сэкономить на установке новых соединений. Сделайте время ожидания для таких соединений поменьше (KeepAliveTimeout 15), чтобы очень медленные или отключившиеся клиенты не тормозили систему в целом. Отключение обратного поиска в DNS Отключите обратный поиск в DNS во время работы веб-сервера. Сервер «знает» только IP-адрес обратившегося к нему клиента. Обратный поиск дает ему возможность использовать в CGI-программах и журнале полные доменные имена. На самом деле этот поиск не нужен, потому что программы, предназначенные
для анализа журналов, способны определять полные имена самостоятельно. CGI-программы тоже могут сами справиться с DNS, если им это действительно необходимо. Недостаток DNS в том, что для работы с данной системой используются блокирующие системные вызовы, которые приостанавливают весь процесс сервера целиком до тех пор, пока вызов не завершится. Поиск в DNS может занимать довольно много времени, поэтому сервер, обслуживающий множество пользователей, из-за этого поиска заметно потеряет в производительности. В Apache 1.3 обратный поиск в DNS отключен по умолчанию. Чтобы отключить обратный поиск в DNS, внесите следующие изменения в файл httpd.conf: HostnameLookups off Не устанавливайте ограничений на доступ для доменов Из заметок о производительности веб-сервера Apache (автор Дин Годе) мы видим, что использование директив allow from домел и deny from домен понижает производительность дважды, потому что сначала веб-серверу приходится выполнять обратный поиск в DNS, чтобы узнать доменное имя браузера клиента, а затем с помощью прямого поиска проверяется, не был ли подделан результат обратного поиска. Ограничение по IP-адресу не создает таких проблем с производительностью. Установите параметр FollowSymLinks Еще один совет от Дина: установите параметр Options FollowSymLinks, чтобы не выполнять вызов Istat для всех элементов пути, включая символические ссылки, каждый раз, когда эти ссылки используются. Вот пример: DocumentRoot /www/htdocs <Directory /> Options FollowSymLinks </Directory> По сути дела, при этом отключается защита для символических ссылок, так что пользователи могут создать ссылку, указывающую на любой файл вашего сервера, и получить этот файл. Fancylndexing Одна из проблем веб-сервера Apache — «красивые» индексы (fancy indexing). Если параметр Fancylndexing в файле srm.conf включен (значение on), то при обращении к каталогу, в котором отсутствует файл index.html, пользователь получает список содержимого каталога в формате HTML. «Красивая» версия этого индекса предполагает, что у вас установлены значки, поставляемые вместе с сервером (каталог /icons). Если вы не установите эти значки, у пользователя вместо них будут отображаться гииерссылки. Каждый раз, когда пользователь будет обращаться к данной странице, он будет создавать всплеск сетевого трафика, связанный с поиском этих значков, даже если он отключит проверку кэширо- ванных страниц в браузере. Значков-то в кэше не будет, потому что их нет на
вашем сервере. Конечно, можно и просто установить значки, но я отключил параметр Fancylndexing. Укажите файлы с индексами явно Вместо того, чтобы указывать индексные файлы с помощью маски, как в приведенном ниже примере: DirectoryIndex index, укажите все возможные варианты явно: Directorylndex index.cgi index.pl index.html Первым должен идти наиболее часто встречающийся вариант файла индекса. MaxRequestsPerChild Этот параметр задает количество запросов, на которые может ответить дочерний процесс, прежде чем он будет завершен принудительно. Идея в том, чтобы ограничить утечки памяти в коде Apache и системных библиотеках. По умолчанию значение этого параметра в Apache 1.3.9 равно 100, но это очень мало. Задайте его равным 10 000, чтобы не тратить лишние ресурсы на создание новых дочерних процессов. Следите за размером процессов httpd. Если они не растут, вы можете смело увеличить этот параметр до 100 000 или еще большего значения. Как настраивать размеры Apache Apache справляется с нагрузкой, распределяя запросы по множеству дочерних процессов. При запуске веб-сервера нужно создавать столько дочерних процессов (параметр StartServers), сколько одновременных соединений вы рассчитываете принимать. Для небольших сайтов вполне достаточно десяти процессов или около того, но для очень загруженных сайтов этого явно недостаточно. Все эти процессы будут порождены заранее и станут ждать поступления входящих соединений. Если вы создадите слишком много процессов, вызов select() будет работать слишком долго. Если процессов окажется слишком мало, вам придется порождать новые процессы именно тогда, когда вам это меньше всего нужно. В системе Apache 1.3 скорость порождения серверов удваивается каждую секунду: в первую секунду порождается один процесс, во вторую — два, в третью — четыре и так далее до тех пор, пока все соединения не будут распределены. Для большинства сайтов с переменной нагрузкой этого вполне достаточно. Минимальное количество процессов (MinSpareServers) должно быть равно среднему плюс некоторая величина, соответствующая колебаниям нагрузки. Максимальное количество процессов ограничивается возможностями компьютера — прежде всего его памятью. Использование mod__status Если вы включите заголовочный файл mod_status и установите правило Rule STATUS=yes в процессе компиляции и компоновки веб-сервера из исходных кодов, то Apache будет осуществлять специальные вызовы для измерения време-
ни, чтобы отчет о работе включал временные параметры. Это понижает производительность, зато дает сведения о ней. Решайте сами. Дополнительная информация Дополнительную информацию вы можете найти по адресу: http://www.apache. org/. Настройка Netscape Netscape — многопоточный коммерческий сервер, который можно купить по адресу: http://home.netscape.com/. Это второй по популярности веб-сервер для платформ Unix после Apache. Серверы Netscape сейчас производятся совместным предприятием Sun Microsystems и AOL, которое получило название iPlanet, поэтому серверы Netscape иногда называются серверами iPlanet. Я полагаю, что сервер Commerce Server с предварительным порождением потоков и простейший Fast Track Server были удалены с рынка в пользу многопоточного сервера Netscape Enterprise. Главным отличием Apache и Netscape выступает то, что серверы Netscape являются многопоточными, в то время как серверы Apache остаются серверами с предварительным порождением процессов (за исключением Apache для NT). Основные конфигурационные файлы серверов Netscape Enterprise называются magnus.conf и obj.conf и находятся в каталоге suitespot/https-M.*** cepeepa/cor\f\g. Файл magnus.conf является главным файлом конфигурации, считываемым в процессе загрузки. Файл obj.conf задает параметры работы с содержимым — например, управляет доступом к каталогам. Серверы Netscape обслуживают каждый запрос при помощи семи серверных функций (Server Application Function — SAF). Настраивается обработка при помощи файла obj.conf. Некоторые этапы при необходимости могут быть пропущены. Вы можете написать свои собственные функции SAF, запрограммировав их с помощью интерфейса Netscape API и указав получившиеся файлы с расширением .so в файле obj.conf. Такие функции называются также подключаемыми модулями сервера (plug-ins). Каждая SAF возвращает серверу код завершения, который сообщает, была ли функция успешно выполнена, надо ли серверу продолжать обработку запроса и какие заголовки должны быть возвращены клиенту на данном этапе. Не используйте блокирующие системные вызовы get- hostbyname или gethostbyaddr в своих подключаемых модулях, потому что так вы можете заблокировать весь серверный процесс. Следовательно, основные этапы обработки запроса и соответствующие серверные функции таковы: 1. Трансляция личных данных (Authorization Translation), в процессе которой предоставленные пользователем личные данные преобразуются в идентификаторы пользователя и его группы (UID, GID). 2. Трансляция имен (Name Translation), выполняемая в экстраординарных случаях, например при перенаправлении запросов.
3. Проверка полного имени файла (Path check) на предмет существования и соответствия разрешений. 4. Типизация объектов (Object Typing), в процессе которой объектам ставятся в соответствие определенные типы MIME, которые впоследствии указываются в заголовках HTTP. 5. Выбор службы (Service Selection), в процессе которого возвращается статический файл, запускается программа CGI или производятся аналогичные действия. 6. Обновление журнала (Update log). 7. Обработка ошибок (Error handling) и информирование о них клиента. Количество процессов Говорят, что количество процессов httpd должно быть на единицу меньше количества процессоров в многопроцессорных системах. Один процессор резервируется за операционной системой. Например, на 8-процессорном компьютере файл magnus.conf должен содержать приведенную ниже строку: MaxProcs 7 Количество серверных потоков Не указывайте в конфигурации сервера большее количество потоков, чем позволяет имеющийся объем оперативной памяти. Если вы генерируете значительные объемы динамического содержимого, помните, что замедление работы связующего сервера, или базы данных, или мейнфрейма приведет к увеличению продолжительности существования потоков и соответственно к возрастанию количества используемых потоков. Если у вас закончатся серверные потоки, пользователи перестанут получать от веб-сервера какие-либо ответы, даже сообщения об ошибке или недоступности. Вы можете сделать все процессы однопоточными, если ваши подключаемые модули небезопасны в поточной среде, но при этом вы потеряете в производительности. Проще всего вам будет программировать, если вы запустите единственный процесс со 128 потоками, но при больших нагрузках гораздо лучшую производительность будут обеспечивать 4 процесса с 32 потоками в каждом, как мы выяснили чуть выше. В конфигурационном файле magnus.conf вы должны написать вот что: MinThreads 4 MaxThreads 32 Я слышал, что нужно еще добавить строку: PostThreadsEarly on В противном случае сервер никогда не будет использовать количество потоков больше минимального.
Отключите обратный поиск в DNS Я объяснял, почему это следует сделать, чуть выше, когда речь шла о сервере Apache, а более подробно данный вопрос разобран в главе 9. В сервере Netscape Enterprise обратный поиск в DNS отключен по умолчанию. В предыдущих версиях он отключается посредством добавления приведенной ниже строки в mag- nus.conf: DNS off В директиву AddLog файла obj.conf нужно добавить следующую команду: iponly-1 Постоянные соединения Ограничьте время существования постоянных соединений 15 с, чтобы отключившиеся клиенты не расходовали ваши ресурсы. Для этого в файле magnus.conf установите: KeepAliveTimeout 15 Постоянных соединений должно быть много, чтобы клиенты действительно могли пользоваться ими. Установите MaxKeepAliveConnections 500 По умолчанию значение этого параметра равно 200, чего может быть недостаточно. Будьте осторожны и не сделайте его слишком большим, чтобы не израсходовать все дескрипторы процесса. Большинство веб-серверов может открывать до 1024 дескрипторов на процесс (устанавливается командой ulimit), но в это число входят не только соединения, но и все открытые веб-сервером файлы. Если дескрипторы закончатся, сервер может завершить работу. Кэш файлов Серверы Netscape имеют внутренний файловый кэш. Размер кэша устанавливается параметром cache-size, который задает суммарное количество кэширован- ных URL-адресов и может быть сделан довольно большим для повышения производительности путем использования лишнего объема памяти. Ограничивает значение этого параметра максимальное количество дескрипторов, доступных процессу, которое может быть получено или изменено командой ulimit. Подробнее о дескрипторах файлов рассказывается в главе 17. С другой стороны, если все ваше содержимое генерируется динамически, кэш лучше уменьшить, чтобы сэкономить на этом память. Я никогда не был уверен в полезности этого кэша, поскольку операционная система Unix кэширует файлы сама по себе. Еще одна проблема с кэшем Netscape заключается в том, что сервер постоянно проверяет, не изменился ли оригинал кэшированного файла, хранящийся на диске, что увеличивает накладные расходы. Если вы знаете, что не будете слишком часто менять свои статические файлы, установите значение параметра Polllnterval равным 30 000 (8 ч), чтобы проверка не отнимала слишком много ресурсов.
Кэширование, судя по всему, производится путем отображения файлов в память. Параметр mmap-max задает максимальный объем памяти, отводимый под отображенные файлы, в килобайтах. Его разумно установить равным суммарному объему всех статических файлов. Если объем статических данных равен 10 Мбайт, установите параметр равным 10 240. Не допускайте превышения реального объема памяти, который может быть отведен под кэш в вашей системе, иначе содержимое все равно будет считываться с диска и все преимущества кэширования будут сведены к нулю. Параметр max-file определяет максимальный размер файла, который может быть помещен в кэш. Вряд ли вы захотите, чтобы редко используемые файлы большого размера вытесняли из кэша все остальное, поэтому установите значение данного параметра равным, к примеру, 1 Мбайт. В итоге в файле obj.conf должна появиться следующая строка: Init fn=cache-init cache-size=512 mmap-max=10240 max-file-1048576 В структуре Request имеется параметр directive_is_cacheable. Серверные функции (SAF), написанные с использованием интерфейса Netscape API, могут использовать этот параметр для того, чтобы последующие запросы для данного URL использовали кэшированную копию ответа, а серверная функция больше не запускалась. Используйте его в тех случаях, когда ответ не зависит от IP-адреса или браузера пользователя, а зависит только от URL. pwfile Приведенная ниже строка загружает файл /etc/passwd в память, что ускоряет доступ к файлам через раскрываемые пути, содержащие символ ~: Unix init-uhome pwfi!e=/etc/passwd Тайм-аут для CGI Приведенная ниже строка ограничивает время выполнения CGI-программы 1 минутой, что предотвращает отказ сервера в случае зависания CGI-программы: init-cgi timeout=60 RqThrottle Для сервера Netscape в отличие от Apache критическим параметром является количество потоков. Когда у сервера Netscape заканчиваются свободные потоки, он зависает, не обслуживая даже установленные соединения. После зависания одного из процессов система балансировки нагрузки повышает загруженность остальных, что может привести и к их зависанию. Компьютер с зависшим вебсервером все равно будет принимать новые соединения, пока не закончится очередь TCP, но Netscape эти соединения обслуживать не будет. Поэтому, чтобы сервер Netscape не завис, значение параметра RqThrottle должно быть меньше, чем количество потоков. Не делайте значение RqThrottle слишком маленьким, иначе пользователи будут подключаться к вашему серверу и ждать, пока освободится поток, способный их обслужить. Если perfdump (см. раздел «Использование perfdump») показывает, что значение WaitingThreads (количество потоков, ожидающих поступления
запросов) мало, значит, у вас почти закончились потоки, то есть мало значение либо RqThrottle, либо MaxThreads. RqThrottle действует на несколько виртуальных серверов, но без балансировки нагрузки. Следить нужно не только за количеством потоков, но и за ограничением памяти для потока. Когда процесс исчерпает всю память, которую он может себе выделить, в журнале появятся сообщения «Fatal, cannot allocate memory», а процесс зависнет. Учтите, что количество потоков не обязательно должно точно соответствовать количеству сокетов. Потоков может быть всего 15, а TCP-соединений больше сотни, и это нормально, потому что соединения принимаются операционной системой, которая затем ждет, пока они будут приняты приложением. После того как приложение завершит свою работу с соединением, последнее существует еще некоторое время, пока клиент не опустошит буфер отправки TCP. Отключите лишние функции Некоторые функции сервера Netscape Enterprise отрицательно влияют на производительность и должны быть отключены, если только вы действительно ими не пользуетесь: О отключите функции Content Management, Search и Agents с помощью управляющего сервера; О установите DaemonStats off в файле magnus.conf, чтобы отключить сбор лишней статистики; О отключите директивы ACLFile в файле magnus.conf, чтобы не работать со списками управления доступом. Использование perfdump Программа perfdump — средство контроля производительности, встроенное в сервер Netscape Enterprise. С помощью perfdump вы можете следить за состоянием сокетов, количеством потоков, постоянных соединений, кэшированных страниц и DNS-имен. Чтобы установить perfdump, добавьте приведенную ниже строку в файл mime.types: type-perf exts-perf, а в файл obj.conf добавьте приведенную ниже строку в качестве первой обслуживающей функции: Service fn-service-dump type-perf После этого вам нужно будет перезапустить сервер, и тогда вы сможете обращаться к странице http://hostname/.perf, где будет выводиться статистика. Интервал обновления в секундах указывают прямо в URL следующим образом: http://hostname/.perf?refresh=5. Подробный комментарий к статистике perfdump можно получить по адресу: http://help.netscape.com/kb/server/971211-7.html.
Дополнительная информация Хорошее руководство по оптимальной настройке веб-серверов iPlanet вы найдете по адресу: http.7/docs.iplanet.com/docs/manuals/enterprise/41/scaling/html/es- tune.htm. В состав некоторых серверов Netscape входит средство Adminserver, предназначенное для контроля производительности в реальном времени. Прочие серверы В последующих разделах описываются самые распространенные веб-серверы и некоторые дополнительные подробности, касающиеся настройки серверов Netscape. Рейтинг 125 веб-серверов вы можете найти по адресу: http://webcompare. internet.com/chart.html, а некоторые сравнительные характеристики веб-серверов имеются на сервере http://www.spec.org. Рейтинги сайтов взяты с сайтов по адресам http://www.netcraft.com/survey/ и http://www.webcrawler.com/WebCrawler/Facts/Ser- vers.html. Помните, что вы всегда можете узнать, какой сервер используется на конкретном сайте, подключившись к нему через порт 80 по протоколу telnet и набрав запрос GET / НТТР/1.0. Boa Веб-сервер Boa (http://www.boa.org) очень маленький и простой, однопоточный и не порождающий процессы. Зато он очень быстрый. Он не обладает избытком параметров настройки и предназначен для небольших простых веб-сайтов. Его можно скачать бесплатно. IIS Информационный сервер Интернета от фирмы Microsoft (Internet Information Server — IIS), обзор которого доступен по адресу: http://www.microsoft.com/pro- ducts/prodef/427_ov.html, очень популярен благодаря тому, что он поставляется с MS Windows. Он может работать только в Windows и начиная с NT 4.0 является, скорее, компонентом NT Server, чем отдельным продуктом. Сервер IIS обладает встроенным механизмом поиска и средствами поддержки потокового видео и аудио, но они работают только для клиентов, использующих Windows. IIS обеспечивает автоматическую проверку подлинности клиентов с Windows. Вместе с ним поставляется утилита, запрашивающая у администратора ожидаемый уровень нагрузки и оптимизирующая сервер соответствующим образом. Это коммерческий продукт. В лицензионном соглашении конечного пользователя для NT присутствует интересная статья: No Performance or Benchmark Testing. You may not disclose the results of any benchmark test of either the Server Software or Client Software for Internet Information Server to any third party without Microsoft's prior written approval. (Тестирование производительности не допускается. Вы не можете предоставлять результаты тестирования производительности серверного или клиентского программного обеспечения IIS третьим лицам без предварительного получения письменного разрешения Microsoft.) Почему Microsoft запрещает независимое тестирование IIS? Этот вопрос мы оставляем читателю в качестве самостоятельного упражнения.
Оставим разговоры о производительности. Надежность IIS весьма низка сравнительно с Apache или Netscape. Швейцарская компания Sysformance занимается измерениями длительности отказов крупных европейских коммерческих веб-сайтов — и, согласно ее результатам для веб-сайтов, использующих продукты Microsoft, среднее время, проведенное в неработоспособном состоянии, за месяц оказывается в 2-4 раза выше, чем для серверов Apache или Netscape. Данные за три последних месяца можно получить по адресу: http://www.syscontrol.ch/ d/SWePIX/SWePIX.html. Java Web Server Веб-сервер Java Web Server (http://www.javasoft.com/products/java-serverwebserver/) был продуктом отдела JavaSoft фирмы Sun, написанным на языке Java. Выпуск этого продукта прекращен в связи с тем, что Sun решила продавать вместо него серверные продукты Netscape. Тем не менее веб-страница, посвященная настройке веб-сервера Java Web Server, может все еще присутствовать по адресу: http://jsen/.javasoft.c»m/produ(te/j^ perfbrmance.html. Jigsaw Программа Jigsaw (http://www.w3.org/Jigsaw) — это веб-сервер, написанный полностью на языке Java. Он превосходит по производительности веб-сервер CERN и сравним с веб-сервером NCSA, но не так быстр, как Apache. Jigsaw поддерживает сервлеты и протокол HTTP 1.1, а администрирование его осуществляется посредством форм CGI. Он распространяется бесплатно. NCSA Демон httpd, разработанный в Национальном центре вычислений (National Center for Supercomputing Applications) на супер-ЭВМ, работает на 68 000 сайтов. NCSA — один из первых веб-серверов, появившийся после CERN. Он является «предком» Apache и Netscape, а также IIS. Многие функции других веб-серверов (управление доступом, к примеру, или CGI-программы) впервые появились именно на веб-сервере NCSA. Он до сих пор поддерживает протокол HTTP 1.1 и, скорее всего, никогда не будет усовершенствован. Разработчики, занимавшиеся NCSA, перешли в проект Apache, но сервер NCSA все еще можно скачать бесплатно. Zeus Веб-сервер Zeus (http://www.zeus.co.uk/) претендует на звание самого быстрого из существующих, и некоторые тесты на http://www.spec.org/ это подтверждают — например, результат теста SPECWeb98 таков: 1837 HTTP-операций в секунду. Этот сервер работает в однопроцессном режиме, используя только неблокируе- мые операции ввода-вывода. Zeus лучше всего работает, если отключить некоторые редко используемые функции управления доступом, запустив его командой zeus -q. У него очень большой объем кэша. Это коммерческий продукт.
Прокси-серверы 409 Недостающие функции Всем веб-серверам не хватает, как мне кажется, по крайней мере, двух функций. О Насколько я знаю, ни один веб-сервер не записывает время начала обработки запроса и окончания отправки ответа. Это очень помогало бы оценивать производительность, особенно если время записывать с точностью до миллисекунд. О Еще одна полезная функция позволяла бы осуществлять запись в журнал всех данных, включая все заголовки и данные, отправляемые клиентом в POST- запросе, чтобы по данным журнала можно было бы воспроизводить запросы и создавать таким образом адекватные тесты на нагрузку. Существующие журналы не могут считаться достаточными для точного воспроизведения запросов. Прокси-серверы Прокси-серверы обычно представляют собой интерфейс между большой организацией и остальным Интернетом. Они устанавливаются как для повышения производительности, так и из соображений безопасности. Прокси-сервер обеспечивает повышенную безопасность потому, что при его использовании никогда не устанавливаются прямые соединения между Интернетом и внутренней сетью. Когда HTTP-запрос направляется во внешнюю сеть, прокси-сервер перехватывает его и выполняет запрос от имени пользователя. Если же страница уже присутствует в кэше прокси-сервера, она отправляется пользователю вообще без обмена пакетами с Интернетом. Если запрошенной страницы нет в кэше прокси-сервера, запрос выполняется значительно медленнее из-за того, что возникает лишнее промежуточное звено между пользователем и сервером — прокси-сервер. С другой стороны, все последующие обращения к странице выполняются гораздо быстрее. Кэши прокси-серверов не используются для динамического содержимого или, по крайней мере, не предназначены для его хранения. Если ваш прокси- сервер кэширует динамическое содержимое, теряется весь смысл концепции формирования специального содержимого «на лету». С динамическим содержимым возникают некоторые дополнительные проблемы. Изображения и другие статические элементы динамических страниц вполне способны кэшироваться для повышения производительности, однако постоянные HTTP-соединения могут помешать загрузке кэшированных изображений и снизить производительность. Все зависит от уровня сложности вашего прокси-сервера. Если он проверяет только первый URL, переданный по соединению, то не поймет, что в его кэше присутствуют изображения, которые будут запрошены пользователем в том же соединении. Если же прокси-сервер будет загружать все встроенные в страницу
изображения, прежде чем отправлять клиенту ее текст, пользователь будет страдать от больших задержек. Прокси-серверы особенно полезны, если все пользователи организации с большой вероятностью могут одновременно обратиться к одной или нескольким страницам — например, когда обновляются страницы служб новостей или по утрам, когда пользователи приходят на работу и идут на сайты www.cnn.com или www.news.com. Очень большой выигрыш достигается также при кэшировании страниц медленных сайтов. Еще одним достоинством прокси-серверов является то, что с их помощью можно отследить и отфильтровать запросы, направленные на получение содержимого, которое явно не имеет никакого отношения к работе, — например, обращения к сайту www.playboy.com. Это позволяет не расходовать зря пропускную способность интрасети и подключения к Интернету, а также помогает пользователям экономить их время, как только они осознают, что подключиться к интересующим их сайтам они не смогут. Тем же, кто на самом деле работает в Интернете, достанется большая производительность и большая пропускная способность. Однако не злоупотребляйте драконовскими мерами. Ваши сотрудники должны быть информированными в вопросах, связанных с сетью, так что пусть путешествуют по ней сколько хотят. Главное — отрезать наиболее очевидные возможности злоупотребления. Если быстрота просмотра очень важна для вашей организации, производительность вашего прокси-сервера оказывается важной вдвойне, потому что на него одновременно ложатся обязанности клиента и сервера. Фирма Intel (http://www.intel.com/) выпустила продукт, который называется Quick Web. Эга программа работает как прокси-сервер, кэшируя наиболее популярные страницы, и использует для изображений алгоритмы сжатия с потерями. При этом изображения занимают меньше места на диске, но не на экране, поэтому качество их заметно ухудшается. Apache и Netscape также производят программное обеспечение для прокси- серверов. Помните, что вы должны указать адрес прокси-сервера в настройках браузеров ваших пользователей. Netscape позволяет указать URL для автоматической настройки прокси-сервера, а также домены, для которых прокси-сервер не должен использоваться. Иерархическое кэширование Последние исследования схем распределенного кэширования привели к появлению двух реализаций иерархического кэширования — Harvest (коммерческая) и Squid (бесплатная). Обе они используют одинаковый протокол кэширования — Inter-Cache Protocol (ICP). Иерархическое кэширование обеспечивает лучший уровень производительности для всего Интернета, но требует большой инфраструктуры. Squid используется в сложной схеме кэширования национальной) масштаба, которая описана на сайте http://ircache.nlanr.net/. (См. также http://squid. nlanr.net/Squid/.)
Основные рекомендации О Отключите обратный поиск в DNS. О Выберите сервер, который поддерживает HTTP 1.1 или, по крайней мере, постоянные соединения. О Регулярно перезагружайтесь в случае наличия утечек памяти. О Сервер не должен закрывать журнал между операциями записи. О Используйте современное программное обеспечение, потому что реализации со временем улучшаются. О Пользуйтесь функциями кэширования веб-серверов. О Оптимизируйте систему с учетом характера содержимого и скоростей клиентов.
19 Содержимое Самое важное в Сети — это содержимое. Браузер, сервер и сеть существуют для того, чтобы передавать биты с одного конца соединения на другой и обратно. В этой главе рассказывается о том, что можно сделать с содержимым, чтобы его передача происходила как можно быстрее. Важен размер Интернету не важно, какое именно содержимое вы передаете. Биты — это просто биты. Самым существенным фактором, определяющим время передачи, является размер содержимого. Следовательно, главный принцип повышения производительности должен быть таким: передавать меньше битов и делать меньше запросов. Старайтесь оценивать размер в единицах времени загрузки, а не в абстрактных битах, потому что время, затрачиваемое человеком на ожидание загрузки вашего сайта, — это конечная мера его производительности. Если большая часть ваших пользователей сидит на модемах на 28,8 кбит/с, установите для себя правило: загрузка любого изображения должна выполняться быстрее, чем за 10 с (это около 35 Кбайт). Сравните сайты Yahoo! (http://www.yahoo.com/) с очень простой и быстрой домашней страницей и CNN (http://www.cnn.com/), где на каждой странице находится много лишнего. Отличие во времени загрузки весьма существенное. Установите для себя жесткие правила и заставьте разработчиков содержимого думать о полосе пропускания. Еще один пример отличного (то есть минимального) дизайна — список Крейга (http://www.craigslist.org/). Все веб-дизайнеры, которых я встречал, нравятся мне как люди, но значительную часть своего времени я провожу, жалуясь на их работу. Дизайнеры любят заниматься дизайном, а это обычно означает создание ярких страниц без вся-
ких мыслей о производительности. Ненужные свойства ведут к несовместимости страниц с браузерами, затрудняют тестирование, а вам приходится платить им за то, что они таким образом вредят производительности вашего сайта. Особенно плохая идея — использовать апплеты, если только они не занимаются чем-то, что действительно невозможно сделать с помощью HTML. Сервлеты — это замечательно, потому что вы можете контролировать среду, в которой они выполняются, но апплеты обычно велики в размерах, совместимы только с одним браузером и гораздо сложнее в тестировании, чем HTML-страницы. Лучше не бывает Давайте представим себе самую быструю веб-страницу из возможных. Эта страница не должна превышать по размеру самый большой пакет, способный добраться от сервера до клиента без фрагментации, — это 1500 байт. При необходимости можно сжать страницу при помощи gzip, добившись того, чтобы в такой пакет поместилось 2500 байт содержимого. Давайте представим, что на обоих концах соединения поддерживается протокол Т/ТСР, так что дополнительные затраты на трехэтапное рукопожатие исчезают: в каждую сторону передается один-единственный пакет. Положим время путешествия пакета с одного побережья на другое равным 15 мс (близко к скорости света). Первые байты страницы могли бы достичь клиента приблизительно через 30 мс, а последние прибыли бы через некоторое время, зависящее от пропускной способности соединения (ее тоже называют скоростью). Это около третьей части десятой доли секунды. Быстрее быть не может. Все перенаправления, фреймы, изображения и апплеты понижают производительность по сравнению с теоретически возможной. Кэширование и отличия Веб-серверы, поддерживающие HTTP 1.1, могут отправлять браузерам фрагменты документов, чтобы те могли загружать лишь изменившиеся данные. Это очень сильно повысило бы производительность, но, к сожалению, браузеры не пользуются данной способностью серверов. Существует коммерческий продукт фирмы FineGround, который называется Condenser. Он повышает скорость работы с веб-сайтом приблизительно тем же способом. Подробнее о Condenser читайте в приложении. См. также http://webreference.com/internet/software/servers/ http/deltaencoding/intro/ — это еще одна попытка спецификации запросов на части документов. HTML и сжатие Языку HTML присуща определенная избыточность, поскольку он состоит из ASCII-текста. Кодировка ASCII использует только 7 бит каждого байта, поэтому 1 бит из 8 A2,5%) пропадает зря.
Гораздо больший уровень избыточности связан с тем, что текст хорошо сжимается, но чаще всего в HTTP-трансферах сжатие не используется. Программы сжатия текстов легко способны уменьшить размер файла вдвое, а это означает, что такой файл может быть загружен за вдвое меньшее время. На данный момент «узким местом» является пропускная способность линии, а мощность процессора стоит дешево, поэтому сжатие веб-страниц имеет смысл, даже несмотря на то, что это затрудняет отладку. Таблицы стилей (stylesheets) могут и повышать, и понижать производительность — в зависимости от того, как конкретно они используются. Связанные таблицы стилей могут быть загружены только 1 раз, после чего заменяют множество форматирующих тегов HTML. Это снижает сетевой трафик. (См. http://www.w3.org/Protocols/HTTP/Performance/Pipeline). С другой стороны, браузер может отказаться отображать HTML-страницу, если он не сможет найти связанную с ней таблицу стилей. Это означает, что вы становитесь более зависимыми. С другой стороны, если вы включите таблицу стилей в саму страницу, то лишняя зависимость и связанная с ней возможность отказа пропадут, зато вы увеличите размер всех страниц, что снизит производительность. gzip Если ваш браузер поддерживает алгоритм сжатия gzip, он будет добавлять в заголовки всех запросов следующую строку: Accept-Encoding: gzip Большие текстовые страницы в сжатом формате будут доставляться на браузер гораздо быстрее. Важно, чтобы браузер поддерживал gzip. Вам нужно только сжать HTML-файл при помощи gzip и сохранить результат с суффиксом .gz, чтобы сервер Apache знал о том, что данный файл сжат при помощи gzip, и до бавлял лишний HTTP-заголовок помимо обычного Content-type: Content-encoding: x-gzip Учтите, что эффективное сжатие достигается только при первом применении программы архивации к файлу. Очевидно, что файл не может становиться меньше при каждой операции сжатия, иначе любой файл можно было бы сжать до 1 бита. Интересно попробовать сжать файл с помощью gzip несколько раз, чтобы убедиться, что он становится меньше только после первого сжатия, а затем с каж дой операцией увеличивается в размерах. Ниже приведен небольшой сценарии интерпретатора, а также пример его работы, иллюстрирующие данную мысль Смотреть следует на количество байтов в файле (число перед датой Apr 23): % while true more> do more> Is -1 index.html more> gzip index.html more> mv index.html.gz index.html more> done -rw-r-r- 1 patrick patrick 2345 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1060 Apr 23 14:49 index.html
-rw-r-r- 1 patrick patrick 1094 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1128 Apr 23 14:49 index.html -rw-г-г- l patrick patrick 1162 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1187 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1221 Apr 23 14:49 index.html -rw-r-r- 1 patnek patrick 1255 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1289 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1312 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1346 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1380 Apr 23 14:49 index.html -rw-r-r- 1 patrick patnek 1414 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1434 Apr 23 14:49 index.html -rw-r-r- 1 patnek patrick 1468 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1502 Apr 23 14:49 index.html -rw-r-r- 1 patrick patrick 1536 Apr 23 14:49 index.html Можно сжать содержимое любым другим методом, а затем настроить свой веб-сервер так, чтобы для этого содержимого использовался конкретный тип MIME, — но тогда вам придется просить пользователей запускать утилиту распаковки, принимая файл с содержимым данного типа. Это потребует некоторой работы как на стороне сервера, так и на стороне клиента. Лучше всего, если сервер будет определять тип браузера и отправлять ему содержимое в формате с наибольшим уровнем сжатия из поддерживаемых данным браузером, однако иногда прокси-серверы кэшируют сжатое содержимое, а затем отправляют его браузерам, которые не поддерживают автоматическую распаковку. В результате на экране пользователя оказывается мусор. Есть смысл включать в свои веб-страницы сценарий на JavaScript, который будет определять наличие поддержки gzip-сжатия в браузере клиента и отправлять ему соответствующий тип содержимого. Советы HTML-разработчикам В этом разделе я приведу некоторые советы и рекомендации, которые помогут авторам веб-страниц ускорить их загрузку. Полегче на сервере! Работая над HTML-содержимым веб-страницы, старайтесь делать имена файлов по возможности короче. Сокращать следует не только количество уровней вложенности каталогов, но и длину их имен. Статическое содержимое масштабируется очень легко. Разные типы содержимого можно разместить на различных серверах, используя для его объединения гиперссылки. Планируя разделение содержимого, рассмотрите возможность один сервер отвести целиком под изображения, другой — под HTML, третий — под апплеты и так далее. Помните, что вы можете включать в свои веб-страницы содержимое с других сайтов, что позволяет полностью снять нагрузку с ваших серверов, однако создает зависимость от других серверов и может вызвать
скандал из-за вопросов авторского права. Например, каталог апплетов сайта Ga- melan (www.gamelan.com) содержит не сами апплеты, а ссылки на сайты, где эти апплеты размещены. Что касается вопросов авторского права, то недавно проходил процесс против сайта, на котором в отдельных фреймах отображались новости с других веб-сайтов, а в верхнем фрейме выводилась реклама, за которую авторы сайта получали деньги. С другой стороны, если вам нужно включить в свою страницу содержимое сочень медленного сайта, попробуйте договориться с администратором этого сайта о возможности копирования его содержимого на ваш веб-сервер. Указывайте в своих ссылках файлы index.html явно либо завершайте ссылки на каталоги символом /. Как уже обсуждалось в главе 15, завершающий символ/ в адресах URL экономит ресурсы сервера и сети, поскольку избавляет вас от лишнего перенаправления. Явное указание файла index.html избавляет веб-сервер от необходимости решать, нужно ли ему заниматься индексированием каталога самостоятельно. Однако помните, что имя файла index.html — всего лишь соглашение. Некоторые веб-серверы, например Jigsaw, не используют для индексирования каталогов файлы index.html. Если ваше содержимое состоит из огромного количества файлов, которые запрашиваются приблизительно с одинаковой частотой (такое может иметь место, к примеру, в большом архиве файлов), буферный кэш вашей операционной системы и кэш веб-сервера не будут справляться со своими обязанностями. Чаще всего файлы будут считываться с диска, поэтому не тратьте слишком много денег на оперативную память, а вместо этого купите самые быстрые диски или массивы дисков, которые вы можете себе позволить, чтобы уменьшить время поиска. Массив дисков с чередованием тоже должен заметно повысить производительность. Полегче в сети! С точки зрения сети самое важное — это чтобы содержимое имело небольшие размеры. Возьмем, например, документ большого объема. Пользователи могут захотеть получить его сразу целиком, а не щелкать несколько раз для загрузки каждой из его частей. С другой стороны, есть смысл представить им краткое содержание документа и его первую часть, чтобы они могли решить, нужен ли он им целиком. Протокол HTTP 1.1 позволяет загружать файлы по частям, в соответствии с запросами пользователя, однако это требует поддержки протокола HTTP 1.1 как сервером, так и браузером. HTML-файлы обычно имеют средний размер около 4 Кбайт, что составляет около двух экранов браузера. Есть смысл стремиться уменьшить текст настолько, чтобы страница поместилась в MTU (максимальный размер пакета данных), если вы ее знаете, чтобы пользователи получали всю ее одним пакетом. Если размер MTU равен 1500 байт (что характерно для локальных сетей стандарта Ethernet), страница размером 1500 байт будет загружаться гораздо быстрее, чем страница размером 1501 байт.
Полегче с браузером! Обработка страниц — ресурсоемкая процедура, поэтому нужно стремиться упростить работу браузера. Для этого надо выбрасывать лишние или бесполезные теги, уменьшать количество украшений, таких как вложенные таблицы или фреймы, а также снабжать браузер всей информацией, позволяющей сократить объем вычислений. Надо отметить, что текстовые редакторы для работы с HTML делают это довольно плохо, вставляя лишние теги, форматирующие пустые строки. Такие вещи можно исправлять и вручную; это довольно просто, но долго, поэтому есть смысл написать несколько сценариев на языке Perl, чтобы подстановка или удаление тегов выполнялись автоматически. Ниже приведен пример сценария Perl длиной в одну строку. Этот сценарий удаляет теги <BR>, находящиеся в строках, где больше ничего нет. Такие теги часто остаются после создания страниц в графических редакторах HTML-страниц: % perl -pi -e ,sr<br>$//i* *.html Не помещайте слишком много всего в заголовок страницы (теги <HEAD></HEAD>), потому что этот раздел должен быть полностью обработан, прежде чем браузер сможет заняться отображением оставшейся части страницы. Так, не следует помещать большие сценарии на JavaScript в заголовок страницы. Поместите сценарий там, где он будет использоваться, — например, в форму, которая будет этим сценарием проверяться. Фоновые изображения выводятся на экран до отображения текста, поэтому либо старайтесь делать их простыми, либо вовсе избавляйтесь от них. Большое фоновое изображение может очень сильно замедлить прокрутку страницы; лучше вместо него использовать маленькую повторяющуюся картинку. Указывайте браузеру размер изображений с помощью параметра SIZE тега <IMG>. Это экономит время на обработку, а также позволяет сформировать вывод до получения всех изображений. Тег должен выглядеть так: <img src«/images/demo.gif" size height-150 width=100> Команда file в системах Unix выводит размеры изображений. Ее можно включить в сценарий Perl для автоматического анализа страниц, включенных в HTML-страницу, и задания их размеров. Можно даже не писать этот сценарий самостоятельно: существуют общедоступные утилиты, делающие то же самое, — например, wwwis. Изображения можно масштабировать, указывая размер, отличающийся от действительного размера изображения, однако указывать размер меньше реального нерационально. Масштабирование с увеличением применять можно, однако оно поглощает некоторый объем ресурсов браузера, а изображение становится более грубым. Загрузка и обработка фреймов тоже занимают некоторое время. Оно может становиться значительным при наличии на одной странице множества вложенных фреймов. На старых браузерах подобные вещи просто поглощали всю память, более современные же обнаруживают рекурсию и отказываются отображать фреймы.
В ссылках вы можете указывать IP-адреса серверов вместо имен доменов во избежание многочисленных обращений к системе DNS. Это позволяет слегка повысить производительность за счет гибкости. Помните, что большинство операционных систем не кэширует информацию DNS (правда, браузер Netscape делает это самостоятельно). Если вы укажете IP-адрес в гиперссылке на веб-страницу, после щелчка на ней он окажется в поле Location окна браузера, что может смутить пользователя. Что касается ссылок на изображения, то тут пользователь заметит лишь, что они стали загружаться немного быстрее. Полегче с пользователем Зачем называть свой сервер «www»? Это легко набрать, но невозможно произнести. Пожалуйста, используйте один слог вместо девяти — назовите свой сервер «web». Например, вместо www.company.com, напишите web.company.com. Дикторы всего мира скажут вам спасибо. Первое, что увидит пользователь, обратившийся к вашей странице, — это текст, указанный в теге <TTTLE>, поэтому постарайтесь сделать его достаточно значащим, чтобы пользователь мог решить, хочет ли он дождаться загрузки всей страницы. Многие пользователи не смотрят на заголовок страницы — продублируйте его для них в теге <Н1>. Делайте домашние страницы сайтов быстрыми, как молния, потому что они задают тон всему сайту. Пользователи согласны подождать загрузки страниц с дополнительными сведениями, но если они не смогут легко войти в «парадный подъезд», им может прийти в голову, что ваш сайт не работает, или они просто уйдут от вас рассерженные. Рассмотрите возможность отведения заглавной странице отдельного сервера. Дублируйте ссылки с изображениями текстовыми ссылками, заботясь о тех пользователях, которые отключили автоматическую загрузку изображений, чтобы быстрее работать с Сетью. Многие сайты без изображений оказываются абсолютно бесполезными, потому что никто не позаботился о тех, кто любит путешествовать по Сети в текстовом режиме. Альтернативой текстовым ссылкам под изображениями может быть специальная ссылка на домашней странице, ведущая к параллельным страницам без графики или с минимальным ее объемом. С помощью cookie вы можете отслеживать, какой вариант страницы предпочтительнее для данного пользователя, однако распознавание cookie создает большую нагрузку на сервер, тогда как параллельное содержимое просто увеличивает общий объем содержимого. Всегда указывайте текст в параметрах ALT тегов изображений, чтобы люди могли решить, стоит ли им загружать что-нибудь, чего они не видят. Сделать свой сайт доступным в текстовом режиме — это шаг навстречу слепым пользователям Сети, которые применяют системы преобразования текста в речь. Аналогичным образом следует дублировать функциональность апплетов между тегами <APPLETx/APPLET>, чтобы пользователи, отключившие поддержку Java, все равно могли полноценно работать с вашей страницей. Браузеры по умолчанию игнорируют те теги, которых не понимают, а если поддержка Java отключена, то тег <APPLET> становится нераспознаваемым. В итоге получаем,
что вы можете написать между этими тегами все что угодно, и это будет обработано только в том случае, если у пользователя отключена поддержка Java. В одном из проектов я применил этот прием, предоставив пользователям альтернативную форму на базе CGI. Форма делала то же, что и апплет, просто апплет был более интерактивным и привлекательным, хотя и загружался несколько дольше. Не указывайте FTP-адресов или адресов электронной почты, не добавив к ним гиперссылок ftp:// или mailto:. В Сети все адреса принято делать гиперссылками, чтобы на них можно было щелкать. Измените страницу, выводимую вашим веб-сервером при отправке сообщения 404-file not found, таким образом, чтобы на ней содержалась карта вашего сайта и пользователям не приходилось щелкать кнопку Back, чтобы узнать, какие альтернативы доступны на вашем сайте. Данный совет тоже имеет отношение к производительности, поскольку позволяет экономить время пользователей. Настройте сервер так, чтобы он отправлял сообщение об ошибке вебмастеру, если в переменной HTTP_REFERER появляется адрес страницы с сообщением об ошибке 404. Нет прощения тем, кто не может отловить все некорректные ссылки на своем сайте. Пользователи могут просить все что пожелают и должны во всех случаях получать вежливые ответы от вашего сервера. Берегитесь предвзятых HTML-редакторов Некоторые программы Microsoft создают HTML-страницы, очень медленно работающие в Netscape, зато очень быстро — в IE. Кроме того, часть программ вставляет в веб-страницы символы, отображаемые корректно только в IE; в Netscape такие символы превращаются в вопросительные знаки. Идите в ногу с миром Порнографические сайты стараются выжать все возможное не только из лазеек в законах, но и из технических особенностей браузеров. Обнажайте скрытое — изучайте исходные коды HTML и JavaScript порносайтов. Используйте средства проверки HTML Корректный HTML-код будет быстро обрабатываться и отображаться множеством браузеров. Существует множество бесплатных средств проверки HTML. О Программа WDG для проверки HTML 4.0 (http://www.htmlhelp.com/tools/ validator/). О Программа консорциума W3C для HTML 4.0 (http://validator.w3.org/). О Программа weblint для HTML 3.2 (http://wwwl.tu-chemnitz.de/urz/www/html-test. html — страница на немецком языке). Попробуйте проверить свой сайт с помощью стандарта доступности Бобби (http://www.cast.org/bobby). Это программа для бесплатного качественного анали-
за веб-содержимого с точки зрения лиц с ограниченными возможностями. Она помогает убедиться в том, что слепой пользователь, к примеру, все равно сможет получить с вашей страницы нужные ему сведения. Это само по себе хорошо, но замечательно также, что большая часть рекомендаций Бобби сделает вашу страницу более соответствующей стандартам и более быстрой в загрузке. Подробнее о языке HTML читайте в конференции Usenet comp.infosys- tems.www.authoring.html. Объектная модель документа Последние версии браузеров дают HTML-разработчикам возможность обращаться к внутренним объектам браузера напрямую. Стандарт описания этих внутренних объектов называется объектной моделью документа (Document Object Model — DOM). Доступ к DOM осуществляется посредством интерфейса JavaScript — как в Netscape 6, так и в IE 5. DOM позволяет избежать ненужных обращений к серверу: например, на стороне клиента может выполняться сортировка таблиц по столбцам, а также динамическое преобразование из XML в HTML. Наконец, становится возможным включение в веб-страницы таких эффектов, которые раньше потребовали бы использования Java, — например, анимации на стороне клиента и трехмерной графики. Графика Средний размер используемых в Сети изображений составляет 10-20 Кбайт, что превышает средний размер HTML-страницы D Кбайт). Разработчики страниц должны стремиться в первую очередь к тому, чтобы уменьшить размер изображений. Следите за весом Уменьшайте файлы изображений в размере, сокращая размер самих изображений в пикселах и глубину цвета (8 разрядов обычно вполне достаточно), а также используя формат с наиболее эффективным для данного изображения алгоритмом сжатия. Если вы закодировали флаг США с глубиной цвета 32 бита, вы можете уменьшить глубину до 8 битов и вообще не проиграть в качестве изображения. JPEG сжимает фотографии лучше, чем GIF, но GIF лучше сжимает рисунки с одноцветными строками. Новый формат PNG обладает отличным уровнем сжатия в обоих случаях, но поддерживается не всеми браузерами. Java часто критикуют за долгое время загрузки виртуальной машины и потребность в больших объемах памяти, но большой рисунок, состоящий из простых элементов, может занимать меньший объем, если его выполнить с помощью классов Java, а не передавать в виде растрового изображения. С помощью метода drawPolygon() я закодировал карту восточной части США со всеми железными дорогами как набор точек, соединенных линиями. Размер карты не только оказался меньше, чем у аналогичного растрового изображения: я добавил в ап- плет возможность увеличения изображения и прокрутки, что было бы невозможно, если бы я передавал пользователям статическое изображение. Однако
помните: Java не поддерживается в стандартной установке Netscape 6 и вообще не поддерживается в IE без загрузки специального модуля. Объединение изображений Избегайте накладных расходов на передачу множества изображений, объединяя их в одно большое. Это сократит время загрузки и время отображения картинки. Если каждая из небольших картинок была ссылкой, вы можете превратить объединенное изображение в карту ссылок (imagemap) и сохранить имевшуюся функциональность. Работайте с картой ссылок на стороне клиента (адреса URL выбираются клиентом), а не на стороне сервера (адрес URL определяется по координатам курсора в момент щелчка мыши процессом на стороне сервера). Вместо отдельного фрейма, предназначенного для навигации по странице, используйте кэшируемую карту ссылок. Это позволит сократить время загрузки основного и навигационного фреймов. Повторное использование Используйте картинки повторно везде, где это возможно. Кэш браузера достаточно «умен», чтобы находить картинки, если вы всегда будете обращаться к ним абсолютно одинаковым образом. Одну и ту же картинку, используемую несколько раз на одной странице, браузер будет пытаться загрузить несколько раз, если пользователь не дождется окончательной загрузки этой картинки в первый раз. Проще говоря, картинка должна быть полностью загружена, чтобы браузер поместил ее в кэш и смог использовать повторно. Психология Стандартный трюк: помещайте картинки в нижней части страницы, чтобы пользователи не замечали, что они что-то еще загружают, читая верхнюю часть страницы. Обязательно указывайте размер изображений в тегах <IMG>, иначе Netscape не сможет отобразить страницу, пока не загрузит изображение целиком и не определит его размеры. Если вы занимаетесь разработкой страницы на мониторе с высоким разрешением, легко забыть о том, что многие пользователи до сих пор работают с разрешением 640x480. В результате на свет может появиться страница, которую пользователям придется прокручивать в горизонтальном направлении. Это сильно затруднит просмотр вашего сайта. Форматы Перечисленные ниже графические форматы пользуются особой популярностью в Сети. О JPEG — обеспечивает более высокую степень сжатия для фотографий, чем GIF, однако он сжимает изображение с потерями, то есть после сжатия такое изображение уже не может быть полностью восстановлено в исходном виде. Алгоритм сжатия достаточно хорош, чтобы большинство пользователей не замечали, что они что-то потеряли.
О GIF — обеспечивает более высокий уровень сжатия, чем JPEG, для изображений с одноцветными линиями, потому что он сжимает пикселы построчно. Сжатие GIF осуществляется без потерь. О PNG — формат переносимой сетевой графики (Portable Network Graphic) — появился в Netscape 4.0 и Internet Explorer 4.0. Он обеспечивает еще более высокий уровень сжатия, чем JPEG и GIF. Анимация Анимация с передачей отдельных кадров по Сети уже устарела. Вместо нее используются анимированные GIF, которые не только быстро загружаются, но, что важнее, отображаются уже без необходимости передавать что-либо по Сети. GIF-анимация превосходит по скорости загрузки (и, разумеется, запуска) Java- апплеты, но ее функциональность ограничена только отображением последовательности картинок. Недостаток GIF в том, что они поглощают значительную долю ресурсов процессора клиента, даже если пользователь переключается на другое приложение, оставляя браузер работать в фоновом режиме. VRML Поддержка языка моделирования виртуальной реальности (Virtual Reality Modeling Language — VRML) обеспечивается многими версиями Netscape посредством подключаемого модуля Cosmo Player фирмы SGI. VRML-миры загружаются достаточно быстро с учетом уровня детализации, однако требуют наличия на стороне клиента достаточно быстрого компьютера. Аудио Большая часть звуковых форматов кодирует зависимость давления воздуха от времени в 8-разрядном формате, что дает 256 возможных значений амплитуды. Этот стандарт называется кодированием импульсной модуляции (Pulse Code Modulation — PCM). Некоторые форматы обрабатывают звук линейно, тогда как другие используют нелинейные свойства человеческого уха. Людям сложнее различить два громких звука, чем два тихих, поэтому низкие амплитуды в таких форматах кодируются с повышенной точностью. Все перечисленные ниже форматы так или иначе основаны на РСМ: О .аи фирмы Sun; О .wav фирмы Microsoft; О AIFF фирмы Apple; О mu-law (телефонная система США); О A-law (европейская телефонная сеть). Звук может кодироваться и в пространстве частот. Это означает, что код содержит команды типа «воспроизводить эту частоту с такой-то амплитудой опре-
деленное время». Таков, например, формат MIDI (он MIDI позволяет воспроизводить не частоты, а звучание конкретных инструментов из набора со всеми обертонами. — Примеч. ред.). Частота дискретизации определяет диапазон кодируемых частот: при частоте дискретизации п Гц максимальная кодируемая частота звука составит п/2 Гц (Теорема Найквиста—Котельникова). Количество возможных значений амплитуды и частота дискретизации определяют размер звукового файла, а следовательно, и время его загрузки. В телефонной сети голос кодируется 8-разрядными значениями с частотой дискретизации 8 кГц, что дает полосу пропускания 4 кГц и вполне приемлемое качество; 8 бит с частотой 8 кГц дают 64 кбит/с — пропускную способность одного голосового канала телефонной сети. Это принципиальное ограничение на скорость передачи информации по модему. В полицейских и пожарных радиосетях используются более низкие частоты дискретизации и меньшее количество значений амплитуды либо применяется сжатие. Все это позволяет экономить пропускную способность, но дает рациям характерное качество звучания. Алгоритмы сжатия голоса для радиопередач исследовались много лет. Сейчас существуют схемы сжатия речи с очень низким коэффициентом дискретизации A200 бит/с и ниже), хотя звучание становится довольно неестественным. На противоположном полюсе находятся компакт-диски со стереозвучанием при частоте дискретизации 44 кГц и 16-разрядном кодировании амплитуды. Такое качество записи требует 44100 х 16 х 2 - 1,4 млн бит/с. Как видите, вполне реально передавать человеческую речь большинству клиентов в Интернете, но передача в реальном времени звука с качеством звучания компакт-диска пока еще невозможна. Потоковая передача аудио ведется с использованием протокола UDP, который обеспечивает более высокую производительность, чем TCP, и не пытается повторно передавать опоздавшие или утраченные пакеты. В этом есть глубокий смысл, потому что опоздавший на секунду пакет может считаться бесполезным. В начале передачи пакеты буферизуются некоторое время, чтобы сгладить эффект от возможных скачков пропускной способности сети. Данные кодируются таким образом, что, если один из пакетов теряется, звук не пропадает, а просто становится хуже. Вся схема работает вполне приемлемо, однако по качеству звучания напоминает радиостанцию, работающую на средних волнах. Узнать, насколько «здоров» сейчас Интернет, можно, послушав передачи радиостанций, вещающих в Интернете по всему миру. Потоковое аудио хорошо работает в незагруженной интрасети, но конференц-связь все равно работает лучше. Видео Потоковое видео передается с большим коэффициентом сжатия, чем потоковое аудио (обычно 20:1 против 5:1 для максимального уровня сжатия без видимых потерь в качестве), однако видео требует передачи гораздо большего объема данных, поэтому видеопередачу реализовать в Интернете еще сложнее, чем вещание радиостанции. Сжатие изображения очень сильно зависит от самого изображения. Головы дикторов, вещающих новости, сжимаются очень легко,
потому что кадры слабо отличаются друг от друга. Остросюжетные фильмы сжимаются плохо, так как в них много действия. Потоковое видео использует UDP по тем же причинам, что и потоковое аудио. Видео еще не может быть использовано в Интернете достаточно широко, но в интрасетях оно весьма полезно. Фирма Precept Software (www.precept. com) производит программное обеспечение для передачи потокового видео в интрасетях, но этот продукт предназначен только для Windows. Фирма Real Networks (www.real.com) занимается и потоковым видео — а производит она клиентское обеспечение для множества платформ (PC, Mac и Unix) и серверное обеспечение для ПК и Unix. Проигрыватель Windows Media от фирмы Microsoft способен работать как с потоковым видео, так и с потоковым аудио. Основные рекомендации О Отправляйте ровно столько байтов, сколько нужно. Этот совет относится к содержимому любого типа. Используйте параметр ALT тега <IMG> для тех, кто отключил изображения. О Не рассчитывайте на то, что экран пользователя обладает более высоким разрешением, чем 640x480. О Указывайте размеры картинок с помощью <SIZE HEIGHT=nnn WIDTH=nnn>. О Используйте картинки многократно. Кэш браузера сам найдет их.
Оf\ Специализированные ^ V/ приложения Если вы генерируете динамическое содержимое веб-сайта, вам так или иначе придется заняться программированием, даже если оно будет заключаться просто во вставке нужных HTML-тегов в заранее подготовленные варианты вебстраниц. Специализированные программы часто являются источником сбоев и «узких мест». В этой главе мы рассмотрим наиболее типичные проблемы. Программисты Программисты очень сильно различаются по своим способностям и эстетическим качествам, как и все люди, однако если вы им платите, то вам становится далеко не безразлично, насколько они хороши. Нужно запомнить одну простую вещь: лучшие программисты пишут самые короткие программы, и эти короткие программы легко могут быть прочитаны и поняты другими людьми. Причина, по которой их программы коротки, заключается в том, что они ясно видят простой способ достижения большинства возникающих целей. Забавно, что большие компании, занимающиеся разработкой программного обеспечения, часто платят программистам по количеству строк, написанных за день. Это служит чему угодно, но только не эффективности. Квалифицированные программисты часто занимаются тем, что удаляют ненужные и чрезмерно усложненные строки кода, написанные другими, поэтому в иной день количество реально написанных ими строк может быть даже отрицательным! CGI-программы Обычные HTML-доку менты, хранящиеся на вашем веб-сервере, могут содержать совершенно произвольный текст, но он будет статическим. Все пользовате-
ли, обращающиеся к документу из браузера, видят на своих экранах одно и то же. Однако очень часто возникает желание настроить страницу под конкретного пользователя. Например, сайт системы магазинов может запросить базу данных о конкретном пользователе и вернуть ему адрес ближайшего филиала этой системы. Один из вариантов реализации такой схемы выглядит следующим образом: веб-сервер запускает программу, которая запрашивает базу данных, после чего преобразует результат в HTML-текст. Первым широко распространенным способом включения динамического содержимого в веб-страницы стал интерфейс шлюзов (Common Gateway Interface — CGI). Стандарт этот появился как часть веб-сервера, разработанного в Национальном центре приложений для суперкомпьютеров (National Center for Supercomputing Applications — NCSA). Интерфейс шлюзов CGI — это стандартный интерфейс между веб-серверами и программами, генерирующими HTML или иное веб-содержимое. Стандарт CGI изначально действительно являлся шлюзом между веб-серверами и старыми программами Unix, направлявшими результаты своей работы на терминал, но очень быстро все поняли, что реальная ценность CGI состоит в том, что этот интерфейс может быть использован практически для любого программного обеспечения. Программы, запускаемые веб-сервером с использованием CGI-ин- терфейса, называются CGI-программами или просто CGI, хотя технически эта аббревиатура относится только к самому интерфейсу, а не к использующим его программам. Подробное описание CGI 1.1 (текущая версия) находится в Интернете по адресу: http://hoohoo.ncsa.uiuc.edu/cgi/. В дальнейшем я буду предполагать, что читатель понимает, как пишутся CGI-программы. Если вам нужно руководство по написанию таких программ, обратитесь к второму изданию книги С. Гуэлиах, Ш. Гундаварама и Г. Бирзниекса «CGI Programming with Perl» (O'Reilly & Associates). Если вы уже знакомы с программированием на CGI и хотите следить за последними новшествами, рекомендую вам регулярно читать сообщения в конференции Usenet comp.infosystems.www.authoring.cgi. Серверные интерфейсы программирования приложений, такие как Apache API, NSAPI и ISAPI, намного превосходят по производительности программы CGI, однако не обладают тем же уровнем переносимости. После того как программа, использующая серверные API, написана, перенос ее на другой сервер будет стоить денег. CGI и Java лишены этого недостатка. С другой стороны, API не требуют обработки параметров и запуска отдельных процессов. Программы, написанные с использованием интерфейсов API, выполняются как часть процесса веб-сервера, то есть они могут привести к сбою последнего. Помните, что некоторые базы данных одновременно являются и веб-серверами, что избавляет их от накладных расходов на запуск отдельных процессов демонов. Внутреннее устройство CGI и вопросы производительности Хотя механизм генерации динамического содержимого веб-сайта с помощью CGI очень гибок и изменчив, сама его суть ограничивает производительность.
Главным образом быстродействие падает из-за того, что для каждого запроса пользователя порождается новый экземпляр программы. Порожденный процесс немедленно завершается сразу же после отправки результатов его работы вебсерверу. Если CGI-программе для работы требуется соединение с базой данных, это соединение должно открываться каждый раз для каждого экземпляра программы. Нагрузка на операционную систему, создаваемая порождаемыми и уничтожаемыми процессами, сильно ограничивает количество CGI-запросов, которые могут быть обслужены за 1 с. Время выполнения CGI становится «узким местом» при любых сколько-нибудь серьезных нагрузках. CGI обычно поглощает гораздо больше времени процессора и других ресурсов, чем доставка HTML- страниц. Низкая эффективность CGI обусловлена еще и тем, что программы часто возвращают большое количество неизменного содержимого и графики с небольшими изменениями в конкретных цифрах (например, веб-страницы с прогнозом погоды). Это загружает сеть бесполезной информацией. Рассмотрим последовательность событий, происходящих при запуске CGI- программы, и определим, где кроются главные проблемы, связанные с производительностью. Когда на веб-сервер приходит запрос, адресованный CGI-программе, ему приходится обработать принятый URL-адрес и заголовки запроса, понять, что пользователь хочет запустить CGI-программу, после чего породить новый экземпляр этой программы системными вызовами fork() и ехес(). Обработка адреса и вызовы fork() и ехес() составляют значительную часть затрат, связанных с использованием CGI-интерфейса. Сервер настраивает переменные окружения и стандартные потоки ввода-вывода для дочернего процесса, после чего начинает записывать переданные в URL-адресе данные в стандартный поток CGI-ввода. Программа считывает данные, завершая чтение в соответствии с количеством байтов, указанных в переменной окружения CONTENT-LENGTH. CGI может считывать аргументы командной строки, которые также задаются в URL- адресе. Эти аргументы помещаются в адресе после имени сценария, как в нижеследующем примере: http: / /patri ck. net/scri pt. cgi 7аргументы_командной_строки Теперь программа должна декодировать запрос и решить, что именно следует возвратить браузеру. В этом, собственно, и заключается назначение CGI. Когда работа программы заканчивается, она передает результаты веб-серверу через стандартный поток вывода. Веб-сервер добавляет HTTP-заголовки и передает получившуюся страницу браузеру. Многие веб-серверы позволяют CGI-npo- граммам указывать все нужные заголовки самостоятельно и общаться с браузером клиента напрямую. После этого программа завершается. Некоторые проблемы с использованием CGI возникают из-за того, что взаимодействие браузера и сервера ограничено параметрами, передаваемыми браузером, и результатами, возвращаемыми сервером. Непрерывное взаимодействие по одному соединению реализовать достаточно сложно. Итак, производительность CGI низка, а программы эти могут лишь ответить на запрос и закрыть соединение. Так почему же люди используют CGI-интер- фейс? Есть несколько причин широкой популярности CGI, благодаря которым этот стандарт будет широко распространен, по крайней, мере еще несколько лет.
О CGI концептуально прост. О Это открытый стандарт, поддерживаемый большинством веб-серверов вне зависимости от оборудования или операционной системы, на которых эти веб-серверы установлены. О CGI-программы легко писать, причем делать это можно практически на любом языке программирования. О CGI-программы не могут привести к сбою веб-сервера (хотя могут его замедлить), поскольку выполняются в отдельных процессах. О В Интернете существует множество бесплатных общедоступных CGI-npo- грамм. Основные рекомендации Не важно, насколько хорошо оптимизированы ваше оборудование и операционная система. Очень легко сделать производительность просто ужасной, плохо написав какую-нибудь CGI-программу. Время выполнения программ ничем не ограничено, поэтому если ваша программа плохо себя поведет или перегрузит компьютер, пострадают пользователи вашего веб-сайта. Здесь нужно провести разделение между просто неэффективными CGI, бесконечными циклами и неудержимо растущими CGI. Эффективное программирование — отдельная тема, а способы повышения быстродействия программ сильно зависят от используемого языка. Мы поговорим об эффективности CGI- программ чуть ниже, в одном из последующих разделов данной главы. Бесконечные циклы Если ваша CGI-программа каким-то образом зациклится, веб-сервер будет ждать ее завершения бесконечно долго. Это означает, что пользователь будет довольно долго сидеть перед пустым или частично заполненным окном браузера и ждать. Либо, что еще хуже, пользователь может просто нажать клавишу Back и попытаться обратиться к той же странице снова, запустив, таким образом, еще один бесконечный процесс на вашем сервере. Время процессора будет тратиться зря. CGI-программы никак не могут узнать, что пользователь нажал в окне своего браузера кнопку Stop. Программа часто узнает об этом лишь в тот момент, когда она пытается записать HTML-текст в стандартный поток вывода и получает в ответ сигнал SIGPIPE, потому что сокет оказывается уже закрытым. Все это, однако, может зависеть от конфигурации операционной системы и вебсервера. Как обнаруживать и завершать зациклившиеся CGI-программы Чтобы завершить зациклившуюся программу, вы должны сначала узнать идентификатор ее процесса. Классическое средство для этого — команда Unix ps. Па-
раметры этой команды зависят от версии Unix. В системе Solaris, к примеру, список всех процессов может быть получен следующим образом: % ps -ef Ищите процессы с аномально большими значениями в столбце TIME и записывайте их идентификаторы. Не стоит пытаться убивать процессы по именам, отображаемым ps, потому что в некоторых системах имя программы может быть установлено в процессе ее выполнения (для этого надо изменить значение элемента массива argv[0]). Зная идентификатор процесса зациклившейся программы, вы сможете завершить ее с помощью команды kill следующим образом: % kill 2353 Это, однако, может и не привести к завершению процессов, игнорирующих сигнал TERM. Если через несколько секунд процесс все еще будет жив, попробуйте завершить его с параметром -9, например: kill -9 2353. Начинать с этого не стоит, потому что процесс, уничтоженный с использованием этого параметра, не получает возможности удалить свои временные файлы или завершить запись буферизованных данных в файл. Команда kill иногда оставляет в системе процессы-зомби, которые не могут быть убиты, однако поглощают минимальное количество системных ресурсов. Эти процессы помечаются программой ps буквой Z или словом defunct. Если процесс не является зомби, но не может быть убит, — значит, он ждет завершения вызова NFS или пытается обратиться к перегруженному устройству. Существуют более дружественные средства для поиска «заглючивших» процессов, такие как top, skill и killall. Неудержимо растущие CGI-программы Частным случаем зациклившегося процесса является процесс, порождающий на каждой итерации такого цикла копию себя самого. Обычный бесконечный цикл может выполняться бесконечно долго, тогда как неудержимо растущий процесс за несколько минут может израсходовать всю таблицу процессов. Признаком появления такого процесса в системе является наличие большого количества процессов с одним и тем же именем и одинаковым идентификатором родительского процесса (PPID) или последовательными идентификаторами PPID. Нужно попытаться убить процесс с тем PPID, который указывается для всех остальных процессов, или, если эти номера изменяются последовательно, — процесс, PID которого является наименьшим из последовательных PPID. Полезно бывает отсортировать вывод команды ps по идентификаторам родительских процессов (PPID), чтобы явственнее видеть картину Например, в системе Solaris это может быть сделано так: % ps -el | sort -k 3 Пользователь, израсходовавший таблицу процессов или оперативную память, увидит сообщение типа No more processes или Out of virtual memory и не сможет больше запустить ни одного процесса, даже программу kill, пока не завершится еще хотя бы один процесс. Этот пользователь, наверное, даже обнаружит, что его клавиатура заблокирована. Вы можете поразвлечься сами, если у вас
есть собственный компьютер с Unix и вы сохранили все документы и закрыли все приложения. Напишите простой сценарий интерпретатора, состоящий из его собственного имени. Например, создайте файл с именем х, поместите в него единственную команду х и сделайте данный файл исполняемым. Когда вы запустите его, у вас очень быстро закончатся все процессы (либо закончится память, потому что этот процесс будет порождать копии себя самого). Запустите ps несколько раз, если успеете, и вы увидите, сколько будет порождено х-процессов. Когда закончится количество доступных процессов или свободная память, вы не сможете породить новый интерпретатор, а все родительские копии интерпретатора завершатся. Учтите, что это «развлечение» может привести к сбою вашего компьютера. Процессы веб-сервера обычно выполняются от имени пользователя nobody и не имеют управляющих терминалов, поэтому вы не увидите никаких сообщений об ошибках, за исключением, может быть, записей в системном журнале. Первым признаком неудержимого роста CGI-программы является сильнейшее замедление сервера. Если клавиатура сервера заблокирована, вы, может быть, еще сможете войти в систему по локальной сети и убить родительский процесс. Защита от зацикливания CGI-программ Лучшая мера предосторожности против зацикливания CGI — аккуратное программирование. Если вы используете рекурсию, обязательно проверяйте наличие условия ее завершения. Добавляя в свою программу вызовы fork() или sys- tem(), убедитесь, что программа не сможет немедленно после своего рождения породить себя еще раз тем же вызовом — fork() или system(). Проверяйте условия всех циклов while: они обязательно должны когда-нибудь становиться ложными, чтобы цикл завершался. Попробуйте ««подвесить» свою CGI-программу самостоятельно, прежде чем это сделают ваши покупатели. Подайте на вход какой-нибудь бессмысленный текст, содержащий кавычки, переводы строки и другие непредусмотренные символы. Один из трюков, используемых CGI-программистами, заключается в установке таймера в начале сценария и создании обработчика сигнала SIGALRM. Если сценарий по какой-либо причине зациклится, он уничтожит сам себя, как только закончит работу таймер. Вот пример: #!/usг/local/bin/perl $SIG{'ALRM} = sub { syswrite(STDERR. "Caught SIGALRM in script.pl\n". 28); exit(-l): }: alarmE): # Таймер сработает через 5 секунд while A) {} # Этот цикл выполнялся бы вечно, если бы не таймер. Системный вызов Unix setrlimit устанавливает ограничение на потребление системных ресурсов процессом и всеми его дочерними процессами. Список кон-
тролируемых ресурсов включает время процессора, размер файла, размер стека, количество процессов и количество открытых файлов. Того же эффекта можно добиться на уровне интерпретатора с помощью команды limit или ulimit (в зависимости от используемого интерпретатора). К сожалению, иногда эти ограничения оказываются не реализованными в операционной системе, даже если соответствующие функции в ней присутствуют. На уровне веб-сервера Apache позволяет управлять ресурсами, отводимыми сценариям CGI, с помощью специальных директив. Не заставляйте клиента ждать Пользователей очень раздражает, когда их браузер подключается к вашему сайту, а затем онивынуждены ждать, пока вы подготовите для них содержимое вебстраницы. Если вам приходится выполнять сложные операции в своих CGI, есть смысл вначале отключить буферизацию ввода-вывода ($|=1 в Perl) и передать браузеру для отправки пользователю тип содержимого (Content-Type) и какой- нибудь текст для отправки клиенту, а затем заняться формированием остального содержимого. Если вы не передадите браузеру данные о типе содержимого, он закроет соединение через достаточно короткий промежуток времени. Все ваши расчеты пропадут зря. Отправив заголовок, опять включите буферизацию ввода-вывода ($|=0 в Perl), чтобы не терять преимущества, даваемые ее использованием. Очень часто CGI-программы застревают в ожидании получения информации из другой части компьютера, на котором они выполняются, или даже с другого компьютера сети. В названную категорию попадает поиск в DNS. Везде, где это возможно, избегайте обращения к DNS, используя в своих сценариях статические IP-адреса. Если выводимые вашим сценарием данные можно отправлять пользователю по мере их формирования, вы можете написать CGI-программу, добавляющую заголовки самостоятельно. Веб-сервер передает данные, выводимые такой программой, непосредственно браузеру клиента. Преимущество сценариев NPH (non-parsed header) в том, что они могут поддерживать соединение с браузером открытым и отправлять ему результаты в течение значительного промежутка времени. Обычная CGI-программа должна передать все данные веб-серверу и закрыть соединение с ним, прежде чем веб-сервер начнет хоть что-нибудь отправлять браузеру. Это может быть полезно, если CGI-программе приходится возвращать клиенту постоянно изменяющиеся данные (например, биржевые котировки акций). Если у вас установлен сервер Apache или NCSA, для преобразования обычного CGI в NPH CGI достаточно добавить к его имени префикс nph (например, nph-script.cgi). Помните, однако, что сценарии NPH отвечают за отправку всех нужных HTTP-заголовков, которые в противном случае передавались бы вебсервером. Если вы неправильно сформируете заголовки, браузер не сможет интерпретировать передаваемые ему данные. Помните также, что сервер не может записывать в журнал размер данных, возвращаемых NPH CGI.
В веб-сервере iPlanet Web Server 4.1 имеется новая директива magnus.conf, которая называется UseOutputStreamSize. Она управляет буферизацией данных, отправляемых браузеру. Размер буфера по умолчанию составляет 8192 байт, что вполне подходит для статического содержимого. Однако при работе с динамическим содержимым иногда бывает нужно отправлять его клиенту по мере готовности. Если буфер будет иметь размер 8 Кбайт, браузер станет ждать его заполнения слишком долго, поэтому в отображении информации возникнут ощутимые задержки. Если вы хотите уменьшить время ожидания и готовы пожертвовать общей пропускной способностью, установите значение UseOutputStreamSize по возможности малым, например: UseOutputStreamSize 20 Причина, по которой эта директива была добавлена в конфигурационный файл, заключается в том, что HTTP 1.1 требует указывать размер содержимого с помощью заголовка content-length, однако многим программам CGI трудно узнать заранее, сколько именно данных они будут передавать. Без такого заголовка браузер сможет узнать о том, что он получил все данные, только когда сервер закроет соединение. Однако закрытие соединения неприемлемо для отметки конца данных, потому что это противоречит концепции постоянных соединений. Если размер буфера известен, сервер может отправлять браузеру блоки данных известного размера, сохраняя соединение для использования даже после завершения CGI-программы. Еще одна новая директива flushTimer позволяет отправлять данные по истечении тайм-аута, а не после заполнения буфера определенного размера. Переложите обработку на браузер Хороший путь к ускорению CGI-программ состоит в уменьшении объема выполняемой ими работы путем перекладывания ее на браузер, который обычно большую часть времени простаивает, ожидая возвращения данных сервером или прочтения страницы пользователем. Отличным примером является проверка введенных пользователем данных на стороне клиента с помощью JavaScript. Отправка проверяющего кода на браузер — небольшая цена за уменьшение нагрузки на сеть и сервер, а также за уменьшение количества ложных CGI-вызовов с некорректными входными данными. Одновременно сократится сама CGI-npo- грамма, поскольку ей не придется выполнять большую часть проверок. Удаление всех проверок из программы может быть опасно. В листинге 20.1 приведен грубый пример, проверяющий введенную дату на соответствие требуемому формату перед отправкой ее на сервер. Листинг 20.1. Проверка введенных данных на стороне клиента (JavaScript) <HTML> <HEAD> <SCRIPT LANGUAGE-"JavaScripts <!- Hide the script from browsers that don't know JavaScript. function validdate(lf) { if ((If.date.value.charAt(O) < ,0) ||
(If.date.value.charAt(O) > '1') || (If.date.value.charAt(l) < *0') jj (If.date.value.charAt(l) > '9') jj (If.date.value.charAtB) !» 7") || (If.date.value.charAtO) < '0') || (If.date.value.charAtO) > '3') jj (If.date.value.charAtD) < '0') jj (lf.date.value.charAtD) > '9') jj (If.date.value.charAtE) !- 7') || (If.date.value.charAtF) < "(Г) |j (If.date.value.charAtF) > '9') jj (If.date.value.charAtG) < '0') jj (If.date.value.charAtG) > '9')) { alertCInvalid date. Please use format MM/DD7YY."): return false } else return true } // End of hiding JavaScript -> </SCRIPT> </HEAD> <TITLE>stuff</TITLE> <F0RM name^'^ateform" action*"/myscript/" method*"post"> mm/dd/yy <INPUT name="date" size-8 maxlength-8 value=""> <INPUT name-"submit_button" TYPE-"submit" VALUE="log on" onclick-"return validdate(dateform)")> </FORM> JavaScript отлично подходит для выполнения простых вычислений на стороне клиента. Мало того, что с сервера снимается лишняя нагрузка; и время отклика значительно сокращается, поскольку все вычисления выполняет браузер. Еще одна полезная функция JavaScript позволяет узнать, какой браузер и какая страница привели к возникновению ошибки. Вот кусочек кода, отображающий упомянутую информацию: <а href="javascnpt:alert ('Agent - ' +navigator.userAgent+ '\nBrowser - *+navigator.appName+ '\nVersion - *+navigator.appVersion)">version</A> <a href*"javascript.alert Сreferrer«,+document.referrer),,>referring page</A> Недостаток JavaScript в том, что пользователю приходится загружать чуть больше данных, а кроме того, что важнее, Netscape и Internet Explorer не вполне совместимы в плане поддержки этого языка. Еще один существенный недостаток заключается в том, что JavaScript просто перестает функционировать, когда у пользователя заканчивается память, так что «наивный» сервер может «подумать», что входные данные были проверены на правильность, тогда как на самом деле этого не произошло. Это означает, что JavaScript не в состояни полностью снять обязанности по проверке данных с сервера. Однако он может снизить нагрузку,
ограничивая проверку на стороне сервера одной операцией, позволяющей выяснить, выполняется ли JavaScript на стороне клиента (если JavaScript не выполняется, входные данные должны сбрасываться). Браузер может сам отказаться отправлять непроверенные данные на сервер. Один из способов достичь этого заключается в том, чтобы отправка формы выполнялась с помощью JavaScript. Если JavaScript не работает, форма не будет отправлена, хотя у пользователя могут возникнуть затруднения с выявлением источника проблем. В листинге 20.2 приведен пример (ссылка на метку # позволяет сгенерировать событие JavaScript). Листинг 20.2. Отправка формы с помощью JavaScript <html> <head> <title>will submit only if javascript working</title> </head> <body> <form name«HtheForm" action-'Vcgi-bin/simpleform.cgi" method-"POST"> name:<br> <input type-"text" name-,,theName" value-"" size-25> </form> <p> <a href-"#" onClick-"theForm.submit( )">click here to submit</a> </body> </html> Еще один способ гарантировать то, что входные данные были проверены — испольовать операторов document.writeln() для динамического создания формы. Если JavaScript не будет работать, пользователь просто не увидит формы. Файлы cookie Еще одна полезная функция браузера, позволяющая снизить нагрузку на сервер, — файлы cookie. Эти файлы позволяют избежать проверки пользователей и их состояния, а также могут применяться для хранения информации о пользователях, чтобы CGI-программам не приходилось их искать каждый раз при обращении к странице. Размер файла cookie ограничен D Кбайта). Браузеры, поддерживающие только HTTP 1.0, не могут кэшировать страницы, содержащие cookie. С файлами cookie всегда связывается определенный домен, что требует поиска в DNS. Браузер может кэшировать имя домена и связанный с ним IP-адрес, но гарантировать это нельзя. Ссылку на спецификацию, определяющую файлы cookie, можно найти по адресу: http://patrick.net/specs/index.html. Java Java-апплеты при условии поддержки их браузером позволяют полностью избавиться от CGI, но в последнее время поддержка Java перестала обеспечиваться.
Java — это язык общего назначения, а апплеты — приложения, способные устанавливать соединение с сервером, с которого они были загружены, и обращаться к базам данных и другим приложениям сервера. Запуск виртуальной машины Java занимает заметное время, однако выигрыш от использования апплетов может быть огромен. Например, работая на одну компанию, занятую доставкой грузов, я написал апплет для слежения за перевозками, который содержал карту, составленную из точек, задававших автомагистрали, железные дороги и границы штатов. Поскольку все данные загружались вместе с апплетом, увеличение и прокрутка осуществлялись гораздо быстрее, чем это в принципе возможно при работе с картами, генерируемыми CGI-программами, потому что эти последние требуют передачи больших объемов данных по сети при каждом изменении режима просмотра. Возможности Java, имеющиеся в браузерах, позволяют обойти использование CGI путем осуществления прямых вызовов методов объектов, размещенных на сервере. Существует два стандартных способа делать это посредством удаленного вызова методов (Remote Method Invocation — RMI) и с помощью технологии CORBA. Программы, использующие RMI, писать легче, однако они выполняются медленнее и требуют поддержки Java как от сервера, так и от клиента. CORBA программировать сложнее, однако в результате программы работают быстрее и оказываются гибче. Третий вариант — продукт Voyager фирмы Object Space (www.objectspace.com), позволяющий легко писать высокопроизводительные программы, однако он не слишком широко используется. Гораздо более подробные сведения о Java вы найдете в главе 21. Обрабатывайте запросы заранее и кэшируйте результаты Приходилось ли вам задумываться над тем, как программы новостей успевают готовить подробные некрологи всего за несколько часов, проходящих с момента смерти какой-нибудь знаменитости до очередного выхода передачи в эфир? Сверхчеловеческая производительность на самом деле заменяется предварительной обработкой. Журналисты заранее подготавливают некрологи всех известных людей, особенно тех, кто серьезно болен. Конечно, они не знают, когда именно умрет конкретный человек, но поскольку количество тех, чья смерть заинтересует зрителей и читателей, ограниченно, можно подготовить некрологи для всех. Принцип в том, что чем меньше входных параметров, тем меньше будет возможных вариантов результатов. Чем меньше результатов, тем более эффективным оказывается кэширование ответов. Задача CGI заключается в генерации разных HTML-страниц в зависимости от вводимых пользователем данных и информации о его состоянии. Однако если количество комбинаций возможных входных данных и состояний ограниченно, можно заранее просчитать их все и кэшировать результаты в виде обычных статических HTML-страниц. Например, если CGI-программа предназначена для выдачи прогноза погоды на завтрашний день для сотни городов США, вы наверняка достигнете гораздо большей производительности и масштабируе-
мости, генерируя 100 статических HTML-страниц заново каждую ночь, вместо того чтобы запускать CGI каждый раз, когда к вам обращается пользователь. Даже если количество возможных вариантов входных данных очень велико, но лишь немногие страницы запрашиваются особенно часто, есть смысл динамически кэшировать часто запрашиваемые страницы. Создайте на стороне сервера кэш часто запрашиваемых результатов CGI и напишите заглушку, которая будет возвращать ответ в формате HTTP Location:, указывающий на статический HTML-файл, если он имеется в кэше. Хороший способ освобождения переполненного кэша — удаление наиболее редко запрашиваемых страниц. Кэш, функционирующий по такому принципу, называется кэшем с вытеснением по давности использования (LRU cache). Пользователи AltaVista могут вводить совершенно произвольные строки поиска длиной до 800 символов (на текущий момент). Поскольку набор данных (все веб-страницы в базе данных сервера) и неопределенность запроса пользователя велики, усилия, требующиеся на то, чтобы справиться с этой неопределенностью, тоже весьма велики. Но это не означает, что серверу AltaVista приходится осуществлять линейный поиск по всему набору данных для обработки каждого запроса. База данных AltaVista, как и большинство больших баз, индексируется, поэтому сервер может просто использовать поступившие на вход слова в качестве индекса к набору данных и возвращать найденные результаты. Поиск по индексу не всегда оказывается быстрее линейного. Линейный поиск обладает тем преимуществом, что головки дисков передвигаются с одной дорожки на другую последовательно, тогда как при поиске по индексу возможны большие скачки. Размер индекса и объем данных определяют, какой метод даст наибольшую производительность. Помимо сказанного веб-сервер AltaVista кэширует результаты наиболее часто поступающих запросов. В качестве примера эффективности индексирования давайте рассмотрим CGI-программу, которой приходится искать в файловой системе сервера конкретный файл, называемый desiree. Несложно сделать, чтобы программа CGI запускала команду Unix find; однако гораздо эффективнее осуществлять поиск по заранее подготовленному индексу файловой системы. Чтобы создать индекс всей файловой системы, достаточно сделать вот что: % find / -print > index Теперь, чтобы найти файл, вы можете выполнить одну из двух команд: % find / -name desiree -print либо % grep desiree index Вы можете сами измерить, насколько быстро эти команды будут выполнены, указав в командной строке первой команду time. Например: % time find / -name desiree -print Смотреть нужно на реальное время выполнения команды (elapsed time). Более подробно о формате вывода команды time в вашей системе читайте на соответствующей странице документации. Поиск с помощью grep должен оказаться
в 10-100 раз быстрее. Это показывает преимущество индексирования. (В Windows создать подобный индекс можно командой dir /S /В > index.txt. Формируется он на удивление быстро, а поиск по нему осуществляется командой find. — Примеч. ред.) Вы должны также заметить, что при скором повторном запуске команда find выполняется быстрее, чем при первом. Почему это происходит? Потому что сама программа загружается в ОЗУ, а еще потому, что часть файловой системы, к которой вы обращались, кэшируется в памяти. Так работает Unix, автоматически обеспечивая высокое быстродействие. Еще одна полезная функция Unix, связанная с кэшированием, позволяет совместно использовать нескольким экземплярам программ процедурный сегмент, который у них общий, — это называется повторным вхождением (re-entrance). Чтобы получить представление о пользе повторно используемого кода, запустите Netscape и заметьте, сколько времени потребуется на загрузку браузера. Затем щелкните File ► New browser. Новый экземпляр браузера запустится мгновенно. Причина в том, что процедурный сегмент или сегмент кода уже загружен и готов к выполнению. Когда к одной и той же CGI-программе пользователи обращаются множество раз за короткий промежуток времени, второй и последующий вызовы работают с тем же процедурным сегментом, что и первый, поэтому объем памяти, отводимый под второй и последующие экземпляры программы, меньше. Это снижает вероятность обращения к файлу подкачки. По названным причинам второй и последующий экземпляры обычно работают быстрее первого, а насколько — зависит от системы. Конечно, на 10-й, или 100-й, или 1000-й экземпляр просто не хватит ресурсов — и им придется ждать в очереди, либо они просто не будут запущены. Практически все браузеры обладают возможностью кэширования данных в памяти и на диске, поэтому запрашивавшаяся ранее страница может быть загружена из кэша, а не передаваться по сети. Однако в некоторых случаях возникает необходимость отказаться от кэширования страницы браузером. Обычно кэширование отключается для страниц, формируемых CGI-программами, поэтому такие сценарии часто указывают заголовок HTTP 1.1 Cache-Control или HTTP 1.0 Pragma:No-cache. Слишком частое использование этих заголовков авторами CGI-программ представляет угрозу для производительности, создавая избыточную нагрузку на веб-сервер. Однажды я участвовал в проекте, связанном с электронной коммерцией, где программисты добавляли заголовок Pragma:No-cache во все страницы. Идея была такова: пользователь может выйти из системы (уйти из электронного магазина), а кто-нибудь другой подойдет к его компьютеру, щелкнет кнопку Back и увидит важные финансовые сведения. Использование HTTPS в этой ситуации не поможет, потому что в сеанс HTTPS можно вернуться, щелкнув кнопку Back. Более эффективное решение могло бы быть таким: страница выхода из магазина должна порождать новый экземпляр браузера, после чего самостоятельно закрываться. В таком случае кнопка Back не поможет злоумышленникам, но будет работать в течение сеанса работы обычного пользователя.
Короткая — значит красивая Короткие программы легче понимать и сопровождать, они загружаются и выполняются быстрее, чем большие программы, и в меньшей степени подвергаются риску замещения страниц или вытеснения в файл подкачки. Хотя программисты всегда испытывают соблазн добавить в программу новые возможности (это ««заболевание» называется ««ползучий улучшизм» — creeping featurism), им следует сопротивляться такому соблазну по мере сил. Он противоречит широко известному KISS-принципу (Keep It Simple, Stupid; буквально — «Сделай Это Проще, Дурачок»). Один из способов уменьшения размеров CGI-программ заключается в переносе проверки правильности входных данных на сторону клиента при помощи Java или JavaScript. Впрочем, об этом уже говорилось. Использовать JavaScript гораздо опаснее, потому что формы работают даже тогда, когда JavaScript отключен. Если же на браузере отключена поддержка Java, то выводимые апплета- ми формы не будут даже появляться на экране, поэтому пользователю будет сложнее отправить на сервер некорректные входные данные. Очень простой способ проверки ошибок заключается в ограничении длины текстовых полей, чтобы пользователи сами замечали, когда они пытаются ввести слишком много символов. Выглядеть это может так: <input name-"dateH size-8 maxlength-8 value-""> Вопросы масштабирования CGI-программы масштабируются не слишком хорошо. Производительность их быстро падает с ростом загруженности из-за того, что все CGI-процессы и порождаемые ими процессы создают заметную нагрузку на операционную систему. Если несколько разных CGI-программ работают с независимыми данными, проще и лучше всего осуществлять масштабирование посредством разделения CGI по разным веб-серверам. Серверам не обязательно даже находиться в одной стране. Если же CGI приходится работать с общими данными, еще один отличный метод масштабирования заключается в разделении по отдельным компьютерам только самих CGI-программ, чтобы веб-сервер сам решал, на каком компьютере должна быть запущена программа, и отправлял результаты клиенту. Это суть стандарта FastCGI, который обсуждается в разделе «Демонизация» этой главы. Круговая схема DNS плохо работает с CGI, сохраняющими информацию о состоянии (обычно с использованием файлов cookie), потому что информацию приходится синхронизировать между серверами. Разделяйте большие формы на несколько маленьких Разделение большой формы на несколько маленьких снижает возможность использования нескольких серверов для масштабирования, но обеспечивает более
высокую производительность в расчете на страницу. Кроме того, вы получаете большую гибкость, потому что можете превратить одну страницу в целое дерево страниц, избавляя себя от необходимости посылать пользователю те запросы, которые впоследствии оказываются не нужны. Поиск в DNS на сервере Обязательно отключите поиск в DNS на веб-сервере. Некоторые CGI ожидают получения имени узла в переменной REMOTEJHOST (IP-адрес записывается в переменную REMOTE_ADDR). Обратный поиск в DNS занимает заметное время. Метод отключения поиска в DNS зависит от используемого вами веб-сервера. (Подробнее см. главу 18.) Отладка и оптимизация Последний совет: протестируйте свою CGI-программу без подключения к сети — так вам проще будет профилировать и отлаживать ее, чем при вызове через веб-серверы. Вы легко напишете тестовый сценарий, который настроит переменные окружения и запустит timeprog.cgi. Измеряя время, не обращайте внимания на разницу между первым и вторым прогонами: по причинам, изложенным выше, важна разница между вторым и третьим. Оптимизация CGI Для написания CGI-программы можно использовать любой язык, поддерживающий концепции стандартных потоков ввода и вывода, однако некоторые языки по своей внутренней структуре подходят для этой задачи лучше, чем другие. В этом разделе я рассмотрю наиболее типичные языки программирования CGI (sh, Perl и С), отмечу их преимущества и недостатки и приведу некоторые рекомендации, касающиеся повышения быстродействия ваших программ. Но для начала дам общие рекомендации, применимые к любым языкам. О Циклы должны быть короткими. О Используйте поиск по таблице вместо расчетов там, где это рационально. О Работайте с целочисленной арифметикой; не используйте числа с плавающей точкой. О Избегайте динамического выделения памяти. О Профилируйте код и оптимизируйте наиболее часто выполняемые функции. Сценарии интерпретатора Сценарии интерпретатора Unix, который называется Bourne shell, обладают следующими достоинствами: переносимостью между разными версиями Unix, удобством работы с файлами и фильтрации. Однако сценарии интерпретатора
440 Глава 20. Специализированные приложения выполняются очень медленно, потому что они интерпретируются и им приходится вызывать другие программы Unix, обеспечивающие нужную функциональность. По названной причине сценарии sh порождают множество новых процессов. На это уходят время и ресурсы. Например, для нахождения в текущем каталоге всех файлов со словом foo и вывода отсортированного списка результатов без повторяющихся строк написать CGI-программу действительно легко (листинг 20.3). Листинг 20.3. Поиск слова в файлах из текущего каталога (сценарий sh) #!/bin/sh echo "Content-type: text/plain" echo grep -h foo * | sort | uniq Хотя время написания приведенной программы пренебрежимо мало, за это приходится дорого платить при ее выполнении. Данный сценарий порождает шесть процессов, обрабатывая единственный запрос: sh, две копии echo и по одной копии grep, sort и uniq. Это очень плохо сказывается на производительности. Если вы считаете, что должны писать CGI-программы на языке сценариев интерпретатора, выберите более современный интерпретатор — например, csh или bash. Эти интерпретаторы позволят вам чаще использовать встроенные команды, избегая накладных расходов на fork и exec. Например, в csh имеется встроенная команда time, которая работает гораздо быстрее, чем программа с тем же именем, хранящаяся в каталоге /bin, потому что встроенная команда выполняется как часть интерпретатора. Полагаясь на встроенные команды, вы теряете некоторую долю переносимости, но выигрыш в производительности стоит того. Если вам нужно запустить из сценария несколько программ, не запускайте их все в фоновом режиме, потому что они будут состязаться за ресурсы. Лучше выполнять команды последовательно, чтобы каждой из них доставалось больше ресурсов и они завершались быстрее. Еще один совет, которым стоит воспользоваться при написании сценариев интерпретатора: стремитесь к минимальному объему переменных окружения. При каждом порождении копии интерпретатора (которое происходит при вызове любой внешней команды) должна выполняться инициализация. Если количество определяемых пользователем переменных и функций будет невелико, fork будет выполняться чуточку быстрее. Perl Perl — это самый популярный язык, используемый при написании программ CGI. Популярность его обеспечивается переносимостью (которая, впрочем, легко нарушается использованием функции system() для вызова специфичных для данной платформы функций), отличными средствами обработки текста и регулярных выражений, а также большой библиотекой встроенных функций. Язык этот сложнее, чем sh, но обладает поразительным набором возможностей. Один мой сотрудник любит говорить, что Perl содержит все приемы программирования, известные человечеству. Хотя Perl считается интерпретируемым языком
наподобие sh, на самом деле Perl-программы компилируются непосредственно перед выполнением, поэтому производительность оказывается существенно выше (хотя и не столь высокой, как у откомпилированных программ на языке С). Подпрограммы для обработки текста писать на языке Perl гораздо проще, чем на С. Perl действительно выглядит как интерпретируемый язык, но все-таки не является таковым. В любом интерпретаторе каждая строка текста считывается, обрабатывается и выполняется. Perl считывает текст программы целиком, обрабатывает его, а затем выполняет — тоже целиком. Чтобы почувствовать разницу, добавьте синтаксическую ошибку в самый конец сценария интерпретатора. Сценарий будет прекрасно выполняться до тех пор, пока дело не дойдет до строки с ошибкой. Если же вы добавите ошибку в конец сценария на языке Perl, его обработка не будет завершена до конца и он вовсе не будет выполнен. Perl оказывается быстрее интерпретируемых программ отчасти потому, что команды выполняются не Построчно. Поскольку Perl используется очень широко, на оптимизацию его было потрачено много усилий. Хорошим источником информации об оптимизации Perl-программ являются телеконференции — например, на www.dejanews.com. Вот несколько основных рекомендаций. О Не вызывайте программы Unix, если существуют эквивалентные им функции Perl (например, sort). Так вы сэкономите на накладных расходах на запуск нового процесса. О Поиск с использованием хэширования выполняется быстрее, чем линейный. О Используйте все что знаете, о том, что ищете, чтобы снизить нагрузку во время выполнения программы. Например, если искомая подстрока может встретиться только в конце строки, скажите об этом Perl с помощью символа $, чтобы ему не нужно было просматривать всю строку. Существует компилятор для Perl, который превращает Perl-программы в программы на С. Хотя Perl и так уже оптимизирован достаточно и такая компиляция может не дать большого выигрыша во времени выполнения программы, компилированные программы на С не требуют запуска интерпретатора Perl, поэтому для часто используемых CGI это может заметно повысить производительность. Компилятор можно скачать по адресу: ftp://ftp.ox.ac.uk/pub/perl/Compiler-al. tar.gz. Он поставляется совместно с прочими файлами Perl, начиная с официальной версии 5.005. (См. также http://www.perl.com/.) Производительность Perl может быть повышена с помощью модуля Perl для веб-сервера Apache. Этот модуль называется mod_perl. (См. http://www.apache. com/). Поскольку интерпретатор Perl становится частью веб-сервера Apache, когда вы подключаете модуль mod_perl, накладные расходы на запуск интерпретатора этого языка в виде нового процесса полностью исчезают. С точки зрения пользователя, скорость выполнения возрастает на 400-2000%. Модуль mod_perl легко может обеспечить более высокую производительность, чем скомпилированные из Perl в С программы, выполняемые как обычные CGI-программы. Однако вам придется несколько изменить сами сценарии и конфигурацию веб-сервера. Компания Velocigen (http://www.velocigen.com/) предлагает аналогичный продукт для ускорения CGI.
с Первые CGI-программы писались на С, и этот язык все еще остается самым подходящим в тех случаях, когда важна скорость выполнения программы. Помните, что CGI-программы, написанные на С, все равно остаются отдельными процессами, поэтому, даже если бы они выполнялись бесконечно быстро, время запуска процесса все равно замедляло бы отправку ответа пользователю. Язык С обладает высокой переносимостью на уровне исходных кодов, хотя программы приходится компилировать заново на новой платформе. Существуют библиотеки для работы с регулярными выражениями на С, но обработка текста требует гораздо больше внимания к деталям при программировании на С, чем на Perl. Оптимизация программ на С — достаточно большая тема, чтобы ей можно было посвятить отдельную книгу, однако вот несколько советов, которые помогут вам вникнуть в суть этого предмета. О Используйте максимальный уровень оптимизации, доступный в вашем компиляторе. Для компилятора GNU (gcc) он включается с помощью параметра -ОЗ. Учтите, что оптимизаторы не обладают бесконечной мудростью, поэтому иногда они замедляют программы, вместо того чтобы ускорять их. Обязательно измерьте время выполнения вашей программы при различных уровнях оптимизации, чтобы быть уверенным, что вы действительно повысили производительность. Более высокий уровень оптимизации может привести к проявлению мелких ошибок в вашем коде. Эти ошибки определяются с помощью программы lint Последние версии компиляторов чаще всего осуществляют оптимизацию наилучшим образом. Прочитайте документацию вашего компилятора на предмет наличия других полезных параметров. О Увеличьте скорость работы программы, используя меньше функций, чтобы вам не нужно было тратить ресурсы на занесение данных в стек и считывание их оттуда. Замена вызова функции кодом самой функции называется ее раскрытием (inlining). Экономия времени возрастает, если вы раскрываете функцию, которая в противном случае вызывалась бы множество раз из цикла. Аналогичным образом вы можете разворачивать циклы: вместо того чтобы увеличивать счетчик и выполнять сравнение на каждой итерации, закодируйте все итерации вручную. Ручное раскрытие и разворачивание считаются плохим тоном в программировании, поскольку они затрудняют чтение и поддержку кода, поэтому пользуйтесь возможностями компилятора. Компилятор дсс позволяет и раскрывать функции, и разворачивать циклы. Еще один недостаток описанных методов заключается в возрастании размера кода, что увеличивает время его загрузки и вероятность вытеснения программы в файл подкачки. О Используйте библиотечные вызовы, а не системные. Системные вызовы стоят очень дорого в плане времени и ресурсов. Хотя библиотечные вызовы сами могут обращаться к системе, они и это часто делают более эффективно. О Всегда включайте буферизацию ввода-вывода. Гораздо эффективнее считать из сети столько, сколько вы сможете, за один раз, чем считывать данные по одному байту. Не стоит заставлять пользователя ждать, пока вы считываете
информацию, поэтому по возможности помещайте операции чтения в отдельный поток. О Подключайте общие библиотеки статически, а не динамически во время выполнения. Код будет выполняться быстрее, потому что не нужно будет искать уже включенные в него данные. Это, как и раскрытие функций, увеличит исполняемый файл и замедлит его загрузку. Поступайте так только в том случае, если у вас много памяти. Компиляторы SPARC подключают библиотеки при указании параметра -dn. Если вы часто используете функцию malloc, компонуйте программу с библиотекой -Ifast. О Везде, где у вас есть выбор, используйте степени двойки A, 2, 4, 8, 16,...). Большинство процессоров работают с такими числами очень быстро, тогда как все прочие числа требуют большего количества циклов процессора. Это связано с природой двоичной арифметики, используемой всеми процессорами. Вы можете заменить умножение и деление на степени двойки операциями сдвига (например, х << 2 вместо х *= 2), однако «умный» компилятор может сделать это самостоятельно в процессе преобразования исходного кода в двоичный. Мой апплет с картой, написанный на Java, увеличивал и уменьшал изображение только в 2 раза. Ему приходится выполнять множество вычислений для отображения карты, однако вычисления эти выполняются гораздо быстрее, чем если бы я умножал все на какое-либо произвольное число. Рекомендации, относящиеся к Java, вы найдете в главе 21. О Арифметика с плавающей точкой работает гораздо медленнее, чем целочисленная, поэтому ее следует избегать везде, где это возможно. Например, можно сдвигать дробные числа в целочисленный диапазон, отбрасывать дробную часть, работать с ними как с целыми, а затем преобразовывать обратно в дробные перед самым выводом на экран. О Используйте программу для профилирования кода и оптимизируйте наиболее часто выполняемые разделы, при необходимости переписывая их на ассемблере, gprof позволит вам узнать, сколько времени вы проводите в каждой из функций, a tcov скажет, сколько раз выполняется любая конкретная строка исходного кода. Имеется хорошее коммерческое средство от фирмы Pure Software, которое называется Quantify. Простое правило гласит, что программы проводят 90% времени в 10% кода. Правда, кодирование на ассемблере — последнее средство, потому что при этом теряется переносимость программ и повышается вероятность ошибок. О Используйте статические массивы. Не стоит выделять память динамически с помощью malloc. О Запустите программу mpstat, чтобы убедиться, что многопоточные программы используют все доступные процессоры. В главе 21 рассматривается возможность замены CGI на Java на стороне сервера.
Демонизация Лучшая альтернатива CGI, обладающая гораздо лучшей производительностью и масштабируемостью, — стандартная методика Unix, которую я называю демони- зацией. Демоны Unix таятся во всех компьютерах, на которых установлена эта операционная система, и ожидают возникновения событий, подлежащих обработке. Основная идея заключается в том, что не стоит каждый раз при поступлении запроса запускать CGI-программу, которая будет сразу же завершаться; вместо этого нужно запустить постоянно существующий процесс (демон), который будет работать вместе с веб-сервером. Демон может даже располагаться на другом компьютере. Когда веб-сервер получить запрос, он соединится с демоном, передаст ему этот запрос и будет ожидать результатов (оставаясь способным в то же время обрабатывать и другие запросы). Сервлеты, написанные на Java, работают как демоны. Вы можете запустить сервлет и подключаться к нему столько раз, сколько захотите, не тратя ресурсы на порождение процессов. Интерпретируемость Java ухудшает производительность меньше, чем ее повышает устранение накладных расходов. Сервлеты являются многопоточными, то есть клиенты оказываются изолированными друг от друга. Еще один метод демонизации CGI был предложен компанией Open Market. Этот метод получил название FastCGI (см. www.fastcgi.com). FastCGI-програм- мы выполняются постоянно и являются весьма масштабируемыми, потому что могут выполняться на любых компьютерах, а не только там, где работает вебсервер, получающий запросы. FastCGI использует один сокет TCP для подключения к веб-серверу, а FastCGI-приложение в отличие от обычного CGI не использует каналы и переменные окружения. Соединение заменяет переменные окружения, стандартные потоки ввода, вывода и сообщения об ошибках. Из-за этого для превращения обычной CGI-программы в FastCGI в нее приходится вносить значительные изменения. Одним из недостатков метода FastCGI является то, что он не поддерживается наиболее распространенными веб-серверами, требуя установки заглушки CGI (Apache представляет собой исключение), что уменьшает выигрыш в производительности. Сборник рекомендаций по повышению производительности FastCGI вы можете найти по адресу: http://www.fastcgi.com/kit/doc/fastcgi-whitepaper/fastcgi. htm. Последние версии ASP для NT ведут себя аналогичным образом в том смысле, что загруженная CGI-программа не выгружается, а остается в памяти резидентно, ожидая следующего запроса. Так же работает и модуль mod_perl для Apache. Демонизированные CGI создают опасность утечки памяти, потому что они выполняются без завершения. Если демон страдает от утечки памяти, он очень быстро поглотит ее в таком объеме, что вам придется его перезапустить. Можете попробовать ограничивать доступную процессам-демонам память с помощью ulimit, однако этот метод не всегда надежен, а вам придется думать, как обрабатывать достижение ограничения. Лучший подход — борьба за чистоту кода.
Средства типа Purify, CodeCenter, Bounds Checker и PURE позволяют обнаружить утечку памяти и часто подсказывают, что именно является ее причиной. Обычно утечки возникают из-за того, что программа не освобождает память при возвращении из подпрограммы. Демоны часто поглощают соединения с базами данных, забирая их из пула и не возвращая обратно. Часто это получается из-за возникновения исключительной ситуации до выполнения кода, освобождающего соединение. Помните, что вы можете сами избавиться от CGI и выполнять серверные программы на других компьютерах. Легко написать программу, которая будет принимать соединения через порт 80 и обрабатывать принимаемые данные, отправляя браузеру HTML-страницу. CGI обладают тем преимуществом, что браузеры умеют передавать программам данные из форм. Для замены CGI можно использовать именованные каналы (очереди) вместо HTML-файлов. Учтите, что именованные каналы не могут принимать аргументы тем же способом, каким это делают CGI-программы. Наконец, вы можете написать заглушку CGI, которая будет взаимодействовать с резидентным процессом через разделяемую память или отображаемый в память файл, если вам не нравятся стандарты CGI или FastCGI. Производительность при обращении к БД Для ускорения обращения к базе данных из CGI-программ принципиально важно устранить накладные расходы, связанные с открытием нового соединения для каждого экземпляра CGI-программы. Открытие соединения с базой иногда занимает довольно продолжительный промежуток времени и может потребовать загрузки больших библиотек. Полезно купить или написать программу управления соединениями, которая будет открывать их только один раз, после чего обслуживать CGI-запросы приблизительно так, как работают FastCGI-npo- граммы. Создатели систем управления реляционными базами данных (Relational DataBase Management Systems — RDBMS) осознали потребность в быстрых или постоянных соединениях и сейчас выпускают продукты, способные заполнить эту маркетинговую нишу. Еще один трюк состоит в использовании одного сложного SQL-запроса вместо множества мелких, результаты которых будут объединяться CGI-процессом перед отправкой пользователю. Это не только сократит время обработки запроса SQL-сервером, но и уменьшит нагрузку на CGI. Пусть база данных занимается своим делом! (Подробнее см. главу 22.) Ведение журналов Запомните одну важную вещь: не записывайте в журнал слишком много — только то, что вам действительно необходимо. Не оставляйте отладочные операторы записи в официальной версии программы. Запись в журнал из программ на Java
потребляет особенно много ресурсов вследствие необходимости преобразования всех символов из Unicode в ASCII, поэтому нужно стремиться избегать лишних записей. NSAPI и ISAPI Интерфейс программирования приложений сервера Netscape (NSAPI) — это интерфейс языка С, позволяющий работать с веб-сервером напрямую. Модули, написанные с помощью NSAPI, будут работать гораздо быстрее любого другого динамического содержимого, однако такие модули могут привести к сбою сервера. (См. введение по адресу: http://developer.netscape. com/docs/manuals/enterprise/ 40/nsapi/contents.htm.) У Microsoft имеется аналогичный продукт, конкурирующий с NSAPI. Он называется ISAPI и предназначается для информационного сервера Интернета (Internet Information Server). Введение в ISAPI можно найти по адресу: htф://www.mjcrosoft.com/msj/0498/iis/iis.htm. Объектная модель документа Объектная модель документа (Document Object Model — DOM) — это способ представления дерева тегов веб-страницы, где корневым тегом является <HTML>. Одновременно данная модель является и интерфейсом JavaScript API, позволяющим управлять этим деревом в браузере. Таким образом, разработчики содержимого получают возможность реализовать эффекты, которые раньше были невозможны без Java-апплетов, — например, сортировку таблицы по столбцу при щелчке по заголовку этого столбца, загрузку части страницы и другие вещи, известные под общим названием DHTML (динамический HTML). К сожалению, версии DOM, предлагаемые Microsoft и Netscape, не вполне совместимы друг с другом. (Подробнее см. http://www.mozJlla.org/docs/dom/.) JSP, ASP, PHP JSP, ASP и PHP — реализуемые на стороне сервера схемы интерпретации специальных HTML-тегов и написания сценариев для вставки содержимого перед отправкой страницы. Они аналогичны существовавшим ранее директивам SSI (включение на стороне сервера), которые поддерживались веб-серверами во времена «юности» веб. Их легко изучать новичкам, но все они создают трудности при обслуживании страниц. РНР — самый открытый и популярный стандарт, поддерживаемый веб-сервером Apache. (Подробнее см. http:// www.php.net/.)
Основные рекомендации О Устанавливайте таймеры в CGI. О Отправляйте что-нибудь пользователю сразу же после запуска CGI-программы. О Не пишите CGI-программы на интерпретируемых языках интерпретатора. О Демонизируйте CGI-программы. О FastCGI масштабируется гораздо лучше, чем CGI. О Используйте mod_perl, если ваши CGI-программы написаны на Perl, а ваш веб-сервер — Apache.
21 Java С некоторых пор стало общепринятым писать серверные приложения на языке Java. На то есть веские основания. Давайте займемся изучением производительности Java-программ при их использовании на веб-сайте. Язык Java никогда не будет достаточно быстрым для пользовательских интерфейсов Компания Netscape пыталась переписать свой браузер на Java и потерпела неудачу. Corel пыталась переписать Word Perfect на Java и тоже потерпела неудачу. Браузер Hotjava работал ужасно медленно. Большая часть программ для разработки на Java написана совсем не на Java. Насколько я знаю, успешных коммерческих приложений на Java с графическим интерфейсом просто нет. Число разнообразных клиентских программ для просмотра веб-страниц слишком велико, что не позволяет обеспечить приемлемый уровень оптимизации. А виртуальные машины (VM) слишком велики, чтобы быстро загружаться и запускаться по требованию. Это не означает, что успешных клиентских приложений на Java не было. Существуют, к примеру, апплеты, отображающие постоянно обновляющиеся котировки акций; такие апплеты очень полезны и эффективны, но лишь благодаря тому, что они очень малы. Дело в том, что расширения HTML, связанные со внедрением объектной модели документа, делают даже без использования Java реальными некоторые вещи, которые раньше можно было сделать только на Java, — это частичная загрузка, трехмерная графика, сортировка по столбцу и так далее. В итоге, если вы в принципе можете написать графический интерфейс на HTML, неразумно будет создавать апплет или приложение, которые будут делать то же самое, но
с большими затратами и меньшей производительностью. Вообще говоря, Java уже не является стандартным компонентом браузеров Netscape и IE. Java достаточно быстр для серверных приложений С другой стороны, язык Java принес успех корпорациям, которые занимаются разработкой на дешевых персональных компьютерах серверных приложений, работающих под управлением Linux и Windows, и устанавливают свои продукты на крупных серверах с системами Solaris и AIX. Производительность Java на сервере обычно достигает приемлемого уровня, за исключением программ, использующих RMI, CORBA и EJB, потому что все эти средства серьезно снижают производительность. Все, что творится на сервере, заранее известно разработчику и контролируется им гораздо лучше, чем великое множество клиентов. Программист получает возможность нарушать правила хорошего тона ООП и Java, которые ведут к созданию медленных программ. Кроме того, виртуальные машины на серверах не завершаются, а просто работают без остановки, поэтому затрат времени на их запуск нет. Еще одной причиной успеха Java является наличие большого количества памяти на серверных машинах, а большой объем памяти означает меньшее количество обращений к файлу подкачки и меньшее количество вызовов мусоросборщика (garbage collector — GC). Интерфейс программирования сервлетов на Java описывает процедуру загрузки и выполнения классов, занимающихся динамической генерацией страниц. Такие классы называются сервлетами. Производительность сервлетов выше, чем у CGI-программ, однако они уступают программам на С, написанным с использованием одного из серверных API. (Подробнее о сервлетах см. http:// java.sun.com/products/java-server/servlets/.) Внутренние проблемы с производительностью, присущие Java Почему же Java работает так медленно? Давайте уделим этому вопросу побольше внимания. Проверка границ массивов Java проверяет границы всех массивов при каждом обращении к ним во время работы программы. Многие ошибки времени выполнения корректно обрабатываются благодаря такой проверке, что, однако, неизбежно увеличивает время выполнения вашей программы, потому что любая операция занимает больше времени, чем ее отсутствие. Это особенно заметно в быстрых циклах. Проверка массивов — благословенный дар для многих программистов, привыкших к C/C++, где одно некорректное обращение к массиву может привести к сбою программы.
Блокирующий сетевой ввод-вывод До недавних пор в Java не было ничего подобного вызовам select() и poll(), имеющимся в Unix. Эти вызовы используются для выбора сокета, в котором содержатся данные, готовые к считыванию программой. В языке Java программист просто пытается считать данные. Если они есть, он их считывает. Если же их нет, вызов read блокируется до тех пор, пока данные не появятся. Таким образом, все вызовы read в Java являются блокирующими, то есть их приходится помещать в отдельный поток, если вы не хотите, чтобы вся программа зависала в ожидании ввода. Даже при наличии множества потоков блокирующий ввод-вывод малоэффективен. Во-первых, считывающий поток постоянно приостанавливается и возобновляется. Было бы лучше, если бы существовала функция, порождающая какое-нибудь событие при появлении на сокете готовых к чтению данных. Во-вторых, использование отдельного потока для каждого соединения серьезно ограничивает масштабируемость, потому что количество одновременных соединений становится зависимым от максимального количества потоков, которые могут выполняться в системе. Характерные значения лежат в диапазоне 1000-2000. В JDK 1.4, в данный момент проходящем бета-тестирование, имеется абсолютно новый пакет java.nio, содержащий функции, обеспечивающие неблокиру- емый ввод-вывод. Этот пакет будет обеспечивать хорошую масштабируемость на сервере. Альтернативой является открытое программное обеспечение NBIO, созданное Мэттом Уэлшем из Калифорнийского университета в Беркли. Оно реализует средства неблокируемого ввода-вывода для существующих версий JDK на платформе Unix. (См. http://wvvw.cs.berkeley.edu/~mdw/proj/java-nbio/.) Мэтт Уэлш был одним из членов экспертной группы, участвовавшей в создании пакета java.nio из JDK1.4. Некоторые производители коммерческих серверов реализуют код, обрабатывающий сетевые соединения на С в виде отдельного модуля. Интерпретация байт-кода Байт-код Java требует преобразования в «родной» машинный код компьютера перед выполнением программы на Java. Преобразование в процессе выполнения программы называется интерпретацией байт-кода. Интерпретация осуществляется достаточно медленно, но занимает меньше половины общего времени выполнения программы. Даже бесконечно быстрый интерпретатор байт-кода не смог бы уменьшить время выполнения программы более чем вдвое. Основная часть времени тратится на выполнение команд, уже записанных в «родном» машинном коде внутри виртуальной машины. Это порождение новых объектов и сбор мусора. Некоторые основные операции, такие как арифметика и работа со строками, тоже реализуются непосредственно в виртуальной машине, а не в библиотеках классов, поставляемых с ней. Поскольку виртуальная машина обычно пишется на С и оптимизируется для конкретной платформы, эти операции считаются выполняющимися с максимально возможной скоростью. Интерпретацию байт-кода на сервере можно полностью исключить, используя статические компиляторы, преобразующие байт-код в «родной» машинный код компьютера. На серверной стороне выше становится эффективность JIT-
компиляторов, потому что на сервере полезно тратить время на компиляцию, — ведь машинный код может выполняться часами или даже днями до следующей перезагрузки. На стороне клиента вся работа JIT-компилятора теряется, как только вы закрываете браузер. Верификация байт-кода Все загружаемые классы пропускаются через программу верификации байт-кода, которая защищает от опасностей, но требует значительного времени. Это не проблема на стороне сервера, где вы сами писали классы и можете им доверять. На сервере классы обычно загружаются только в момент запуска системы, а затем работают в течение длительного времени, поэтому проверка если и происходит, то выполняется один раз — при перезапуске серверного приложения. Динамическая привязка методов Методы языка Java не привязываются к отдельным участкам памяти во время компиляции в отличие от методов других компилируемых языков. Если метод не отмечен ключевым словом final, он размещается во время выполнения программы. Методы кодируются в файлах классов как строки, а не как адреса. Это обеспечивает большую гибкость и затрудняет атаки, использующие переполнение счетчика, поскольку невозможно знать заранее, в какой области памяти будут размещены методы. Однако это же означает, что существенная часть времени выполнения программы тратится на обработку строк и размещение методов, — в отличие от ситуации в С, где при выполнении происходит непосредственный переход по адресу:, заданному в процессе компиляции. Сбор мусора Сбор мусора (garbage collection — GC) должен происходить, когда приложение бездействует, но некоторые приложения, особенно серверные, никогда не простаивают в бездействии. В такой ситуации сбор мусора приводит к приостановке вашего приложения. «Синхронный» сбор мусора означает, что GC запускается тогда, когда вы его попросите. Синхронным он, впрочем, был назван неправильно, потому что вы не можете точно управлять моментом его начала, даже если выполните вызов System.gc() или эквивалентный ему Runtime.getRunti- meO-gcC). Сборщик мусора обычно работает как фоновый поток, что соответствует обычному асинхронному режиму, когда сборщик мусора запускается в моменты простоя приложения при недостатке памяти. В Java 1.3 и старших версиях разработчики получили больше возможностей управлять сборщиком мусора. Еще одна проблема связана с тем, что сборщик мусора обычно является од- нопоточным. С помощью mpstat в системе Solaris вы можете убедиться, что в процессе сбора мусора загруженным оказывается только один процессор. Если куча очень велика, однопоточный GC может создать весьма длительную задержку. IBM претендует на то, что их сборщик мусора многопоточный и, более того, способен отличать долгоживущие объекты от короткоживущих.
Косвенная адресация Чтобы добраться до переменной экземпляра, вам нужно сначала получить доступ к классу, а это значит, что требуется несколько обращений к памяти — по крайней мере, одно для получения ссылки на объект и еще одно для обращения к переменной экземпляра объекта. Поскольку скорость процессора во много раз превышает быстродействие памяти, проблема доступа к ней становится все более серьезной. Виртуальной машине приходится раскрывать несколько уровней косвенной адресации, чтобы найти класс; затем она должна проверить наличие синхронизирующих блокировок, доступность переменной в данном классе и так далее. Другие блокировки также могут влиять на производительность вашего приложения. Они устанавливаются на время работы сборщика мусора, компоновки классов, загрузки, верификации, а также на время создания и уничтожения потоков. Виртуальная машина может реализовывать эти блокировки так, как ей будет угодно, и поэтому разные виртуальные машины отличаются друг от друга по производительности. Виртуальная машина Microsoft работала значительно быстрее, чем первая реализация Sun, потому что Microsoft устранила один уровень косвенной адресации. У Sun имелись отдельные дескрипторы для данных и инструкций класса, тогда как Microsoft обошлась одним указателем на единственный блок, содержащий данные и инструкции, что, впрочем, замедляло сбор мусора. Интернационализация и локализация Интернационализация и локализация приводят к разбуханию библиотек Java из-за включения в них шрифтов, форматов, дат и других вещей, которые, возможно, никогда вам не пригодятся, двух байтовые символы Unicode удваивают длину строк по сравнению с ASCII. Это не создает таких уж больших проблем на стороне сервера, где памяти много, но усложняет работу клиентов с малыми объемами памяти. Объектная ориентированность Объектная ориентированность должна повышать производительность труда программиста, а не производительность по времени выполнения, и это очень заметно проявляется во время работы программы. Одна из проблем объектной ориентированности связана с тем, что загрузка класса в виртуальную машину приводит к загрузке всех его предков. В процессе скачивания класса по сети обязательно производится поиск родительских классов в библиотеках клиента или в Интернете. Еще одна проблема состоит в том, что создание экземпляра класса может потребовать загрузки и создания других классов, от которых зависит данный класс, причем часто бывает трудно определить, сколько именно классов будет загружено. Впрочем, и это не слишком серьезная проблема на стороне сервера, где загрузка классов должна быть выполнена лишь единожды. Рассмотрим, к примеру, создание временных объектов в Java. Консультант по этому языку Нейл Кэннон сказал мне, что всего одна команда наподобие приведенной ниже:
Integer.parselnt(new SimpleDateFormatC'yyyyMMdd").format(new Date( )))); создает около сотни временных объектов, причем все они практически сразу же уничтожаются. Если вы используете Java вместо C++, вам приходится мириться с тем, что все объекты хранятся в куче, а не на стеке. Это делается для устранения утечек памяти и повышения безопасности, но требует времени на обработку объектов кучи. Особенно плохо то, что большинство виртуальных машин заставляет все потоки бороться за последовательный доступ к диспетчеру кучи. Создание объектов осуществляется, по сути дела, одним потоком. Если вы создаете множество объектов в такой виртуальной машине, производительность вашей программы не сможет сильно возрасти с добавлением нескольких процессоров. Стековая ориентация Виртуальная машина Java хранит все локальные переменные в стеке, никак не учитывая существование регистров процессора. Это затрудняет отображение виртуальной машины на реальный процессор и использование преимуществ очень быстрых регистров. Компиляторы С могут использовать регистры для помещения в них часто используемых локальных переменных. Java хранит параметры и локальные переменные на стеке. Стек имеет неопределенный размер, поэтому его проще всего реализовать, поместив целиком в ОЗУ. Это означает, что для обращения к часто используемым переменным процессору приходится работать с ОЗУ — а оно гораздо медленнее регистров процессора. Синхронизация Java позволяет блокировать классы и методы для защиты данных от повреждений, которые могут быть вызваны одновременным обращением к ним нескольких потоков. Получение блокировки замедляет вашу программу. Использование блокировки тоже замедляет ее. Многопоточное программирование Java делает многопоточное программирование доступным даже для неопытных программистов, что, вообще говоря, не слишком хорошо. Без должной синхронизации многопоточные программы могут при большой нагрузке попадать в ситуации взаимной блокировки потоков либо повреждать данные, причем проблемы эти бывает очень тяжело найти и устранить, потому что они зависят от соотношения значений времени выполнения потоков. Если для устранения проблем будет использоваться избыточная синхронизация, программа станет работать очень медленно, потому что большинство потоков основную часть времени будет проводить в ожидании освобождения блокировки. Многопоточное программирование затрудняет понимание программ. Вместо программы, выполняемой от начала к концу, вы получаете клубок «макарон» — вне зависимости от того, насколько ясно написана программа. Потоки Java требуют планировки выполнения либо внутри виртуальной машины («зеленые» потоки — green threads), либо внутри операционной системы
(«собственные» потоки — native threads). Использовать Java в однопоточном режиме нельзя. Планировка создает накладные расходы. Сколько нужно использовать потоков в сервлете — вопрос сложный. Если потоков будет очень мало, задания для них будут слишком быстро накапливаться. В принципе, можно выбирать количество потоков в соответствии с желаемым количеством одновременных подключений к базе данных. В системе Web- logic каждое подключение к базе данных требует внимания, по крайней мере, одного потока. Так что если вы хотите, чтобы 50 пользователей могли одновременно выполнять запросы, вам нужно по меньшей мере 50 потоков. Если потоков будет слишком много, накладные расходы на планировку их выполнения поглотят большую часть ресурсов процессора. Я поставил эксперимент на системе Weblogic под управлением Solaris, сильно нагрузив сервлеты при разных значениях количества потоков выполнения Weblogic. Я измерял среднее и максимальное время получения домашней страницы при заданной нагрузке (рис. 21.1). В результате время ожидания оказалось наименьшим при количестве потоков, заданном по умолчанию A5). Когда их количество превышало 70, процессор тратил больше времени на переключение контекста, чем на реальную работу. Поэтому вам приходится выбирать: либо много потоков с низкой производительностью каждого из них, либо 15 потоков с максимальной производительностью, но ограниченными возможностями. Рис. 21.1. Минимальное время задержки достигается для 15 потоков
Советы программистам Итак, теперь мы знаем все недостатки Java. Давайте поговорим о том, как можно с ними бороться. Используйте хорошие алгоритмы Архитектура и алгоритмы вашей программы гораздо важнее любых оптимизаций на низком уровне. Плохая архитектура и плохие алгоритмы могут сделать медленной любую систему. Преждевременная оптимизация может считаться корнем всего зла в программировании (по словам Кнута), но если не учитывать производительность с самого начала, вся программа может оказаться бесполезной. Вот несколько добрых советов. О Начинайте оптимизацию с самого верхнего уровня. О Сделайте так, чтобы наиболее распространенная ситуация обрабатывалась быстрее всего (совет Амдала). О Используйте все, что знаете, о платформе и условиях выполнения программы. Правда, это в каком-то смысле противоречит требованию переносимости и может даже повредить вам впоследствии, когда изменится платформа или условия использования программы. Например, оптимизации, которые помогали до появления Hotspot JIT, будут вредны после его установки. О Последите за неработающей системой, чтобы убедиться, что она не тратит ресурсы зря, даже когда на ее вход ничего не поступает. Делайте цепочки наследования короткими Стоимость создания объекта возрастает с увеличением цепочки наследования этого объекта. До того как объект будет создан, все его «предки» должны быть загружены в систему. Использование апилетов или RMI с объектами, имеющими длинную родословную, может вызывать большой рост сетевого трафика. С другой стороны, короткая цепочка наследования противоречит основным принципам объектно-ориентированного программирования (ООП). Я бы пожертвовал принципами ООП, но не стал писать очень медленную программу Вам в любом случае придется мириться с накладными расходами на ООП в Java. Даже для простейшего класса Java вам потребуется порождать объект. Вот пример: class Nothing {} Этот класс отлично компилируется и порождает объект java.lang.Object: % javap -с Nothing Compiled from Nothing.java class Nothing extends java.lang.Object { NothingC ); Method NothingC ) 0 aload J)
1 invokenonvirtual #3 <Method Java.1ang.Object.<init>( )V> 4 return } Файл Nothing.class, полученный в системе Linux с помощью компилятора chapman:10/12/12-23:12, имеет размер 234 байт, а компилятор JDK 1.2.2 в системе Solaris порождает класс размером 259 байт. Параметр -О делает размер класса равным 204 байт в системе Linux, но не уменьшает его в Solaris. Этот класс запустить нельзя, потому что у него нет функции main(), однако добавление main привело бы лишь к добавлению байт-кода функции return. Сравним это с языком С. Напишем программу nothing.c: main( ) {} Скомпилировав ее в Linux с помощью дсс, я получил файл a.out размером 3695 байт, состоящий в основном из стандартных функций ввода-вывода. Вы можете запустить эту программу, хотя она и не будет ничего делать. Ключи -ОЗ и -04 никак не влияют на размер программы. Используйте стековые переменные Переменные классов требуют большего количества уровней косвенной адресации и создаются дольше, чем стековые. Объединяйте классы Ценность объединения классов зависит от того, к чему вы стремитесь. Один большой класс может содержать большой объем бесполезного кода; но, с другой стороны, вам нужно будет загрузить и инициализировать только один класс. Аналогичным образом, если у вас будет несколько больших классов, вы достигнете небольшого прироста производительности, потому что виртуальной машине не придется загружать множество классов, хотя это и считается плохим стилем в ООП. Следует уменьшать не только количество классов, но и количество объектов. Используйте класс повторно, если это возможно, а не порождайте его заново. Даже небольшой класс, использованный повторно, даст более высокую производительность, чем порожденный заново. Разработчики HotSpot утверждают, что в их компиляторе этот метод не сработает. Вы можете уменьшить время начальной загрузки апплета, но при этом замедлить его выполнение динамической загрузкой нужных классов во время работы программы с помощью вызова Class.forname() или других методов. Таким образом, вы получаете очевидные преимущества перед вариантом с длительной начальной загрузкой: ненужный вам код просто не загружается. С другой стороны, вам придется устанавливать TCP-соединение для каждого из загружаемых в процессе выполнения классов, поэтому чем меньше их будет — тем лучше. Если у вас имеется больше 2-3 классов, вы наверняка захотите поместить их в один файл .zip или .jar, который будет загружаться по одному ТСР-соедине-
нию. Улучшение модульности программы путем помещения взаимозависимых или родственных классов в один файл .dass, пакет или .zip-файл может дать преимущество благодаря большей локальности ссылок. Часто возникает потребность в коде, имеющем отношение к выполняемому в данный момент, поэтому если код будет поблизости, это снизит временные затраты на его поиск. Аккуратно используйте пакеты из Сети. Примитивные реализации регулярных выражений, к примеру, могут работать невероятно медленно. Используйте всю имеющуюся информацию, уточняя регулярные выражения. Однажды я писал программу для поиска последовательности символов, которая должна была находиться в конце строки, и производительность стала в 70 раз лучше, когда я добавил в строку поиска символ конца строки ($). Используйте библиотеки Java Обычно бывает проще и быстрее использовать уже написанные функции, чем пытаться заново реализовать их. Например, drawPolygon() работает быстрее, чем последовательность вызовов drawLine(), рисующая ту же картинку. Не опрашивайте Не опрашивайте источники событий, потому что это приводит к затратам ресурсов. Используйте объекты-«слушатели» (event listeners), особенно при работе с RMI. «Финализируйте» методы Поскольку «нефинализированные» методы привязываются во время выполнения, объявляйте методы с помощью директивы final везде, где это возможно, то есть там, где вы знаете, что не станете изменять метод в дочернем классе. Если можно, то финализируйте весь класс целиком. Это особенно важно в больших циклах. С другой стороны, разработчики HotSpot утверждают, что при работе с их системой никакого выигрыша от финализации методов не будет. Если можете вовсе избавиться от метода, включив его содержимое в код другого метода (раскрытие функций), вы избежите накладных расходов на помещение информации в стек и снятие ее оттуда. Создавайте поменьше объектов Используйте объекты повторно везде, где это возможно. Правда, мне известна одна статья, посвященная производительности Java, показывающая, что стоимость синхронизованного извлечения объекта из массива приблизительно совпадает со стоимостью создания объекта с небольшой родословной и без переменных экземпляров. Если вы используете повторно только один объект, сделайте его статическим и напишите для него функцию reinitialize(). Убедитесь, что ваш объект безопасен в многопоточной среде, потому что потоки могут одновременно выполнять один и тот же участок кода.
Библиотеки Java нередко создают ненужные объекты. В некоторых виртуальных машинах запись числа в поток вывода на экран часто приводит к созданию нового объекта для каждого символа, а затем объекта для строки целиком. Сингал (Singhal) утверждает, что программам, работающим с сетью, приходится создавать новые объекты DataGramPacket для каждого принимаемого пакета UDP. Опасайтесь утечек объектов То, что в Java нет указателей в традиционном смысле, не означает, что программист не может потерять все ссылки на объект. Особенно велика вероятность создания множества неисчезающих объектов в повторно вызываемых функциях. Эта проблема имелась у ORB фирмы Visigenic с вызовом orb.init(). Средства профилирования типа j Probe и Optimizelt помогут вам обнаружить утечки подобного рода. Попробуйте не пользоваться методами для работы с переменными В ООП считается хорошим тоном писать методы для доступа к переменным экземпляра, не разрешая прямой доступ к ним, однако это увеличивает накладные расходы, потому что добавляет в программу лишний вызов метода. Методы доступа должны скрывать реализацию get и set и позволять дочерним классам изменять синхронизацию get и set, но за это приходится платить. Используйте сложные операторы Сложные операторы типа п += 4 выполняются быстрее, чем n = n + 4, потому что они порождают меньше команд байт-кода. Оптимизирующий компилятор должен уметь создавать сложные операторы за вас. Поразрядный сдвиг выполняется быстрее, чем умножение, но и это компилятор должен уметь делать сам. Наконец, умножение выполняется быстрее, чем возведение в степень. Используйте шаг типа int Шаг типа int обрабатывается быстрее, чем шаг типа short или byte. Я не знаю, почему это так, но с использованием JIT-компиляторов разница становится еще более заметной. Возможно, процессоры оптимизированы для выполнения операций с 32-разрядными целыми числами. Числа с плавающей точкой обрабатываются гораздо медленнее, чем любые целые. Это, судя по всему, связано с накладными расходами на выполнение операций с плавающей точкой. Причем операции с типом Double выполняются несколько медленнее, чем с типом Float.
Следите за скоростью доступа к различным переменным Вот список категорий переменных в порядке убывания скорости доступа: О локальные стековые переменные; О экземплярные переменные наднадкласса (родителя родителя); О экземплярные переменные надкласса (родительского класса); О экземплярные переменные данного класса; О статические переменные класса. Иногда повышению производительности помогает копирование медленных переменных в быстрые, если вы собираетесь выполнять с ними много операций (например, перед циклом). Битовый сдвиг выполняется в 1,5-3 раза медленнее, чем чтение локальной переменной. Локальные переменные быстрее, чем переменные класса Приведенная ниже команда 1 - 17; выполняется быстрее, чем эта: this.i - 17: Дело в том, что переменные класса требуют обращения к самому классу перед обращением к переменной внутри него. JIT-компиляторы могут помещать локальные переменные в регистры, которые работают очень быстро. Это еще больше повышает производительность. Переменные класса быстрее, чем массивы Операция this.i - 17; выполняется быстрее, чем аггау[0] - 17; Поскольку каждое обращение к массиву требует проверки его границ, лучше присвоить значение элемента массива локальной переменной, особенно если вы собираетесь работать с этим значением в цикле. Это называется удалением инвариантов из цикла (loop invariant code motion), поскольку вы выносите неизменные операции наружу из цикла, вместо того чтобы выполнять их при каждом его проходе. Обращение к массиву часто осуществляется медленнее, чем к переменным класса.
Используйте собственные методы Если для вас важна производительность, вы можете написать программу на компилируемом языке типа С и подключить ее к программе на Java посредством интерфейса собственных методов. Вам может показаться, что это ведет к потере переносимости программ на Java, но на самом деле нетрудно включить альтернативные методы Java, которые будут использоваться при переносе ваших классов на платформу, не поддерживающую ваши собственные методы. Примеры применения этого приема вы можете найти по адресу: http://www.javaworld. com/javaworld/javatips/jw-javatipl3.html. Короче говоря, вы должны попытаться подключить собственный метод, а если это не сработает — альтернативный метод на Java. Используйте тайм-ауты сетевой подсистемы Устанавливайте тайм-ауты для сокетов (TCP_NODELAY, SO_TIMEOUT), особенно при работе с DNS-серверами. Это предотвратит зависание вашей программы. Буферизуйте ввод-вывод Типичная ошибка — забыть о необходимости буферизации чтения и записи. В результате операции чтения или записи 1 байт выполняются по 1000 раз вместо выполнения одной операции с целым буфером. Такие ошибки легко отловить с помощью трассировщика системных вызовов (strace в Linux или truss в Solaris). В главе 17 приведен пример трассировки побайтовой записи. Используйте сокеты вместо URL Подключиться к URL по протоколу HTTP в Java достаточно легко, но если вам нужно передавать не HTML, а другие данные, прямое подключение через сокет обеспечит вам несколько большую производительность. Это особенно полезно, если вам нужно передать несколько файлов, потому что одно и то же ТСР-сое- динение будет использоваться для всех них. Еще большего повышения производительности можно добиться путем использования UDP-сокетов, хотя этот протокол и ненадежен: вам придется самостоятельно проверять принятые данные на цельность. Используйте UDP Используйте UDP вместо TCP, если скорость для вашего приложения важнее, чем точность. Эта рекомендация относится не только к Java, но и к другим языкам. Использование UDP в Java ограничено необходимостью создания нового объекта для каждого пакета UDP.
Используйте потоки Потоки на Java программировать гораздо легче, чем на С или C++. Это очень хорошо, потому что многопоточность позволяет создавать несколько последовательностей выполнения внутри одной программы, что весьма важно для высокопроизводительных приложений на Java. Одна из причин, по которой потоки так важны для производительности Java, заключается в том, что до версии Java 1.4 все операции ввода-вывода в рассматриваемом языке были блокирующими (потоку приходилось ждать завершения операции чтения или записи). Поэтому приходилось использовать несколько потоков, если программист не хотел, чтобы его приложение зависало в ожидании, например, приема данных по медленной сети. Если вы выделите операцию ввода-вывода в отдельный поток, остальная программа сможет выполняться в других потоках, пока тот отдельный поток будет заблокирован. Поток, осуществляющий ввод-вывод, может уведомлять прочие потоки о завершении своих действий с помощью удачно названного метода notify(). Потоки обладают тем преимуществом, что взаимодействие между ними осуществляется очень быстро посредством общих переменных. Они могут выполняться параллельно на многопроцессорных машинах, занимают не так много памяти и очень быстро переключаются. Выполнение всех приложений и апплетов начинается с одного родительского потока. Создав и запустив дочерние потоки, вы можете заставить родительский прекратить управление с помощью вызовов suspend() или sleep(), чтобы дочерние работали быстрее. Учтите, что модель реализации потоков в Java зависит от операционной системы и способа взаимодействия с ней виртуальной машины. Например, в системе Unix «зеленые» потоки используют приоритетную многозадачность, тогда как в Windows потоки должны самостоятельно отдавать друг другу ресурсы. Отсюда возникают различия в поведении программ на разных платформах, если управление потоками будет недостаточно продуманным. Производительность потоков также зависит от платформы. Ранние версии Java не могли выполняться на нескольких процессорах (SMP), a Java 2 (по крайней мере, версия для Unix) теоретически может распределять потоки по процессорам, что должно приводить к хорошей масштабируемости приложения. В реальности же схема срабатывает не всегда (см. главу 16). Далее, «зеленые» потоки не всегда работают медленнее собственных. Виртуальной машине с «зелеными» потоками не приходится делать системные вызовы, чтобы управлять потоками, однако такую машину труднее реализовать, потому что для всех блокирующих системных вызовов должны быть написаны функции-обертки. «Зеленые» потоки могут оказаться неспособными использовать все процессоры компьютера с SMP, но можно запустить несколько машин и спокойно загрузить все процессоры. Помните, что вы можете присваивать разным потокам различные приоритеты. Увеличивайте приоритет жизненно важных потоков, понижая приоритет всех прочих. Виртуальная машина Java не гарантирует, что ваши потоки не будут зависать. Зависание — это ситуация, когда несколько потоков ждут событий, кото-
рые могут быть порождены только ими. Вы должны самостоятельно использовать ключевое слово synchronized и классы Monitor, чтобы гарантировать, что зависания не произойдет. Синхронизированные методы выполняются несколько медленнее, чем методы без синхронизации, однако синхронизация обязательна для безопасной работы потоков. Используйте notify Используйте notify вместо notifyAII везде, где это возможно, потому что вызов notifyAII гораздо дороже. Используйте синхронизацию как можно реже Синхронизация обязательна для корректной работы многопоточных программ, однако она не бесплатна, и по возможности ее следует избегать. Чем больше у вас потоков, тем хуже будет влиять синхронизация на производительность, однако тем важнее она будет для правильной работы программы. Вместо того чтобы использовать синхронизацию, вы можете управлять доступом к данным из самого приложения или просто писать однопоточный код. Синхронизация может приводить к еще большему замедлению кода при использовании JIT. Программа выделения памяти тоже является синхронизированной, и поэтому на нее уходят ресурсы. Синхронизация по умолчанию блокирует текущий объект, то есть ключевое слово synchronized означает synchronized(this). Вы можете получить выборочную блокировку, создавая блокировочные объекты и синхронизируя методы при обращении к этим объектам. Изначально синхронизация осуществлялась именно таким образом, но компилятор HotSpot снизил накладные расходы на синхронизацию; она теперь осуществляется путем изменения одного-единственного бита, что делается очень быстро, однако этот метод ускорения работает только для synchronized(this), а не для синхронизации посредством других объектов. Вы можете достичь некоторого повышения быстродействия, переписав библиотеки Java или код других фирм так, чтобы синхронизация в нем использовалась как можно меньше, если вам не нужно, чтобы ваши программы были безопасными в многопоточной среде. Например, объекты Vector.elementAt() и Enumeration. nextltem() являются синхронизированными, но вы можете написать свои собственные классы, которые будут решать те же задачи, только без синхронизации. Используйте классы библиотеки Collection (в Java 1.2 и более новых версиях) вместо старых классов java.util.*. Классы из этой библиотеки не содержат внутренней синхронизации, поскольку ориентированы на повышенную производительность; впрочем, они позволяют программисту при необходимости применять к ним внешнюю синхронизацию. Вы можете повысить производительность цикла, использующего синхронизированный класс, поместив этот цикл целиком внутрь блока, синхронизируемого с этим классом. Таким образом, каждый поток будет получать шанс закончить цикл, прежде чем ему придется отдавать блокировку другому потоку.
Не помещайте синхронизируемые методы внутрь циклов Классы библиотеки ввода-вывода активно пользуются синхронизацией, поэтому лучше выполнять все операции ввода-вывода подряд, в одном блоке, не помещая их в цикл, потому что иначе при каждом проходе цикла на установку и снятие блокировок будет теряться время. По той же причине следует считывать все содержимое потока (например, с помощью метода readFullyO), а любые преобразования типов применять позднее, вместо того чтобы считывать данные в цикле по порциям и преобразовывать их сразу же. Следите за родительским потоком Возможно, вам придется явно указать родительскому потоку на необходимость передать управление дочерним с помощью методов suspend() или sleep(), иначе вы не сможете добиться от дочерних потоков приемлемой производительности. Обратный отсчет бывает быстрее прямого Виртуальная машина может выполнять быструю операцию «ветвление при нулевом значении» (branch on 0), а не несколько последовательных операций, означающих «ветвление при условии что, одно не равно другому». Уменьшайте количество строк Если вы попробуете профилировать свою программу при помощи Optimizelt, первое, что вы заметите, — великое множество объектов типа String. Строк будет много по разным причинам. Модель событий Java 1.02 основана на строках. Библиотеки Java часто используют строки. У всех объектов имеется метод toSt- ring, поэтому с ними связываются объекты типа String. JSP работает быстрее, чем жесткое кодирование строк в сервлетах, потому что значительная часть операций со строками выполняется в процессе компиляции, а не во время выполнения программы. В противном случае Java-программа должна была бы вызывать метод charToByteConvertor, создавая поток вывода для каждого оператора print. Используйте строчные буферы или массивы Если вам приходится выполнять много операций со строками, используйте объекты типа StringBuffer, а не String, потому что расширение строки обязательно требует копирования ее целиком, тогда как расширение объекта типа StringBuffer часто осуществляется посредством заполнения уже выделенного пространства. Добавление в StringBuffer также осуществляется несколько быстрее, чем сложение строк оператором +, который сначала создает объект типа StringBuffer, помещает в него оба аргумента, а затем преобразует получившийся объект обратно к типу String.
Байтовые массивы работают быстрее, чем строчные буферы, по нескольким причинам. Особенно сильно это проявляется при использовании метода System. arraycopy(). В типичных операциях при работе с протоколами Интернета большая часть операций выполняется с отдельными байтами. Храните подобные данные в байтовых массивах, а не в строках. В создаваемой официальной версии JDK 1.4 будет пакет Java.nio, содержащий буферные классы для работы с байтами. Берегитесь медленных шрифтов Скорость прорисовки у разных шрифтов разная. По какой-то причине шрифт NY Times отображается во время выполнения программы гораздо быстрее, чем некоторые другие. Это может быть связано с тем, что отдельные шрифты встроены в виртуальную машину, тогда как обращение к другим требует загрузки шрифта и работы с косвенной адресацией. Упрощайте метод Paint Метод paint() должен быть максимально упрощен, потому что он будет вызываться постоянно. Если в вашем методе paint() слишком много расчетов, пользователи будут мучиться, ожидая, пока ваш апплет или приложение перерисует свое окно. Это очень важно, потому что вызовы paint() помещаются виртуальной машиной в очередь, если они не могут быть выполнены немедленно. Если вы напишете большой метод paint(), а пользователь решит прокрутить окно или каким-либо иным образом потребовать множество перерисовок, он наверняка закроет ваше приложение с отвращением, потому что ему надоест ждать, пока вызовы repaint() будут медленно выполняться, заставляя экран мерцать и мешая пользователю делать что-то другое. Эта проблема особенно заметна в Windows. Если вам приходится выполнять в методе paint() множество расчетов, используйте обрезку, то есть перерисовывайте только изменившуюся часть экрана, чтобы дать своему приложению шанс быть востребованным. Разумеется, вычислительные затраты на перерисовку квадрата возрастают пропорционально площади этого квадрата. Двойная буферизация обеспечит плавность анимации Используйте двойную буферизацию вывода на экран везде, где это возможно, чтобы анимация была плавной. Рисуйте картинку на виртуальном экране, где это происходит быстрее, а затем копируйте ее в экранную память. Пусть система отлавливает ошибки за вас Если вы предполагаете, что ошибки будут возникать редко, не тратьте время на проверку их на уровне приложения, так как виртуальная машина все равно
будет «отлавливать» их за вас. Нет смысла проверять выход за границы массива, если имеется исключительная ситуация ArraylndexOutOfBoundsException. Поскольку эта проверка будет выполняться в любом случае, вы можете с ее помощью даже завершать циклы, исключая явную проверку их условия. Например, вместо такого цикла public class test { public static void main(String[] args) { int array[] - new mt[1000000]: for (int i-0: i<array.length; i++) { array[i] - i: } } } вы могли бы написать такой: public class test { public static void main(String[] args) { int array[] - new int[1000000]: try { for (int i-0: : i++) { array[i] - i: } } catch (ArraylndexOutOfBoundsException aioobe) {} } ) Первая программа выполняется на старом компьютере Pentium 233 за 1,5 с, а вторая — за 1,1 с. Однако еще быстрее будет записать границу массива в локальную (стековую) переменную, поэтому наш пример не слишком практичен. Еще один пример — исключение вызова instanceof и замена его вызовом cast для объекта и обращением к его методу с перехватыванием исключительной ситуации ClassCastException. Исключительные ситуации стоят дорого. Это не создает проблем, если они возникают редко, но использовать их в качестве основного средства при написании программ не рекомендуется. В конце концов, не зря эти ситуации названы исключительными. Не преобразуйте даты и время Для некоторых приложений, часто работающих с датами, полезно бывает выдать местный часовой пояс за гринвичский, чтобы они не выполняли никаких преобразований. Например, в старом веб-сервере Java нужно было устанавливать параметр log.time=GMT. Тогда каждое обращение к серверу больше не требовало преобразования даты, и сервер начинал работать значительно быстрее.
Берегитесь RMI, EJB и CORBA Распределенные системы объектов замечательно выглядят как концепции, но работают очень плохо. В большинстве виртуальных машин сборка выполняется крайне медленно. Если вам приходится выполнять сборку, используйте ключевое слово transient для тех экземплярных полей, которые не должны попадать в эту сборку. Одна из альтернатив сборке — использование интерфейса Extemalizable и написание своих собственных подпрограмм сборки, но тогда вам придется поработать. Еще одна альтернатива — не передавать никаких объектов в качестве параметров. Прочие проблемы включают избыточное копирование данных, загрузку всех требуемых надклассов по сети, а также недооценку времени ожидания сети, потому что разработчики обычно тестируют все на одном компьютере — на том же, где разрабатывают, — и там у них все работает прекрасно. Питер Дойч из Bunyip писал: Практически все программисты, впервые создающие распределенное приложение, делают восемь предположений, которые в конце концов оказываются неверными и приводят к большим неприятностям: сеть надежна, время ожидания равно нулю, пропускная способность бесконечна, сеть защищена, топология ее не меняется, в сети один администратор, стоимость передач нулевая, сеть однородна. Нетрудно увидеть, что все предположения являются ложными, однако разработчик, у которого клиент и сервер расположены на одном компьютере, страдает от необоснованной уверенности в истинности этих предположений. Одна из причин, по которым сеть работает так хорошо, заключается в том, что пользователь знает, когда он обращается к далекому серверу, и не ждет от него быстрого ответа. Компиляторы Каким бы компилятором вы ни пользовались, используйте последнюю доступную версию. Компиляторы с каждым следующим поколением порождают все более совершенный код. Компиляторы могут повышать производительность следующими методами. О Вынесение инвариантов цикла — все, что не меняется внутри цикла, должно быть вынесено наружу, чтобы избежать повторных вычислений. Это называется «вынесением инвариантов цикла» — и не случайно. О Удаление одинаковых выражений — нечто вроде вынесения инвариантов цикла. Сложные расчеты выполняются лишь единожды, после чего их результат сохраняется в локальной переменной. Объем байт-кода может возрасти, но расчетов станет меньше. О Упрощение — это использование конструкций, которые дают более короткий байт-код или меньшее количество ссылок (например, +=). Другие примеры: □ создание одномерного массива, содержащего столбец двухмерного массива. С одномерным массивом вычисления выполняются быстрее, потому
что это экономит операции iload (загрузка целого в локальную переменную) и aaload (загрузка ссылки на массив) для каждого обращения к массиву; О использование super() для обращения к суперклассу и работы с полями, определенными в этом классе. Позволяет компилятору применять команду aload (загрузка ссылки из локальной переменной) вместо getfield (получение поля объекта). О Объявление переменных. Первые четыре численных переменных или аргумента обрабатываются меньшим объемом байт-кода, поэтому вы можете ускорить работу программы, объявив наиболее часто используемые переменные в первую очередь. Оптимизация Используйте параметр -О компилятора javac, но делайте это аккуратно. При получении этого параметра компилятор автоматически выполнит раскрытие всех ваших финализированных, закрытых (private) и статических методов (то есть их вызовы будут заменены кодом самих методов, что позволит избежать затрат на помещение текущего состояния в стек, однако увеличит объем вашего кода). Учтите, что оптимизация может выявить скрытые ошибки в вашей программе. Это связано с тем, что оптимизатор строже относится к синтаксису программы, но может быть вызвано и ошибками в самом оптимизаторе. Он, к примеру, может раскрыть какой-нибудь метод, который раскрывать не следовало. После оптимизации необходимо вновь тщательно протестировать код. Однажды мне пришлось столкнуться с программой, которая без оптимизации компилировалась за час, а с оптимизацией — за три дня, причем после этого она просто отказалась работать. Существует и коммерческое средство «Dash О». Оно изменяет порядок байт- кода после компиляции, оптимизируя то, чего не может улучшить компилятор. (См. http://vvvvw.preemptive.com/DashO/index.html.) Профилируйте свой код Профилирование на Java осуществляется, например, с помощью параметра -prof, указываемого при вызове виртуальной машины: % java -prof MyClass.Java Профилирование будет учитывать реальное время выполнения, однако оно не дает вам информации о том, сколько раз выполняется конкретная последовательность команд байт-кода. В результате работы виртуальной машины получается файл, не вполне доступный для чтения человеком. Для интерпретации файла имеются бесплатные программы, например Hyperprof. Они скажут вам, какая часть кода выполнялась большую часть времени. Именно на ней вам надо будет сосредоточить особое внимание в процессе оптимизации программы. Параметр -hprof позволяет профилировать кучу и процессор, однако его использование приводит к десятикратному увеличению размера кода и времени
его выполнения. Параметр -hprof исключает использование JIT-профилиров- щика. Перечисленные ниже средства позволяют не только профилировать ваш код, но и отображать результаты в удобном для восприятия формате: О Visual Quantify for Java фирмы Rational; О JavaSpec отдела JavaTest фирмы Sun; О Optimizelt (http://www.optimizeit.com/) — лучший из известных и самый простой в использовании пакет; О jProbe фирмы The KL Group (http://www.klgroup.com/). Версия Enterprise позволяет профилировать удаленные приложения; О Metamata; О HAT (Heap Analysis Tool) фирмы Javasoft. Бесплатный, но неподдерживаемый продукт. Если вы занимаетесь профилированием и программа сообщает вам, что она не может обратиться к откомпилированному коду, дело может быть в том, что вы запустили JIT-компилятор и профилировщик одновременно. Попробуйте не запускать JIT-компилятор. Полезно бывает запустить консоль Java в Netscape и нажать клавишу 9 в окне консоли. На экран будет выведена подробная статистика о работе апплета. Нажмите клавишу ?, чтобы получить список всех предоставляемых консолью возможностей. Консоль эта может быть очень полезна. JVMPI В Java 2 имеется стандартный интерфейс профилирования Java VM Profiling Interface, но он предназначен для разработчиков средств профилирования, а не для программистов, пишущих приложения на Java. Декомпиляторы Поскольку Java помещает имена методов и классов в байт-код для облегчения динамического построения программы, вы можете декомпилировать класс и увидеть практически все его содержимое, за исключением имен локальных переменных. Вот несколько методов декомпилирования файлов классов. О javap -с выводит названия команд байт-кода, но не исходный код Java. Программа javap поставляется с JDK. О Mocha способна выводить исходный код Java. Эту программу можно скачать по адресу: http://patrick.net/software/. О Программа SourceAgain тоже может выводить исходный код Java. Существуют специальные средства, затрудняющие чтение кода после деком- пиляции.
Средства профилирования на уровне операционной системы Не бойтесь применять к Java-процессам более традиционные средства профилирования. Java-процесс является точно таким же процессом, как и любой другой, поэтому передаваемые им данные можно перехватить с помощью snoop (входит в состав Solaris), а вызовы виртуальной машины можно отследить с помощью truss (Solaris) или strace (Linux). Я все еще надеюсь, что кто-нибудь напишет программу, которая будет отображать все вызовы методов Java по мере их выполнения. ЛТ-компиляторы JIT-компиляторы (Just In Time — JIT) преобразуют участки байт-кода (от одной инструкции до целого метода) в эффективный «родной» код процессора по мере выполнения байт-кода. В следующий раз, когда дело доходит до того же участка кода, вместо него сразу запускается откомпилированный «родной» код. Например, циклы в JIT-компиляторах выполняются гораздо быстрее, потому что виртуальная машина больше не интерпретирует байт-код на каждой итерации цикла. При первом проходе цикла возникает небольшая задержка, связанная с работой компилятора, однако второй и последующие проходы выполняются быстрее. JIT-компиляторы обычно значительно повышают производительность, но помните, что они ускоряют только повторяющиеся операции и никак не помогают работе графического интерфейса пользователя. Такой код может даже замедлиться от подключения JIT-компилятора. Проблема заключается в том, что нет смысла компилировать код, который будет выполнен лишь однажды; тем не менее JIT-компиляторы недостаточно «умны», чтобы выбирать, что нужно компилировать, а что нет, поэтому они перерабатывают все подряд. Компилятор HotSpot фирмы JavaSoft ведет себя по-другому. HotSpot собирает статистику во время работы программы и в соответствии с ней компилирует только те части кода, которые выполняются много раз (активные участки — hot spots). Это позволяет ускорить даже GUI-приложения. JIT-компилятор не может ускорить выполнение кода, который и так является «родным», как, например, реализация некоторых методов библиотеки java.lang. JIT-компиляция не ускоряет создание объектов, потому что тоже выполняется виртуальной машиной, написанной в «родных» машинных кодах. JIT-компиляторы плохо работают с синхронизированными участками кода. Вот список некоторых JIT-компиляторов, их адреса, платформы и сведения о доступности. О Apple (http://www.applejava.apple.com/). Виртуальная машина Apple Mac OS Runtime for Java MRJ2.0 включает JIT-компилятор для Java 1.1.3. Ее можно скачать бесплатно. Она входит в состав MacOS 8.1. О DEC (http://www.digital.com/java). JDK 1.1.5 только для Digital Unix V4.0x. Это единственная 64-разрядная реализация Java. Распространяется бесплатно.
О HP (http:// www.hp.com/esy/go/java.html). JDK 1.1 только для HPUX. Распространяется бесплатно. О Kaffe (http://www.kaffe.org/). Для компьютеров Alpha, 68K, PowerPC, MIPS, Sparc, x86. Распространяется бесплатно. О Microsoft (http://www.microsoft.com/visualj). Internet Explorer для Windows и Mac. Распространяется бесплатно. О Netscape (http://www.netscape.com/). Windows 3.1/95/NT, Mac, Solaris. Коммерческая программа. О SGI (http://cosmo.sgi.com/code/index.html). Irix. Коммерческая программа. О Sun (http://www.sun.com/workshop/java/jit). Windows 3.1/95/NT и Solaris. Распространяется бесплатно. О Symantec (http://www.symantec.com/javacentral/index.html). Windows 95/NT и Mac. Коммерческая программа. Статические компиляторы Программу на языке Java можно откомпилировать в «родной» код процессора и подключить к получившемуся исполняемому файлу библиотеку со сборщиком мусора. Это называется статической компиляцией. Статическая компиляция противоречит ортодоксальной «религии» Sun, потому что Sun боится, что программы на Java будут компилироваться и оптимизироваться для Windows, но на самом деле не стоит следовать политике Sun, занимаясь разработкой на стороне сервера, где программы на Java не требуют сильной переносимости. Компиляция и оптимизация будут выполняться гораздо лучше, если у вас будет на это достаточно времени. JIT-компиляция выполняется «на лету», поэтому у компилятора имеется меньше возможностей улучшения кода. Есть два способа статической компиляции Java: можно сначала преобразовать Java в С, а затем откомпилировать С стандартными компиляторами, а можно непосредственно скомпилировать программу на Java в исполняемый машинный код. Вот список программ для статической компиляции: О Harissa (http://www.irisa.fr/compose/harissa/harissa.html); О j2c (http://www.webcity.co.jp/info/andoh/java/j2c.html); О JCC (http://www.geocities.com/CapeCanaveral/Hangar/4040/jcc.html); О ТоЬа (http://www.cs.arizona.edu/sumatra/toba/; только приложения); О TowerJ (http://www.towerj.com/). Используя одну из этих программ, помните, что получающийся исполняемый файл не будет переносимым и его придется подключать к библиотеке сборщика мусора, что обычно выполняется виртуальной машиной. Кроме того, вы, скорее всего, потеряете возможность динамически загружать обычные классы Java (те, которые не скомпилировали заранее). Если вы предпочитаете получать
исполняемые файлы, компилятор Java фирмы Microsoft будет рад предложить вам свои услуги, как и компилятор Symantec Cafe Pro 2.0. Виртуальные машины Производительность виртуальных машин постепенно возрастает с течением времени, поэтому стоит установить самую современную версию для вашей платформы. Обработка событий осуществляется в Java 1.1 гораздо быстрее, чем в Java 1.02. В качестве примера возможных улучшений я решил привести список различий виртуальных машин Java 1.1 и 1.2 фирмы Sun. О У каждого потока имеется собственный кэш кучи и монитора, что уменьшает накладные расходы на блокировку и синхронизацию. О Загружаемые классы могут использовать алгоритмы сжатия памяти и совместно использовать объекты типа String. О Скорость выделения объектов значительно возросла, как и быстродействие сборщика мусора. О JDK 1.2 не использует дескрипторы, то есть указатели на указатели. В нем применяется только один уровень косвенной адресации. Это ускоряет обращение к объектам и позволяет избежать фрагментации памяти. Если вы знаете, что ваша программа будет выполняться на конкретной платформе, — например, потому, что вы пишете серверное приложение, — убедитесь, что у вас имеется самая последняя виртуальная машина для этой платформы. Лучше выбирать виртуальную машину, написанную производителем операционной системы, потому что именно он наверняка лучше всех знает, как оптимизировать Java под свою операционную систему Используйте MRJ на компьютерах Macintosh, DEC VM в Digital Unix и так далее. SunSoft делает самые быстрые виртуальные машины для Solaris, поддерживающие собственные потоки и JIT-компиляцию, однако Sun производит и «ссылочную» виртуальную машину от Javasoft, которая работает гораздо медленнее. Быстрая виртуальная машина поставляется с системой Solaris. Реализация виртуальной машины Java 2 умеет не только расти в размерах, но и уменьшаться. Раньше виртуальные машины могли только расти или сохранять размер постоянным. Microsoft производит самые быстрые виртуальные машины для Windows, но будьте аккуратны с ними, иначе вы сами не заметите, как начнете писать код, который не работает нигде, кроме Windows. Для Linux имеется множество бесплатных виртуальных машин: http://www. kaffe.org; The Blackdown VM (http://www.blackdown.org/), The Sun VM, The IBM VM и еще одна с сайта http://www.hungry.com/. Самые популярные машины для Linux — это Blackdown JVM и IBM JVM для JDK 1.2. Виртуальная машина Sun JDK 1.2 плохо поддерживает собственные потоки, хотя в версии Java 1.3 их поддержка уже реализована вполне прилично. Некоторые неудачные реализации виртуальных машин могут вовсе не заниматься сбором мусора. Это значит, что рано или поздно у вас закончится память и виртуальная машина остановится.
Параметры времени выполнения У виртуальной машины Java имеются определенные параметры времени выполнения, о которых стоит знать. Они обсуждаются в последующих подразделах. -verbosegc Параметр -verbosegc заставляет Java выводить больше сведений о процессе сбора мусора. Этот параметр можно указывать до 3 раз, увеличивая уровень детализации. Так можно обнаруживать источники проблем, связанных со сбором мусора. -noverify По умолчанию верификация байт-кода выполняется для всех классов, загружаемых по сети, но не для локальных классов (то есть, к примеру, она не выполняется при работе приложения на сервере). Верификация подтверждает соответствие байт-кода спецификациям Java. Автоматическую верификацию можно заменить ручной, выполняемой командой Java -verify класс после компиляции класса. Скоро, наверное, можно будет отключать верификацию байт-кода в браузерах (для приложений она отключена по умолчанию). Это будет создавать угрозу вашей безопасности, зато вы будете выигрывать в производительности. -Xmsn и -Xmxn Параметры -Xmsn и -Xmxn (устанавливающие начальный и максимальный размеры кучи соответственно) могут быть очень полезны. Установите начальный размер кучи в соответствии с требованиями вашей программы. Предлагаемое по умолчанию значение в 1 Мбайт очень мало для приложений класса сервера, а недостаток места в куче будет приводить к работе сборщика мусора при запуске приложения. Максимальное значение размера кучи в 64 Мбайт тоже мадо для серверных приложений. Увеличение его позволит избавиться от исключительных ситуаций OutOfMemory. Сделайте Рай побольше В Java 2 реализован сбор мусора по поколениям. Объекты сначала создаются в участке памяти, называемом «Eden* (Эдем, Рай). В Раю сбор мусора выполняется довольно часто; таким образом, учитывается тот факт, что большая часть объектов в Java существуют очень недолго. Если объект выживает после нескольких сборов мусора в Раю, он попадает в основную кучу, где сборщик работает гораздо реже. Если Рай будет слишком мал, его сборщик мусора будет работать очень уж часто, поглощая ресурсы процессора и приводя к хаотичным изменениям времени отклика приложения. Эдем должен быть достаточно велик
для нужд вашего приложения. В приведенной ниже строке устанавливается минимальный и начальный размер Эдема в 32 Мбайт: -Xgenconf i g: 32m. 32m. semi spaces: 192ml92m. markcompact Более подробные сведения о работе нового сборщика мусора вы найдете в документации Java 2. -train Сбор мусора обычно останавливает весь процесс, поэтому лучше иметь возможность разбивать процесс сбора на небольшие группы операций. Это особенно важно для больших куч, которые могут потребовать работы сборщика мусора на протяжении нескольких минут. Параметр -train выполняет такое разбиение в Java 1.3; если вы его укажете, сбор мусора будет вызывать несколько коротких пауз вместо одной длинной. Используйте собственные потоки Собственные потоки включаются в момент запуска виртуальной машины путем использования переменной окружения либо с помощью параметра -D. Собственные потоки обычно довольно сильно повышают быстродействие. Используйте архивы .jar Используйте архивы .jar и .zip всегда, когда вам нужно загружать по сети более одного класса, потому что загрузка каждого класса требует установки отдельного TCP-соединения (если, конечно, вы не используете стандарт HTTP 1.1). Удаляйте из архивов то, что вы не будете использовать (если вы действительно уверены в том, что не будете). Подключаемый модуль Java Подключаемый модуль Java, созданный фирмой Sun, может загружаться браузерами Netscape и IE. Это убирает зависимость от «выходок* виртуальной машины Microsoft, а также позволяет пользоваться преимуществами гораздо более быстрой загрузки классов (по сравнению с виртуальной машиной Netscape). Самое главное преимущество — кэширование апплетов, исключающее необходимость повторной загрузки файлов большого объема. Кэширование апплетов по умолчанию производится в кэш браузера. Это неприемлемо для больших апплетов, потому что они могут вытесняться из кэша другим содержимым. Подключаемая виртуальная машина Javasoft версии 1.3 может осуществлять постоянное кэширование апплетов. (См. http://java.sun.com/ products/plugin/appletcaching.html.)
-start_ Java Браузеры не запускают виртуальную машину, пока не загрузится апплет. Это приводит к задержке на время инициализации виртуальной машины при первом запуске апплета. Netscape позволяет запускать Java одновременно с браузером с помощью параметра командной строки -start_ java. Java-процессоры Раньше считалось, что производительность Java можно поднять на тот же уровень, что и производительность обычных компилируемых программ на обычных процессорах, или даже выше, реализовав виртуальную машину аппаратно. Термин «виртуальная» при этом перестанет быть точным. Виртуальная машина Java разрабатывалась таким образом, чтобы когда-нибудь быть реализованной аппаратно, а Java-процессор действительно должен быстрее выполнять байт-код. К сожалению, некоторые команды байт-кода достаточно сложны (например, объявление нового объекта), и их непросто реализовать аппаратно. В некоторых программах на Java интерпретация байт-кода занимает всего лишь 15% общего времени выполнения. По указанным причинам, а также потому, что первые Java-процессоры были слишком велики и потребляли слишком много энергии, большинство проектов в этом направлении было приостановлено. Тесты для Java Самый широко распространенный тест для Java — SPEC JVM98. Его можно скачать по адресу: http://www.spec.org/osg/jvm98/. Но есть и другие. О Volano. Приложение для общения по сети, http://www.volano.com/markvedocs.html О CaffeineMark. Результаты теста могут быть фальсифицированы. http://www.webfayre. com/pendragon/cm2/index.html О Doug Bell's Benchmark Applet. http://www.javaworld.com/javaworld/jw-04-1997/jw-04-optimize.html О Jonathan Hardwick's Java Microbenchmark. http://www.cs.cmu.edu/~jch/java/microbench.html О Пакет Unpack Джека Донгарра и Рида Уэйда. http://www.netlib.org/benchmark/linpackjava/ http://www.cs.cmu.edu/~jch/java/linpack.html О Bill and Paul's Excellent UCSD Benchmarks for Java. http://www-cse.ucsd.edu/users/wgg/JavaProf/javaprof.html О Прочие. http://www.cs.cmu.edu/~jch/java/resources.html
Недостатки тестов Тесты для Java часто используют вызов System.currentTimeMillis() для записи моментов начала и завершения операций. Упомянутый метод сам по себе может выполняться до 0,5 мс, и он не может быть ускорен JIT-компилятором, потому что реализован как «родной» системный вызов. Понять, что он реализован именно так, можно, заглянув в исходный код java.lang.System.java: public static native long currentTimeMillist ): Веб-сайты, где размещены сведения о производительности Java Если вам нужны еще более подробные сведения о повышении производительности Java, вот вам список адресов: О http://www-cse.ucsd.edu/users/wgg/JavaProf/javaprof.html О http://www.cs.arizona.edu/sumatra/toba/ О http://www.cs.cmu.edu/~jch/java/compilers.html О http.7/www.cs.cmu.edu/~jch/java/optimization.html О http://www.cs.cmu.edu/~jch/java/size.html О http://www.geocities.com/CapeCanaveral/Hangar/4040/jcc.html О http://www.ibm.com/java/education/javahipr/javahiprl.html О http://www.javaworld.com/javaworld/jw-04-1997/jw-04-optimize.html О http://www.netlib.org/benchmark/linpackjava/ О http://www.preemptive.com/ О http://www.webcity.co.jp/info/andoh/java/j2c.html Основные рекомендации О Используйте современный компилятор и виртуальную машину, желательно — оптимизированные для вашей платформы. О Профилируйте код и оптимизируйте наиболее часто используемые методы. О Используйте потоки. О Буферизуйте ввод-вывод. О Используйте HTML вместо Java-апплетов везде, где это возможно.
22 Базы данных Быстрый рост популярности Интернета отчасти был вызван тем, что он обеспечил относительно дешевый и простой доступ ко множеству баз данных всего мира. Большая часть этой информации хранилась на мейнфреймах или в системах управления реляционными базами данных. Существует три стандартных класса обращений к базам данных. У каждого из них могут быть свои требования. О Отдельные запросы к базе данных, доступной только для чтения, — например, AltaVista. О Очень сложные запросы, ищущие характерные последовательности в больших объемах данных, обычно в маркетинговых целях. Это называется анализом информации из баз данных (data mining). Известный пример использования этой технологии: бакалейные лавки объединили сведения о продажах всех товаров — и обнаружилось, что пиво и подгузники часто покупались одновременно. Никто раньше не мог этого предполагать, но звучало это достаточно осмысленно, потому что и пиво и подгузники регулярно заканчиваются и людям приходится специально ездить за ними в магазин. После этого открытия торговцы стараются держать пиво и подгузники поблизости друг от друга. Анализ информации требует доступа только для чтения, а запросы обычно так сложны и выполняются так долго, что использование для них веб-интерфейса не рекомендуется. О Обработка транзакций: проверка кредитных карт, электронная торговля и доступ к банковским счетам. Обработка транзакций очень быстро становится главным видом деятельности в Интернете. Эти три класса доступа к базам данных отличаются по потребностям и возможностям масштабируемости. Базы данных для простого доступа легко масштабируются путем репликации. Базы данных, предназначенные для анализа
информации, обычно не масштабируются, потому что очень немногие пользователи обращаются к ним с запросами. Базы данных с обработкой транзакций масштабировать тяжелее всего, потому что в любой момент времени данные должны записываться только в основной экземпляр, а это создает значительную нагрузку на него. Планирование и оптимизация баз данных — широкая тема, гораздо шире, чем оптимизация всех веб-служб. Нужна ли вам реляционная база даных? Людям, занимающимся разработкой для сети, часто приходит в голову, что им нужна SQL-совместимая СУБД типа Oracle, когда на самом деле имеющийся у них небольшой объем данных можно было бы поместить в одну таблицу. Коммерческие СУБД стоят дорого, и их непросто устанавливать и администрировать. Как узнать, что вам нужна база данных? Вот несколько признаков, позволяющих определить, что вам нужна высокопроизводительная база данных. О У вас есть более мегабайта данных. О У вас есть множество таблиц, и вы хотите дать пользователям возможность делать сложные запросы. О Вам нужны очень высокие надежность и производительность. О Вам нужно обрабатывать транзакции. Если что-нибудь из этого относится к вашей ситуации — значит, вы выиграете от установки коммерческой СУБД (которая, к примеру, может работать непосредственно с диском (без обращения к операционной системе), имеет собственные модели потоков и оптимизирует обработку запросов). Альтернативы Существуют альтернативы традиционным SQL-базам. Некоторые из них обладают низкой производительностью, но так просты в программировании, что разработчик веб-сайта с малым количеством пользователей должен рассматривать в первую очередь их. Самая простая стратегия при наличии небольшого объема данных и отсутствии необходимости в сложных запросах — отправить все данные клиенту в виде HTML-страницы, и пусть он сам ищет, что ему нужно, с помощью функции браузера «поиск». Если пользователи хотят выполнять более сложные запросы
на поиск в небольшом наборе, напишите Java-апплет, который будет загружаться вместе с данными и предоставлять пользователю интерфейс для поиска, а также упрощать его запросы. Если набор данных слишком велик с учетом скоростей доступа ваших клиентов, одно из решений может быть таким: выполняйте поиск на стороне сервера с помощью обычной CGI-программы, серверного API или Java-сервлета. Команда grep, имеющаяся в Unix, обладает приемлемой эффективностью, и ее легко можно использовать в CGI-программах. Иногда поиск в простом ASCII- файле с данными позволяетдостичь (с учетом затрат) гораздо лучшего результата, чем любая база данных, потому что программировать такой поиск очень легко. В языке Perl имеются очень удобные в использовании хэш-таблицы, а файлы ndbm, имеющиеся в Unix, осуществляют аналогичное хэширование — для тех, кто любит писать CGI-программы на С. Любители С могут работать с отображаемыми в память файлами, что обеспечивает очень высокую производительность, если затраты на запуск CGI-программы уменьшаются путем ее демониза- ции или использования серверного API. Наконец, если вы чувствуете, что вам нужен SQL для выполнения сложных запросов, но набор данных у вас невелик, рассмотрите возможность использования MiniSQL (mSQL) с сайта http://www.Hughes.com.au/. Этот пакет распространяется за небольшую цену вместе с исходным кодом, обладает хорошей производительностью и поддерживает широкое подмножество ANSI SQL. Для небольших баз данных можно использовать и MySQL, который распространяется вообще бесплатно. Повышение производительности Веб-сайт, предоставляющий доступ к базе данных, должен строиться вокруг этой БД. Сначала оцените, какую нагрузку ей придется выдерживать, а затем выберите программное обеспечение и оборудование веб-сервера в зависимости от этой нагрузки. У базы данных наверняка будет гораздо больше работы, чем у веб-сервера, поэтому она станет «узким местом» системы. Подготовленные операторы и связанные переменные В базе данных можно хранить прошедшие синтаксический анализ операторы с переменными, стоящими в определенных местах. Такие переменные называются связанными (bind variables). Производительность подготовленных операторов гораздо выше, чем у тех, которые должны обрабатываться и оптимизироваться перед выполнением, но создание подготовленных операторов требует некоторых накладных расходов. Подготовленные операторы лучше всего использовать тогда, когда вы знаете, что пользователи будут выполнять множество одинаковых запросов, отличающихся по параметрам, а не по структуре или таблицам. Учтите, что сохранение
подготовленного оператора стоит довольно дорого, поэтому его лучше выполнять лишь однажды, а не в цикле. Денормализуйте таблицы Некоторого выигрыша в производительности можно легко достигнуть, сохраняя наиболее часто используемые данные в общих таблицах, что позволяет избежать расходов на выполнение дорогостоящих операций объединения (join). Это упрощает и написание запросов, потому что опять же устраняется необходимость объединения. С другой стороны, денормализованная таблица увеличивает вероятность несогласованности данных, когда данные, которые должны быть одинаковыми, оказываются разными в различных таблицах. Денормализованные таблицы администрировать сложнее. Не создавайте курсоры в циклах Создание курсоров (областей памяти, хранящих результаты запроса) стоит дорого, поэтому не следует помещать эту операцию внутрь циклов. Прямые соединения Прямые соединения с Oracle потребляют больше памяти, но избавлены от накладных расходов на работу диспетчера. Базы данных в основной памяти Если вы можете кэшировать всю базу данных в ОЗУ (суперкэширование) — сделайте это. Если вы знаете, какие виды SQL-запросов будут выполняться — подготовьте для них достаточно памяти. Сложные операции объединения поглощают значительный объем памяти и могут израсходовать даже виртуальную память, если вы не будете осторожны. Производители баз данных имеют естественное преимущество в написании самых быстрых драйверов и средств подключения к своим базам данных, зато стандарт Java DataBase Connectivity (JDBC) обладает переносимостью. Лучшие драйверы JDBC общаются с базами данных напрямую по их «родному» протоколу. Открытый стандарт подключения к базам данных (Open DataBase Connectivity — ODBC) работает несколько медленнее. Многоярусные системы Система «браузер/веб-сервер/база данных» кажется многоярусной, но не обладает всеми преимуществами многоярусной системы без специального планирования. Двухъярусная система, в которой веб-сервер является одновременно и базой данных, даст большую производительность при малом числе пользователей, но она может не обладать достаточной масштабируемостью.
При большом количестве пользователей нужно применять трехъярусные системы, которые могут использовать объекты на веб-сервере или сервере приложений повторно — как читая из них, так и записывая в них, без немедленного обращения к базе данных, что обеспечивает большой прирост производительности. Промежуточный ярус дает вам возможность объединять несколько баз данных в единое целое, то есть распределять базу данных. Средства управления транзакциями, работающие на промежуточном ярусе, также могут повышать производительность, управляя доступом к соединению с базой данных, исключая необходимость открывать и закрывать это соединение для каждого нового запроса. Конфигурация пула соединений Для большого сайта пул подключений является необходимостью, а не улучшением. Установка соединений с базой данных занимает много времени, поэтому вряд ли вы захотите, чтобы она выполнялась при каждом обращении к вашему серверу. Если вы установили сервер приложений типа Weblogic, настройте пул так, чтобы начальный размер пула совпадал с максимальным. Рост пула занимает много времени, а пользователям приходится ждать. Если вы сразу же создадите пул максимального размера, вам никогда не придется ждать его увеличения, поэтому некоторые запросы будут обрабатываться гораздо быстрее. Недостаток такого подхода — в большем расходе ресурсов базы данных. Запросы Хорошая схема уменьшает объем затрат на обработку запроса. Учтите, что в современных базах данных имеются оптимизаторы, которые бывают двух категорий. Одни оптимизируют в соответствии с определенными правилами, а другие — в соответствии со стоимостью определенных запросов. Вы можете давать оптимизаторам подсказки в своих SQL-операторах. О Кэшируйте результаты наиболее частых запросов. О В первую очередь выполняйте наиболее ограничивающую часть запроса. Второй части запроса придется работать с меньшим объемом данных, поэтому она будет выполняться быстрее. О Обычно лучше работать с базой данных на более высоком уровне, то есть выполнять несколько масштабных запросов вместо множества маленьких. О Компилируйте запросы заранее. О Вы можете переложить заметную часть работы на базу данных при помощи расширенного SQL или хранимых процедур. Хранимые процедуры позволяют сделать ответственным за запросы администратора базы данных, а не программиста. Администратор наверняка знает больше об оптимизации SQL, чем программист. Хранимые процедуры могут служить и для установки стандартов выполнения запросов, а также определять предварительную и заключительную их обработку. Гораздо легче изменить одну хранимую процедуру,
чем множество SQL-операторов, разбросанных по программе на Java или С. SQL переносим, но языки хранимых процедур привязывают вас к конкретной базе данных. О Ограничивайте область блокировки теми данными, которые вы действительно хотите заблокировать. Если запросы блокируют одну и ту же таблицу, они будут выполняться последовательно, так что производительность упадет. Тут может помочь блокировка на уровне строк. О Один плохой SQL-запрос может создать сокрушительную нагрузку на базу данных. Не открывайте свободный неограниченный доступ к своей базе данных даже в интрасети. Индексы Индексы, которые вы строите, должны соответствовать тому, что люди будут искать чаще всего. Иначе вы просто будете тратить время на построение и обновление индекса, а также дисковое пространство на его хранение. Создание индекса выполняется одним SQL-запросом — например, так: create index newsjndex on news_story(user. story_age. already_read); Блокировка на уровне строк Блокировка на уровне строк дает значительный выигрыш в производительности по сравнению с блокировкой целых таблиц, но не все базы данных поддерживают ее. Объединение веб-сервера и базы данных Некоторые базы данных одновременно являются HTTP-серверами. Таким образом устраняется промежуточный ярус между клиентом и базой данных. Подобные пакеты могут формировать HTML-страницы «на лету» как CGI-программы, а также сохранять информацию о состоянии при обработке транзакций. Их можно настроить на использование одного подключения к базе данных для всех запросов, что невероятно повысит производительность по сравнению с архитектурой, в которой для каждого запроса открывается свое соединение. Недостаток в том, что все названные пакеты являются закрытыми продуктами частных фирм и не очень хорошо масштабируются. Приложения, написанные для одного из таких гибридных серверов, не будут работать в других серверах. База данных может позволить вам подключаться по сети к другим базам данных, но при этом вы потеряете преимущество, которое имели, работая с единственным процессом. Ниже приведен список гибридов веб-серверов и баз данных: О Merchant Server фирмы IBM — использует СУБД DB2; О Informix Web Datablade — использует СУБД Informix; О NS LiveWire Pro — использует СУБД Informix и Oracle;
О Oracle Web Server — использует СУБД Oracle; О web.SQL фирмы Sybase — использует СУБД Sybase. Сколько соединений может обслужить ваша база данных? Если вы генерируете динамическое содержимое из базы данных, ваши возможности могут быть ограничены количеством соединений, обслуживаемых базой. Для большинства баз данных этот параметр можно изменять, однако если его значение окажется слишком велико, у вас, скорее всего, закончится память или какой-либо иной ресурс, прежде чем вы достигнете ограничения на количество соединений. В следующем листинге приведена быстрая программа на Java, которая создает произвольное количество соединений с базой данных и распечатывает их номера. Она предназначена для того, чтобы нагрузить базу данных и, возможно, даже привести к ее сбою, поэтому не испытывайте эту программу в системах, которые не должны останавливаться. Программа использует «тонкий» драйвер Oracle, однако вы можете ее изменить и подключить любой другой драйвер. Откомпилируйте программу командой Java jdbcCxnTest. Скачать ее можно по адресу: http://patrick.net/software/jdbcCxnTest.java. import java.sql.*; // Определение максимального количества одновременных соединений с БД. // Вызов: java jdbctest <компьютер> <порт> <экземпляр> количество потоков> // При необходимости измените ограничение на количество дескрипторов // командой ulimit. Например: ulimit -n 1024 public class jdbcCxnTest implements Runnable { static String where: static int cxn - 0; public static void main (String args[]) { if ( args.length !» 4 ) { System.out.printlnC "Usage: java jdbcCxnTest <host> <port> <dbname> <connections>" ): return: } String host » args[0]: String port » args[l]: String sid - args[2]: where - "jdbc:oracle:thin:@" + host + ":" + port + ":" + sid : try { DriverManager.registerDriver(new oracle.jdbc.driver.OracleDri ver( )): } catch (SQLException e) { System.out.printIn ГregisterDriver failed"): return: } for (int t - 0: t < Integer.parselnt(args[3]): t++) new Thread(new jdbcCxnTest0).start( ): } public void run( ) {
try { // укажите правильное имя пользователя и пароль вместо // scott/tiger Connection conn - DnverManager.getConnect ion (where, "scot Г. "tiger"); Statement stat - conn.createStatementC ); ResultSet resu = stat.executeQueryCselect * from dual"): while(resu.next( )) { System.out.println(resu.getString(l) + inc( )): } while (true) { // бесконечное ожидание Thread.sleepA00000); } //не закрываем соединения } catch ( SQLException e ) { e.printStackTrace( ); while (e !» null) { System.err.println(e.getErrorCode( )); System.err.pri nt1n(e.getMessage( )); System.err.println(e.getSQLState( )); e - e.getNextException( ); } } catch UnterruptedException e) { System.err.pri ntln("sieep i nterrupted"); > } public synchronized int inc( ) { return ++cxn; } } Когда база данных перегружена Я попытался перегрузить базу данных Oracle, устанавливая одновременно слишком большое количество соединений, но мне не удалось довести ее до сбоя. Новые соединения просто завершаются по тайм-ауту или вообще не устанавливаются. Это может происходить, например, при переполнении очереди прослушиваемого ТСР-сокета. В главе 15 об этой очереди рассказывается подробно. После тестирования в журнале можно обнаружить такие сообщения (процесс Oracle, СУБД Oracle): TNS-00505: Operation timed out TNS-12535: TNS:operation timed out TNS-12560: TNS:protocol adapter error Анализ Существует множество хорошо отработанных методов диагностики баз данных. Ваш администратор должен быть знаком, по крайней мере, с некоторыми из них. Для СУБД Oracle можно попытаться выполнить трассировку SQLfNet для диагностики сети, a tkprof и autoprof применить для профилирования запросов или
трассировки работы самой СУБД. Если вы знаете, какие именно запросы будут выполняться, вы можете вручную измерить время их обработки с помощью команды SQL+ set timing on. Основные рекомендации О Используйте пул подключений. О Небольшие объемы данных можно обрабатывать без СУБД. О Создавайте индексы. О Выполняйте в первую очередь наиболее ограничивающую часть сложных запросов.
Приложение Обзор продуктов, предназначенных для оптимизации веб-сайта В этом приложении приведен список основных коммерческих программных средств, предназначенных для контроля производительности, тестирования на нагрузку, оптимизации и других целей — в общем, всех программ, которые могут заинтересовать моих читателей. Я постарался не говорить о коммерческих продуктах в основной части книги, отведя им место в приложении. Недостатки коммерческих средств У большинства коммерческих средств, предназначенных для оптимизации работы в сети, имеется целый набор одинаковых недостатков. Эти программы делают полезные вещи, которые мне очень нравятся, но приходится постоянно обходить эти общие проблемы. О У большинства программ такого рода имеются графические интерфейсы, которые нельзя отключить. Особенно это характерно для Windows-приложений. Данные продукты просто не могут работать без GUI. Гораздо удобнее пользоваться командной строкой и журналами в формате ASCII. Мне часто приходится выполнять тестирование, находясь по другую сторону брандмауэра, и получать результаты этого тестирования. Даже не пытайтесь запускать Windows-приложения с графическим интерфейсом сквозь бранд-
мауэр! Вы зря потратите время. Даже в X Window System удаленный доступ не будет работать, потому что брандмауэры по самой своей природе не пропускают трафик по большинству портов и протоколов, включая X. Даже если у программного средства имеется виртуальный клиент без графического интерфейса, основное приложение обычно все равно не обходится без GUI. О Они устанавливаются на персональных компьютерах, расположенных слишком далеко от комнаты с серверами. Невозможно эффективно протестировать сервер через соединение с низкой пропускной способностью и большим временем ожидания. Сеть становится «узким местом». О Большинство коммерческих средств сохраняют результаты своей работы, мягко говоря, в сжатом виде. Если быть более откровенным, они скрывают ваши данные в своем собственном формате. А мне нужны журналы в формате ASCII. Я могу искать в них то, что хочу, обрабатывать их, изучать их начало и конец с помощью программ head и tail, а также просматривать их в браузере или по Telnet. В них нет скрытых битов, и для них не нужно специальных средств. Не обладают ASCII-журналы и скрытыми ошибками. О Все эти коммерческие средства требуют, чтобы вы изучили их собственный язык сценариев для написания тестов. Мне не нужен новый язык сценариев. Почему бы им не использовать Perl? Да потому, что они хотят, чтобы вы как программист работали на них. О Они стоят очень дорого. Средства контроля Общая проблема автоматизированного контроля производительности (пли автоматизированного тестирования любого рода) заключается в том, что автоматизация работает не слишком хорошо, если ваше содержимое или среда постоянно меняются. Для борьбы с изменениями требуется участие человека — а это противоречит определению автоматизации. Выигрыш от автоматизации тестов обычно оказывается больше в статической среде. С другой стороны, один мой коллега эффективно применил Perl и интерфейс DBI для проверки постоянно меняющихся динамических веб-страниц. Сначала он запрашивал из базы данных конкретные поля, а затем проверял, появляются ли те же самые данные на веб-страницах в нужном месте. Таким образом он вырвался вперед в гонках, в которых приходится принимать участие большинству авторов тестов (изменяющих свои тесты при каждом изменении веб-страницы). Отдельный класс средств контроля содержит пакеты, называемые трассировщиками транзакций, которые обычно рекламируются как обеспечивающие полную видимость всего, что делает ваше приложение. Часто это осуществляется путем пометки пакетов специальными идентификаторами. Данная схема обычно работает плохо по двум причинам. Во-первых, запросы проходят через пулы, куда за ними не могут последовать пометки. Например, запрос к веб-сайту мо-
жет вызвать обращение к базе данных, но если это обращение осуществляется через пул, то вы, скорее всего, не сможете определить, какое именно соединение данного пула было использовано. Во-вторых, чтобы действительно узнать, что происходит после пулов, нужно разрабатывать специальные программы с учетом внутренней структуры приложения. Программы общего назначения тут не сработают. На рынке имеется множество полезных средств контроля, в которых отсутствуют упомянутые недостатки. Приведенный ниже список является лишь кратким обзором. О AIM (http://www.aim.com/). Компания AIM Technology создает программное обеспечение для измерения производительности для Unix и NT. О Baseline (http://www.teamquest.com/). Baseline — продукт компании TeamQuest, измеряющий производительность процессора, дисков, буферного кэша и прочего для компьютеров Unix и NT, отмечая «узкие места» и осуществляя подробный анализ с выводом предупреждений. К отчетам можно обращаться через браузер, а на сайте фирмы имеется даже интерактивная демонстрация. О Best/1 (http://www.bgs.com/). Продукты Best/1 фирмы BGS работают на большинстве корпоративных компьютеров, включая мейнфреймы, Unix-серверы и NT. Они не только собирают данные, но и передают их средству планирования мощностей. Вы можете создавать датчики производительности, задавать пороги предупреждений, генерировать отчеты и планировать наращивание мощностей. О ВМС Patrol Knowledge Module for Internet Servers (http://www.bmc.com/). Набор продуктов Patrol от фирмы ВМС контролирует производительность всех типов корпоративных систем, включая веб-серверы. Вы можете создавать правила для автоматического обнаружения проблем и даже их устранения или уведомления об их возникновении. Patrol CGI Analyzer позволяет, в частности, контролировать производительность программ CGI. О Пакет NETSYS фирмы CISCO (http://www.cisco.com/). Эти средства предназначены для контроля сетей (в частности, маршрутизаторов), а не веб-серверов, но ведь состояние сети, разумеется, очень важно для производительности вашего веб-сервера. О CyberGauge (http://www.neon.com/CyberGauge.html). Продукт CyberGauge фирмы Neon — это утилита для измерения пропускной способности Интернета, основанная на протоколе SNMP. Она поддерживает работу с большинством маршрутизаторов, но может работать только на компьютерах с Windows и Macintosh. О Набор средств Open View от HP (http://www.hp.com/openview/rpm/netmetds.htm, http://www.hp.com/openview/rpm/mwds.htm). Агент HP MeasureWare собирает статистику производительности распределенных систем в целом, а не только веб-серверов. MeasureWare собирает и анализирует времена отклика приложений, а также данные о системах — параметры дисков, процессоров и сети. Он хорошо интегрирован с другими средствами HP Open View, однако хра-
нит данные в фирменном недокументированном формате, поэтому использовать его с другими средствами остаточно сложно. Проще говоря, он не интегрируется в мир Unix. Большая часть пользователей просматривает данные с помощью консоли управления HP PerfView. Measureware не требует установки агентов в контролируемых системах. Сбор данных осуществляется при помощи стандарта измерения отклика приложений (Application Response Measurement — ARM). HP Open View может получать системную информацию с помощью агентов Sun. О Netmetrix — средство контроля сети, основанное на протоколе RMON и работающее с операционной системой IOS фирмы Cisco. Оно контролирует производительность, собирая данные у маршрутизаторов. О INS Enterprise Pro (http://www.ins.com/). Enterprise Pro — средство для контроля сетей от фирмы International Network Services. Оно контролирует вебсайты и предоставляет доступ через веб к отчетам о пропускной способности, времени ожидания и количестве ошибок. О Keynote Perspective и аналогичные средства (http://www.keynote.com/). Keynote Perspective — средство контроля производительности, созданное фирмой * Keynote. Оно измеряет и выводит данные о реальной доступности вашего сайта с сотни серверов, разбросанных по территории страны. Отчеты можно просматривать через веб. Они содержат данные о времени ожидания, поэтому вы можете получить представление о том, насколько быстрым кажется ваш сайт тем или иным пользователям. Аналогичные услуги предоставляют фирмы Service Metrics (http://www.servicemetrics.com/), NetCool (http://www. netcool. com/), Freshwater Software's SiteScope и SiteSeer services (http://www.freshtech. com/), а также несколько других компаний. Я знаю, по крайней мере, один небольшой сайт, на котором все содержимое динамическое. Этот сайт перестал пользоваться услугами Keynote из-за того, что постоянный контроль создавал совершенно неприемлемую нагрузку на серверы. Если поразмыслить о таких программах, то можно прийти к выводу, что довольно глупо тестировать Интернет так, как если бы информация об этом общем средстве связи была доступна только им. О Mercury Topaz ActiveWatch (http://topazactivewatch.merc-int.com/). Программа Topaz ActiveWatch фирмы Mercury Interactive предоставляет услуги географически распределенного контроля, аналогичные услугам Keynote Perspective. О Multi Router Traffic Grapher (http://www.mrtg.org/). Очень популярное бесплатное открытое средство контроля сетевой производительности называется MRTG -Multi Router Traffic Grapher, а написана эта программа Тобиасом Оэтикером (Tobias Oetiker). Ее можно скачать по адресам http://www.mrtg.org/, http://people.ee.ethz.ch/~oetiker, она применяется на многих сайтах по всему миру. MRTG использует протокол SNMP и бесплатные графические средства для построения графиков трафика через маршрутизаторы в реальном времени. Эти графики можно просматривать через сеть.
О ProactiveNet (http://www.proactivenet.com/). Фирменный интерфейс API для контроля, сервер для сбора информации на отдельном компьютере и агенты, являющиеся маленькими браузерами. Информация отображается в формате HTML, что хорошо. Определяет корреляцию отклонений. Может отслеживать загрузку процессора, время отклика базы данных, загрузку сетевых интерфейсов и прочие параметры. Интерфейс достаточно прост. О Prognosis (http://www.ir.com/). Фирма Integrated Research стала известна благодаря средствам контроля Tandem, но впоследствии она разделилась на несколько фирм, производящих продукты для Solaris и других операционных систем класса Unix. Prognosis — лидирующий продукт, состоящий из агентов, размещаемых на каждом компьютере. Агенты используют общее хранилище данных. Данные сжимаются для экономии места. Prognosis включает в себя средства контроля процессора, подсистемы ввода-вывода, сетевой активности и других системных параметров. Он может генерировать предупреждения при достижении пороговых значений параметров. О RAPS (http://www.foglight.com/). RAPS, или Real-time Applications Performance System, — продукт фирмы Foglight Software, который контролирует приложения, серверы и сети с помощью небольших агентов, регулярно связывающихся с центральным сервером для передачи информации. Собираемые данные могут анализироваться с целью определения текущей производительности и прогноза необходимости обновления компонентов для борьбы с возрастающей нагрузкой. Набор правил позволяет искать корреляцию данных и выполнять корректирующие действия. О Resolve (http://www.crosskeys.com/). Фирма CrossKeys продает продукт, который называется Resolve. Этот пакет контролирует соглашения на уровне служб (Service Level Agreements — SLA) для глобальных сетей (WAN). Он генерирует отчеты, позволяющие определить, получаете ли вы качество обслуживания, за которое платите. О Resonate (http://www.resonate.com/). Хотя пакет Resonate является средством балансировки нагрузки, он осуществляет балансировку посредством постоянного контроля. Информацию, собираемую в результате контроля, можно просматривать на веб-страницах при использовании консоли Enterprise Services Console. Эти веб-страницы очень полезны для получения общей картины текущей производительности. Один из недостатков системы заключается в том, что довольно сложно бывает определить, к каким компьютерам относятся внутренние IP-адреса Resonate, если у вас нет доступа к консоли (а доступ к ней обычно бывает у небольшого числа людей). Сравните это с круговой системой DNS, где каждый может узнать, какие IP-адреса сопоставляются доменным именам, с помощью бесплатного средства nslookup. О SE toolkit (http://www.sun.com/sunworldonline/swol-01-1998/swol-01-perf.html). Набор средств SE, созданный Адрианом Кокрофтом и Ричардом Петтитом, на самом деле представляет собой средство контроля и анализа производительности Unix, а не собственно веб. Поскольку операционная система сильно влияет на производительность веб-сервера, имеет смысл собирать статистику
и с помощью этого средства. Оно измеряет пропускную способность TCP, количество соединений, повторных передач, скорость сетевых карт, количество коллизий и переполнений буферов, активность процессора и дисков, а также время существования приложений в памяти. Пакет SE содержит средства работы с журналами, поддерживающие стандартный формат журналов (Common Log File format — CLF), но написаны они на интерпретируемом диалекте С и могут работать только в Solaris для SPARC и х86. О Symon. Программа Symon фирмы Sun Microsystems работает по протоколу SNMP, обладает графическим интерфейсом, написанным на Java, и устанавливает агентов, работающих только в системе Solaris. О Tivoli (http://www.tivoli.com/). Пакет Tivoli от IBM содержит множество разных вещей. Это хранилище журналов, система распределения программного обеспечения и множество средств контроля. Я не работал с ней сам, но слышал, что она может породить столько предупреждений, что вам придется просто отключить ее, чтобы не выискивать среди предупреждений действительно важные. О Veritas FirstWatch (http://www.veritas.com/). Пакет Veritas FirstWatch содержит контролирующий компонент, который существует только для того, чтобы Veritas знал, когда переключаться на запасной сервер. О Visual UpTime (http://www.visualnetworks.com/). Программа Visual UpTime — еще одно средство контроля глобальных сетей на уровне служб. Оно автоматизирует сбор, интерпретацию и представление информации о службах WAN, таких как frame relay, ATM, арендованные линии, Х.25 и Интернет. О xperfmon. Бесплатное средство контроля производительности для X с сайта ftp.x.org. Кратко перечислю прочие пакеты из этой категории: sarcheck с сайта http://www.sarcheck.com/, Oracle Enterprise Manager, NetView фирмы IBM, Doma- in/SunNet/Site Manager фирмы Sun Microsystems, CA Unicenter, AnySpeed, Transaction Tracker фирмы Measureware, Service Metrics, сайт www.webmeter.net, Network Physics, FireClick, LastMile и программа измерения полосы пропускания с сайта http://www.2wire.com/. Средства создания нагрузки Средств генерации нагрузки существует примерно столько же, сколько и средств контроля. Данный список опять же не претендует на полноту. Недостаток подобных средств, записывающих действия пользователя, заключается в том, что они позволяют легко создавать сценарии, но их сложно масштабировать, потому что для этого требуется столько же браузеров, сколько будет виртуальных клиентов. Средства, основанные не на браузерах (такие, как моя собственная программа sprocket, описанная в главе 4), обладают другими недостатками: например, им сложно записывать операции SSL и работать с URL-адресами, содержащими информацию о состоянии, зато их гораздо проще масштабировать.
О CapCal (http://www.capcal.com/). Расшифровывается как Capacity Calibration (калибровка мощностей). Производит тестирование нагрузки через Интернет. О EJB Test (http://www.ejbtest.com/). Это веб-средство, опрашивающее ваши EJB и выполняющее их методы путем построения графиков времени ожидания. EJB Test не является, строго говоря, средством контроля производительности в Сети. Оно стоит очень дорого — от 30 000 долларов США, — но хорошо работает в затруднительных ситуациях. EJB сложно тестировать, потому что клиенты обычно используют фирменный графический интерфейс и протокол, разработанный для данного конкретного приложения. О eValid (http://www.soft.com/eValid/). eVaild — модифицированная версия IE, предназначенная для тестирования на нагрузку, а также проверки работы. Тесты записываются посредством браузера. Эта программа работает только в Windows, и ее демо-версия содержит ошибки. Мне не удалось понять графиков производительности, построенных ею после выполнения простого сценария тестирования. О Mercury Loadrunner. Loadrunner — программа с графическим интерфейсом, предназначенная для создания сценариев. Основанная на GUI, она способна записывать сценарий даже с URL-адресами, содержащими информацию о состоянии, однако эти сценарии не масштабируются. Как можно запустить 1000 таких сценариев? А на 1000 компьютерах? О Microsoft Web Application Stress (http://www.microsoft.com/). Бесплатное средство анализа производительности в Сети от Microsoft. Работает только под Windows, предназначено в первую очередь для тестирования ASP и IIS. О PointForward (http://pointforward.compuware.com/scalability/). Тестирование нагрузки через Интернет. Производитель — Compuware. О Velometer (http://www.binaryevolution.com/velometer/velometer.vet). Написанное на Java средство создания нагрузки и измерения времени отклика для HTTP. О VTS (http://www.sun.com/microelectronics/vts/). Продукт фирмы Sun. VTS — средство поиска ошибок, но может использоваться и для тестирования на нагрузку. О WebSizr (http://www.technovations.com). WebSizr — средство тестирования на нагрузку, которое может имитировать одновременную работу 200 пользователей и записывать результаты. Программа работает только под Windows, но может использоваться для тестирования любого HTTP-сервера. О К прочим средства тестирования на нагрузку относятся ApacheBench из проекта Apache, J Meter (сайт www.webperfcenter.com), а также продукты фирмы RadView под названием WebLoad и WebQuantify. Упреждающие загрузчики Пользователи, подключающиеся по медленным коммутируемым линиям, могут пользоваться продуктами, загружающими в фоновом режиме все ссылки с про-
сматриваемой пользователем в данный момент страницы. Однако выигрыш от таких средств невелик, а загружать множество страниц, на которые вы никогда не посмотрите, — невежливо. На рынке имеются следующие программы упреждающей загрузки: SpeedSur- fer, TurboExplorer, Legion (загружает IP-адреса, сокращая время на поиск в DNS), сайт www.SolidSpeed.com, BoostWeb, сайт www.fireclick.com и Blueflame. Blue- flame — прокси-сервер, который загружает невидимый Java-апплет, предназначенный для упреждающего просмотра веб-страниц. Оптимизаторы сетей Перечисленные ниже продукты могут использоваться для оптимизации вашего подключения к сети. Оптимизаторы MTU Этот класс продуктов занимается тем, что устанавливает параметры TCP оптимальным образом. Особое внимание уделяется размеру максимального передаваемого блока (Maximum Transmission Unit). Это программы РРР Boost, MTU- speed pro, NetMedic и Vital Signs (http://www.ins.com/). Optimal Application Expert Фирма Optimal Networks (http://www.optimal.com) сейчас принадлежит корпорации Compuware (http://www.compware.com). Программа Optimal Application Expert — Windows-приложение, перехватывающее сетевой трафик и строящее различного рода графики. Я пытался использовать его, но обнаружил, что большинство графиков трудно для понимания, хотя интерфейс самого средства в достаточной степени интуитивен. Программа может быть полезна, потому что snoop и traceroute не являются стандартными средствами NT (в отличие от Solaris). Характерная для Windows-приложений проблема: графический интерфейс не позволяет создавать сценарии действий и использовать получаемые данные в других приложениях. Контроль трафика на уровне IP Один из недостатков протокола IP состоит в том, что все пакеты обрабатываются одинаково вне зависимости от требований ко времени ожидания и пропускной способности, выдвигаемых протоколами более высокого уровня. Эту проблему можно решить при помощи средств управления трафиком на уровне IP (другое название — программы, «формирующие» трафик), аппаратных устройств, обеспечивающих качество обслуживания (Quality of Service boxes), а также продуктов, распределяющих пропускную способность сети. Некоторые продукты
в действительности являются устройствами, тогда как другие представляют собой обычные программы для стандартного оборудования. Подобные продукты классифицируют и помечают IP-пакеты, устанавливая для них разные уровни приоритета. Когда пакеты попадают в очередь на маршрутизаторе, продукты, формирующие трафик, изменяют порядок очереди в зависимости от приоритета пакетов. Они постоянно измеряют состояние сети и определяют для различных классов их долю в полосе пропускания. Пакеты из потоков, превысивших выделенную полосу пропускания, могут даже сбрасываться. Учтите, что качество обслуживания в данном случае — понятие относительное, потому что некоторые пакеты считаются более важными, чем другие, но никакие гарантии относительно суммарной пропускной способности и времени ожидания не даются. Сравните это с ATM, где для разных видов услуг устанавливаются жесткие спецификации времени ожидания и пропускной способности. ATM может это делать, потому что данный протокол второго уровня, ориентированный на установку соединения, имеет возможность непосредственно управлять физической линией между двумя концами соединения. IP — протокол третьего уровня и не может управлять протоколом второго уровня (ATM, Ethernet, Frame Relay), no которому передаются его пакеты. Так что никаких гарантий, что вы сможете сделать качественный голосовой звонок через Интернет, у вас не будет никогда. Не имея возможности контролировать Интернет, вы все-таки обладаете всей полнотой власти в своей интрасети, где можете определять политику для разных пакетов и распространять ее на маршрутизаторы и другое сетевое оборудование вашей компании. Для этого, вероятно, необходимо, чтобы все оборудование сети было изготовлено одним производителем, поэтому возникает новая опасность — попасть от него в зависимость. RSVP — протокол Интернета, созданный с той же целью, — обладает аналогичным недостатком, потому что требует, чтобы все маршрутизаторы по пути следования пакетов поддерживали его. Общие недостатки продуктов этого рода таковы: время ожидания возрастает пропорционально количеству определяемых классов QoS, а при большой загруженности сети эти продукты все равно бесполезны, потому что они могут просто сбрасывать пакеты всех классов. Вот список лидирующих продуктов, управляющих трафиком на уровне IP О Checkpoint Software (http://www.checkpoint.com/). Фирма Checkpoint стала известной благодаря программному обеспечению брандмауэров, однако сейчас она создала продукт FloodGate-1, позволяющий устанавливать приоритеты пакетов в локальных сетях. О Internet QOS фирмы Cisco (http://www.cisco.com/). Фирма Cisco — это один из крупных «китов» мира IP-сетей: обладает самой большой долей продаж на рынке маршрутизаторов. Она добавила поддержку качества обслуживания в операционную систему маршрутизаторов IOS 11.1. Эта поддержка позволяет маршрутизаторам связываться и согласовывать политику расстановки приоритетов. Данный продукт, судя по всему, был разработан для того, чтобы в сетях по-прежнему использовалось преимущественно оборудование Cisco.
О NetScaler (http://www.netscaler.cx)m/). NetScaler 3100 — устройство, устанавливаемое перед веб-сервером и поддерживающее постоянные соединения протокола HTTP 1.1, уменьшая нагрузку на веб-сервер, которому приходится обрабатывать меньшее количество соединений. Стоит, как минимум, 20 000 долларов США. О Packeteer (http://www.packeteer.com/). Packeteer — устройство, выделяющее пропускную способность и определяющее возможности клиента по скорости поступления запроса. Оно может отличить клиента с модемом на 14 400 от клиента с линией Т1 и отправить ему ответ с той скоростью, которая этому клиенту будет в самый раз. О Bandwidth Allocator фирмы Sun (http://www.sun.com/software/band-allocator/). Продукт Bandwidth Allocator фирмы Sun — это модуль библиотеки потоков, выполняющий выделение пропускной способности в соответствии с политиками. Он может, к примеру, не давать протоколу FTP занимать большую часть полосы пропускания, чем HTTP, либо обеспечивать наилучшее качество обслуживания выделенным доменам. О Torrent (http://www.torrentnet.com/). Torrent обладает способностью обеспечивать гарантированную минимальную пропускную способность для IP, а не только устанавливать приоритеты. О Xedia (http://www.xedia.com/). Оборудование Access Point фирмы Xedia и ее программные продукты занимаются формированием IP-трафика, контролем и управлением. Больше всего они полезны для Интернет-провайдеров. Системы сжатия содержимого Существует несколько продуктов, таких как Gifwizard (http://www.gifwizard.com/) и Condenser фирмы Fineground Networks (прокси-сервер), которые пытаются сжимать веб-содержимое перед отправкой или во время ее. О Condenser. Продукт Condenser фирмы Fineground Networks (http://www.fine- ground.com/) — это прокси-сервер, работающий перед веб-сервером и использующий возможности JavaScript и DOM, имеющиеся в последних версиях браузеров, для отправки браузеру только обновленной информации, если у того в кэше имеются какие-то данные. Это уменьшает сетевой трафик и потенциально должно улучшать время отклика. Пакет Condenser использует файлы cookie для отслеживания потребителей и запрошенных ими страниц. Он является конечной точкой соединений HTTPS; в противном случае у него не было бы возможности видеть содержимое страниц. Это может создавать проблемы при наличии нескольких серверов HTTPS. Размер кэша программы Condenser тоже может стать проблемой. Наконец, аккуратное применение JavaScript позволит вам самостоятельно пользоваться всеми преимуществами, предоставляемыми этой программой. Ее стоимость — от 50 000 долларов США.
О Т/Х 2100 Series от Redline Networks. Продукт фирмы Redline (http://www. redlinenetworks.com/) сжимает содержимое и пытается уменьшить количество пакетов, используя фирменное оборудование и программное обеспечение. Оборудование устанавливается перед веб-сервером и поддерживает соединение с ним, снимая с него нагрузку, связанную с установкой и разрывом соединений. Стоимость — не ниже 59 000 долларов США. Гибриды средств разработки и баз данных Ниже перечислены фирменные продукты, интегрирующие в себе средства веб-разработки, клиенты и базы данных. О FileMaker — это одновременно имя компании и название ее продукта для Windows и Macintosh. Продукт этот объединяет в себе базу данных и соединительный веб-сервер, который позволяет публиковать данные из базы на веб-страницах. Имеется и фирменный клиент для просмотра данных. (См. http://www.filemaker.com/.) База данных FileMaker несколько сложнее, чем простая электронная таблица, но не так сложна, как стандартная СУБД типа Oracle. Ее проще изучить, чем большую часть серьезных СУБД, однако простота в изучении оборачивается тем, что вы будете уметь работать только с продуктом этой фирмы. FileMaker Pro и версия «Unlimited» являются одно- поточными. FileMaker Server 5 (сервер базы данных) может, согласно рекламе, одновременно обслуживать до 250 клиентов. Если вы знаете, что вам не придется масштабировать систему выше этого уровня и ваши серверы работают под управлением Windows или на Macintosh, пакет FileMaker будет вполне приемлемым вариантом для вас. Однако для больших сайтов, которым требуется очень высокая производительность, я порекомендовал бы использовать Unix. О Microsoft Access — это еще одна база данных для Windows и фирменный клиент. Во многом похожа на FileMaker. Клиент Access может подключаться и к серверу Microsoft SQL Server — более мощной СУБД — однако это не обязательно избавит вас от ограничений, присущих Access. Процитирую вебстраницу http://www.sql-server-performance.com/access.asp: «Если вам действительно нужна высокая производительность, не используйте Access в качестве интерфейса к базе данных SQL Server». Эта программа разрабатывалась не для достижения высокой производительности, а для простоты в изучении. О Tango. Продукт Tango (не путать с браузером, имеющим то же название) — фирменная визуальная среда разработки веб-приложений. Вы можете перетаскивать объекты СОМ и JavaBeans на сервер приложений и подключаться к базам данных, совместимым с ODBC. Этот продукт, согласно рекламе, работает в системах Windows, Linux, Macintosh и Solaris. И снова производительность конечного продукта принесена в жертву быстроте разработки и простоте изучения. (См. http://www.witango.com/.)
О Lasso. Продукт Lasso фирмы BlueWorld (http://www.blueworld.com) — набор средств разработки для сети и веб-серверов. Функционируя в качестве сервера приложений, Lasso может работать на веб-серверах и подключаться к базам данных. Обычно он используется между IIS и SQL Server в Windows. Эта программа является многопоточной. Согласно опубликованным результатам тестирования, Lasso превосходит в производительности ColdFusion, FileMaker, ASP и Tango. О Cold Fusion — еще один интерфейс для визуального программирования и сервер приложений для Сети. Он производится фирмой Allaire (http://www.allaire.com) и является многопоточным. Работая с ним, вы будете использовать фирменное расширение языка HTML, которое называется CFML (Cold Fusion Markup Language). Сервер может работать в системах Windows, Solaris, HP-UX и Linux. Профилировщики и оптимизаторы Java Профилирование кода — хорошо разработанная методика поиска чаще всего выполняемых участков кода, а также контроля используемой программой памяти. Вот несколько средств, которые могут применяться для профилирования и оптимизации программ на языке Java: DashO, Optimizelt, NuMega, TrueTune, Intel Vtune, Visual Quantify, Rational Performance Studio и Gnu gprof. Службы кэширования Сейчас количество компаний, предлагающих услуги «зеркалирования» вашего веб-содержимого, измеряется десятками. Самые популярные — Akamai и Inktomi, но есть еще и ANS (http://www.ans.net/), принадлежащая AOL; Exodus Communications; GlobalCenter (http://www.isi.net/), купившая фирму ISI; GTE/BBN; InterNex; MCI и Sandpiper. Дублирующие службы и продукты могут сильно сократить ваши расходы на связь, потому что пользователи будут ближе к содержимому. Это особенно важно, если вы работаете в экстрасети с выделенными соединениями, устанавливаемыми на большие расстояния. Учтите, что дублирование — это еще и путь к большей отказоустойчивости: система может передавать запросы на другие серверы при отказе одного из них. Программное обеспечение, управляющее дублированием (то есть такое, которое выбирает для каждого запроса ближайший сервер и обеспечивает быстроту распространения обновлений между серверами), пока что находится в зачаточном состоянии. Репликация содержимого по дублирующим сайтам может осуществляться при помощи продуктов фирм F5 Labs (http://www.f5labs.com/), Inktomi (http:// www.inktomi.com/), Studebaker (http://www.tigereye.com/) и Versant (http://www. versant.com/).
Профессиональные услуги Организации, предоставляющие профессиональные услуги в данной области, будут рады справиться с вашими проблемами, связанными с производительностью. IBM на данный момент является крупнейшей, но, конечно, не единственной компанией такого рода. С ней конкурируют www.hudsonwilliams.com, Sun Professional Services и я. Средства балансировки нагрузки Средства балансировки нагрузки переносятся из специализированных устройств и служб в саму сеть, в особенности на маршрутизаторы. О LocalDirector и DistributedDirector. Фирма Cisco (http://www.cisco.com/) продает системы балансировки нагрузки LocalDirector и DistributedDirector. LocalDirector — выделенное устройство, которое не может использоваться ни для чего другого, так что когда оно устареет, его придется выкинуть. Кроме того, оно может само становиться «узким местом» и источником опасности, хотя его можно установить в защищенной от отказов конфигурации, то есть в составе кластера из нескольких таких устройств. Подробнее см. на сайте http://www.cisco.com/ (воспользуйтесь средствами поиска, имеющимися на этом сайте, чтобы найти информацию про LocalDirector). Система LocalDirector переписывает заголовки IP-пакетов, перенаправляя соединение на локальный сервер с максимально доступной емкостью. Она определяет возможности сервера по использованию сети, а не статистику сервера, потому что не требует запуска каких-либо процессов на веб-сервере. Из-за этого данная программа не является нормальным средством балансировки нагрузки и может быть непригодна для использования с серверами различной емкости. Конечный пользователь, приложение и DNS-сервер могут ничего не знать о системе балансировки; для них она является прозрачной. Это позволяет нескольким серверам работать с одним внешним IP-адресом аналогично системе Resonate. DistributedDirector предназначен для территориально разбросанных серверов. Вы можете либо установить службу DNS DistributedDirector, которая будет возвращать пользователям IP-адрес ближайшего к ним сервера, либо сделать так, что DistributedDirector будет отправлять клиентам код возврата HTTP «302 Temporarily Moved» с именем наиболее подходящего сервера. Это имя будет использовано браузером для обращения уже к самому вебсерверу. DistributedDirector измеряет расстояние в прыжках между маршрутизаторами и направляет пользователя на ближайший сервер. Однако он не анализирует производительность серверов и не принимает решений исходя из их возможностей, а ближайший в топологическом смысле сервер может и не давать пользователям самой лучшей производительности.
С помощью DistributedDirector вы можете распределять пользователей, обращающихся к одному URL, по веб-серверам, разбросанным по всему миру. Один из недостатков этих продуктов заключается в том, что они основаны на использовании фирменного оборудования, которое становится уязвимым местом системы. Еще одна проблема заключается в том, что эти серверы отображают один IP-адрес на несколько, а значит, возникает та же проблема с сохранением информации о состоянии, что и при использовании круговой системы DNS. DistributedDirector позволяет принудительно направлять пользователя на один и тот же сервер при помощи параметра sticky. О Resonate Dispatch фирмы Resonate Inc. (http://www.resonate.com/) — программная система балансировки нагрузки без уязвимых мест. Она не требует установки избыточного оборудования для обеспечения отказоустойчивости. Dispatch делает один IP-адрес адресом нескольких веб-серверов аналогично продуктам Cisco. Она распределяет нагрузку в соответствии с имеющимися ресурсами серверов, поэтому данная система действительно является балансировщиком. Dispatch может использоваться для сайтов с обработкой транзакций. Одна из проблем заключается в том, что постоянная проверка состояния сервера сама по себе создает для него серьезную нагрузку. Интервал между проверками может быть увеличен с нескольких секунд до нескольких минут, но тогда будет больше шансов, что запрос перенаправится на уже перегруженный сервер, хотя накладные расходы на контроль будут сокращены. Resonate сама потребляет IP-адреса и требует некоторых умственных усилий при настройке, однако является отличным средством контроля производительности. О lbnamed — средство балансировки нагрузки, основанное на использовании DNS. Одному имени сопоставляется динамически изменяемый набор компьютеров. Выбор конкретного компьютера зависит от загруженности каждого из них. Каждый сервер может принадлежать к нескольким группам и, таким образом, обладать несколькими именами DNS. Программа lbnamed была написана на языке Perl Рональдом Дж. Шемерсом III (Ronald J. Shemers III) и бесплатно доступна по адресу: http://www-leland. stan- ford.edu/~schemers/docs/lbnamed/lbnamed.htrnl. О Network Dispatcher фирмы IBM — еще одно средство балансировки нагрузки, отображающее один IP-адрес на несколько серверов, соединенных локальной сетью. Network Dispatcher выбирает компьютер в соответствии с указанным набором весов и переписывает IP-заголовки, поэтому он работает независимо от DNS. Network Dispatcher можно скачать по адресу: http:// www.ics.raleigh.ibm.com/netdispatch/netspec.htm. О Web Server Director фирмы RND — балансировщик нагрузки для компьютеров с одинаковым содержимым. Это устройство, имеющее 2-4 порта Ethernet или 2 порта Fast Ethernet. Один виртуальный IP-адрес может представлять целое семейство серверов. WSD способен обслуживать 512 виртуальных IP-адресов, а количество серверов может достигать 50 000. Нагрузка распределяется в соответствии с одним из трех алгоритмов, что позволяет некоторым серверам работать с повышенной нагрузкой. Другие серверы могут на-
страиваться как резервные. Отказ сервера контролируется на физическом уровне и на уровне приложений. Другие средства балансировки нагрузки называются Arrowpoint, Radware, Sun Bandwidth Manager и Big/IP. Средства моделирования HyPerformix позволяет моделировать приложения и возможности сети. Optimal Application Expert моделирует только саму сеть. Я скептически отношусь к моделирующим утилитам, предпочитая реальное тестирование на нагрузку.
Алфавитный указатель i .htaccess, файл, 398 /ргос, каталог, 169 @Ноте, фирма, 259 3Com, фирма, 135 56К, линия, 260 68К, процессор, 240 А Accelerated Graphics Port. См. AGP accept, вызов, 395 Access Point, оборудование, 494 access.conf, файл, 398 access.log, файл, 167 ACID, критерий, 49 ACK, сегмент, 285, 300, 308 ACLFile, директива, 406 ActiveX, управляющие элементы, 76, 226 Add Log, параметр, 404 Address Resolution Protocol. См. ARP adjtime, вызов, 138 AGP, 246-247 AIM Technology, фирма, 487 AIX, операционная система, 352, 449 Akamai, служба распространения данных, 42- 43, 50, 61, 496 Allaire, фирма, 496 AllowOverride, параметр, 398 Alpha, процессор, 326, 352 ALT, тег, 418 для апплетов, 41 использование, 37, 40 AltaVista, поисковый сервер, 326, 352, 436, 476 Amaya, браузер, 220 AMD, фирма, 246 America OnLine, провайдер, 42 analysis.cgi, программа, 153 analyze, программа, 158 animate, программа, 97 AOL, провайдер, 42, 278, 402 Apache, веб-сервер, 57-58, 62-63, 311-314, 375, 392-393, 395, 399, 410, 431, 444 API, 63 CGI, 398 CGI , 431 Java-сервлеты, 398 PHP, 446 включение сжатия, 219 кэш страниц в ядре, 358 многопоточная версия, 398 модуль Perl, 441 настройка, 392, 398 ограничения на домены, 400 отключение поиска в DNS, 399 отображение файлов в память, 395 параметры журнала, 158 требования, 82 требования к памяти, 399 API, интерфейс, 284 производительность и переносимость, 426 Apple, фирма, 234, 244, 422 APPLET, тег, 418 appletviewer, программа, 229, 357 Application Response Measurement. См. ARM aps, программа, 302 ARM, 135 ARP, протокол, 287 кэширование, 287 прокси-сервер, 287 AS/400, операционная система, 350 ASP, 444, 446 Asymmetric Digital Subscriber Line. См. DSL Asynchronous Transfer Mode. См. ATM AT&T, фирма, 349, 350 ATA. Cm. IDE ATM, протокол, 261, 323, 493 принцип действия, 261 реализация, 261 Authorization Translation, функция, 402 autoexpect, программа, 91
autoprof, программа, 483 autosys, демон, 43 конфигурация, 139 в Bandwidth Allocator, пакет, 494 BASE, тег, 224 Baseline, программа, 487 bash, интерпретатор команд, 352, 440 Basic Input Output System. См. BIOS bcopy, функция, 321 BEDO, 324 Bell Labs, лаборатории, 349 benchmark, 148 BeOS, файловая система, 347 Berkeley File System, 364 Best/1, пакет, 487 BGP, протокол, 56, 288 BGS, фирма, 487 Big Brother, программа, 110 bing, программа, 91 BIOS, 244, 249 включение FPU, 249 включение кэша, 249 настройка, 249 обновление прошивки, 232 разгон памяти, 249 скорость процессора, 249 спящий режим, 250 Blackdown, виртуальная машина, 471 BlueWorld, фирма, 496 ВМС, фирма, 487 Boa, веб-сервер, 407 Bounds Checker, программа, 445 Bourne shell, интерпретатор команд, 439 BR, тег удаление, 417 branch prediction, 241, 326 bridge, 264 BSDI, операционная система, 231, 353 bus, 322 byterange, запрос HTTP, 61, 313 bzero, функция, 363 с C#, язык, 76 С, язык, 439, 442 оптимизирующий компилятор, 442 профилирование, 443 Cabletron, фирма, 135 cachefs, программа, 305 cache-size, параметр, 404 CaffeineMark, программа, 152, 474 Capacity Calibration, программа, 491 Cbench, программа, 247 CD, индикатор наличия несущей, 33 Cello, браузер, 219 CERN, институт, 306 CFML, язык, 496 CGI, интерфейс, 57, 63, 426-427 nph, 431 альтернативны, 444 борьба с зацикливанием программ, 430 буферизация и ожидание, 431 взаимодействие с БД, 445 масштабируемость, 359, 438 недостатки, 427 отключение кэширования страниц, 437 отключение поиска в DNS, 431, 439 открытость стандарта, 76 отладка и оптимизация программ, 439 последовательность событий, 427 предварительная обработка, 208 причины популярности, 427 производительность, 426 разделение форм, 438 рекомендации,428 сокращение объемов вычислений, 432 спецификация, 426 требования к памяти, 83 уменьшение размеров программ, 438 установка таймера в программе, 430 эффективность, 427 chargen, служба, 91, 148 Checkpoint, фирма, 493 Cheetah, веб-сервер, 390 chroot, программа, 188 CISC, архитектура, 241, 327, 331 Cisco, фирма, 135, 264, 279, 487, 488, 493, 497 ClearCase, система слежения за обновлениями недостатки, 45 CLF, 158, 162, 490 close, вызов, 354 CMOS, 249 CMOS, память, 244, 249 CNN, служба новостей, 412
CodeCenter, программа, 445 ColdFusion, среда программирования, 496 Complementary Metal Oxide Semiconductor. См. CMOS Complex Instruction Set Chip. См. CISC CompuServe, провайдер, 273 Computer Associates, фирма, 43 Сотри ware, фирма, 491 СОМ-порт, 33 обработка прерываний, 232 Condenser, программа, 413, 494 Connectix, фирма, 235 content. См. содержимое CONTENT-LENGTH, переменная, 427 content-type, заголовок, 120 cookie, файл, 215, 303, 307, 434-438 CORBA, архитектура, 283, 316, 435, 449 масштабируемость, 316 недостатки, 45 производительность, 316 Corel, фирма, 448 creat, вызов, 354 creeping featurism, 438 cron, демон, 96, 139, 381 автоматический перезапуск, 180 борьба с утечками памяти, 120 значение PATH, 178 конфигурация, 139 отключение, 43 падение производительности, 43 перезагрузка компьютера, 397 создание задания, 101 crontab, файл, 101 CrossKeys, фирма, 489 csh, интерпретатор команд, 440 CSU/DSU, концевое устройство, 251 curl, программа, 229 CWIX, провайдер, 273 CyberGauge, пакет, 487 D DaemonStats, параметр, 406 Dash О, программа, 467 data mining, 476 DBI, интерфейс, 110,486 DBUFFERED_LOGS, параметр, 399 dcopy, программа, 369 dd, программа, 369 DEC VM, виртуальная машина, 471 DEC, корпорация, 244 defrag, программа, 233 Denial of Service. См. DoS df, программа, 366 DF, флаг, 289 Diamond Multimedia, фирма, 257 diff, программа, 139 Digital Unix, операционная система, 352 Direct Memory Access. См. DMA directive_is_cacheable, параметр, 405 Directorylndex, параметр, 401 Dispatch, программа, 498 DistributedDirector, система балансировки нагрузки, 497 DMA, 376 DNLC, кэш, 368 увеличение размера, 368 DNS, 303 UDP, 303 быстродействие службы, 215 загруженность сервера, 304 использование браузером, 215 как иерархическая база данных, 304 круговая система, 54, 176 обратный поиск, 41, 191 отключение обратного поиска , 41 повышение производительности, 303 производительность, 215 размер пакета, 290 ускорение, 155 устранение неполадок, 34 файлы конфигурации, 303 DNS, смена сервера, 40 Document Object Model. См. DOM DOM, 53, 217, 315, 420, 446 перспективы, 61 поддержка, 53 различия трактовки, 54 Domain Name Service. См. DNS DoS Tracker, программа, 291 DoS, атака, 147, 291, 294 DRAM, 323 DRAM. См. оперативная память drawPolygon, функция, 420 DSL, 260 пропускная способность, 260 DSL, стандарт, 37, 253
Е EDO, 324 efficiency, 85 EIDE, интерфейс, 43, 344 EISA, шина, 244 EJB, пакет, 316, 449 Test, 491 недостатки, 45 eMikolo, фирма, 229 Enterprise Java Beans. См. EJB Enterprise Pro, программа, 488 Error handling, функция, 403 etherfind, программа, 383 Ethernet, 135,251,265,416 100BaseT, 265 lOBaseT, 265 MTU, 291 быстрый, 37, 270-271, 322 влияние шумов, 271 гигабитный, 270, 323 двусторонний режим, 37, 266 кадры, 265 коллизии, 265 коммутируемый, 270 обычный, 37 ограничения на кабель, 271 односторонний режим, 266 ошибки в конфигурации, 45 перехват пакетов, 267 производительность, 87 пропускная способность, 71, 265 размер пакета, 289 сетевой адаптер, 269 смешанный режим, 267, 301 терминаторы, 271 толстый, 271 упаковка пакетов, 267 уровень, 286 eVaild, программа, 491 Exceed, эмулятор X Window, 102 exec, вызов, 354, 359, 392, 427, 440 execl, вызов, 387 Executor, эмулятор, 240 exit, вызов, 354 Exokernel, проект, 355, 390 Expersoft, фирма, 316 expires, заголовок, 310 eXtreme Programming, 51 F Fancy Indexing, параметр, 400 FastCGI, интерфейс, 358 FastCGI, стандарт, 63, 438, 444-445 недостатки, 444 FD_SETSIZE, параметр, 374 FDDI, 270 fdisk, программа, 370 Fibre Channel, интерфейс, 345 пропускная способность, 346 физический носитель, 346 File Transfer Protocol. См. FTP file, программа, 417 FileMaker, база данных, 495 FIN_WA1T_2, состояние, 297 final, ключевое слово, 451 Fineground Networks, фирма, 413, 494 ftps, программа, 370 First Watch, программа, 179 FIX, 275 Floating-Point Unit. См. FPU FloodGate-1, пакет, 493 flushTimer, параметр, 432 Foglight Software, фирма, 489 FollowSymLinks, параметр, 400 fork, вызов, 354, 359-360, 387, 392, 427, 430, 440 FPU, 241,327 FQDN, 303 Frame Relay, протокол, 261 надежность, 261 обработка приоритетов, 261 экономическая эффективность, 261 FrameMaker, программа, 212 free, вызов, 174 FreeBSD, операционная система, 231, 353 frontside bus, 326 fsflush, процесс, 369 FTP, протокол, 292, 315, 350 поддержка браузерами, 315 ftpd, демон, 392 fully qualified domain name. См. FQDN runnel, 59 fuser, программа, 168, 348 G Gamelan, веб-сайт, 416 garbage collector. См. GC GC, 45, 449
gcc, программа, 102, 327, 352, 456 вывод на ассемблере, 332 оптимизация, 332 gd, программа, 97 GET, программа, 94 gethostbyaddr, вызов, 402 gethostbyname, вызов, 402 GIF, формат, 97, 422 анимация, 97, 422 библиотека Perl, 97 gifsicle, программа, 97 Gifwizard, программа, 494 Global Director, система балансировки нагрузки, 56 GlobalCenter, фирма, 279 GNU, проект, 352 gnuplot, программа, 97, 113, 162 конфигурационный файл, 100 функционирование, 97 gnutella, протокол, 229 Gopher, система, 212 goto, оператор, 387 gprof, программа, 443 Graphical User Interface. См. GUI grep, программа, 168, 312, 436 GUI, 53 разработка на HTML, 53 gzip, программа, 186, 310, 414 многократное сжатие, 414 уровень сжатия, 219 н HI, тег, 418 Harissa, программа, 470 Harvest, программа, 410 hash, команда FTP, 90 HAT, программа, 468 HEAD, команда HTTP, 214, 310 head, программа, 486 hop, 42 hosts, файл, 304 Hotjava, браузер, 448 HotSpot, компилятор, 456, 457, 462, 469 HP, фирма, 135, 487 hstat, программа, 380 HTML, язык, 212, 283, 306, 312, 420 динамический, 446 объектная модель документа, 315 проверка страниц, 419 HTML, язык (продолжение) расширения и переносимость, 76 сжатие, 413 HTTP 1.0, протокол, 434 HTTP 1.1, протокол, 218, 306, 358, 408,413 загрузка диапазона, 313 загрузка файлов по частям, 416 новшества, 311 особенности, 432 параллельная обработка, 312 поддержка браузерами, 312 постоянные соединения, 68, 208, 216, 300,310-311,393 проверка подлинности, 312 реализация для Мае, 235 HTTP, протокол, 50, 213, 283-284, 292, 305, 312 асимметричность, 307 время жизни соединения, 296 загрузка диапазона, 313 информация о состоянии, 51, 306 история, 350 история создания, 305 масштабирование, 307 масштабируемость, 51 обращение к серверу, 306 операция, 306 передача HTML, 306 переносимость, 200 подслушивание на прокси-сервере, 156 порт, 306 постоянные соединения, 310 прокси-серверы, 312 сжатие содержимого, 310 соединения, 306 текстовые команды, 308 типы MIME, 306 уровень, 286 файл cookie, 307 через Telnet, 308 эффективность, 51 эхо-сервер, 308 НТТР.протокол принцип действия , 306 HTTP_REFERER, переменная, 419 httpd, демон, 320, 356, 392, 397, 399 история, 350 распространение, 350
httpd.conf, файл, 395, 399-400 HTTPS, протокол, 36, 183, 437 поддержка прокси-сервером, 35 порты, 36 hub, 264 HyPerformix, средство моделирования, 499 Hyperprof, программа, 467 HyperText Markup Language. См. HTML HyperText Transfer Protocol. См. HTTP i 120, спецификация, 322 IBM, фирма, 135, 490, 497-498 ICMP, протокол, 89, 291 обработка маршрутизаторами, 89 перенаправление, 288 IDE, интерфейс, 43, 244, 319, 344 подключение к PCI, 245 пропускная способность, 245 identd, программа, 168 IDL, язык, 316 ifconfig, программа, 33, 139, 265, 289 if-modified-since, заголовок, 203, 214, 310 IIS, веб-сервер, 57, 407, 496 надежность, 408 производительность, 407 уязвимость, 57 imagemap, тег, 208, 421 IMG, тег, 216,417 index.html, файл, 400, 416 inetd, демон, 391,392 Informix, база данных, 63 Web Datablade , 481 Inktomi, служба распространения данных, 50, 496 mode, узел, 364, 366 второго уровня, 364 константа INODE, 367 константа NINODE, 367 размер таблицы, 367 Integrated Drive Electronics. См. IDE Integrated Research, фирма, 489 Integrated Service Digital Network. Cm. ISDN Intel, фирма, 246,410 Interface Definition Language. См. IDL International Network Services, фирма, 488 Internet Control Message Protocol. Cm. ICMP Internet Explorer, браузер, 212, 217, 312, 433 автозаполнение, 225 зависимость от платформы, 76 загрузка диапазона, 314 обработка изображений, 38 плавная прокрутка, 227 поддержка DOM, 218 рекомендации,227 создание процессов, 227 Internet Information Server. См. IIS Internet Protocol. См. IP Internet QOS, программа, 493 Internet2, 281 InterNex, провайдер, 275 Interse, программа, 158 Iona, фирма, 316 IOS, операционная система, 264, 488 приоритетные пакеты, 279 iostat, программа, 345, 348 перегруженность дисков, 43 IP, протокол, 288 MRU, 289 адрес, 33, 288 алгоритм Ван Якобсона, 291 пакет, 288 размер заголовка, 289 упаковка остаточных данных, 362 уровень, 286 фрагментация пакетов, 289 ip_path_mtu_discovery, параметр, 289 ipconfig, программа, 33, 265 i Planet, веб-сервер, 402 буфер отправки, 432 i Planet, фирма, 402 Irix, операционная система, 353 ISA, шина, 244 ISAPI, интерфейс, 63, 76, 446 ISDN, 257 недостатки, 258 пропускная способность, 258 сравнение с модемом, 37 установка, 258 з j2c, программа, 470 JacORB, пакет, 316 jar, архив, 208 Java Web Server, веб-сервер, 397, 408
Java, язык, 135, 283, 435 CORBA, 435 JIT-компиляция, 469 RMI, 435 библиотеки, 457 блокирующий ввод-вывод, 450 буферизация, 460 декомпиляторы, 468 динамическая привязка методов, 451 зеленые и собственные потоки, 453 интерфейс профилирования, 468 компиляторы, 466 косвенная адресация, 452 многопоточное программирование, 453, 461 на стороне сервера, 449 объединение классов, 456 оптимизация, 455 переносимость, 470 поддержка SMP, 329, 334 поддержка в браузерах, 38 построение изображений, 420 преобразование байт-кода, 450 производительность, 135, 449 профилирование, 467 процессоры, 474 работа с массивами, 449 Рай,472 синхронизация, 453, 462 сложные команды, 458 собственные методы, 460 собственные потоки, 473 создание временных объектов, 452 спецификация, 284 статические объекты, 457 статический компилятор, 470 стековые переменные, 456 строчный буфер, 463 типы переменных, 459 цепочки наследования, 455 экономия трафика, 420 java.nio, пакет, 450 javac, компилятор, 467 JavaScript, язык, 72 DOM, 446 вывод сообщений, 433 вывод форм, 434 выполнение проверок, 432 поддержка в браузерах, 38 расширения и переносимость, 76 JavaSpec, программа, 468 Java-апплет, 434 производительность, 435 Java-сервлет, 444, 449 количество потоков, 454 JCC, программа, 470 JDBC, стандарт, 479 JDBCAdmin, программа, 196 Jigsaw, веб-сервер, 408 JIT-компилятор, 174, 335, 469 JPEG, формат, 421 j Probe, программа, 458, 468 jre. Cw.JVM JSP, 446 jumper, 247 Just in Time. См. JIT-компилятор JVM, 240, 327, 435, 448, 471 Blackdown Java 1.1.6v5, 335 Java 1.2.2, 339 Microsoft, 452 Sun Java 1.1.7, 335, 339, 340-341 аппаратная реализация, 327 время загрузки, 39 ключи комадной строки, 472 поддержка SMP, 373, 461 подключаемый модуль, 473 стековая структура, 453 типы данных, 458 JXTA, программа, 229 к KeepAlive KeepAliveTimeout, параметр, 297 KeepAlive, параметр, 399 KeepAliveTimeout, параметр, 399, 404 Keynote Perspective, программа, 488 Keynote, фирма, 62, 134, 179, 273, 488 khttpd, веб-сервер, 358, 359 kill, программа, 112, 429 /bin/kill, 146 killall, 429 KISS, принцип, 210, 438 ktrace, программа, 381 L Ll, кэш, 240, 324 L2, кэш, 243, 324 LAMP, набор программ для веб-сайта, 58 Land, атака, 152
LAP-M, 254 Lasso, набор средств разработки, 496 latency, 85 lbnamed, система балансировки нагрузки, 498 LD_LIBRARY_PATH, переменная, 339, 370-371 libc, библиотека, 174 Light Weight Process. См. LWP limit вызов, 431 программа, 373 limits.h, файл, 373 Link Access Procedure for Modems. Cm. LAP-M Linpack, тест, 135, 152, 474 lint, программа, 442 Linux, операционная система, 58, 62, 231, 236,351-352,449 история создания, 352 контроль веб-клиента, 237 масштабируемость, 352 на мейнфрейме, 60 настройка MTU, 238 обновление, 238 поддерживаемые процессоры, 352 поддержка SMP, 352 производительность, 237 требования к памяти, 82 ядро реального времени, 61 listen, вызов, 294 listenQ, параметр, 295 Loadmnner, программа, 491 Local Director, система балансировки нагрузки, 55 Local Director, система балансировки нагрузки, 497 Location, заголовок HTTP, 436 lpd, демон завершение, 44 LRU removal, 368, 436 lsof, программа, 168, 374 lstat, вызов, 400 LWP, библиотека, 97, 228, 339 lynx, браузер, 140, 219 запуск по Telnet, 94 измерение времени отклика, 93 преимущества, 38 проверка ссылок, 220 м Mac OS, операционная система, 234-236 дефрагментация, 347 сетевая библиотека, 235 Mach OS, операционная система, 353 Macintosh производительность сети, 235 удаление неиспользуемых расширений, 231 Macintosh , 234 МАС-адрес, 264, 267, 287 МАЕ, 275 magnus.conf, файл, 185-186, 295-396, 402-406, 432 makefile, файл, 374 malloc, функция, 174, 443 многопоточная реализация, 184 реализации, 174 manageable switch, 264 Management Information Base. См. MIB Marimba, компания, 50 mathopd, веб-сервер, 120 MaxClients, параметр, 395, 399 max-file, параметр, 405 Maximum Segment Lifetime. См. MSL Maximum Segment Size. См. MSS MaxKeepAliveConncctions, параметр, 404 MaxKeepAliveRequests, параметр, 399 MaxRequestsPerChild, параметр, 401 MaxThreads, параметр, 396, 406 maxuproc, параметр, 360 MAXUSERS, константа, 367 MCI, провайдер, 276 Measureware, программа, 364, 487 memepy, функция, 321 Memory Management Unit. См. MMU memtool, программа, 364 Merchant Server, веб-сервер, 481 Mercury Interactive, фирма, 488 МЕТА, тег, 133 refresh, 313 перенаправление, 41 Metamata, программа, 468 MIB, база, 135 Microcom Network Protocol. См. MNP Microsoft Access, база данных, 495 Microsoft Office, пакет программ, 240 Microsoft Web Application Stress, программа, 491
Microsoft, фирма, 422 middleware, 57 MIDI, формат, 423 mime.types, файл, 406 MinSpareServers, параметр, 401 MIPS, 86 mkfs, программа, 347 mmap, вызов, 371, 395 mmap-max, параметр, 405 MMU, 355 MMX, набор команд, 246 кэш мультимедиа, 246 MNP, протокол, 254-255 Mocha, программа, 468 mod_log_config.html, файл, 158, 398 mod_perl, модуль, 441 modstatus, файл, 401 Mosaic, браузер, 212, 219 Motorola 68000, процессор, 234 mount, программа, 348 МРМ, модуль, 393 mpstat, программа, 45, 336, 338, 443, 451 MQ, система передачи сообщений, 50, 57 MRJ, виртуальная машина, 471 MRU, 289 MSL, 296 mSQL, база данных, 478 MSS, 289, 298, 300, 357 значение по умолчанию, 289 MTU, 35, 288,357,416,492 в интрасети, 265 изменение размера, 234, 235, 238 оптимальный размер, 234 Multi Router Traffic Grapher, программа, 280, 488 Multics, операционная система, 350 MySQL, база данных, 58, 62, 478 N Name Translation, функция, 402 NAP, 251, 274-276 NBIO, пакет, 450 nCipher, фирма, 184 производительность карты, 184 NCSA, веб-сервер, 408, 426, 431 настройка, 398 формат журнала, 159 NCSA, центр, 212 ndbm, файл, 478 ndd, программа, 139, 148, 289, 293, 299, 384 единицы измерения, 293 Neon, фирма, 487 Neoplanet, браузер, 218 net.Analysis, программа, 158 Net.Medic, программа, 34 Netcat, программа, 147, 229 Netcom, провайдер, 276 Netmanager, программа, 135 Netmetrix, программа, 488 Netperf, программа, 135 Netra, интерфейс администрирования, 390 NetScaler 3100, устройство, 494 Netscape Enterprise, веб-сервер, 62, 63, 190, 312,393,396,402,410 Adminserver, 407 perfdump, 406 количество потоков, 403 количество процессов, 403 конфигурационные файлы, 402 кэш страниц в ядре, 358 лишние функции, 406 отключение поиска в DNS, 404 параметры журнала, 158 постоянные соединения, 404 серверные функции, 402 тайм-аут для CGI, 405 управление потоками, 175 файловый кэш, 404 Netscape Navigator, браузер, 312, 433 DNS helper, 304 выбор домашней страницы, 38 загрузка диапазона, 314 запуск Java, 474 история создания, 217 исходный код, 217 количество цветов, 227 место на диске, 233 настройка в Мае, 235 обработка изображений, 38 отключение автозагрузки изображений, 37 отключение проверки кэшированных страниц, 39 поддержка DOM, 217 предварительный запуск Java, 227 размер кнопок, 228 рекомендации,227
форматирование вывода, 216 Netscape, фирма, 212, 396, 402, 448 открытый и закрытый подходы, 350 NetSpec, программа, 91 netstat, программа, 82, 157, 168, 175, 216, 237, 265, 269, 294-297, 301, 312, 383-384 NETSYS, пакет, 487 Nettest, программа, 91 Network Access Point. См. NAP Network Dispatcher, программа, 498 Network File System. См. NFS Network General, фирма, 269 Network Interface Card. См. NIC Network News Transport Protocol. Cm. NNTP Network Time Protocol. См. NTP Next Generation Internet. См. NGI NFS, 305 UDP, 303 настройка сервера, 305 NGI, 281 NIC, 269, 320 размер буфера, 269 nice, программа, 376 NNTP, протокол, 316 nobody, пользователь, 430 nonparsed headers. См. nph notify, метод, 461 nph-, префикс, 120 NS LiveWire Pro, веб-сервер, 481 NSAPI, интерфейс, 63, 446 nscd, программа, 304 nslookup, программа, 237, 489 NTP, 291 Number Nine, фирма, 247 О obj.conf, файл, 175, 185, 402, 404-406 Object Space, фирма, 317, 435 Object Typing, функция, 403 ODBC, стандарт, 479 Open Market, фирма, 444 Open Transport TCP/IP, реализация TCP/IP, 235 open, вызов, 347, 354, 370 OPEN_MAX, параметр, 373 OpenView, пакет, 135, 487 Opera, браузер, 38, 218 поддержка DOM, 218 Optimal Application Expert, средство моделирования, 499 Optimal Networks, фирма, 492 Optimizelt, программа, 458, 468 Oracle, база данных, 59, 63, 477, 483 Oracle Web Server, 59 Oracle Web Server , 482 ORACLE_HOME, переменная, 116 Orbix, фирма, 316 OSPF, протокол, 288 P Packeteer, устройство, 494 paging, 361 paint, метод, 464 par, программа, 381 patch, 178 Path check, функция, 403 Path MTU Discovery, 289 PATH, переменная, 370 Patrol, пакет, 487 PAWS, 292, 299 PCI, шина, 244, 322 64-разрядная, 322 параллельная, 322 тактовая частота, 244 PCM, 422 PDF, формат, 212 peer-to-peer networking, 229 Pentium, процессор, 326, 331 Pentium Pro, 327 архитектура ядра, 327 perfbar, программа, 378 perfdump, программа, 405-406 установка, 406 perfmeter, программа, 43, 92, 111-112, 325, 355, 361, 378-379 выбор прокси-сервера, 36 perfmon, программа, 379 PerfView, программа, 488 Perl, язык, 58, 439-440, 486 компилятор, 441 оптимизация, 441 переносимость, 440 permanent virtual circuit. См. PVC PHP, 446 PID, 168 piggy-backing, 285 ping flooding, 291
Ping of Death, атака, 152 ping, программа, 89, 147, 237, 274, 291 flood, 147 в Windows, 233 размер пакетов, 89 PIPE_BUF, параметр, 399 pipelining, 241, 323, 326 pmap, программа, 84 PNG, формат, 97, 422 Point of Presence. См. РоР PointForward, программа, 491 poll, 450 poll, вызов, 374 Polllnterval, параметр, 404 РоР, 278 POST, команда HTTP, 58, 228, 249 Power-On Self Test. См. POST PowerPC, процессор, 234, 240-241, 352 PPID, идентификатор, 429 PPP, протокол, 235, 248, 254, 266, 287 значение MTU по умолчанию, 289 коррекция ошибок, 287 Precept Software, фирма, 424 priocntl, программа, 376 Prognosis, программа, 489 promiscuous mode, 267 Protection Against Wrapped Sequence Numbers. См. PAWS proxy .рас, файл, 36 prtconf, файл, 139 prtmcm, программа, 364 ps, программа, 83, 84, 120, 354, 359-360, 364. 377, 386, 397, 428-430 версия Беркли, 377 запуск через Telnet, 122 запуск через веб, 120 поиск идентификатора, 168 построение графиков, 123 сохранение статистики в БД, 122 public_html, каталог, 103 Pulse Code Modulation. См. PCM Pure Software, фирма, 443 PURE, программа, 445 Purify, программа, 75, 173, 397, 445 PVC, 261 Q QNX, операционная система, 355 QoS, 261 классы, 493 Quality of Service. См. QoS Quantify, программа, 443, 468 Quick Web, прокси-сервер, 410 QuickRoute, программа, 234 R RAID, массив, 67, 343, 346-347 концепция, 346 надежность, 74 производительность, 346 чередование записи, 346 Rainbow, фирма, 184 RAM Doubler, программа, 235 RAM. См. оперативная память Ramp Networks, фирма, 257 Random Access Memory. См. оперативная память RAPS, пакет, 489 Rational, фирма, 468 RDBMS, 445 rdist, программа, 50 read, вызов, 347, 354, 371, 450 Real Networks, фирма, 424 RealAudio, протокол , 303 real-time operating system. См. RTOS Redline, фирма, 495 Reduced Instruction Set Chip. См. RISC Redundant Array of Inexpensive Disks. Cm. RAID REMOTE_HOST, переменная среды, 41 repeater, 263 Resolve, программа, 489 Resonate, фирма, 55, 134, 176, 489, 498 revision control systems, 45 RIP, протокол, 288 RISC, архитектура, 241, 327, 331 rlim_fd_cur, параметр, 374 rlim_fd_max, параметр, 374 максимальное значение, 374 rlimit_no_file_max, параметр, 374 rlimit_nofile_cur, параметр, 374 RMCmem, пакет, 364 RMI, 57, 435, 449, 455, 457 недостатки, 45 RMON, 135, 488 RND, фирма, 498 Rockwell, фирма, 259 Round Robin DNS. См. RRDNS route, программа, 33
router, 264 rpc.rstatd, демон, 111 rpcstatd, демон, 378 RqThrottle, параметр, 175, 405-406 оптимальное значение, 405 RRDNS, 54, 176, 304, 438 конвоирование, 54 недостатки, 54 сбои серверов, 55 RST, сегмент, 35, 216, 296, 396 rstat, программа, 35, 111, 380 возможности, 111 выбор прокси-сервера, 36 запрос данных из БД, 115 запуск, 112 использование для автовыбора прокси-сервера, 36 построение графиков, 116 сохранение статистики в БД, 114 rstatd, демон, 35, 111, 121 выбор прокси-сервера, 36 запуск, 112 RSVP, протокол, 493 rsync, программа, 50 rt_sigaction, вызов, 395 RTFM, пожелание, 210 RTOmax, переменная, 295 RTOS, 356 RTT, 298 гир, программа, 111-112, 380 RWIN, 297 значение по умолчанию, 298 оптимальный размер, 298 S S3, фирма, 247 SAF, 402, 405 sam, программа, 374 sar, программа, 345, 361, 384 запуск через веб, 120 SAVVIS, провайдер, 273 SBus, шина, 322 SCO Unix, операционная система, 231 SCSI, интерфейс, 43, 245, 319, 345 Differential, 345 Narrow Ultra, 345 UltraSCSI 2, 345 Wide Ultra, 345 длина кабеля, 345 SCSI, интерфейс (продолжение) контроллеры, 345 пропускная способность, 345 SDRAM, 324 SDRAM. См. оперативная память SE, пакет, 489 Secure Sockets Layer. См. SSL security off, параметр, 185 seek time, 43 select, вызов, 374, 401, 450 select, оператор, 142 SendBufferSize, директива, 375 Server-Side Include. См. SSI Service Selection, функция, 403 servlet, 57 set-cookie, заголовок HTTP, 104 setrlimit, вызов, 430 setsockopt, вызов, 298, 357, 375 SGI, фирма, 244 sh, интерпретатор команд, 439 Shotgun, программа, 257 showrev, программа, 179 SIGALRM, сигнал, 430 SIGPIPE, сигнал, 217, 428 Silicon Graphics, фирма, 353 SISS, заплата, 373 size, программа, 84 skill, программа, 429 SLA, 489 sleep, вызов, 142, 146, 461, 463 SLIP, протокол, 248, 287 Small Computer System Interface. См. SCSI smartdrv.exe, программа, 232 smit, программа, 374 SMP, 81, 209, 328 SSL, 184 балансировка нагрузки, 81 масштабируемость, 81 производительность, 328 Smurf, атака, 152 SNCA, сетевой ускоритель, 358 Sniffer, торговая марка, 269 SNMP, протокол, 121, 134, 280, 488 RMON, 135 snoop, программа, 192, 267, 269, 301, 305, 383, 492 параметры, 301 прием пакетов, 35 so_q01en, константа, 295
so_qlen, константа, 295 SO_RCVBUF, параметр, 357, 375 SO_SNDBUF, параметр, 357, 375 SOJTIMEOUT, параметр, 460 sock, программа, 228 SoftPC, эмулятор ПК, 240 Solaris, операционная система, 351, 361, 449 tempfs, 365 х86, 231 выделение памяти, 351 заплаты, 373 история, 351 поддержка SMP, 329 сетевой кэш, 358 требования к памяти, 82 SOMAXCONN, параметр, 295 sotruss, программа, 381 SourceAgain, программа, 468 SPARC, процессор, 241, 326, 331, 351-352 Sparcstation, компьютер, 240 SparcStorage, массив дисков, 348 SPECwcb99, тест для веб-сервера, 151 Speed Doubler, программа, 235 Speed Mark, программа, 247 spray, программа, 147 Sprint, провайдер, 276 sprocket, прокси-сервер, 103, 143 журнал, 109 запуск, 103 Spyglass, фирма, 212 SQL Server, 496 SQL, язык, 121 Squid, программа, 410 Squid, прокси-сервер, 152 Squid, тест для прокси-сервера, 152 SRAM. См. оперативная память srm.conf, файл, 219, 400 SSI, 44, 190 SSL, 36, 183 SSLeay, реализация, 187 взаимодействие с SMP, 184 вместе с gzip, 187 поддержка в браузерах, 38 подслушивающий прокси-сервер, 156 порт, 183 SSL3SessionTimeout, параметр, 186 SSLCacheEntries, параметр, 184, 186 StartServers, параметр, 401 stat, вызов, 395 stdio, библиотека, 374 strace, программа, 156, 169, 237, 371, 381, 460, 469 обращения к журналу, 45 String, тип, 463 stylesheets. См. таблицы стилей Sun Ultra, процессор, 326, 327 Sun, корпорация, 229, 244, 284, 305, 351, 402, 490-491, 494 Sun, фирма, 322, 329, 422, 468 SunOS, операционная система, 351 suspend, вызов, 461, 463 SVR4, стандарт, 351 swap file, 361 switch, 264 Sybase база данных, 63 фирма, 482 Symantec JIT, компилятор, 236 Symmetric Multiprocessing. См. SMP Symon, программа, 490 SYN flooding, 152, 291, 294 защита, 294 SYN, сегмент, 291, 294 synchronized, ключевое слово, 175 sysdef, программа, 373 sysmon, программа, 233 system, вызов, 430 т T/TCP, протокол, 62, 302, 413 поддержка, 303 Т1, линия, 251 пропускная способность, 260 ТЗ, линия пропускная способность, 260 T3AdminJDBC, страница, 127 tail, программа, 157, 159, 486 talk, программа, 89 Tandem, линейка операционных систем, 74 Tango, браузер, 220 Tango, среда разработки, 495 tcov, программа, 443 TCP Monitor, программа, 235 TCP, протокол, 213, 292, 460 keepalive, 297 MSS, 298
TCP, протокол (продолжение) алгоритм Нагла, 395 контроль, 301 масштабирование окна, 293, 300 медленный старт, 299 многопоточные реализации, 81 надежность, 292 назначение, 292 недостатки, 292 оптимизация для HTTP, 292 отложенное подтверждение, 299 очередь сокета, 293 параметры, 293, 300 пропускная способность, 293 размер заголовка, 289 тайм-аут повторной передачи, 295, 301 транзакции, 62 трехэтапное рукопожатие, 307 уровень, 286 установка и закрытие соединения, 292 TCP/IP, стек протоколов, 248, 283, 307 пропускная способность, 322 реализация, 2{И, 321 tcp_defered_ack_interval, параметр, 299 tcp_mss_max, параметр, 300 tcp_mss_min, параметр, 300 TCP_NODELAY, параметр, 460 tcp_rexmit_interval_initial, параметр, 295 tcpdump, программа, 192, 269, 301, 302, 383 прием пакетов, 35 tcpListenDrop, параметр, 295 TeamQuest, фирма, 487 telnet, программа, 34, 36, 62, 89 обращение к chargen, 148 Telnet, протокол, 121, 273, 297, 308 tempfs, файловая система, 365 TFTP, протокол размер пакета, 290 thrsetconcurrency, интерфейс, 339 thread, 328 throughput, 85 Tibco, система передачи сообщений, 50, 57 time, команда встроенная, 440 time, программа, 436 TIME_WAIT, состояние, 296 timed, демон, 138, 139 TimeSys, компания, 61 TITLE, тег, 418 Tivoli, система, 135, 179, 490 tkprof, программа, 483 Toba, программа, 470 top, программа, 83-84, 237, 325, 360-361, 363, 376, 380-381, 386, 397, 429 завершение процессов, 36 запуск через веб, 120 контроль ресурсов, 44 слежение за объемом процессов, 43 статистика использования ресурсов, 36 Topaz ActiveWatch, программа, 488 Torrent, программа, 494 toString, метод, 463 touch, программа, 146 TowerJ, программа, 470 TPC-C/D, тесты для транзакционного веб-сервера, 151 traceroute, программа, 34, 62, 88, 237, 258, 276, 291, 492 в Windows, 233 определение MTU, 290 отключение поиска в DNS, 88 tracert, программа, 34, 233 trailer encapsulation, 362 Transaction TCP. См. Т/ТСР Transmission Control Protocol. См. TCP truss, программа, 156, 169, 179, 348, 371, 381,460,469 обращения к журналу, 45 ttcp, программа, 91 tunefs, программа, 370 Tuxedo, программный пакет, 57, 59 и UART, контроллер, 248 16450, 248 16550А, 248 8250, 248 буфер, 248 версия, 233 переполнение буфера, 232-233, 249, 254, 256 UDP, протокол, 71, 303, 423-424, 460 надежность, 303 производительность, 303 UFS, файловая система, 364 максимальный размер блока, 364 организация, 364
ulimit, вызов, 376, 431 ulimit, программа, 138, 173, 373-374, 404 Ultra ATA. См. IDE UltraSPARC, процессор, 326 uname, программа, 372 Unified File System. См. UFS Universal Asynchronous Receiver and Transmitter. См. UART Unix, операционная система, 73, 349-350, 354-355 AIX, 352 AT&T, 350 Berkeley, 350 BSDI, 350, 353 Digital Unix, 352 Irix, 353 Mach OS, 353 SCO Unix, 350 Solaris, 351 System V Release 4, 350 версии, 350 версии для ПК, 390 дефрагментация, 347 достоинства и недостатки, 389 драйвера, 177 история, 349 копирование данных, 356 кэширование файловой системы, 437 оптимизация доступа к диску, 347 оптимизация записи, 368, 369 принципы, 353 системные вызовы, 354 структура каталогов, 366 файловая система, 364 фрагментация, 284 Unshielded Twisted Pair. См. UTP Update log, функция, 403 UPS, 75 URL, адрес, 214 завершающий /, 310, 416 UseOutputStreamSize, параметр, 432 User Datagram Protocol. См. UDP utilization, 85 UTP, 271 UUNet, провайдер, 275 v V32, протокол, 253 V34, протокол, 253 Velometer, программа, 491 verbosegc, ключ, 45 Veritas First Watch, программа, 490 Veritas, файловая система, 348, 367 vi, текстовый редактор, 273 VidSpeed, программа, 247 Visigenic, фирма, 316, 458 Visual UpTime, программа, 490 Vital Signs Software, 34 vmstat, программа, 82, 112, 237, 325, 361, 364, 368, 384 запуск через веб, 120 проверка памяти, 42 Volano, программа, 474 Voyager, пакет, 317, 435 VRAM, 246 VRML, язык, 240, 247, 422 VTS, программа, 491 W W3C, консорциум, 311, 419 wait state, 244 wait, вызов, 354, 386 WaitingThreads, параметр, 405 wc, программа, 312 WDG, программа, 419 Web Server Director, система балансировки нагрузки, 498 web.SQL, веб-сервер, 482 webget, программа, 94 weblint, программа, 419 Weblogic, система, 127, 340, 454, 480 Weblogic, фирма, 196 Webmin, программа, 390 WebNFS, файловая система, 373 WebRamp M3t, программа, 257 WebSizr, программа, 491 WebStone, тест для веб-сервера, 150 недостатки, 150 спецификация, 151 WebTV, устройство, 219 whatroute, программа, 234 Windows NT, операционная система, 349, 388 Server, 389 Workstation, 389 достоинства и недостатки, 389 ограничения масштабируемости, 73 оптимизация записи, 368
Windows XP, операционная система, 284 Windows, операционная система, 231, 449 API, 284 дефрагментация, 347 драйвер экрана, 232 кэширование, 232 определение размера MTU, 234 оптимизация для браузера, 231 пакеты обновлений, 232 поддержка SMP, 329 регулярная дефрагментация, 369 устранение беспорядка, 231 Winsock, реализация TCP/IP, 232, 248 Wintach, программа, 247 Wisconsin Proxy Benchmark, тест для прокси-сервера, 152 Worldcom, провайдер, 275 write, вызов, 354, 371 wwwis, программа, 417 х X Window System, оконный интерфейс, 352 X Window, оконный интерфейс, 317 х86, семейство процессоров, 351 Xbench, программа, 247 Xedia, фирма, 494 XFree86, оконный интерфейс, 352 xload, программа, 379, 381 XML, язык, 61, 420 xntpd, демон, 138, 139 ХР. См. eXtreme Programming xperfmon, программа, 490 xterm, терминал, 372 Xvfb, программа, 112, 372 Y Yahoo!, поисковый сервер, 397, 412 yes, программа, 147 z Zeus, веб-сервер, 408 A автоматизированный контроль, 98 автоматическая генерация сценариев, 103 автоматическая загрузка изображений, 223, 418 автоматический перезапуск, 180 администратор базы данных, 176 адресация от отправителя, 288 анимация, 422 асимметричная цифровая абонентская линия. См. DSL асинхронный режим передачи. См. ATM аттестация, 148 аудио сжатие, 423 форматы, 422 частота дискретизации, 423 Б база данных, 58 альтернативы, 477 анализ информации, 476 блокировка, 481 денормализация таблиц, 479 диагностика, 483 зависание и веб-сайт, 169 запросы, 480 индексирование, 436, 481 конфигурация пула подключений, 480 максимальное количество соединений, 482 многоярусная, 479 назначение, 180 обработка транзакций, 476 объединение с веб-сервером, 481 перегрузка, 483 повышение производительности, 478 получение данных, 110 помещение данных, НО построение графиков, 116 предварительная компиляция, 480 признаки необходимости, 477 прямые соединения, 479 пул подключений, 44, 445 работа со стандартными потоками, 115 рост таблиц, 189 связанные переменные, 478 создание курсоров, 479 статистика подключений, 129 статистика производительности, 109 суперкэширование, 479 типы запросов, 476 базовая система ввода-вывода. См. BIOS
байт-код балансировка нагрузки, 54 Local Director, 55 RRDNS, 54 многоадресная передача, 56 уровень Ethernet, 56 библиотечный вызов, 354 блок управления памятью. См. MMU блокирование сайтов, 36 блокировка потоков, 174 блокировка таблиц, 179 бод, 253 брандмауэр, 187 влияние на производительность, 187 возможные проблемы, 180 шифрование и производительность, 187 браузер, 53, 212 автономный режим, 33 быстродействие, 221 возможности и производительность, 214 горячие клавиши, 225 длительность загрузки, 38 домашняя страница, 38 дополнение адресов, 225 зависание, 33 запрос страницы, 213 идеальный, 220 использование IP-адресов, 215 кнопка Stop, 224, 226 компоновка страниц, 216 кэширование, 437 кэширование изображений, 421 кэширование сайтов, 224 многозадачность, 226 настройка, 222 настройка прокси-сервера, 103 обновление, 222 обработка cookie, 215 обработка HTML, 213, 215, 240 обработка URL, 214 обработка ответа, 215 обращение к DNS, 33, 214 объем памяти, 223 остановка загрузки, 35 отключение cookie, 224 отключение автозагрузки изображений, 37 отключение лишнего, 223 открытие окна, 227 браузер (продолжение) официальные и бета-версии, 223 очистка журнала, 223 подключаемые модули, 223, 226 поиск, 477 поиск в кэше, 214 принцип работы, 212 проверка актуальности кэша, 223 проверка кэшированных страниц, 38 программа управления, 96 размер кэша, 38, 226 скорость, 38 скрытие кнопок, 133 сохранение страниц, 224 требования к оперативной памяти, 242 утечка памяти, 226 формат кэшированных файлов, 222 частота установки соединений, 222 эмуляция, 139 в ввод-вывод, 202, 247 веб-клиент, 228 вебмастер, 34 веб-сайт UPS, 75 архитектура, 53 безопасность, 183 восстановление после отказа, 181 время ожидания, 77 выбор названия, 418 выбор провайдера, 276 доступность, 74 дублирование, 35, 47, 49, 180 зависание БД, 169 запросы к БД, 169 зеркало, 35 кластеризация, 50 оптимизация под браузер, 53 отладка, 138 примеры архитектуры, 58 примеры конфигураций, 62 проверка на перегруженность, 35 пропускная способность, 76 рейтинги, 64 с большой нагрузкой, 63 с низкой нагрузкой, 62 со средней нагрузкой, 63 тестирование на нагрузку, 137, 139
веб-сайт (продолжение) типичные проблемы, 172 топологическая схема, 170 транзакционный, 74 требования к архитектуре, 76 цель создания, 70 веб-сервер, 57 аппаратная реализация, 327 безголовый, 319 бюджет, 74 возможности, 65 выбор провайдера, 41 выбор программного обеспечения, 43 динамического HTML, 65, 71 дополнительные службы, 72 дублирование, 43, 74, 279 жесткий диск, 319 замена сетевого интерфейса, 42 и оконный интерфейс, 44 интрасеть и интернет, 263 информация о состоянии, 47 качество обслуживания, 70 коммутация пакетов в шинах, 319 максимальное количество процессов, 386, 395 максимальное количество соединений, 385 масштабирование, 328 масштабирование с помощью NFS, 70 масштабируемость, 47, 72, 320 многопоточный, 393 многопроцессорный, 320 нагрузка в течение дня, 69 недостающие функции, 409 оконный интерфейс, 318 оперативная память, 320 параметры электропитания, 40, 343 первого поколения, 391 подключение по ISDN, 258 подсистема ввода-вывода, 319 порождение самого себя, 392 потоки мультимедиа, 71 потребление памяти, 396 предварительное порождение процессов, 392 пропускная способность, 79 размещение в интрасети, 262 расстояние до клиентов, 41 рейтинг, 407 сетевой адаптер, 320 веб-сервер (продолжение) статического HTML, 65, 80 тайм-аут повторной передачи, 41 тестирование, 67 трассировка вызовов, 393 требования, 42, 67, 80-83 требования к дискам, 347 требования к оборудованию, 356 требования к операционной системе, 349 управление по Telnet, 372 уровня ядра, 358 утечка памяти, 74, 397 хиты, 68 шина, 319, 322 веб-страница заголовок, 417, 418 загрузка обновленной версии, 39 идеальная, 413 имена файлов, 415 контроль содержимого, 127 объем, 159 проверка, 419 распределение размеров файлов, 161 удаление баннеров, 224 удаление тегов, 229 видео, 423 видеоадаптер, 245 глубина цвета, 246 драйвер, 247 объем памяти, 246 разрешение, 246 тесты, 247 видеопамять. См. VRAM виртуальная машина Java. См. JVM виртуальная машина. См. JVM виртуальная память, 360 виртуальный узел, 395 витая пара. См. UTP включение на стороне сервера. См. SSI время обработки, 165 всплески активности, 165 время ожидания, 77, 85, 252 зависимость от нагрузки, 87 интернета, 272 интерфейсы, 252 маршрутизаторы, 273 модема, 254 преобразование протоколов, 252
время ожидания (продолжение) примеры, 86 сетевая составляющая, 88 составляющие, 153 тестовая программа на С, 94 тестовый сценарий на Perl, 96 время передачи, 156 время поиска, 43 время работы, 39 входящая точка подключения. См. РоР выделенная линия, 260 вызов асинхронный, 50 синхронный, 50 вынесение инвариантов, 466 вытеснение по давности использования. См. LRU removal г гиперссылка, 212, 419 глобальная оптимизация, 207 графический интерфейс пользователя. См. GUI д демилитаризованная зона, 60, 187 демонизация, 444 дескриптор файла, 373 динамический HTML, 446 динамическое содержимое, 44 диспетчер задач, 36, 233 контроль ресурсов, 44 для транзакций. См. Т/ТСР долгоживущие блокировки, 175 домашняя страница, 213 драйвер, 247 ж жесткий диск, 244, 342 IDE, 244, 344 SCSI, 244, 345 алгоритм лифта, 343 время ожидания, 342, 343 время поиска, 43 выбор, 43 интерфейс, 43 контроллеры, 344 кэш контроллера, 43 кэш-память, 343 жесткий диск (продолжение) локальный, 344 максимальное время поиска, 244, 343 массив RAID, 346 надежность, 343 оптимизация доступа, 347 отслеживание доступа, 348 производительность, 87, 346 пропускная способность, 347 сетевой, 344 скорость вращения, 43, 244, 343 требования веб-сервера, 344 устройство, 342 фрагментация, 245, 347 чередование, 347 журнал, 445 адекватность, 166 анализ, 157 буферизация, 397 время хранения, 206 момент записи хита, 166 ограничения, 159 переполнение диска, 172 поля данных, 158 преобразование даты, 465 расширенный формат, 158 сообщения об ошибках, 175 средний объем файлов, 160 точность записей, 167 формат CLF, 158 з зависание, 174 зависимости, 181 завсегдатай, 167 загрузка диапазона байтов. См. byterange замещение страниц. См. paging заплата, 178 запуск через веб, 120 зацикливание, 428 защита от превышения последовательного номера. См. PAWS защищенный протокол передачи гипертекста. См. HTTPS зомби, 429 и избыточный контроль, 134 измерение отклика приложений. См. ARM изображен не-карта, 208
индексирование, 436 интернационализация, 452 интернет, 272 MTU, 291 будущее, 281 время ожидания, 272 динамическая маршрутизация, 288 экономическая эффективность, 93 интернет следующего поколения. См. NGI интерфейс встроенной электроники. См. IDE интерфейс программирования приложений. См. API интерфейс шлюзов. См. CGI интрасеть, 262 единое значение MTU, 289 моделирование, 272 сегментирование, 262 статическая маршрутизация, 288 Информационный сервер интернета. См. IIS информация, 203 источник бесперебойного питания, 75 к кабельный модем, 37, 259 безопасность, 259 пропускная способность, 259 скорость отправки, 259 кабельный. См. кабельный модем каскадная перегрузка, 179 каталог, 366 качество обслуживания. См. QoS квант времени, 354 кластеризация, 50, 75 клиент-сервер, архитектура, 307 двухъярусная схема, 307 трехъярусная схема, 307 кодирование импульсной модуляции. См. РСМ коллизия пакетов, 265 коммутатор, 264 Ethernet, 270 IP, 280 ячеек, 285 коммутация второго уровня, 271 коммутация на уровне IP, 280 компиляция на лету. См. JIT-компилятор конвейерная обработка. См. pipelining конкуренция поставщиков, 75 консорциум всемирной сети. См. W3C контекст ядра, 355 контроль и оповещение, 120 концевое устройство, 251 концентратор, 264 коэффициент использования, 85, 92 rstat, 111 кривая нагрузки, 140 круговая система DNS, 54 куча, 84 кэширование, 202, 208 CGI, 208 алгоритмы, 203 апплетов, 39 записи, 232 иерархическое, 410 ключей SSL, 186 прокси-серверы, 209 секретный ключ, 184 файловой системы, 209 чтения, 232 кэш-память, 243 л линейный поиск, 436 линия связи, 251 телефонная, 251, 252, 255 локализация, 452 м максимальное время жизни сегмента. См. MSL максимальный передаваемый блок. См. MTU максимальный размер сегмента. См. MSS маршрутизатор, 251, 264, 279 аппаратный, 279 время ожидания, 279 проверка, 34 пропускная способность, 279 рабочая станция, 279 с множеством портов, 279 сжатие на канальном уровне, 280 установка приоритетов, 279
маршрутизация от отправителя, 277 масштабируемость, 47 Java, 339 идеальная, 72 кластеризация, 50 компонентов, 73 компьютеров Sun, 329, 331, 333, 341 корпоративных приложений, 329 определение, 72 персонального компьютера, 389 рекомендации, 48 статического содержимого, 415 стековая архитектура, 59 транзакционных серверов, 48 математический сопроцессор. См. FPU межпроцессное взаимодействие, 328 мейнфрейм, 60 надежность, 74 многоадресная передача, 56, 291 многозадачность, 349 многопользовательский режим, 349 многопоточное программирование, 209, 328, 359 Java, 328 синхронизация, 462 многопроцессорный компьютер, 328 многосетевой узел, 60 многоуровневая архитектура, 60 модем, 252 ISDN, 258 V42, 255 аппаратное сжатие, 249, 254 аппаратное управление потоком, 255 внутренние и внешние, 256 время ожидания, 253 выбор, 37 интерфейс, 256 коррекция ошибок, 255 нагрузка на последовательный порт, 254 объединение каналов, 257 определение качества линии, 255 принцип действия, 253 программное управление потоком, 255 пропускная способность, 253, 254 синхронизация, 254 ускорение набора, 257 устранение неполадок, 32, 33 молчание сервера, 156 монитор, 245 монитор обработки транзакций, 84 мост, 264 н надежный набор дешевых дисков. См. RAID недостаток дескрипторов, 173 терминалов, 176 указателей, 176 недостаточные разрешения, 178 некорректная адресация, 173 некорректный драйвер, 177 необрабатываемые заголовки. См. nph неправильные пути, 178 неправильный шаблон, 178 неудержимо растущая программа, 429 о обработка ошибок, 179 обратный прокси-сервер. См. узел-бастион объектная модель документа. См. DOM объектно-ориентированное программирование. См. ООП объявление переменных, 467 одноранговая сеть, 229 окно, 286 окно приема. См. RWIN оконный интерфейс, 372 приоритеты программ, 372 ООП, 52, 455 распределенное, 52 оперативная память, 323 банк, 242 виды, 242 динамическая, 242, 323 динамический пул, 361 динамическое выделение и освобождение, 363 измерение доступного объема, 363 копирование данных, 362 максимальный объем, 361 ограничение масштабируемости, 73 ограничение объема, 82 ограничение процессов, 376 повышение производительности, 242 признаки недостатка, 37, 43
оперативная память (продолжение) с быстрым доступом, 243 с расширенным выводом, 243 синхронная динамическая, 243 скорость, 243 статическая, 242 статическое содержимое, 83 страница, 361 требования CGI, 83 требования веб-сервера, 83 требования операционной системы, 82 шина, 242-243 операционная система, 349 заплаты, 372 надежность, 74 оптимизация под веб-сервер, 373 реального времени, 60, 355 статистика веб-сайтов, 349 оптимизация, 207 амортизация, 208 схемы, 208 оптимизирующий компилятор, 332 основной шлюз, 33 отказ в обслуживании. См. DoS отказ оборудования, 177 отказ питания, 177 открытый стандарт, 75, 200 очередь запросов, 165 сокета, 293 установленных соединений, 294 п пакет данных оптимальный размер, 286 фиксированной длины, 285 параллельная обработка, 209 перегрузка подсети, 176 переключение контекста, 325, 355 частота, 325 перекручивание кабеля, 194 перенаправление, 41 переносимость и производительность, 199 на уровне исполняемых файлов, 351 на уровне исходного кода, 200, 351 на уровне объектного кода, 200 переполнение диска, 172 персональный компьютер, 239 планирование программ, 51 планировщик, 354 повторитель, 263 повторное вхождение, 437 повторное использование, 52, 421 подключение на стороне сервера, 44 подслушивание в сети, 383 поиск в файле, 478 ползучий улучшизм, 438 политика, 263 полное доменное имя. См. FQDN последовательный порт, 33 постоянные соединения, 68, 393 оптимизация тайм-аута, 311 постоянный виртуальный канал. См. PVC построение графиков, 97 построчная оплата, 425 поток, 328 зависание, 461 зеленый, 461 мультимедиа, 71 параллельное выполнение, 360 переключение, 359 собственный, 461 создание, 359 ядра, 339 правило 80/20, 207 предварительная обработка, 435 предельная оптимизация, 199 предсказание ветвления, 326 прерывание таймера, 377 настройка, 142 принцип неопределенности, 197 приоритет, 263 провайдер, 251 влияние на производительность, 276 второго уровня, 278 выбор, 278 первого уровня, 278 поиск виновного, 280 производительность, 277 размещение, 276 смена, 34, 39 топологическая близость, 276 требования к прокси-серверу, 278 прогнозирование ветвления. См. branch prediction программист, 425
программный поток. См. поток Проигрыватель Windows Media, 424 производительность автоматизированный контроль, 96 анализ, 197 ввод-вывод, 202 вероятные источники проблем, 170 взаимозависимости, 198 завершение оптимизации системы, 199 знания о данных, 204 знания о пользователях, 204 и абстрагирование, 200 и защищенность, 201 и переносимость, 199 количество прыжков, 288 конференции, 207 кэширование, 202, 207 нелинейность ухудшения, 206 оборудование и программы, 205 определение источников проблем, 280 определение максимальной, 170 отображение статистики, 133 отсутствие узких мест, 205 падение из-за измерения, 198 параметры, 85 пересылка изменений, 203 принципы повышения, 197 размер страниц, 206 сбор статистики в БД, 109 стоимость повышения, 198 учет реальных условий, 204 прокси-сервер, 35, 263 Condenser, 494 proxy .рас, 36 SSL, 109 блокирование содержимого, 36 быстродейтсвие, 409 в организации, 410 возможные проблемы, 40 и HTTPS, 35 кэш, 409 основания для установки, 39 подслушивающий, 156 поиск самого быстрого, 36 получение имени, 36 принцип действия, 409 проверка наличия, 35 требования к, 40 фильтрация запросов, 410 пропускная способность, 76, 85, 86 SSL с ускорителем, 184 гарантированная, 277 зависимость от нагрузки, 87 интернета, 251 недостаточная, 37 оценка с помощью FTP, 90 примеры, 86 справочные данные, 77 средства измерения, 91 протокол веб, 287 закрытый, 284 маршрутизации, 288 односторонний или двусторонний, 286 открытый, 283 сетевой, 285 уровень, 286 ценность, 283 протокол интернета. См. IP протокол передачи гипертекста. См. HTTP протокол передачи файлов. См. FTP протокол пользовательских дейтаграмм. См. UDP протокол разрешения адресов. См. ARP протокол управления передачей. См. TCP протокол управляющих сообщений интернета. См. ICMP профилирование, 207, 209, 496 пользователей, 209 пропускной способности, 209 процедура доступа к каналу. См. LAP-M процесс, 354 адресное пространство, 361 выгружение, 361 завершение, 429 запуск, 361 зомби, 429 идентификатор, 168 идентификация, 168 изменение имени, 168 контроль, 119 оптимальное количество, 355 освобождение памяти, 362 планирование выполнения, 354 порождение, 388 приоритет, 376 создание, 359 увеличение кванта времени, 358 установка приоритета, 358
процессор, 324 64-разрядный, 241 CISC, 241 HTTP, 327 RISC, 241 wait state, 324 архитектура, 325, 327 веб-клиента, 239 загруженность, 37 конвейерная обработка, 241 контроль загрузки, 324 кэш-память, 240 недостаток мощности, 324 обработка HTML, 240 оптимизация, 326 отключение, 334 портативного компьютера, 241 пропускная способность, 327 разрядность, 326 суперскалярный, 324 тактовая частота, 241, 326 тестовый сервлет, 340 требуемая мощность, 325 эмуляция, 240 прыжок, 42, 286 прямой доступ к памяти. См. DMA ПТТ, 281 пул подключений восстановление, 180 размер, 44 рост и производительность, 195 утечки, 44 р разворачивание циклов, 442 раздвоение личности, 180 разделяемая память, 328 разработка программ, 51 раскрытие функций, 442 расширенный набор команд. См. CISC резол ьвер, 215 с сбор мусора, 451 сборка мусора, 472 синхронная, 451 сборщик мусора, 45, 449 сборщик мусора. См. GC свопинг, 37, 43 связующая программа, 57 сегмент неинициализированных данных, 84 сегмент текста, 84 сегментирование, 263 семафор, 328 серверная функция, 405 сервлет, 57 сетевая файловая система. См. NFS сетевой адаптер, 320 захват шины, 321 обновление прошивки, 321 производительность, 321 размер буфера, 321 сетевой буфер, 375 установка размера, 375 сетевой протокол передачи новостей. Gn.NNTP сетевой протокол синхронизации времени. Gh.NTP сжатие данных, 204 символические ссылки, 370 симметричная многопроцессорная обработка. См. SMP синхронизация, 48 системный вызов, 354 Системный монитор, 82, 233 проверка качества линии, 233 системы слежения за обновлениями, 45 служба доменных имен. См. DNS смешанный режим, 267 совмещенная отправка. См. piggy-backing согласованность данных, 49 соглашение на уровне служб, 489 содержимое, 412 апплеты, 418 борьба с дизайнерами, 413 графика, 420 звуковые форматы, 422 обработка браузером, 417 оптимизация под конкретный браузер, 419 потоковое видео, 423 размер, 412,416 разрешение экрана, 421 советы разработчикам, 415 уменьшение размеров изображений, 420 форматы графики, 421
соединение TCP, 50 контроль состояния, 383 логическое, 50 сокращенный набор команд. См. RISC спецификация, 148 список Крейга, 412 спутник связи, 262 спящий режим, 40 стандарт доступности Бобби, 419 статический компилятор, 470 стек, 84 стековая архитектура, 59 масштабируемость, 59 СУБД, 445, 477 сценарий интерпретатора переменные окружения, 440 производителность, 439 счетчик команд, 325 т Т/ТСР, протокол недостатки, 303 таблицы стилей, 414 связанные, 414 такт ожидания. См. wait state твердотельный диск, 344 телефонная компания. См. ПТТ тенденции, 61 тестирование для рынка, 150 тестирование на нагрузку sprocket, 140 кривая нагрузки, 140 подготовка, 137 пример сценария, 140 реальность результатов, 139 сеть, 147 синхронизация, 146 синхронизация времени, 138 статистика URL, 137 эмуляторы, 140 эмуляция распределения скоростей, 138 точка доступа к сети. См. NAP трассировщик системных вызовов, 169, 381 трассировщики транзакций, 486 трехмерная графика, 247 трехэтапное рукопожатие, 302 триггер, 242 труба, 59 у удаление одинаковых выражений, 466 удаленные вызовы методов, 57 узел-бастион, 187 универсальная цифровая сеть. См. ISDN универсальный асинхронный приемник и передатчик. См. UART унифицированная файловая система. См. UFS управление сигналами, 395 управляемый коммутатор, 264 управляющие сообщения. См. ICMP упрощение, 466 упрощенный интерфейс компьютерных систем. См. SCSI уровень защищенных сокетов. См. SSL установка соединения ускорение, 155 устройства ввода-вывода быстродействие, 65 утечка памяти, 444 определение, 173 поиск, 75, 170, 173 утечка подключений, 174 поиск, 129 ф файл, 364 длина имени, 397 изменение даты, 370 отображение в память, 371 подкачки, 361 проверка разрешений, 370 распределение размеров, 162 файловая система, 364 длина имени, 365 заполнение, 366 каталоги и файлы, 367 кэш DNLC, 367 кэширование, 368 оптимизация под содержимое, 364 очистка буферов, 376 размер блока, 364 фрагментация, 369
фоновое изображение, 417 фрагментация, 358 X хит, 306 распределение по времени, 161, 163 холостая операция, 325 ч чтение данных с экрана, 181 ш шина, 243, 322 пропускная способность, 244 шифрование аппаратный ускоритель, 184 длина ключа, 184 и сжатие, 186 с открытым ключом, 183 с секретным ключом, 183 шпиндель, 342 э экстремальное программирование, 51 эмуляция Java, 240 эталонный тест, 148 воспроизводимость, 149 обработка транзакций, 151 описания, 149 слабое звено, 148 экстраполяция, 149 эффективность, 92 экономическая, 92 я ядро, 354 язык описания интерфейсов. См. IDL язык разметки гипертекста. См. HTML ячейка, 285
лзлАтсльскпй а ом Г\^ПУШ Ж1КР® специалистам 1/&Z Ш ШШШ Ш ШшШ^ КНИЖНОГО БИЗНЕСА! V^^ WWW.PITER.COM ПРЕДСТАВИТЕЛЬСТВА ИЗДАТЕЛЬСКОГО ДОМА «ПИТЕР» предлагают эксклюзивный ассортимент компьютерной, медицинской, психологической, экономической и популярной литературы РОССИЯ Москва м. «Калужская», ул. Бутлерова, д. 176, офис 207,240; тел./факс @95) 777-54-67; e-mail: sales@piter.msk.ru Санкт-Петербург м. «Выборгская», Б. Сампсониевский пр., д. 29а; тел. (812) 103-73-73, факс (812) 103-73-82; e-mail: sales@piter.com Воронеж ул. Ленинградская, д. 138; тел. @732) 49 68 86; e-mail: piter-vrn@vmail.ru Екатеринбург ул. 8 Марта, д. 2676; тел./факс C432) 25-39-94; e-mail: piter-ural@r66.ru Нижний Новгород ул. Премудрова, д. 31а; тел. (8312) 58-50-15,58-50-25; e-mail: piter@infonet.nnov.ru Ростов-на-Дону ул. Калитвинская, д. 17в; тел. (8632) 95-36-31, (8632) 95-36-32; e-mail: jupiter@rost.ru Самара ул. Новосадовая, д. 4; тел. (8462K7-06-07; e-mail: piter-volga@sama.ru УКРАИНА Харьков ул. Энгельса, д. 29а, офис 610; тел. @572) 23-75-63, @572) 28-20-04, @572) 28-20-05, факс @572) 14-96-09; e-mail: piter@tender.kharkov.ua Киев пр. Красных Казаков, д. 6, корп. 1; тел./факс @44) 490-35-68,490-35-69; e-mail: office@piter-press.kiev.ua БЕЛАРУСЬ Минск ул. Бобруйская д., 21, офис 3; тел./факс C7517) 226-19-53; e-mail: piter@mail.by МОЛДОВА Кишинев «Ауратип-Питер»; ул. Митрополит Варлаам, 65, офис 345; тел. C732) 22-69-52, факс C732) 27-24-82; e-mail: lili@auratip.mldnet.com rw Ищем зарубежных партнеров или посредников, имеющих выход на зарубежный рынок. *^ Телефон для связи: (812) 103-73-73. E-mail: grigorjan@piter.com £^ Издательский дом «Питер» приглашает к сотрудничеству авторов. ^ Обращайтесь по телефонам: Санкт-Петербург - (812) 103-73-72, Москва -@95) 777-54-67. У^ Заказ книг для вузов и библиотек: (812) 103-73-73. ^ Специальное предложение - e-mail: kozin@piter.com
ПЗПАТЕЛЬСКПП ПОМ УВАЖАЕМЫЕ ГОСПОДА! /■v ^ мтмллшшмтмт® книги издательского дома «питер» /J>^ ММ ММ мЕм^ ВЫ МОЖЕТЕ ПРИОБРЕСТИ 1Ч^ W WV? PI Т Е RXO М 0ПТ0М И В ГОЗНИ1*У ^ У НАШИХ РЕГИОНАЛЬНЫХ ПАРТНЕРОВ. Башкортостан Уфа, «Азия», ул. Зенцова, д. 70 (оптовая продажа), маг. «Оазис», ул. Чернышевского, д. 88, тел./факс C472) 50-39-00. E-mail: asiaufa@ufanet.ru Дальний Восток Владивосток, «Приморский торговый дом книги», тел./факс D232) 23-82-12. E-mail: bookbase@mail.primorye.ru Хабаровск, «Мире», тел. D212) 30-54-47, факс 22-73-30. E-mail: sale_book@bookmirs.khv.ru Хабаровск, «Книжный мир», тел. D212) 32-85-51, факс 32-82-50. E-mail: postmaster@woridbooks.kht.ru Европейские регионы России Архангельск, «Дом книги», тел. (8182) 65-41 -34, факс 65-41 -34. E-mail: book@atnet.ru Калининград, «Вестер», тел./факс @112) 21 -56-28,21 -62-07. E-mail: nshibkova@vester.ru http://www.vester.ru Ростов-на-Дрну, ПБОЮЛ Остроменский, пр. Соколова, д. 73, тел./факс (8632) 32-18-20. E-mail: ostrom@don.sitek.net Северный Кавказ Ессентуки, «Россы», ул. Октябрьская, 424, тел./факс (87934) 6-93-09. E-mail: rossy@kmw.ru Сибирь Иркутск, «ПродаЛитЪ», тел. C952) 59-13-70, факс 51-30-70. E-mail: prodalit@irk.ru http://www.prodalit.irk.ru Иркутск, «Антей-книга», тел./факс C952) 33-42-47. E-mail: antey@irk.ru Красноярск, «Книжный мир», тел./факс C912) 27-39-71. E-mail: book-world@public.krasnet.ru Нижневартовск, «Дом книги», тел. C466) 23-27-14, факс 23-59-50. E-mail: book@nvartovsk.wsnet.ru Новосибирск, «Топ-книга», тел. C832) 36-10-26, факс 36-10-27. E-mail: office@top-kniga.ru http://www.top-kniga.ru Тюмень, «Друг», тел./факс C452) 21-34-82. E-mail: dmg@tyumen.ru Тюмень, «Фолиант», тел. C452) 27-36-06, факс 27-36-11. E-mail: foliant@tyumen.ru Челябинск, ТД «Эврика», ул. Барбюса, д. 61, тел./факс C512) 52-49-23. E-mail:evrika@chel.surnet.ru Татарстан Казань, «Таис», тел. (8432) 72-34-55, факс 72-27-82. E-mail: tais@bancorp.ru Урал Екатеринбург, магазин № 14, ул. Челюскинцев, д. 23, тел./факс C432) 53-24-90. E-mail: gvardia@mail.ur.ru Екатеринбург, «Валео-книга», ул. Ключевская, д. 5, тел./факс C432) 42-56-00. E-mail: valeo@etet.ru
Киллелиа Патрик Тюнинг веб-сервера 2-е издание Перевел с английского Д. Солнышков Главный редактор Е. Строганова Заведующий редакцией И. Кормеев Руководитель проекта В. Шанин Научный редактор Д. Солнышков Литературный редактор Т. Маслова Художник Н. Биржаков Иллюстрации В. Шендерова Корректоры А. Моносов. О. Слоева Верстка Л. Панин Лицензия ИД №05784 от 07.09.01. Подписано к печати 25.12.02. Формат 70x100/16. Усл. п. л. 42,57. Тираж 3000. Заказ 11 ООО «Питер Принт», 196105, Санкт-Петербург, ул. Благодатная, д. 67в. Налоговая льгота — общероссийский классификатор продукции ОК 005-93, том 2; 95 3005 — литература учебная. Отпечатано с готовых диапозитивов в ФГУП ордена Трудового Красного Знамени «Техническая книга» Министерства Российской Федерации по делам печати, телерадиовещания и средств массовых коммуникаций 198005, Санкт-Петербург, Измайловский пр., 29.
Second Edition Web Perfomance Timing Patrick Killelea O'REILLr Beijing • Cambridge • Fdrnham • Koln • Paris • Sebastopol • Taipei • Tokyo