Pull to refresh

Прогрессивные технологии, как способ выжать из сервера максимум

Reading time 5 min
Views 12K

Вступление


Просто красивый rrdtool =)
Забавно, но когда программист разрабатывает какой-либо продукт, он редко задумывается над вопросом могут ли на одну кнопку в один момент времени нажать одновременно 2000 человек. А зря. Оказывается могут. Как ни странно но большинство движков, написанных такими программистами, очень плохо ведут себя под большими нагрузками. Кто бы подумал, а всего один лишний INSERT, не проставленный index, или кривая рекурсивная функция могут поднять load averages чуть ли не на порядок.

В этой статье я опишу как мы, разработчики проекта, сумели выжать из одного сервера с Pentium 4 HT / 512Mb RAM, максимум, держа одновременно 700+ пользователей на форуме и 120,000 на трекере. Да, проект этот — торрент трекер. Предлагаю сразу оставить в стороне разговоры о копирайтах и правах, мне это не интересно, что действительно интересно — это HighLoad.

Для начала опишу проект таким, каким он был:

Обычный торрент трекер на движке TorrentPier (он же в девичестве phpbb 2.x)
  • Сервер на FreeBSD 6.0
  • Pentium 4 HT / 512Mb RAM
  • Web-сервер Apache
  • База MySQL
  • Вся логика на PHP

То есть практически LAMP

Вкратце сразу распишу последовательно те шаги которые мы предприняли:
  • Установка на сервер opcode cache
  • Замена apache на nginx
  • Кэширование некоторых промежуточных выборок в НЕ RDBMS
  • Перевод ключевой части (читай трекера) на C++
  • Оптимизация сетевого стека FreeBSD, а также её обновление до последней -STABLE
  • Оптимизация MySQL
  • Кэширование BB-кодов
  • Переписка кода на использование SphinxSearch
  • Профайлинг кода и установка средств мониторинга
  • Разборка запросов из MySQL slow query log

Теперь о каждом пункте поподробнее

Установка на сервер opcode cache


Он нужен всегда! Установка php-cache дало 300%+ производительности, потратив 15 минут времени.
Кэши бывают разные: eAccelerator, xCache, APC и т.д… Мы остановились на последнем, из-за хорошей скорости и возможности хранить в нём пользовательские данные

Замена apache на nginx


Apache — тяжёлый и медленный, сначала стоял как основной web-сервер, потом перед ним был поставлен nginx, отдающий статику и сжимающий ответы gzip'ом. Далее от apache отказались вообще в пользу связки nginx+php-fpm (если быть точным на тот момент это был spawn_fcgi, но сейчас такой вариант лучше). Связка в те времена была не самая популярная для production, но у нас она работала замечательно!

Кеширование некоторых промежуточных выборок в НЕ RDBMS


RDBMS — это зло. Оно удобно, но за удобство надо платить. В данном случае скоростью. А нам именно она и нужна. Так, что часть результатов самых популярных и не критичных к актуальности запросов к мускулу мы закешировали в APC. Сразу предчувствуя множество вопросов почему не в memcached… Как бы вам ответить… мне уже надоело даже это слово слышать memcached,memcached,memcached как будто это панацея от всего. Его не предлагают последнее время разве, что только от диареи. В нашем случае выбор пал на APC ибо он не использует TCP соединение и из-за этого работает в разы быстрее. Темболее пока у нас всё отлично крутится на одном сервере и нам распределённое хранилище не так уж и нужно.
Вы можете выбрать любое другое key/value хранилище, не обязательно хранящее данные в оперативной памяти.
Но весьма вероятно, что в вашем случае memcached/memcachedb/memcacheQ будут лучшим вариантом.
Вообще была идея сделать многоуровневую кэш-прослойку в которой php искал значение в глобальных переменных, потом в APC, далее в memcached, а лишь потом лезет в базу SELECT'ом. Но так как проектом занимаемся в свободное от учёбы/работы/семьи время, то до этого пока не дошло.


Перевод ключевой части (читай трекера) на C++


120000 активных пиров создают не мало коннектов к nginx, что ещё хуже, так каждый из них дёргает php, который дёргает мускул. Вам не кажется что ето уж слишком? Нам тоже так показалось. Один из наших разработчиков собрался с силами и переписал код XBTT под фронтенд TorrentPier'а. Оно того стоило, теперь клиент обращается к трекеру на 2710 порт, который держит в памяти табличку с пирами, там его быстро находит, делает что надо и отдаёт ответ пиру обратно. Раз в минуту скидывает результаты в базу. Всё прекрасно. +100000% производительности.
Вот результаты теста, когда мы поставили время анонса — 1 минута
input (rl0) output
packets errs bytes packets errs bytes colls drops
20K 0 2.5M 16K 0 1.5M 0 0

PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
10 root 1 171 52 0K 8K RUN 1 538.6H 47.12% idle: cpu1
6994 root 1 108 0 98140K 96292K CPU0 0 3:57 33.98% xbt_tracker
11 root 1 171 52 0K 8K RUN 0 595.0H 31.20% idle: cpu0
35 root 1 -68 -187 0K 8K WAIT 0 17.1H 21.14% irq21: rl0
12 root 1 -44 -163 0K 8K WAIT 0 482:57 9.96% swi1: net

[root@****] /usr/ports/devel/google-perftools/> netstat -an | wc -l
24147

Цена вопроса 100 Метров памяти и 30% загрузка однго проца. Итого получается, что с такой же загрузкой можно держать примерно 8 Миллионов пиров на одной машине при получасовом времени анонса

Оптимизация сетевого стека FreeBSD, а также её обновление до последней -STABLE


В последних версиях FreeBSD 6 очень хорошо переработан планировщик 4BSD, а в 7ке так вообще есть такая приятная вещь как ULE, с которой мускул работает в разы шустрее на SMP
Также в любой высокопроизводительной инсталяции FreeBSD нужно крутить sysctl, я рекомендую это делать по Сысоеву

Оптимизация MySQL


База данных это то, во что рано или поздно упирается любой проект, мы не исключение.
В то время myisam у нас использовался по двум причинам
  • он используется по-умолчанию
  • в нём есть FULLTEXT индекс для поиска по форуму

Так мы потратили немало времени крутя буферы. Особенно в этом помог tuning-primer.sh
В дальнейшем планируется перевод базы на Xtradb. В любом случае нам пока хорошо — база влезает в память =)

Кэширование BB-кодов


Оказывается phpbb «на лету» преобразовывает bbcod'ы в html. Не хорошо. Закешировали сгенерированный html код в отдельном поле базы данных для каждого поста/подписи. В итоге база потяжелела почти в 2 раза, зато сайт начал летать.

Переписка кода на использование SphinxSearch


Как-то читал презентацию фликера, по поводу того как они у себя делали поиск. Так как база у них на innodb они сделали отдельную ферму Master-MultipleSlaves на myisam, чтобы обрабатывать на ней поиски. Что ж, мы не так богаты, сервер у нас только один. Ещё один наш разработчик, взяв волю в кулак, перевёл весь поиск по сайту на сверхбыстрый SphinxSearch. Результат превзошёл все ожидания. Сервер опять залетал.
Как косвенный эффект это позволило нам ввести просто супер-мега-удобный rss со встроенным поиском, который почти не грузит сервер.

Профайлинг кода и установка средств мониторинга


Странно, но многие этим ещё не пользуются. А зря. Если не знаешь где находится bottleneck устранить его невозможно. Для этого мы напихали в php код hook'ов профайлера, а на сервер установили munin.

Разборка запросов из MySQL slow query log


Тут классика! 20% запросов к базе занимают 80% времени. Приглядитесь может и у вас так. А после разбора логов, подписок FORCE INDEX к запросам и закоментирования нескольких строчек в php загрузка в час пик упала в два раза, а главная страница начала грузится в 10(!!) раз быстрее.
В общем очень рекомендую проводить такую операцию раз-два в год или после введения множества мелких нововведений. Очень помог инструмент mysqlsla.

Вместо послесловия


Вот как несколькими шагами мы превратили обычный LAMP в комплексную систему. Сейчас мы живём на обычном Core2Duo 2Ггц с 3Гб оперативки, сейчас ноутбуки в магазинах продаются «покруче», но нам хватает, а загрузка в час пик не поднимается выше 1.5 при 200000 тысячах пиров и ~500 пользователях форума. Интересно каких объёмов потребовался бы парк если бы мы тупо росли горизонтально используя LAMP и репликацию?
Посмотрим как всё изменится когда нам перестанет хватать одного сервера.

Если вы дочитали до этого момента, то тема вам интересна. Чтож, тогда добро пожаловать в блог Серверная Оптимизация!

UPD: исправил опечатки и неточности
Tags:
Hubs:
+310
Comments 184
Comments Comments 184

Articles