/
Теги: компьютерные технологии оргсвязь
ISBN: 5-94723-476-9
Текст
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