Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slow CW-config apply on instance under load #2141

Open
palage4a opened this issue Aug 23, 2023 · 1 comment
Open

Slow CW-config apply on instance under load #2141

palage4a opened this issue Aug 23, 2023 · 1 comment

Comments

@palage4a
Copy link
Contributor

palage4a commented 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.

local function save(clusterwide_config, path)
checks('ClusterwideConfig', 'string')
local random_path = utils.randomize_path(path)
local ok, err = utils.mktree(random_path)
if not ok then
return nil, err
end
for section, content in pairs(clusterwide_config._plaintext) do
local abspath = fio.pathjoin(random_path, section)
local dirname = fio.dirname(abspath)
ok, err = utils.mktree(dirname)
if not ok then
goto rollback
end
ok, err = utils.file_write(
abspath, content,
{'O_CREAT', 'O_EXCL', 'O_WRONLY', 'O_SYNC'}
)
if not ok then
goto rollback
end
end
ok = fio.rename(random_path, path)
if not ok then
err = SaveConfigError:new(
'%s: %s',
path, errno.strerror()
)
goto rollback
else
return true
end
::rollback::
local ok, _err = fio.rmtree(random_path)
if not ok then
log.warn(
"Error removing %s: %s",
random_path, _err
)
end
return nil, err
end

Так, например, если среднее время прокрутки 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

Варианты решения

  1. Рефакторинг бизнес-логики и/или модели данных, чтобы уменьшить среднее время прохода евент-лупа
  2. Уменьшение количества секций в КВ-конфиге
  3. Увеличение тайм-аута для prepare фазы
  4. Оптимизация кода функции save

Первый и второй пункт не всегда реалистично выполнить в продовом кластере. Увеличение таймаутов может помочь, но может скрыть другие проблемы, влияющие на скорость применения cw-конфига, например, сетевые. Если оптимизировать функцию save для таких сценариев, то можно решить проблему применения cw-конфига на больших нагруженных кластерах без необходимости изменять код пользовательского приложения. Такую оптимизацию можно сделать с помощью вынесения логики сохранения cw-конфига из tx-треда.

@palage4a
Copy link
Contributor Author

Also related to #2119

@palage4a palage4a changed the title Медленное применение КВ-конфига на нагруженном инстанса Slow CW-config apply on instance under load Aug 23, 2023
@palage4a palage4a linked a pull request Nov 28, 2023 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant