Алексей Лесовский, Data Egret
В компаниях любого размера бывают проблемы. Откуда они берутся?
-
Из фич. Начинаем использовать продвинутые фичи, утилиты и прочее. «Хочется взять дежурный пистолет, положить в ящик стола, иногда достать, застрелиться и работать дальше».
-
Из хранения данных. Когда оно усложняется, больше шансов написать кривой запрос.
-
Из жизненного цикла. Разработчики пилят, админы настраивают, а улучшать систему некому. База работает с дефолтными конфигами и когда-нибудь ломается.
Пока проект новый, всё работает быстро. Потом приложение растёт, появляется больше клиентов — приложение тормозит. Где могут быть проблемы:
- Диск занят
pg_xlog
. Разработчик: «а давайте его удалим!». Не надо так. Там журнал транзакций. - Диск занят базами, больше всего в
history_log
. Пытаемся почистить базу запросом, но она не уменьшается, потому что постгрес не отдаёт автоматически место ОС. - Disk I/O. Некто составил запрос на M таблиц в N потоков X тысяч раз в секунду. Результат — сервер пятисотит.
- Тормоза фоновых процессов СУБД.
- Накладные расходы от виртуализации
- Хранилище от китайского noname
- Дефолтные конфиги
- ...
Что делать? Мониторить и планировать!
- Сразу на SSD, не раздумывая.
- Схема данных: планировать заранее и писать только нужное. Например, не писать в логи JSON весом в несколько мегабайт.
- Партиционирование
Мониторинг:
- Storage: latency, utilization
- PostgreSQL: подключенные клиенты, ошибки, запросы (statements)
Типичный разработчик видит БД как строчку конфига и не интересуется тем, как она работает. Это источник проблем.
OLTP-транзакции — быстрые, короткие, лёгкие. OLAP-транзакции — медленные, долгие и тяжёлые.
Те и другие нужно разносить. Вторые мешают первым. Как масштабировать PostgreSQL так, чтобы разнести нагрузку?
- Streaming replication — создаём реплики, в том числе каскадные, на разные реплики вешаем разные запросы. Например, аналитику на отдельную реплику.
- Logical publications, subscriptions. Конкретные наборы таблиц подключаем в соседние базы и их приложения могут ими пользоваться.
- Внешние таблицы (foreigh tables), декларативное партиционирование (declarative partitioning). Несколько баз с разными наборами таблиц. С помощью механизма внешних таблиц объединяем их в одной базе, приложение работает с ней, но на самом деле качает данные из тех нескольких баз.
С чего начать?
- С репликации. Разнести нагрузку на чтение и запись. Пишем в мастер, читаем из реплик. Для аналитических запросов делаем отдельную реплику.
- Балансировка: лучше на стороне приложения, можно DNS round robin, интересно Keepalived и Haproxy, совсем хорошо Patroni, DCS.
Idle transactions приводят к снижению производительности, блокировкам и дедлокам, потом к пятисотым.
Откуда берутся такие транзакции?
-
Внешний источник:
- Приложение открывает транзакцию
- Потом идёт на какой-то другой источник, встречает там ошибку, падает.
- Profit, транзакция висит, пока её явно не убьют.
-
Нет обработки ошибок
-
Человеческий фактор — открыл и забыл.
Что делать:
- Алерты в мониторинге
pg_terminate_backend
- устранять ошибки в приложении
Избегайте пустых транзакций любой ценой!
Фоновая обработка событий. Бизнес хочет необычного. Появляются самописные очереди. От долгих транзакций эти таблицы распухают. Растёт время их обработки, очередь перестаёт работать.
Что делать: использовать Skytools PgQ. Но и в нём есть проблемы:
- Мало документации
- Нужно применять джедайские техники
- Много нужных знаний находятся в почтовых рассылках (mailing lists)
Плюсы PgQ:
- Настроил и забыл.
- Дешевле отдельных брокеров.
Вывод: для каждой задачи сначала ищите инструменты, которые уже изобретены.
Админы хотят:
- инстансы
- деплой
- конфиги
Разработчики хотят:
- деплой
- миграции катить без ручных вмешательств
Все хотят autofailover! Но всё не так просто:
- Случается split-brain. Потеряли связность сети, fencing'а нет, приложения пишут сразу в два мастера. Так было недавно у GitHub.
- Каскадный failover. Мастер падает, переключаем на второй, который не успел отреплицироваться, он тоже падает, остаётся один сервер, который складывается под нагрузкой.
Как делать failover?
А что, если развернуть базу в k8s?
- Нужно где-то хранить. Решения есть (CEPH, GlusterFS, DRBD), но они медленные. И нужно поддерживать кластерную файловую систему. Это работает, пока база маленькая, нет требований к производительности и не страшно потерять данные. Т.е. это не работает.
Вывод: использовать для стейджингов и девелоперских машин, но не на проде. Если очень хочется — то использовать local volumes, streaming replication и операторы PostgreSQL.