Description
openedon Aug 23, 2023
tl;dr
Столкнулись с тайм-аутами кв-конфига при деплое кластера, особенно больные приводят к локу конфига (two-phase commit is locked
). Выяснили, что тайм-ауты связаны с нагрузкой на кластер и неоптимальными запросами по спейсам. Рефакторинг логики сейчас мы позволить не можем, поэтому копали в сторону решения на стороне картриджа. Оказалось, что в фазе prepare происходит много йилдов из-за обращений к файловой системе. Время prepare фазы прямопропорционально количеству секций в кв-конфиге и времени прохода евент-лупа. Кажется, от этой связи можно избавиться, вынеся часть логики в отдельный тред, тем самым значительно ускорив применение cw-конфига.
Описание
Мы столкнулись с проблемами применения cw конфиг в проде на большом нагруженном кластере.
Ошибки, которые мы ловили:
upload not found
timed out
two-phase commit is locked
Что имеем
- Большой кластер - 200 стораджей (100 + 100);
- Нагруженный кластер - сотни файберов, конкурентно выполняющих запросы;
- Сложная бизнес-логика - есть агрегирующие запросы;
- Неоптимальная модель хранения - некоторые запросы скроллят много записей при выполнении и редко передают управление,
время прокрутки event loop’а иногда может достигать сотен миллисекунд.
Что выяснили
В ходе расследования мы выяснили, что часто ошибка применения кластер-вайд конфига вызвана долгим выполнения процедуры prepare на инстансах,
находящихся под нагрузкой. Под нагруженным инстансом мы имеем ввиду инстанс, у которого среднее время прохода евент лупа составляет десятки и более миллисекунд.
Далее оказалось, что в процессе выполнения процедуры prepare происходит большое количество йилдов, которые обусловленны необходимостью в обращениях к файловой системе. Эти обращения зачастую происходят в функции, которая отвечает за сохранение конфига - cartridge.clusterwide-config.save
.
cartridge/cartridge/clusterwide-config.lua
Lines 485 to 533 in 8345c47
Так, например, если среднее время прокрутки event-loop’а составляет 25 мс и функция в процессе выполнения совершает 10 йилдов (явных или неявных), то время работы всей функции будет не менее, чем 250мс - 10 * 25 = 250.
При выполнении, функция save сохраняет кластервайд конфиг в виде дерева файлов, осуществляя различные проверки по пути. Для каждой секции просходит много неявных йилдов, см. таблицу ниже.
Поэтому, чем больше секций в конфиге, тем больше йилдов, и, соответвенно, дольше выполняется фукция save
.
Следовательно, если в кластере хотя бы один инстанс долго прокручивает event-loop и/или в cw-конфиге много секций, то очень вероятны ошибки применения cw-конфига из-за наступления таймаутов. Так, например, во время деплоя происходит частое обновление cw-конфига, а таймауты по-умолчанию не очень большие.
Ниже мы провели некоторые замеры, чтобы показать зависимость времени выполнения функции save
от кол-вa секций в CW-конфиге и среднего времени выполнения event loop’а.
# sections | event loop (ms) | duration (ms) | # yields |
---|---|---|---|
4 | 25 | 1532 | 59 |
4 | 50 | 3084 | 59 |
8 | 25 | 2966 | 107 |
8 | 50 | 5682 | 107 |
16 | 25 | 5596 | 203 |
16 | 50 | 10822 | 203 |
В этом gist можно посмотреть, как делали замеры.
Ветка: palage4a/debug-2pc-yields
Варианты решения
- Рефакторинг бизнес-логики и/или модели данных, чтобы уменьшить среднее время прохода евент-лупа
- Уменьшение количества секций в КВ-конфиге
- Увеличение тайм-аута для prepare фазы
- Оптимизация кода функции
save
Первый и второй пункт не всегда реалистично выполнить в продовом кластере. Увеличение таймаутов может помочь, но может скрыть другие проблемы, влияющие на скорость применения cw-конфига, например, сетевые. Если оптимизировать функцию save
для таких сценариев, то можно решить проблему применения cw-конфига на больших нагруженных кластерах без необходимости изменять код пользовательского приложения. Такую оптимизацию можно сделать с помощью вынесения логики сохранения cw-конфига из tx-треда.