Пример диагностики перегруженных шардов и нехватки ресурса CPU

Как и в предыдущей статье, здесь мы рассматриваем пример диагностики перегруженных шардов и решения этой проблемы. Но в этом случае ситуация осложняется недостатком ресурсов CPU.

Дополнительную информацию о проблемах, диагностируемых в этой статье, см. в следующих материалах:

Статья начинается с описания возникшей проблемы. Затем мы проанализируем графики в Grafana и информацию на вкладке Diagnostics в Embedded UI, чтобы найти решение, и проверим его эффективность.

В конце статьи приводятся шаги по воспроизведению проблемы.

Описание первоначальной проблемы

Вас уведомили о задержках при обработке пользовательских запросов в вашей системе.

Примечание

Речь идёт о запросах к строковой таблице, управляемой data shard'ом.

Рассмотрим графики Latency на панели мониторинга Grafana DB overview и определим, имеет ли отношение наша проблема к кластеру YDB:

DB Overview > Latencies > Write only tx server latency percentiles

См. описание графика

График отображает процентили задержек транзакций на запись данных. Примерно в 10:17:00 эти значения выросли в три-четыре раза.

DB Overview > Latencies > Write only tx server latency

См. описание графика

График отображает тепловую карту (heatmap) задержек транзакций на запись. Транзакции группируются на основании их задержек, каждая группа (bucket) окрашивается в свой цвет. Таким образом, этот график показывает как количество транзакций, обрабатываемых YDB в секунду (по вертикальной оси), так и распределение задержек среди транзакций (цветовая дифференциация).

К 10:18:00 доля транзакций с задержками от 2 до 4 секунд (Группа 4.0, голубой) выросла примерно в десять раз. Доля транзакций с задержками от 4 до 8 секунд (Группа 8.0, жёлтый) увеличилась в три раза. Доля транзакций с задержками от 8 до 16 секунд (Группа 16.0, красный) уменьшилась в три раза. Доля транзакций с задержками от 16 до 32 секунд (Группа 32.0, синий) практически исчезла. А также выделились новые группы транзакций с ещё более высокими задержками — Группа 64.0 и Группа 128.0.

DB Overview > Latencies > Read only tx server latency percentiles

См. описание графика

График отображает процентили задержек транзакций на чтение данных и демонстрирует рост значений p99.

DB Overview > Latencies > Read only tx server latency

См. описание графика

График отображает тепловую карту (heatmap) задержек транзакций на чтение данных. Транзакции группируются на основании их задержек, каждая группа (bucket) окрашивается в свой цвет. Таким образом, этот график показывает как количество транзакций, обрабатываемых YDB в секунду (по вертикальной оси), так и распределение задержек среди транзакций (цветовая дифференциация).

К 10:18:00 мы видим рост количества транзакций на чтение начиная с Группы 4.0, но соотношения между группами транзакций остаются примерно одинаковыми.

Таким образом, мы видим, что задержки действительно выросли. Теперь нам необходимо локализовать проблему.

Диагностика

Давайте определим причину роста задержек. Могли ли они увеличиться из-за возросшей нагрузки? Посмотрим на график Requests в секции API details панели мониторинга Grafana DB overview:

API details

Количество пользовательских запросов выросло приблизительно с 8 000 до 13 000 в 10:20:00. Но может ли YDB справиться с увеличившейся нагрузкой без дополнительных аппаратных ресурсов?

Загрузка CPU увеличилась, что видно на графике CPU by execution pool.

CPU

Мы видим рост нагрузки на CPU в пуле ресурсов пользователей (красный) и интерконнекта (жёлтый).

Мы также можем взглянуть на общее использование CPU на вкладке Diagnostics в Embedded UI:

CPU diagnostics

Кластер YDB не использует все ресурсы CPU.

Взглянув на секцию DataShard details на панели мониторинга Grafana DB overview, мы увидим, что после роста нагрузки на кластер один из data shard'ов был перегружен (нагрузка на него выросла до 73%).

Shard distribution by load

См. описание графика

Этот график отображает тепловую карту распределения data shard'ов по нагрузке. Каждый data shard потребляет от 0% до 100% ядра CPU. Data shard'ы делятся на десять групп по занимаемой ими доле ядра CPU — 0-10%, 10-20% и т.д. Эта тепловая карта показывает количество data shard'ов в каждой группе.

График показывает два data shard'а, нагрузка на которые изменилась примерно в 10:18:00 — один data shard перешёл в Группу 80, содержащую шарды, нагруженные на 70–80%, а второй — в Группу 60 .

Чтобы определить, какую таблицу обслуживает перегруженный data shard, откроем вкладку Diagnostics > Top shards во встроенном UI:

Diagnostics > shards

Мы видим, что один из data shard'ов, обслуживающих таблицу kv_test, нагружен на 73%.

Далее давайте взглянем на информацию о таблице kv_test на вкладке Info:

stock table info

Важно

Таблица kv_test была создана с включённым партиционированием по нагрузке, но максимальное количество партиций ограничено двумя.

Учитывая, что data shard'ы являются однопоточными компонентами и обрабатывают за раз только один запрос, такой подход неэффективен.

Решение

Нам необходимо увеличить лимит на максимальное количество партиций для таблицы kv_test:

  1. Во встроенном UI выберите базу данных.

  2. Откройте вкладку Query.

  3. Выполните следующий запрос:

    ALTER TABLE `kv_test` SET (
        AUTO_PARTITIONING_MAX_PARTITIONS_COUNT = 1000
    );
    

Результат

После увеличения максимального лимита на количество партиций для таблицы kv_test перегруженные data shard'ы начали делиться и их количество выросло до шести.

Shard distribution by load

См. описание графика

График показывает, что количество data shard'ов выросло примерно в 10:29:00. Судя по цвету групп, их нагрузка не превышает 50%.

Теперь шесть data shard'ов обрабатывают запросы к таблице kv_test, и ни один из них не перегружен:

Overloaded shard count

Давайте убедимся, что задержки транзакций вернулись к прежним значениям:

Final latency percentiles

См. описание графика

Примерно в 10:29:00 процентили задержек упали практически до прежних значений.

Final latencies

См. описание графика

Транзакции на этом графике теперь распределены по трём основным группам:

  • Группа 8.0 — примерно 8% транзакций выполняется с задержкой от 4 до 8 миллисекунд.
  • Группа 16.0 — примерно 58% транзакций выполняется с задержкой от 8 до 16 миллисекунд.
  • Группа 32.0 — примерно 34% транзакций выполняется с задержкой от 16 до 32 миллисекунд.

Размеры остальных групп незначительны.

Final latency percentiles

Final latencies

Проблема с недостаточным количеством ядер CPU

Однако, если мы откроем диагностику во встроенном UI, то мы увидим предупреждение о том, что кластеру YDB не хватает ресурсов процессора в пользовательском пуле:

CPU diagnostics

Загрузка CPU еще раз увеличилась, что видно на графике CPU by execution pool.

CPU

Количество пользовательских запросов выросло приблизительно с 13 000 до 18 000 в 10:30:00.

CPU

Решение проблемы с нехваткой ресурсов CPU

Проблему недостатка ресурсов CPU можно решить несколькими способами:

  • Увеличить количество ядер для серверов, на которых запущены узлы YDB.
  • Увеличить количество ядер, доступных акторной системе узлов кластера YDB, в конфигурации кластера.
  • Добавить новые узлы в кластер YDB.

В нашем примере мы увеличим количество ядер CPU на серверах YDB и затем увеличим количество ядер в пуле ресурсов узлов кластера YDB на каждом сервере:

  1. Увеличить количество ядер CPU выделенных серверам YDB. В нашем случае мы увеличили количество ядер с 16 до 24.

  2. На каждом сервере YDB изменить динамическую конфигурацию кластера:

    1. Открыть файл конфигурации /opt/ydb/cfg/ydbd-config-dynamic.yaml в текстовом редакторе:

      sudo vim /opt/ydb/cfg/ydbd-config-dynamic.yaml
      
    2. Увеличить количество ядер в параметре cpu_count раздела actor_system_config:

      actor_system_config:
          use_auto_config: true
          node_type: COMPUTE
      cpu_count: 24
      
  3. Чтобы применить новую конфигурацию, перезапустить узлы YDB с помощью утилиты ydbops, ansible или вручную.

Результат

После увеличения количества ядер CPU в кластере YDB предупреждение о недостатке ресурсов CPU пропало:

Aftermath - CPU diagnostics

А теперь давайте проверим производительность.

Количество обрабатываемых запросов увеличилось примерно до 14-15 тысяч в секунду.

Aftermath - Requests

Помогло ли добавление ядер CPU снизить задержки?

Aftermath - Write Only TX Server Latency

См. описание графика

На графике опять появилась Группа 4.0 с задержками от 2 до 4 миллисекунд. Группа 8.0 выросла в три раза. Группа 16.0 изменилась незначительно. Практически пропала Группа 32.0.

Aftermath - Write Only TX Server Latency Percentiles

См. описание графика

Процентили задержек на запись немного снизились, а также прекратились всплески p99.

Aftermath - Read Only TX Server Latency

См. описание графика

График задержек транзакций на чтение стал очень похож на график пишущих транзакций. Вернулась Группа 4.0 с задержками от 2 до 4 миллисекунд, чья доля оказалась еще больше, чем при записи. Группа 4.0 выросла в три раза. Группа 16.0 изменилась незначительно. Практически пропала Группа 32.0.

Aftermath - Read Only TX Server Latency Percentiles

См. описание графика

Процентили задержек на чтение тоже снизились, а также практически исчезли всплески p99.

Тестовый стенд

Топология

Для этого примера мы использовали кластер YDB из трёх серверов на Ubuntu 22.04 LTS. На каждом сервере был запущен один узел хранения и три узла баз данных, обслуживающих одну и ту же базу данных.

Аппаратная конфигурация

Аппаратные ресурсы серверов (виртуальных машин) приведены ниже:

  • Платформа: Intel Broadwell
  • Гарантированный уровень производительности vCPU: 100%
  • vCPU: 16
  • Память: 32 GB
  • Диски:
    • 3 × 93 GB SSD на каждом узле YDB
    • 20 GB HDD для операционной системы

Тест

Нагрузка на кластер YDB была запущена с помощью команды CLI ydb workload. Дополнительную информацию см. в статье Нагрузочное тестирование.

Чтобы воспроизвести нагрузку, выполните следующие шаги:

  1. Проинициализируйте таблицы для нагрузочного тестирования:

    ydb workload kv init --min-partitions 1
    ydb yql -s 'ALTER TABLE `kv_test` SET (
        AUTO_PARTITIONING_MAX_PARTITIONS_COUNT = 2
    );'
    

    Мы намеренно ограничиваем максимальное количество партиций в таблице kv_test до 2 после инициализации.

  2. Воспроизведите стандартную нагрузку на кластер YDB:

    ydb workload kv run mixed -s 600 -t 250 --rate 8000
    

    Мы запустили простую нагрузку, используя базу данных YDB как Key-Value хранилище. Точнее, мы использовали нагрузку mixed, которая одновременно пишет и читает данные, дополнительно проверяя что все записанные данные успешно читаются.

    Параметр -t 250 используется для запуска нагрузочного тестирования в 250 потоков. Параметр --rate 8000 используется для ограничение максимального количества запросов до 8000 запросов в секунду.

  3. Создайте перегрузку на кластере YDB:

    ydb workload kv run mixed -s 600 -t 400
    

    Как только первый тест завершился, мы немедленно запустили тот же самый тест в 400 потоков без ограничения максимального количества запросов в секунду, чтобы создать перегрузку.

Смотрите также