Comments 36
Наконец-то Яндекс признал, что насамом деле все там держится на PHP
И mysql 5.7
пытаюсь поддерживать легаси проект на PHP после C# и это ужасно
Добрый день, есть несколько вопросов!
Почему вы переносили данные в postgres, а не YDB? есть же своя собственная БД с которой больше экспертизы.
В каких целях вы успользуете galera? из статьи ясно что у вас есть проблема с FC, но зачем galera не раскрыто.
Зачем вы использовали TableSwitcher + "собирали данные из проложения" кроме того, что описано в статьи ? данные операции покрывает proxysql.
Зачем хранить в реляционной СУБД архивные данные? Кажется Clickhouse от Яндекса как для этого.
Почему не использовали kafka, CDC коннекторы при миграции?
Какие еще варианты решения проблемы рассматривали и почему отвергли их?
Статья больше показывает, что вы использутете инструменты которые не умеете готовить и ловите проблемы (мое личное мнение), 4ТБ, всего 400 таблиц и всего 100rps - но это нормальная нагрузка для многих
Автор писал про 100К RPS. Это невероятно много, по сравнению с реальным количеством обращений.
postgres, а не YDB?
Привет! Конкретно в нашем стриме, у нас экспертизы все таки больше с pg, все наши сервисы по дефолту работают с pg.
В каких целях вы используете galera?
У нас все таки легаси монолит) Яндекс.Еда как проект, изначально принадлежал и разрабатывался другой компанией (до того как его купил Я.), решение в виде использования galera cluster принималось видимо по каким то своим соображениям, актуальным на тот момент. Могу предположить, что использовали из-за multi master схемы, которая одновременно позволяет и разгрузить бд, и особо не прилагать усилий для поддержки логики по получению неконсистентных данных из слейвов
Почему не использовали kafka
kafka в нашем проекте у нас нет вообще, а затащить ее только ради этого очень дорого
Зачем хранить в реляционной СУБД архивные данные? Кажется Clickhouse от Яндекса как для этого., CDC коннекторы при миграции?
Как уже сказал, хранятся они там по причине "исторически так сложилось, никто не переделывал". Использовать clickhouse актуально только для таблиц логов, а как я писал выше, переносили мы таблички не только с такими данными. Нужен был какой то универсальный инструмент, который могли бы использовать другие команды для своих таблиц.
Так же, все решения, которые нельзя реализовать в рамках приложения, требуют привлечения ребят из инфраструктуры, а это дополнительные ресурсы и время. В нашем решении пришлось привлечь ребят из инфры только чтобы получить квоты на создание баз. Остальное уже чисто руками разработчиков
Какие еще варианты решения проблемы рассматривали и почему отвергли их?
Был вариант например, с вынесением таблиц при помощи DataTransfer, но нам он не подошел потому что там нет плавной раскатки. К тому же, при переключении приложения на новый коннект потребуется какой то небольшой downtime.
P.S. Хотя с помощью него мы уже успешно мигрировали базу в облако)
100k rps - но это нормальная нагрузка для многих
100к рпс да, это нормально, но у нас и не было проблемы с читающим трафиком, проблема именно с пишущим, когда прилетала большая пачка модифицирующих запросов и срабатывал flow control.
Спасибо за ваши ответы! Всё стало намного прозрачнее – вы просто избавляетесь от легаси в пользу того, где больше экспертизы. Желаем вам удачи!
P.S. У нас Percona XtraDB Cluster (3 ноды, одна из них мастер), перед ними ProxySQL. В среднем нагрузка — 180K QPS, из них модификации — 12K QPS. Редко wsrep-очереди стреляют 500+.
Это к тому, что Galera без проблем держит большие нагрузки. Но, как вы верно отметили, в первую очередь важно бороться с медленными запросами.
Те получается вы начали пилить велосипед, потому что у вас нет нормального взаимодействия между отделами?
не совсем понял откуда у вас такой вывод получился? вроде про проблемы взаимодействия с другими отделами я ничего не писал
Такое мнение сложилось после нескольких упоминаний про то что самим быстрее чем девопсов привлекать, сколько времени заняла эта фича кстати в днях?
Изначально мы стали говорить про clickhouse и kafka, эти решения тяжелые и не универсальные для нашего случая, поэтому я в дополнение к тому, что они нам не подходят, добавил что это требует дополнительных сил в виде инфраструктуры) Проблем в коммуникации нет, просто у каждого свой бэклог/цели и нельзя просто принести огромный проект который сразу же все начнут делать
сколько времени заняла эта фича кстати в днях?
Первый десяток табличек где то за 3 месяца в 1 руки. Это со сборами всяких аппрувов под квоты на базы, написание кода и переключение. Когда попробовали и написали доку, тогда уже остальные команды стали разносить свои таблички, но опять же, занималась не фулл тайм. Итого где то до полу года ушло на все от старта, до решения основных проблем.
такой вывод напрашивается хотя бы при взгляде на такую картинку:

обычно такая картинка получается когда третья рука справа не знает что делает 5-я рука слева, и они часто делают одно и то же и еще и жалуются что пальцев на все не хватает. Но с другой стороны если бы не было такого богатства вам бы нечего было делать и эта статья не появилась бы.
Вам успехов в борьбе с космической запутанностью.
К сожалению всегда есть опасность что система заставит вас переродиться и вы начнете добавлять запутанность вместо того чтобы уничтожать ее. Не поддавайтесь!
Отличная статья.
Изменились ли показатели на первых графиках с временем выполнения запросов в бд? Или срез пика в прошлом году это и есть итог ваших работ?
Не кажется ли средний показатель в 300 мс неприемлемо большим?
Как несколько коннектов повлияло на rps монолита?
Стал ли haproxy чаще сбоить? Замечал сбои при подобных распилах
Изменились ли показатели на первых графиках с временем выполнения запросов в бд? Или срез пика в прошлом году это и есть итог ваших работ?
В целом, не изменилось. Так и есть, пик показывает, что основные проблемы были исправлены в конце 23, когда собрали самые проблемные запросы, всеми навалились и исправили. На остальном таймлайне просто хотелось показать, что мы продолжали мониторить запросы и в случае появления новых проблем их быстро правили. Сейчас, по выгрузкам мы видим, что "стреляющие" случаи - единичные, поэтому вкладываться в их оптимизацию нет имеет смысла.
Не кажется ли средний показатель в 300 мс неприемлемо большим?
А это же только в рамках выборки slow queries, а не всех запросов базы. Т.е. в эту выборку может попасть например 10 запросов за неделю, а для такого незначительного кол-ва думаю что приемлемо. К сожалению график собирал с агрегированных данных уже, поэтому кол-во этих запросов на тот момент посмотреть не получится
Как несколько коннектов повлияло на rps монолита?
RPS в монолите не изменился никак, вроде и не должен был) Может имелось ввиду тайминги? Если да, то в моменте, когда писали в обе базы, на некоторых эндпоинтах выросли на ~100мс, после полного перехода тайминги пришли в норму
Стал ли haproxy чаще сбоить? Замечал сбои при подобных распилах?
Нет, проблем не наблюдали, все как часики
Как редко компании рассказывают про свое легаси, на котором все держится, одни микросервисы да микросервисы на конференциях, а работать начнёшь- там пхп, сям хранимки, а ещё местами C++ код 20-летней давности...
Как решалась проблема, если удавалось сделать запись только в одну БД, а вторая была недоступна или же происходил откат транзакции?
Хороший вопрос)
или же происходил откат транзакции
Т.к. TS у нас последовательный, то в обертке это выглядело по типу conn1->rollback();
conn2->rollback(); тут вроде проблем не словили
если удавалось сделать запись только в одну БД, а вторая была недоступна
На эту ситуацию у нас был алерт и мы запускали вручную скрипт чтобы синхронизировать данные за какой то интервал времени. Но за весь период переноса, такая ситуация возникала буквально пару раз и то, потому что мы долго задерживались на стратегии когда писали в обе базы.
действительно хорошая статья. В яндексе появились разработчики, которые разгребают мусорные завалы, а не насыпают в них. А главное появилась понимание необходимости разгрести эти завалы. Похоже можно подумать о покупке акций кампании.
Не очень понятно с кластером - в начале статьи 3 ДЦ и в каждом мастер и слейв, а потом - один переходящий мастер и три слева.
Но в любом случае вопрос - а можно было сделать какой-нибудь статичный шардинг ключ? По регионам например? Тогда одну базу можно разбить на 89 меньшего размера. Хотя Москва и Питер все равно останутся самыми нагруженным.
Может где то некорректно выразился но да, 3 ДЦ, в каждом master+slave. Galera cluster же это заворачивает в multi master схему, что позволяет писать в любой мастер из ДЦ. Слейвы для чтения, либо для замены вышедшего из строя мастера рамках ДЦ
Тогда одну базу можно разбить на 89 меньшего размера
А не было необходимости вроде. Проблема же не в том что данных очень много и выборки медленно работают, а в том что из за большого количества вставок в базу в моменте, данные не успевали доезжать до реплики из за чего мастер останавливался. Т.е. решать надо было что то с модифицирующими запросами. Вот тут про шардирование и репликацию ответил)
Может невнимательно читал, но обычно начинают с партиционирования нагруженных транзакционных таблиц. Если там лежат исторические данные, то просто по дате. Тогда большинство запросов будут работать только с одной партицией за последний месяц или нделю, а данные попадать в кэш. То есть, памяти и дисковых операций потребуется на порядок меньше, как и CPU. Требует ревью нагруженных запросов.
При заявленном RPS и размере БД такого подхода обычно хватает.
Ещё можно разделять на партиции по ID клиента, номеру партнёра или ещё как-то. Это обычно более заморочено и не всеми БД поддерживается разделение на партиции сразу по нескольким полям. Но это больше про классическое шардирование, когда сервера физически можно разделить, а справочники реплицировать между ними.
Ежедневные или еженедельные чистки по расписанию тоже отлично, если бизнес позволяет. Обычно приходится сливать куда-то данные для аналитики и отчетности при таком подходе. Тут вы большие молодцы:)
Наша проблема же заключалась в том, что у нас срабатывал flow control при большом RPS на insert, данные не успевали засинкаться с репликами (а galera cluster - это multi master схема). Поэтому не думаю, что партиции бы нам помогли в данном случае, ибо объем данных не меняется
Классическое шардирование возможно бы помогло, но тут несколько моментов:
Неизвестно, как себя поведет тот же галеровский wait sync с бОльшим количеством нод. Т.е. если один шард притупит, есть вероятность словить еще больше проблем (это просто предположение)
В конечном итоге, после таких оптимизаций, данные то никуда не денутся и в ближайшем будущем их все придется разносить по сервисам) А тут мы вроде и подготовились к реализации нового сервиса, перенеся данные в отдельную базу), и тут же нагрузку сняли с базы монолита
В совокупности это 6 ТБ ОЗУ и 1536 ядер
как монолит на этом работал? чуть подробнее про это, плиз
Это ресурсы не монолита, а дедиков, на которых базировался mysql. У нас 3 ДЦ, в каждом по master+slave, итого 6 ног. Ресурсы одной ноды - 1ТБ ОЗУ и 256 ядер.
На вопрос почему так много, нет точного ответа, но предполагаю, что эти сервера были собраны еще до того, как Еда, как проект, стала принадлежать Яндексу. Просто собрали сервера сильно с запасом, выкрутили настроечки в виде threads и buffer_pool_size в максимальные значения и в таком виде продалось Я. Ну а нам в целом, этого хватало с лихвой.
Похоже, что проблемы с производительностью наступили по причине большого объёма данных. Не только большое количество изменений данных мешает синхронизации реплик, но и нагрузка самих реплик запросами. Достаточно дать на реплику слишком большую нагрузку запросами, и синхронизация сломается.
Для решения проблем достаточно было почистить базу от ненужных старых данных. Это уменьшает нагрузку на реплики запросами чтения данных. Запросы по маленьким таблицам требуют меньше ресурсов, чем по большим таблицам. Вот и освобождаются ресурсы для синхронизации.
Не надо было делать недостаточно продуманные и протестированные изменения на production. Привезли некоторые проблемы с согласованностью данных и доставили неприятности бизнесу и клиентам («но были потери в заказах»).
У вас есть какие то подробности или может материалы по поводу того, что селективная нагрузка или объем данных (который не переливается в данный момент) влияет на синк реплик?
Binlog же не хранит никакой информации о старых данных, а тем более информации о селектах, поэтому нет никакой причины тормозить синк. Единственное место которое я вижу, где может повлиять размер таблиц - это неоптимизированные запросы, в которых используется какой нибудь file sort.
Предъявить какие-то подробности о влиянии нагрузки процессоров, оперативной памяти и дисков на вторичном узле кластера отказоустойчивости без разделяемых ресурсов на процесс синхронизации вторичного узла?! Это каким образом будет происходить эта синхронизация, если нет ни процессоров, ни оперативной памяти и дисков, всё занято выполнением запросов на чтение данных?! Синхронизация будет стоять и ждать освобождения ресурсов. Это ваш случай. «Чтобы все реплики смогли догнать мастер и применить накопившиеся транзакции, flow control останавливает запись в мастере вовсе...». Это касается всех кластеров отказоустойчивости без разделяемых ресурсов всех производителей. MS SQL Server Availability Groups отваливается примерно так же. Нельзя нагружать вторичные узлы чрезмерной нагрузкой, это общее правило.
Рассмотрим крайний/граничный случай, когда в кластере отказоустойчивости без разделяемых ресурсов всего два сервера и кластер используется по своему прямому назначению для отказоустойчивости. В этом случае резервный сервер нагружать запросами нельзя совсем. Это чтобы при поломке любого сервера оставшийся сервер мог гарантированно выдержать нагрузку пока не подъедет замена. В этом граничном случае нагрузка на вторичный узел будет намного меньше нагрузки первичного узла, угрожать процессу синхронизации могут только какие-то внезапно приключившиеся проблемы типа выхода из строя какого-то оборудования.
У вас не этот случай, кластер отказоустойчивости без разделяемых ресурсов используется не для отказоустойчивости, а для распределения нагрузки и вторичный узел нужен для выполнения запросов на чтение данных. И эта нагрузка на чтение оказалась чрезмерной, не стало хватать ресурсов для синхронизации и пошли проблемы. Сначала проблемы возникают редко, потом чаще, а потом и вообще всё может остановиться, если не принять какие-то срочные меры. В вашем случае было достаточно почистить базу данных от ненужных старых данных. Как это повлияло? Таблицы стали сильно меньше. Реплика – это копия, если удалить данные в основной базе, то и на реплике удалятся. Запросы на чтение стали потреблять меньше ресурсов, ресурсов стало хватать, проблемы синхронизации решены. Вы просто вернулись к состоянию на сколько-то месяцев/лет назад, когда данных было меньше и проблем не было.
нет ни процессоров, ни оперативной памяти и дисков, всё занято выполнением запросов на чтение данных?! Синхронизация будет стоять и ждать освобождения ресурсов. Это ваш случай
Не наш случай. Flow control преимущественно срабатывал когда с ресурсами было все ок. ОЗУ и CPU в полке скорее всего исключение за счет неоптимизированных запросов в моменте. Само собой, когда ресурсов недостаточно, то очевидно, что проблемы могут быть не только с синком
эта нагрузка на чтение оказалась чрезмерной...
Запросы на чтение стали потреблять меньше ресурсов, ресурсов стало хватать
На репликах постоянная нагрузка не более 5-10%, т.е. по ресурсам все свободно.
В вашем случае было достаточно почистить базу данных от ненужных старых данных
Запросы на чтение стали потреблять меньше ресурсов, ресурсов стало хватать, проблемы синхронизации решены.
Почему запросы на чтение должны меньше потреблять ресурсов из за того что база весит меньше? RPS ушел? Или может объем данных получаемых стал меньше? Где корреляция? База же не переливается постоянно полностью, а ДО наливается в соответствии с курсором в binlog. Поэтому базе относительно синка, по большей части равно какого она размера, главное данные в моменте которых не достает в реплике и которые надо перенести
«Почему запросы на чтение должны меньше потреблять ресурсов из за того что база весит меньше?»
Просто проверьте экспериментально. Сделайте две одинаковых таблицы с первичным ключом, в одну добавьте 10 записей, а в другую миллиард. И проверьте запросы по первичному ключу из середины таблиц.
В MS SQL Server AlwayOn Availability долгий запрос на вторичном узле может заблокировать синхронизацию, общая нагрузка небольшая, но синхронизация не идёт. Возможно, у вас что-то подобное.
Подскажи как в Managed Postgres Yandex cloud настроить дашбор использования таблиц если это не секрет)
Заранее спасибо!
Секреты стройности монолита: подходы по снятию нагрузки с БД