- PVSM.RU - https://www.pvsm.ru -
Прочитав статью Базы данных в онлайн играх [1] и особенно комменты к ней, я в очередной расстроился от мысли, что многие разработчики меняют БД в своём проекте, пытаясь этой сменой решить свои проблемы, не исчерпав, однако, всех возможностей, предоставляемой заменяемой БД. Я принимаю участие в работе над проектом, БД которого характеризуется:
В силу, как говорится, исторических причин, вся база представляет из себя, гхм, одну базу, пока без шардинга, который мог бы решить ряд проблем. Тем острее стоит вопрос о поиске решений, заключённых именно в особенностях PostgreSQL. Решений, которые можно реализовать малой кровью.
Я опишу некоторые проблемы, с которыми мы сталкиваемся, и применённые решения. Если кто-то сочтёт это полезным — ради Бога. Если кто-то поправит — я буду только рад обнаружить уязвимость в используемых подходах и увеличить эффективность работы БД. Описанное может быть применено без вмешательства в логику приложения, исключительно путём модификации схемы БД.
Речь пойдёт о PostgreSQL 9.2 (9.3 еще не щупали). И, да, здесь не будет админских советов по оптимальной настройке конфигов — я бы сам рад был узнать, как правильно их точить.
Капитанские рекомендации вроде «создавайте правильные индексы» тоже будут отсутствовать. Предполагаю, что эти нанотехнологии лежат на поверхности.
Не секрет, что чем интенсивнее производится запись в БД, тем быстрее уменьшается в среднем скорость выборок и база начинает «тупить». Связано это напрямую с транзакционной сущностью БД. Поскольку строки (кортежи) имеют версионность, при изменении значения в некой строке это значение нельзя просто так взять и записать вместо предыдущего. PostgreSQL вместо этого дублирует строку и её новый, изменённый вариант записывает отдельно. Т.е., грубо, если взять таблицу в 1ГБ и единой операцией сделать UPDATE любому полю, то таблица «внезапно» увеличится в размере до 2ГБ. То же самое примерно происходит и с индексами. Увеличение размеров БД сразу сказывается и на скорости выполнения запросов.
Разумеется, регулярно будет работать AUTOVACUUM (если настроен), ну или можно запускать руками VACUUM по мере необходимости.
Работа механизмов MVCC была бы невозможна без существования счётчика транзакций. Загадка, почему до сих пор счётчик этот 32-х битный, но имеем то, что имеем — через каждые 2 миллиарда с хвостом транзакций счётчику полагается обнулиться. А для того, чтобы не произошло непоправимое, к этому моменту должны обнулиться номера транзакций у всех строк в БД. Точнее, этим строкам ставится в соответствие некий зарезервированный FrozenXID. Что характерно, AUTOVACUUM и ручной VACUUM не занимаются простановкой FrozenXID и для нормальной работы БД при достижении счётчиком транзакций определённого конфигом значения запускается автовакуум с красивым комментом «to prevent wraparound». При больших таблицах (в десятки ГБ) этот процесс может занять томительные часы, в течение которых таблица будет недоступна ни для чтения, ни для записи.
Сделать тут что-либо, не задевая логику и архитектуру приложения, не представляется возможным (мне). Надо либо уменьшать количество транзакций, укрупняя их (что может обернуться другими проблемами и вообще неэффективно), либо разбивать БД на куски, что тоже на оперативный способ решения проблемы не тянет.
Это достаточно очевидно, но на всякий случай упомяну.
Речь идёт не о длинных транзакциях как таковых, а о ситуациях, когда приложение из-за бага не закрыло транзакцию и ушло делать свои дела дальше (к примеру, фоновые обработчики задач, способные висеть сутками). В списке активных процессов PostgreSQL такое соединение будет висеть со статусом «idle in transaction». Регулярно отрабатывающий VACUUM освобождает место, занятое старыми версиями строк (оставшимися после редактирования или удаления), ориентируясь по номеру транзакции, в которой было произведено удаление или редактирование. Грубо говоря, если были строки, удалённые транзакциями 1 и 2, а минимальный номер среди текущих открытых транзакций — 3, то эти две строки можно удалить «по-настоящему», т.к. они не попадают в область видимости любой текущей открытой транзакции. В случае подвисшей транзакции VACUUM не сможет удалить ни одну строку, отредактированную после запуска этой транзакции, в результате чего база за несколько часов может чудовищно вырасти.
Совет тут один — мониторить текущие процессы и отлавливать негодяев с «idle in transaction».
Репликации, при всей своей привлекательности, не спасают от ситуаций, когда база была побита, к примеру, кривым патчем. Сделали патч по какой-нибудь там перелинковке объектов, всё добро среплицировалось — и привет. Поэтому бекапы, как ни крути, нужны. Большая база бекапится у нас около часа. Практически всё это время проект бездействует. Тут, откровенно говоря, посоветовать ничего не могу. Наоборот, буду рад выслушать, кто и как с ситуацией справляется. Единственная мысль — бить на шарды и бекапить кусками, думая, как при этом сохранить консистентность данных.
В версии 9.3 произведена заметная работа над представлениями, которые тоже могут позволить оптимизировать работу с БД, но это уже отдельная тема.
Автор: TerminusMKB
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/postgresql/56089
Ссылки в тексте:
[1] Базы данных в онлайн играх: http://habrahabr.ru/company/mailru/blog/182088/
[2] CLUSTER: http://www.postgresql.org/docs/9.2/static/sql-cluster.html
[3] Источник: http://habrahabr.ru/post/214183/
Нажмите здесь для печати.