|
|
Вернуться в оглавление
Оптимизация сайта 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.
|
|