В начало
Разделы

Вернуться в оглавление

Оптимизация сайта OpenNET.ru

Maxim Chirkov описал свой путь по оптимизации сайта www.OpenNET.ru.

Используемое ПО

  • ОС: FreeBSD 4.10
  • Язык программирования: Perl
    • Модули: Темплейты - MCTemplate, Кэш - MCCache, Локи - MCLock, CGI - MCCGI;
  • Web-сервер: Apache 1.3 + FastCGI + mod_deflate
  • SQL-сервер: PostgreSQL
  • FTP-сервер: vsftpd
  • MTA: Postfix
  • Поиск на сайте
    • используется htdig - для объема индексируемого материала примерно 1.5 Гб htdig пока остается оптимальной системой (с хранением индексов в btree Berkeley DB файлах), главные минусы - нет предкеширования типовых запросов (можно реализовать внешним wrapper'ом или через mod_accel), не оптимальная работа при выводе результата поиска по часто встречающемуся в индексируемых документах словам (например, если ищем по слову которое встречается десятки тыс. раз - поиск будет занимать несколько минут).
    • OpenFTS - слишком медленный и ресурсоемкий конечный поиск для клиента, не хочется создавать лишнюю нагрузку на PostgreSQL сервер, который обслуживает первичные БД сайта.
    • Aspseek и mnogosearch - требуют слишком много памяти для расчета коэффициентов релевантности (не меньше 1 Гб ОЗУ), требуют MySQL для обеспечения более или менее высокой скорости операций поиска (не хочется поднимать MySQL на сервере).
  • Бэкап: fsbackup
  • Мониторинг: alertmon3

Заметки по технологии и оптимизации

  • Все что можно - преобразовывать в статику. Предгенерация контента.
  • Со временем убедился, что персональные настройки на сайте - лишнее усложнение, почти всегда достаточно разумного дефолта. Стремлюсь к простоте в оформлении и лаконизму в изложении.
  • В динамике - поиск, динамическая часть форума, контент который не выгодно хранить или отдавать в статике:
    • когда контент слишком часто изменяется;
    • когда необходимо обеспечить большую гибкость запроса;
    • когда объем контента в статике слишком велик;
    • когда запрашивается только "верхушка айсберга" (например - вывод текста новостей, интенсивно запрашиваются только последние новости, которые и можно предкэшировать "на лету", но не предгенерировать);
    • когда предгенерация требует значительных ресурсов, несопоставимых с ресурсами затрачиваемыми при отдаче того-же динамикой (например, когда много вариантов представления - выгоднее предкэшировать отдельные блоки, а не всю страницу сразу).
  • Все что нельзя превратить в статику (предгенерировать) - кэшировать через статику. Предкэширование типовых запросов и промежуточное сохранение часто используемых выборок в кэше. Например, можно прокэшировать только наиболее часто встречающиеся запросы.
  • Ту динамику, что невозможно прокэшировать - снабжать средствами защиты от перегрузок.
    • защитой от DoS/flood потоков запросов;
    • ограничить число одновременных потоков на клиента;
    • ограничить число запросов на клиента в ед. времени (средства ipfw, mod_limitconn или mod_throttle);
    • квоты на дисковое пространство (не переусердствовать, отделить первичные области диска (например, хранилище БД, данные форума - не восстановимы), от вторичных (например, предгенирированный контент, кэши - влияют на отображение, но восстановимы из первичных областей) и третичных (например, логи - потеря не так страшна));
    • квоты на процессорное время
    • квоты на размер процесса;
    • квоты на число процессов;
  • Практические рекомендации по тюнингу Apache:
    • FreeBSD ядро собираем с "options ACCEPT_FILTER_HTTP" (или "kldload accf_http"), в конфигурацию Apache добавляем "AcceptFilter on", перезапускаем Apache;
    • Убираем лишние модули;
    • "KeepAlive Off", а картинки отдаем через отдельный мини-http сервер для отдачи статики (mathopd, thttpd);
    • В "Options" должно быть "FollowSymLinks", но не нужно "SymLinksIfOwnerMatch" (приводит к лишней lstat() проверке при каждой отдаче файла).
    • Не используем .htaccess (AllowOverride None), все настройки, включая авторизацию, в httpd.conf (apache тратит ресурсы на попытки открыть .htaccess в каждой родительской директории);
    • Ограничиваем число одновременных запросов с одного IP через "ipfw add allow tcp from any to $IP 80 via fxp0 setup limit src-addr 15" или "iptables -A INPUT-p tcp --dport 80 -m iplimit --iplimit-above 10 -j REJECT", но не через модули apache (mod_throttle, mod_bandwidth, mod_limitconn);
  • Использовать FastCGI/mod_perl для динамики (устраивает использование FastCGI). Наиболее выгодно использовать для небольших скриптов, время загрузки и парсинга которых сравнимо с временем выполнения скрипта, либо если промежуточные данные можно держать в памяти (пример, скрипт "хинтов" в opennet). Выгода почти не ощутима для тяжелых скриптов, требующих значительного времени для выполнения и не использующих одни и те же области данных (например - скрипты поиска).
  • Использовать mod_accel - для буферизации клиентских запросов и создания внешнего кэша запросов к динамике. Увеличение sendbuffer в apache и send/recv буферов на уровне ОС. Написание скриптов с учетов кэширования. (в opennet mod_accel не используется)
  • Использовать mod_deflate для сжатия отдаваемого пользователям контента (трафика меньше и клиенту быстрее информация отдается, нагрузка на CPU от сжатия - почти незаметна);
  • Если статики очень много (например отдаются картинки) - не тратим на нее силы apache, а отдаем через спец. средства - mathopd (мой выбор) или thttpd. Можно использовать squid в режиме акселератора. Окажет помощь балансировка данных на несколько дисков, особенно если на сервере используются SCSI накопители. Или выдача статики прямо из ram-диска.

Надежность

  • Для обеспечения надежности системы важными составляющими являются системы мониторинга и резервного копирования.
    • Мониторинг.
      • Слежение за возникновением проблем
      • Попытки автономно решить проблему
      • Оперативное сообщение о возникновении проблемы.
      • Сохранение информации о факте проблемы и дампа состояния системы в момент проблемы.
      • Визуализация текущего состояния.
      • Визуализация динамики изменения состояния (наглядное представление на графиках):
      • Мониторинг инфраструктуры (группы серверов и оборудования)
        • Карта сети, в которой отображено состояние точек и связей
      • Удаленный мониторинг
        • Достижимость ресурса
        • Работоспособность сервисов ресурса
      • Локальный мониторинг
        • Контроль наличия запущенных процессов
        • Контроль за состоянием процессов (число процессов, расход ресурсов CPU, ОЗУ)
        • Контроль за состоянием сетевых соединений (определение флуда)
        • Контроль расхода дискового пространства.
        • Периодическая оценка логов на предмет наличия фатальных или предупреждающих сообщений.
        • Контроль общего состояния системы, нагрузки, расхода памяти, сетевого трафика и т.д.
    • Резервное копирование.
      • Территориальный вынос бэкапа (пожар, форс-мажор)
      • Инкрементальное накопление изменений
      • Несколько уровней отката.
      • Несколько уровней детализации и полноты бэкапа.
      • Безопасность и конфиденциальность бэкапа (бэкап с важными данными должен быть зашифрован)
      • Экономия дискового пространства за счет сжатия бэкапа.
      • Легкость восстановления без необходимости доп. ПО, кроме архива бэкапа (открытый формат архива)
      • Автономность, автоматическая работа без участия оператора
      • Гибкость формирования бэкапа (маски файлов/директорий для помещения в бэкап и исключения из него)
    • Схема и планирование бэкапа.
      • На критичные к времени простоя или содержащие ценные данные сервера, ставим RAID. Обязательно, hi-end SCSI диски, хороший SCSI RAID контроллер (сейчас используем LSI Logic SCSI 320-2 MegaRAID, RAID5 + hot-spare). Не стоит экономить при выборе контроллера, лучше без RAID, чем чувство ложной безопасности). Крайне рекомендуется иметь запасной hot-spare диск для автоматической горячей замены.
        Восстановление после сбоя производится автоматически (время простоя нулевое).
      • Если бюджет не позволяет установить хороший RAID контроллер, следует добавить на сервер IDE диск большого размера и еженощно зеркалировать туда всю информацию. Рекомендуется, использовать двойное зеркало, каждое из которых обновляется через день. Подобная перестраховка необходима для предотвращения потери данных в ситуации краха во время бэкапа и защиты от синхронизации в бэкап не фатальных повреждений ФС ведущих к пропаданию файлов (сбой, fsck, случайное удаление) или их обнулению (следствие переполнения раздела).
        Для восстановления необходимо загрузить систему с бэкап диска (несколько минут)
      • Ежедневное инкрементальное резервное копирование уникальных для данного хоста данных и файлов конфигурации на территориально удаленный бэкап сервер (например, используя fsbackup).
        Для восстановления следует установить операционную систему и восстановить конфигурацию и данные из бэкапа (простой - несколько часов).
    • Дополнительные системы отказоустойчивости: разбалансировка на несколько серверов (самое простое - балансировка по DNS) или БД, использование RAID, системы бесперебойного питания, резервные сетевые линки, промежуточное оборудование повышенной надежности (маршрутизаторы, коммутаторы), размещение в спец. помещении (неприкосновенность оборудование, вентиляция, фильтрование пыли, температурный режим, защита от пожара и протечки систем водоснабжения).
    • Дополнительные системы увеличения производительности
      • Кэширование контента.
      • Кэширование SQL запросов.
      • Кэширование промежуточных данных
      • Кэширование результата.
      • Предкешированные объекты.
      • Использование оптимальных алгоритмов.
      • Оборудование - SCSI диски, машины с SMP.
      • Тюнинг ОС.
      • Разделение нагрузки на несколько серверов, вынос сервисов на отдельные машины.
      • Функциональное разделение (по IP) и равномерное разделение (SQL)
      • Субъективное разделение (разделение функций и операций, DNS-балансирование, IP-балансирование и т.д.)
      • Разделение процессов (кластер, 2 SQL сервера для балансировки SELECT запросов.)

    Безопасность

    • Ежедневное слежение за отчетами с описанием новых проблем с безопасностью в рассылках и на специализированных сайтах.
    • Не дожидаться обнаружения ошибок, попытаться предотвратить их проявление. Всегда считать, что в программе есть ошибки, обдумать что можно сделать чтобы система не пострадала от их проявления. Система должна быть неприступна, невзирая на вероятные проблемы с безопасностью в программах.
      • Избыточные, параноидальные проверки в своем коде. Проверки на каждом этапе использования полученных от пользователя или иного внешнего источника данных.
      • Понижение привилегий и запуск в chroot.
      • Использование библиотек-врапперов подменяющих потенциально опасные библиотечные вызовы или сборка спец компиляторами с средствами защиты от переполнения буфера.
    • Сниффинг. Особое внимание следует уделить внутренней безопасности, для предотвращения появления злоумышленника в доверительной сети. Сниффер в доверительной сети, не меньшая угроза, чем открытая брешь в ПО. Средства защиты от злоумышленника в локальной сети:
      • Шифрование трафика, особенно актуально для сервисов в которых присутствует передача паролей в открытом виде. Но, на одно шифрование тоже нельзя полагаться, об этом ярко говорят ошибки в реализации ssh1, openssl, mod_ssl приводящие к возможности анализа перехваченного шифрованного трафика.
        (Примеры, замены: http => SSL+http, ftp => sftp, telnet, ssh1 => ssh2, pop3 => apop или pop over TLS/SSL).
      • Жесткая политика доступа к ресурсам управления (ssh, snmp).
        • Разграничение доступа внутренними средствами: ACL программы или tcp wrapper (/etc/hosts.allow). Желательно, чтобы доступ разграничивался как по имени пользователя совместно с ограничением по IP (каким пользователям какие действия можно производить с каких IP).
        • Дублирующее ограничение средствами фаервола, можно как на локальном сервере, так и на пограничном маршрутизаторе.
      • Мониторинг переполнения ARP таблиц. Использование коммутаторов (свичей), не избавляет от возможности сниффинга. Проброс каждого клиента используя VLAN через маршрутизатор или привязка MAC адреса к порту коммутатора - дорогое удовольствие, особенно в больших сетях. Частично проблему помогают решить программные средства слежения за изменением MAC адресов (чтобы пользователи самовольно не меняли IP адреса и не выставляли IP соседа) и мониторинга за переполнением ARP таблиц. Другой способ борьбы с arp-спуффингом - использование специальных патчей на шлюзовой машине или жесткая привязка MAC адресов к IP.
      • Использование временных паролей (One-Time Passwords - OTP, opie, s/key). Например, генерируется список паролей и при каждом входе используется следующий пароль из списка, использованные пароли блокируются.
      • Применение средств автоматического обнаружения вторжения (IDS) под вопросом, так как в таких средствах часто находят критичные ошибки способствующие взлому (пример: snort, tcpdump).
    • Закрытая система для решения спец. задач, без публичных сервисов (например, рутер, фаервол)
      • Полное отсутствие сетевых сервисов.
      • SSH доступ только с IP администратора и резервного trusted сервера.
      • Закрытые сервисы доступны только непосредственным потребителям.
      • Двойное или тройное блокирование, пакетный фильтр, libwrap/tcpwrapper и настройки самой программы.
      • Если система не в trusted сети - шифрование всех потоков данных.
    • Закрытая система с сетевыми сервисами.
      • SSH доступ только с IP администратора и резервного trusted сервера.
      • Открыты только реально необходимые сервисы.
      • Для открытых сервисов используется только доверительное ПО, в котором ранее не замечали проблем безопасности и прошедшее беглый аудит.
      • Все остальное, если невозможно обойтись без него или заменить в CHROOT.
      • Доверяю ПО: postfix, qmail, popa3d, vsftpd (практика прецедента - не доверять ПО в котором хоть раз найдена критическая ошибка безопасности или программа разработана без использования жесткой политики безопасности (в документации и коде это сразу заметно)).
      • Запускаю в CHROOT: bind/named, apache, ftpd (BSD), inn. Доступ к OpenSSH только с доверительных хостов.
      • Не запускаю в public никогда: все реализации IMAP, samba, sendmail, proftpd, wuftpd, mysql, postgresql, dhcpd, ntpd. Пример особенно безграмотных с точки зрения безопасности систем - proftpd, qpop.
      • Не использовать антивирусы для проверки почты, как правило это закрытые проекты в которых не проводится аудит исходного кода. Вместо антивирусов, можно практиковать полную блокировку пересылки выполняемых файлов, или отключить проверку в архивах и запускать в chroot. Подобному решению способствуют прецеденты DoS атак (переполнение диска) через вложенные, специально скомпонованные, сжатые файлы или возможность выполнения кода на сервере через специальным образом скомпонованные заголовки письма.
    • Открытая система с локальными пользователями (например пользователи могут запускать CGI-скрипты)
      • Разделение привилегий, запретить доступ к другим пользователям и системным файлам по возможности
      • Желательно noexec /tmp и патч для noexec stack.
      • Если можно то в chroot jail.
      • Не давать исходящих коннектов, если не требуют условия.
      • Убрать все suid программы которые можно убрать, использовать TCB для хранения паролей, вместо /etc/shadow
      • Не оставлять бэкапы в открытом месте, иногда злоумышленник может взломать систему используя старую suid программу из бэкапа или обнаружив общедоступный файл с паролями.
      • Вести подробные логи, включая аккаунтинг выполняемых процессов. syslog логи дублировать по сети на соседнюю машину.
      • Применять программное обеспечения для слежения за целостностью участков файловой системы и поиска root-китов.
      • Дополнительные ограничения для скриптов пользователей системы хостинга (apache в chroot):
        • Запрещение connect(2), невозможность установки исходящих соединений пользовательскими скриптами (используя библиотеку враппер, подгружаемую через LD_PRELOAD в suexec, принудительно меняем для listen и connect IP на 127.0.0.1).
        • Запрещение listen(2), предовращение приема соединений на сетевой порт. Борьба с процессами демонами, через мониторинг.
        • Ограничение возможности использования группы exec вызовов, предусмотреть использование относительных путей и список исключений (текущая cgi-bin, /bin и т.д.);
        • Запретить для cgi-скриптов возможность создания и перезаписи файлов в директориях с исполняемыми скриптами (cgi-bin).
        • Квоты на дисковое пространство, время выполнения скрипта и объем используемой одним скрптом памяти.
        • Права доступа к диреткории пользователя "drwx--x--- user hosting", где user - id пользователя, hosting - группа из под которой запущен apache (для раздачи статики). Таким образом скрипт пользователя не имеет доступа к диреториям других пользователей.
        • Использование mod_php в режиме safe_mode (php_admin_flag safe_mode on), запретить использование URL в open (php_admin_flag allow_url_fopen off), ограничить обем ОЗУ (php_admin_value memory_limit 2M), ограничить время выполнения (php_admin_value max_execution_time 10).
        • Мониторинг in/out трафика через mod_watch. Раньше получал полные данные о трафике используя "per user ip accounting", но он учитывал также mysql и прочий локальный трафик, после введения блокировки на listen() и connect(), использование mod_watch вполне оправдано. Предотвращение использование ftp аккаунта для файлового обмена, через дополнительный мониторинг.
    • Аспекты безопасности при написании CGI-скриптов
      • Применение suexec и жесткое разграничение прав доступа (пользователь не должен видеть системных файлов и логов, не должен иметь возможность получить доступ к данным другого пользователя)
      • Полностью исключить использование типовых бесплатных скриптов. Лучше все писать самостоятельно, если написание затруднено - обязателен полный аудит кода чужих скриптов.
      • Паранойя при написании кода - дублирующие проверки всех параметров получаемых в диалоге скрипта с пользователем (как минимум проверка валидности с выводом сообщения об ошибке на этапе инициализации переменных с данными пользователя и жесткое вырезание недопустимых символов (s/[^\w\d_\-.]//g) перед опасными функциями (open, system)), обязательное экранирование переменных при использование в regex выражении (/\Q$var\E/, иначе $var может содержать "?{код}").
      • Perl пишем на Perl: никаких `` и вызовов shell функций, скрипт с perl -w и в strict режиме;
      • Перед написанием кода - обязательное планирование, перед кодированием скрипт должен уже иметь четкую структуру.
      • После написание - отладка и crash тест.
      • Доступ к системе web-управления, только с "trusted" хостов, желательно по HTTPS.
    • Защита обслуживаемой сети c пользователями.
      • Оборудование и рабочее место администратора не должны быть подключены в рамках одной физической сети (см. выше пункт "сниффинг"). Желательно разделить сеть по отделам (директора и бухгалтерию подключить отдельно).
      • Не допустить доступ к оборудованию посторонним (охрана, дети сотрудников). Обязательная парольная аутентификация на каждой машине и жесткие административные правила пользования сетью.
      • Машины сети снабдить IP адресами из интранет блока. Выход во вне только через прокси или транслятор адресов. Фаерволом закрыть все кроме необходимых сервисов.
      • Установка локального ПО для борьбы с вирусами, постоянное обновление пользовательских систем (установка service pack) и программ для работы в сети (IE, Opera, The Bat, Outlook).
      • Повышение грамотности пользователей.
      • Мониторинг уязвимостей в локальной сети, средства сканирования пользовательских машин на предмет известных уязвимостей.
    • Защита от DoS и DDoS.

Автор: Maxim Chirkov
URL оригинала: http://www.opennet.ru/guide.shtml


Строчка любимых сайтов OpenNET Афиша Петербурга


Яндекс цитирования