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