2. Кто я?
§ Меня зовут Саша
§ Я инженер, главный инженер
§ В компании Git in Sky
§ Я люблю оптимизировать производительность
§ Потому что это как волшебная сказка!
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
3. Где я? Кто вы?
§ Любите волшебные сказки?
§ Пришли послушать про базу данных?
§ Пришли послушать про оптимизацию производительности?
§ Разрабатываете проекты для веб?
§ Поддерживаете проекты в веб?
§ У вас уже есть PostgreSQL?
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
4. О чем речь?
§ Доклад в жанре “field report”
§ Если угодно - “trip report” (см. подназвание доклада)
§ Предыстория: http://www.slideshare.net/profyclub_ru/08-6
§ Однажды ко мне в дверь постучал
добрый волшебник
§ И все заверте...
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
5. Краткое содержание предыдущих серий
§ Заказчик — конструктор сайтов http://setup.ru
§ Пользовательский статический контент (файлы) хранится в
базе данных (PostgreSQL)
§ Для больших файлов используются large objects
§ Приложение на Perl, работает под Apache + mod_perl
§ Переходим из 2012-го года в 2014-й, и...
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
6. Наше время
§ Было 6 миллионов файлов в базе — стало 207 миллионов (с
версиями)/85 миллионов (без версий)
§ Времена, когда индексы были 2Gb, давно прошли
§ Синхронизация тоже не 100 файлов в секунду, а в лучшем
случае 80, обычно — от 20 до 50
§ База данных занимает на дисках ~6Tb
§ И объем будет только расти
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
7. Почему не ...?
§ Россия — страна советов! (Каждый суслик — агроном!)
§ “Работает — не трогай” (на самом деле, нет, но)
§ У решений могут быть бизнес-причины
§ TIMTOWTDI! (Кстати, Perl же!)
§ Один из путей — “долго и дорого”
(“никогда и дорого”?)
§ Вывод очевиден?
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
8. Все же, почему не ...?
§ OpenStack Swif
§ Elliptics
§ Ceph, MogileFS, MooseFS, whatever
§ Слово “кислотный” из подзаголовка (Atomicity, Consistency, etc)
§ Либо делать групповую транзакцию в бизнес-логике
(переписать всё приложение)
§ Либо транзакции берет на себя хранилище
^ Много ли мы знаем таких хранилищ?
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
9. Объекты предметной области и базы
§ Таблица domains — содержит имена доменов, пример —
setup.ru
§ Таблица content — содержит метаинформацию о файле (время
последнего изменения, на основании которого принимается
решение об актуальности бинарных данных)
§ Таблица stat — содержит собственно сами бинарные данные и
их sha1-хэш (дедупликация!)
§ Таблица deleted — содержит признак того, что файл был удален
§ Итого, у нас есть четыре связанных между собой таблицы
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
10. Пользовательские сценарии
§ Публикация и синхронизация файлов:
§ Публикуем изменения всегда на одну и ту же ноду
§ Иначе пользователь будет видеть старый контент
§ Кастомный синхронизатор не очень быстро
распространяет изменения на все узлы
§ Отдача статического контента:
§ Нужно отдавать а) последнюю, б) неудаленную версию
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
11. Что не очень хорошо?
§ Отдача работает не очень быстро
§ Публикация и синхронизация работают не очень быстро
§ Существующее железо справляется не очень хорошо
§ Пара слов о железе:
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
12. Полный Хетцнер!
§ Исходно — RAID0 на 2*3Tb SATA диска, 16G RAM, RAID1 на 2
SSD для pg_temp и временных файлов nginx — сортировка
и объединение таблиц в PostgreSQL и буферизация в nginx
работают быстро
§ Переезд на RAID10 4*4Tb SATA диска (стало не хватать места),
48G RAM
§ Несмотря на наличие технической возможности, поставить
SSD под кэш или временные файлы больше нельзя —
добро пожаловать в Хетцнер!
§ ^ Надо как-то жить с этим
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
13. Есть ли у вас план, мистер Фикс?
§ Как это делается обычно:
§ slow queries log
§ pgFouine или pgBadger
§ Раз в сутки (или даже чаще) — красивый рейтинг «плохих»
запросов статистика с победителями
§ Смотрим план (опять это слово!) запроса
§ Кто знает, что такое “план запроса”?
§ Кто не знает — тот тоже оптимизатор
(но поисковый)
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
14. За спичками
§ Дело не выглядит сложным, кстати:
§ “Найти неудаленный файл” при отдаче - это запрос к
view
§ “Найти данные для синхронизации” - это тоже запрос к
view
§ Это самые распространенные запросы
§ Их планы и надо смотреть и оптимизировать
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
15. And the Oscar goes to...
§ А вот и план, о котором мы так долго говорили:
§
§
§
§
§
§ Что-то он какой-то большой
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
16. Чрезвычайные и срочные меры
§ Материализовать нематериализованный view!
§ PostgreSQL 9.2 — нет “родной” поддержки materialized view
§ ^ не беда
§ В книге “Enterprise Rails” отлично описано, как эмулировать
materialized view при помощи триггеров
§ BTW WTF is “Enterprise Rails”?
§ У нас опять есть план — чего же мы ждем?
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
17. Кстати, как это работает?
§ Буквально в двух словах (explain to me like I'm five years old):
§ “Поверх” нематериализованного view делается таблица
с такими же полями
§ Она работает как кэш — записи в ней создаются по
запросу
§ Сначала идем в эту таблицу, потом во view, если там не
нашлось
§ Записи инвалидируется при помощи триггеров на всех
таблицах-участниках исходного view
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
18. Все сделал как в книге!
§ Надо как-то проверить, что все удалось?
§ Честно скажу, pgBadger и pgFouine я не трогал вообще
§ Потому что slow log нерепрезентативен и не отражает динамику
§ Расширение pg_stat_statements
§ ^ должно быть включено у всех без исключения
на планете Земля
§ Позволяет смотреть статистику в реальном времени
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
19. pg_stat_statements
§ SELECT
(total_time / 1000 / 60) as total_minutes,
(total_time/calls) as average_time,
calls, query
FROM pg_stat_statements
ORDER BY total_minutes/average_time desc;
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
21. Вскрытие показало
§ Кэширующая таблица действительно работает
§ Примерно 30-40% запросов не попадает в кэш
§ ^ Хорошо, надо подождать
§ На второй день ожидания ситуация не изменилась
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
22. Знай и люби бизнес-логику!
§ Алгоритм:
§ Посмотреть в таблице
§ Посмотреть в исходном view (долго)
§ А что, если такого файла вообще нет?
§ 30-40 процентов запросов — к файлам, которых вообще
нет
§ Зачем ходить во view за ними?
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
23. Наступило утро, проснулся комиссар
§ Ночью — 15 миллисекунд в среднем
§ Днем — 40-50 миллисекунд в среднем
§ Вносить изменения лучше ночью
§ Но результат будет известен только в середине дня!
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
24. Наступило утро, проснулся комиссар
§ Ночью — 15 миллисекунд в среднем
§ Днем — 40-50 миллисекунд в среднем
§ Вносить изменения лучше ночью
§ Но результат будет известен только в середине дня!
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
25. Возвращение целесообразности
§ Наша главная метрика — время отдачи контента
пользователю!
§ При чем тут pg_stat_statements?
§ Zabbix
§ Graphite/StatsD
§ https://github.com/alexclear/ansible-graphite-playbook
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
28. Еще пара слов про Zabbix
§ Ворон
Каркнул:
НИКОГДА!
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
29. Ogres have layers
§ Graphite/StatsD stack:
§ Dashboard (тысячи их, я просто взял стандартный, он
плох)
§ Веб-интерфейс отдачи графиков (на Django)
§ Collector w/RRD-like storage (Carbon)
§ Aggregator/preprocessor w/UDP interface (StatsD)
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
30. StatsD implementation
§ На Go, Node.JS, Python, Perl, C, ... (тысячи их)
§ Сначала я взял Python:
§ ^ Автобус не придет
§ Старый добрый Perl!
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
31. Покой нам только снится
§ Снится не покой, а те самые 40-50 миллисекунд, которые не
хотят уменьшаться
§ Что делать?
§ Как обычно, построить более подходящие индексы
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
32. Момент истины
§ Для самого частого запроса построен хороший индекс на три
столбца (до того был — на два столбца, а исходно был на
один столбец)
§ В этот момент все стало еще хуже :)
§ Размер индекса — 18 гигабайт
§ Все предыдущие докладчики, наверняка, говорили, что
маленький индекс лучше, чем большой
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
33. One size does not fit all
§ Один из столбцов, по которому построен индекс — varchar
§ Превращаем varchar в int:
§ http://stackoverflow.com/a/9812029/601572
§ create function h_int(text) returns int as $$
select ('x'||substr(md5($1),1,8))::bit(32)::int;
$$ language sql;
§ Забыл сказать — я не боюсь хранимых процедур и триггеров
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
34. После шлифовки отполировать
§ SET enable_bitmapscan=false; <= старые добрые nested loops
SELECT something
FROM stat s JOIN domains d ON d.id = s.domain JOIN content c ON c.id = s.content
LEFT JOIN deleted e ON e.id = s.id
WHERE d.name = domname
AND h_int(s.name) = h_int(filename <= работает новый маленький индекс
AND s.name = filename
AND date_part('epoch'::text, s.ptime) = filerev
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
35. Начинаем спать по ночам
§ Индекс занимал 18 гигабайт, стал занимать 8 гигабайт
§ Среднее время выполнения запроса днем в моменты
пиковой нагрузки было 40-50 миллисекунд, стало 20-25
миллисекунд
§ 90% запросов обслуживаются за 100 миллисекунд (время от
момента начала обработки запроса Perl-приложением до
момента конца обработки, включает все SQL-запросы)
§ В среднем запрос обслуживается приложением за 50 мс
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
36. Мы строили-строили, и, наконец...
§ ...и, наконец:
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
37. Zabbix strikes back
§ ...и, наконец:
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
38. Выводы:
§ «Теория малых дел», внезапно, работает
^ несмотря на свой почтенный возраст
§ Ломать — не строить!
§ Знание — сила!
§ Учение Маркса всесильно, потому что оно
верно!
§ Кажется, я не туда пишу...
§ В планах — шардинг, да
Оптимизация производительности большой унаследованной PostgreSQL базы. 2014
39. С вами был Александр Чистяков,
главный инженер Git in Sky
alex@gitinsky.com
http://gitinsky.com
http://meetup.com/DevOps-40
Пожалуйста, ваши вопросы.
Спасибо за понимание!