Александр Чистяков - Большой веб-проект: развитие,...
DESCRIPTION
Доклад о проблемах в строительстве и развитии большого веб-проекта. История развития высоконагруженного сайта глазами работника эксплуатационной команды. Как говорил Чебурашка: "Мы строили-строили и, наконец, построили". В IT фаза "строили-строили" далеко не всегда переходит в "и, наконец", кроме того, вместо "построили" обычно наступает "версия 2.0", где 2.0 может быть любым числом. Докладчик находился на стройке между версиями 1.0 и 2.0, помогал таскать кирпичи, мешать раствор и караулил территорию по ночам. В свободное от этих обязанностей время он задавался вопросами "как мы строили?", "почему мы строили?", "зачем мы взяли гвозди, а не нитки", а также "почему в версии 2.0 получился высоконагруженный сайт, а не космический корабль". Именно история развития высоконагруженного сайта глазами работника эксплуатационной команды и составляет основу доклада. Поскольку история еще не закончена, слушатели познакомятся и с ее новейшими главами, в том числе будут затронуты такие важные темы, как "как выжить в современном мире адепту Церкви Графиков" и "выпуск major release в пятницу вечером - плюсы и минусы".TRANSCRIPT
Большой веб-проект:
Александр ЧистяковСистемный администраторКупиКупон
http://www.kupikupon.ruhttp://www.slideshare.net/[email protected]
развитие, рост, проблемы, решения с точки зрения
отдела эксплуатации
Давайте познакомимся
Я:✔ Очень долго писал код✔ Пока не понял, что так я только увеличиваю
энтропию✔ Не пишу свой код, а читаю и исправляю чужой✔ Строю инфраструктуры и управляю ими✔ Консультирую по разным вопросам
(“мышки, станьте ежиками!”)
Александр Чистяков 2/51
Давайте познакомимся
Вы:✔ Разрабатываете веб-приложения?✔ Работаете с базами данных?✔ Занимаетесь эксплуатацией веб-проектов?✔ Проектируете архитектуру приложений?✔ Живете в Сибири
(кстати, я первый раз в жизни забрался на Восток дальше Казахстана)
Александр Чистяков 3/51
Цели моего нахождения здесь
✔ Осуществить обмен опытом:✔ Обрисовать ситуацию в статике и динамике✔ Рассказать о достижениях✔ Предостеречь от ошибок
✔ Зачекиниться✔ Попробовать местное пиво✔ Обратить вас в свою веру
Александр Чистяков 4/51
Отказ от ответственности
✔ Мое мнение – это только мое мнение:✔ Не является официальной позицией моего
работодателя✔ Не может быть применено при работе на
ядерных и медицинских объектах✔ Вообще не может приниматься в расчет,
пока вы самостоятельно не проведете эксперимент
Александр Чистяков 5/51
Суть проекта✔ Купонный сервис, top 20 списка Forbes✔ Какие задачи должен решать?
✔ Рассылать большое количество почты✔ Предоставлять пользователям сайт, где
можно регистрироваться и покупать✔ Предоставлять партнерам возможность
регистрироваться и управлять процессом✔ Предоставлять менеджерам возможность
создавать аналитические отчеты
Александр Чистяков 6/51
С чего все начиналось✔ Проект на LAMP:
✔ MySQL 5.0.95 (!)✔ Drupal
✔ Хостинг:✔ OpenVZ контейнер размером во весь хост✔ Доступа к хост-машине нет✔ Установлена cPanel (!!!)
✔ Нагрузка - ~20 RPS к бэкенду
Александр Чистяков 7/51
Что в проекте делал я
✔ Год и семь месяцев назад зашел рассказать про мышек и ежиков
✔ Да так и остался✔ Настраивал, мониторил, чинил, деплоил,
документировал, собеседовал, консультировал✔ То есть, в составе отдела эксплуатации
выполнял обычные для отдела эксплуатации задачи
Александр Чистяков 8/51
Один переезд и два пожара
✔ Проект переехал с PHP на Ruby почти год назад✔ Вопрос из зала: “Зачем?”✔ Неужели PHP настолько хуже Ruby?✔ ^ Я этого не говорил✔ Разговор про “лучше” и “хуже” возможен,
только если есть какие-то метрики✔ Какие же тут могут быть метрики?
Александр Чистяков 9/51
Как делаются веб-проекты
✔ Один из десяти веб-проектов выживает и становится крупным
✔ А, может, даже из двадцати✔ Мы имеем дело со случайным событием✔ Чудо: команда энтузиастов, какой-то движок и
вполне реальная база пользователей✔ Я только что описал хаос✔ Управление хаосом возможно, но сильно
сокращает жизнь и ведет к неврозам
Александр Чистяков 10/51
Хаос (он же “Drupal”)
✔ Проекту жизненно необходим постоянный прогнозируемый прирост новой функциональности, но:
✔ см. картинку,
✔ команда также должна расширяться
Александр Чистяков 11/51
картинка взята с http://habrahabr.ru/post/144857
Что дает Ruby/RoR?
✔ Фреймворк, а не “CMS”:✔ Сделано разработчиками для разработчиков✔ Best practices действительно хороши✔ Высокая расширяемость
✔ Ruby это тренд✔ Ruby-разработчик: MB Pro, Converse, Github,
Travis-CI, zsh✔ PHP-разработчик: угадать невозможно
Александр Чистяков 12/51
Эксплуатационные проблемы
✔ Drupal не справляется с нагрузкой, так как:✔ MySQL не справляется с нагрузкой✔ Apache/PHP не справляется с нагрузкой
✔ Включение кэша Drupal не спасло:✔ Отвалился геотаргетинг (все
незалогиненные видят одно и то же)✔ Совсем отвалился геотаргетинг (выбор
города вручную в меню не помогает)
Александр Чистяков 13/51
Первые принятые меры - 1
✔ Apache/PHP:✔ Выкинули suPHP – избавились от форков✔ (Почти) выкинули cPanel (инвазивнейший
монстр, внедрившийся по всей системе)✔ MySQL:
✔ Убрали MyISAM – перестали блокировать базу при дампе
✔ Размер буфера, размер биинлога и другие обычные действия (см. доклад Аксенова)
Александр Чистяков 14/51
Первые принятые меры - 2
✔ MySQL:✔ Включили query cache (зло, но меньшее)✔ slow log, mk-log-parser и индексы, где нужно
✔ Платформа:✔ etckeeper (спасал нас впоследствии)✔ Приведение в порядок конфигов cron и
других сервисов✔ Без доступа к хост-машине не настроить FS,
swappiness, I/O priority, etc
Александр Чистяков 15/51
Первые результаты
✔ Удалось избавиться от кэша Drupal✔ Нагрузка на машину существенно снизилась✔ Когда через пару месяцев трафик на сайте
возрос в два раза, это не вызвало никаких срочных проблем
Александр Чистяков 16/51
Тем временем, Ruby-версия✔ Платформа:
✔ RHEL 5.5✔ Ruby 1.8.7 (REE), Rails 3✔ MySQL заменили на PostgreSQL
✔ ^ Единственное с моей точки зрения преимущество для подобных проектов – наличие online ALTER, да и то не при любых условиях (при добавлении столбца с дефолтным значением все равно будет блокировка таблицы)
Александр Чистяков 17/51
Ruby-версия, железо
✔ Dell R710, 24 или 48 Gb, SAS-диски✔ HW RAID контроллеры с BBU✔ Production конфигурация:
✔ Один сервер для БД✔ Один сервер для RoR✔ Сервер для бэкапа✔ Сервера для статики, телефонии,
разработки – не Dell и параметры скромнее✔ Как видите, железо было взято с запасом
Александр Чистяков 18/51
Ruby-версия, компоненты
✔ RVM (да, и в продакшне тоже)✔ Unicorn✔ god для управления Unicorn'ами (not anymore)✔ Периодические задачи – cron+rake✔ Обработчики очередей✔ Resque как сервер очередей✔ god для управления обработчиками (сейчас
заменен на runsv)
Александр Чистяков 19/51
Тем временем, PHP-версия
✔ Менеджерам нужна статистика – вынос “тяжелых” запросов на R/O реплику и отдельное backoffice приложение (так же будет и потом в Ruby-версии)
✔ (Кстати, эта реплика все время дохла)✔ А трафик, тем временем, продолжает расти✔ Внезапно, DDoS
Александр Чистяков 20/51
DDoS - 1
✔ Быстро выделили шаблон и собрали список “плохих” IP (~6000 за первый час)
✔ Доступа к хост-машине нет – ipset установить невозможно
✔ Передали список “плохих” IP хостеру с просьбой сделать блокировку на их оборудовании
✔ Поставили mod_evasive
Александр Чистяков 21/51
DDoS - 2
✔ С утра передали еще один список ~8000 адресов
✔ Техподдержка хостера заблокировала все адреса на нашем же iptables
✔ %$^#!✔ Арендовали сервер в другом месте, установили
на нем ipset, сделали его фронтэндом к старому
Александр Чистяков 22/51
Это еще не конец PHP-версии
✔ Легитимный трафик со временем все больше✔ PHP-версия не справляется, разработчики
вынуждены опять включить кэш Drupal✔ Не помогает, база время от времени “выносит”
диск✔ Аренда еще одного сервера у того же хостера
(сервер стоит дороже, у него лучше дисковая подсистема – выносим базу на него)
Александр Чистяков 23/51
Запуск Ruby-версии
✔ Запуск поэтапный, по странам✔ В России больше всего клиентов – ее запускали
в последнюю очередь✔ Процедура запуска: остановка платежей,
домиграция пользователей, проксирование сайта со старого места на новое, смена записей в DNS
Александр Чистяков 24/51
Один переезд = два пожара
✔ Миграции с первого раза не проходят – не сходятся балансы, приходится править код и перезапускать миграцию
✔ Миграции идут через Resque✔ Один пользователь – одно сообщение в
очереди✔ Одно сообщение в очереди – один fork()✔ Fork rate - ~80 forks/s
Александр Чистяков 25/51
Один переезд = два пожара
✔ Приложение для России запустили в пятницу вечером (тем и спаслись), в субботу днем оно начало втыкать
✔ Началась великая битва за живучесть✔ Не забыли ли мы о нагрузочном тестировании?✔ Не забыли, но где-то ошиблись с оценкой
Александр Чистяков 26/51
Битва за живучесть✔ Сразу было видно, что проблемы не на базе
данных✔ “Продать что-нибудь ненужное”:
✔ Выкинули GlusterFS – не помогло✔ Переехали из KVM-based виртуалки на хост
– не помогло✔ Увеличили количество воркеров Unicorn – не
помогло✔ А поставка нового сервера на площадку
хостера – 10 дней (да, мы заказали)
Александр Чистяков 27/51
Битва за живучесть
✔ А как понять, где втыкает приложение?✔ Сделать профайлинг?
✔ Ограничение – профайлить надо под нагрузкой
✔ Никто в команде не умеет толком профайлить Ruby-приложение под нагрузкой, в том числе, и я
✔ Но ясно, что нужно что-то не очень инвазивное, чтобы сам профайлер не мешал работе сайта
Александр Чистяков 28/51
Битва за живучесть
✔ А вот если бы я был джавистом...✔ ...стоп, так я уже! Я сделал бы сэмплинг
стектрейсов jstack'ом✔ Но под Ruby нет jstack!..
✔ ...зато есть PMP, http://poormansprofiler.org✔ При помощи тривиального sh-скрипта gdb
превращается в сэмплирующий профайлер
✔ Я записывал сэмпл в секунду партиями по 50-600 сэмплов за один запуск скрипта
Александр Чистяков 29/51
PMP
✔ Что хорошо – RVM собирает Ruby с debug info✔ Что плохо – стектрейсы приходится
анализировать и классифицировать вручную✔ Сейчас я все еще пытаюсь написать
автоматический сборщик и классификатор, но он пока не готов для публичного показа
Александр Чистяков 30/51
Победа
✔ Сэмплирование показало, что втыкает GC✔ Попытки настроить GC через переменные
окружения почему-то провалились✔ Срочный переезд REE 1.8.7 – MRI 1.9.3✔ После переезда GC заработал как надо✔ Тем временем, разработчики приделали
фрагментарный кэш✔ Ура, белый господин разрешил нам немного
поспать!
Александр Чистяков 31/51
А сколько нужно воркеров?✔ Автор Unicorn рекомендует от 4 до 8 воркеров
на ядро✔ Double facepalm✔ На самом деле, воркеров нужно столько, чтобы
они могли держать нагрузку✔ Что же такое “держать нагрузку”?✔ 50-70% сэмплов должны быть “сижу на select(),
жду работу”✔ Почему 50-70%? а) А мне так нравица! б) А
почему было 4-8 на ядро? :)
Александр Чистяков 32/51
Когда в руках PMP...✔ ...все вокруг выглядит как программное
обеспечение✔ В норме воркеры Unicorn стоят на select() и
ждут запроса от nginx✔ А что бывает не в норме?
✔ Стоят на вызовах GC✔ Стоят на записи в лог (GlusterFS!!!)✔ На select() внутри EventMachine (да, у нас
была Sinatra)✔ На обмене с БД
Александр Чистяков 33/51
Помните о рассылке почты?
✔ Мы аутсорсим рассылку, но запускаем ее через rake task
✔ При миграции 1.8.7 – 1.9.3 возникли проблемы с его производительностью
✔ Сэмплер показал, что уперлись в старый добрый GC
✔ В этот раз настройка через переменные окружения удалась
Александр Чистяков 34/51
Хотим еще баек из склепа!✔ Запрос для построения аналитической
таблицы: UPDATE purchases SET user_created_at =
us.created_at FROM purchases p
INNER JOIN users us ON us.id = p.user_id
AND p.user_id >= 2000000 AND p.user_id < 2100000;
✔ На первый взгляд все окей✔ По идее, ему просто нужно сделать один full
scan✔ В реальности это SQL bomb (as in “fork bomb”)
Александр Чистяков 35/51
И еще!
✔ Sinatra:✔ Штука клевая, но в чем была ее немдленная
польза для Республики?✔ Кому-то не хватало строк в резюме?
✔ Суть проблемы:
✔ Sinatra при ошибке приложения перестраивает модели путем опроса базы
✔ Если 1/10 трафика – ошибки (в JS косячок), то база встает на колени
Александр Чистяков 36/51
Proof or did not happen!✔ На графике какая-то чушь, вощемта:
✔ Одно ясно: базе очень плохо
✔ Мы в эту ловушку попали дважды, так как не вели бортжурнал
Александр Чистяков 37/51
Британские ученые открыли ад
✔ Однажды мы забыли на продакшне mc с поиском по большому файлу, и он отъел 16Gb RAM
✔ Я знал, что этим кончится, поэтому не использую mc последние лет семь
✔ Кстати, для расследования подобных инцидентов мы используем atop, чего и вам желаем
Александр Чистяков 38/51
Как мы готовили БД✔ Ежедневные отчеты pgfouine✔ Если индекса нет, а нужен – строим✔ Как настраивать сам движок?
✔ Зависит от потребностей✔ Включаем log_checkpoints и следим, чтобы
чекпойнты начинались по таймауту, а не по нехватке места в логах
✔ Таймаут, кстати, ставим минут 20✔ Много сегментов для массовой записи, мало
– если нужно быстрое восстановление
Александр Чистяков 39/51
Как еще мы готовили БД
✔ Hot standby репликация (9.0 и выше)✔ Умеет отваливаться молча, просто теряя
данные на реплике✔ Попробовали Slony-I
✔ Не дружит с миграциями Rails✔ Однажды вернулись на hot standby, а там все
окей (нет, в чудеса не верим)✔ Как я уже говорил, с реплики считается долгая
аналитика
Александр Чистяков 40/51
Как мы бэкапили БД
✔ Первое время – pg_dumpall прямо с продакшн✔ Но недолго музыка играла
✔ pg_dumpall с реплики✔ Реплика не может отставать надолго и
просто канселит бэкапные SELECT'ы✔ WAL archiving при помощи pg_rman
✔ Японские разработчики такие японские✔ И тут кто-то сказал “ZFS!”
✔ Вот, думаем...
Александр Чистяков 41/51
Эволюция деплоймента
✔ Из git вручную✔ Caplite (homemade рецепты для Capistrano)✔ Собственно Capistrano в полный рост✔ Jabber-бот✔ Кстати, мы деплоимся минут по 6-8, что для
старого джависта привычно, но несколько необычно (“спасибо” SASS и прекомпиляции эссетов)
Александр Чистяков 42/51
Эволюция процесса разработки
✔ Креативный хаос (быстро, грязно, все бегают и орут)
✔ Peer reviews✔ Unit tests✔ CI:
✔ Bigtuna✔ ^ долго не проплавала✔ Jenkins (греет сердце джависта)
✔ Итог: рутина и всем макбук, пацаны!
Александр Чистяков 43/51
Управление конфигурацией
✔ Вручную✔ Chef (пока на начальном этапе)✔ У каждого разработчика – своя виртуальная
машина✔ ^ чему они очень рады✔ Вот только дамп базы для разработчика очень
большой...
Александр Чистяков 44/51
Церковь Графиков и ее адепты
✔ Munin✔ NAGIOS✔ http://host-tracker.com✔ Airbrake✔ NewRelic✔ Smokeping✔ Мониторинг от хостера (100% useless)✔ A big project never sleeps (just like Moscow)
Александр Чистяков 45/51
Как мы нанимали✔ Из десяти человек
✔ Один устраивает ~полностью✔ Семеро не знают разницу между Apache и
nginx✔ У всех серьезные места работы в резюме и
неплохие аппетиты✔ Берите тех, кто хотя бы умеет пользоваться
поисковиком
✔ Не ошибетесь, мы не ошиблись (Дима, привет и удачи на новом месте!)
Александр Чистяков 46/51
Проблемы✔ “Я разработчик, я не хочу думать, я хочу
разрабатывать”✔ Что такое “план SQL запроса”?✔ Почти 50% времени – не на БД (WTF?)
✔ Хостер становится обузой:
✔ Хостерская экспертиза нерелевантна✔ Нам не хватает ручек и рычагов✔ Машины тяжеловаты, причем, не там, где
надо
Александр Чистяков 47/51
Планы на будущее
✔ Мировое господство✔ Стандартизация, унификация:
✔ Довнедрение Chef✔ Консолидация сервисов и серверов✔ Еще больше графиков
✔ Уменьшение количества SPOF✔ Больше рутины и макбуков
Александр Чистяков 48/51
Выводы
✔ Мы можем многое✔ Вы тоже все это можете✔ Большой проект это всегда интересно✔ Ruby on Rails – продукт эволюции, а не
революции (хороший продукт, кстати)✔ Понимание происходящего в системе все еще
важно, несмотря на уровни абстракции (и всегда будет важно)
Александр Чистяков 49/51
Вопросы
✔ Почему нет автоматического деплоймента?✔ ШТОА?!
✔
✔
✔
✔
Александр Чистяков 50/51
Спасибо, с вам был...
✔ ...Александр Чистяков✔ http://alexclear.livejournal.com✔ http://github.com/alexclear✔ [email protected]✔ Первый раз в Сибири✔ Моя первая презентация в OpenOffice✔ Еще раз спасибо организаторам!
Александр Чистяков 51/51