...

пятница, 16 декабря 2016 г.

Боремся с нагрузками в HPE Vertica

Типовой сценарий работы «just in time» хранилища данных выглядит так: десятки (ETL) сессий почти непрерывно захватывают с источников данные и вставляют их в хранилище. Параллельно множество других (ELT) сессий отслеживают поступление данных, заполняют консолидированный слой и ведут расчет агрегатов и витрин. Одновременно с этим, на поступающих первичных и рассчитанных данных, выполняют запросы пользователи, BI и другие системы. Вся эта каша должна ладно вариться в рамках сервера хранилищ данных, без тормозов и затыков, какими бы не были пиковые нагрузки.

В HPE Vertica для планирования работы сервера под нагрузками разработан специальный механизм, под названием «ресурсные пулы». Идея его в том, что каждый пользователь сервера работает в рамках выделенного ресурсного пула, который регулирует приоритетность доступа к ресурсам кластера, ограничивает конкурентность выполнения запросов и описывает правила резервирования и работы с памятью сервера.

По умолчанию после установки сервера Vertica на созданной базе данных это выглядит примерно так:



На каждом сервере (ноде) кластера доступная для Vertica память обозначается, как ресурсный пул General. Для различных нужд сервера автоматически создаются служебные пулы, которые отрезают от General для себя кусочки памяти:
  • WOS — для хранения в области памяти порционно вставляемых данных
  • TM — для фонового служебного процесса Tuple Mover, выполняющего moveoute и mergeout операции
  • Прочие служебные — Vertica имеет дополнительные ресурсные пулы для проведения операций восстановления нод кластера, построения проекций, выполнения служебных запросов и т.д.

По умолчанию пользователи сервера крутятся под управлением самого пула General. Можно посмотреть его текущие настройки:
dbadmin=> SELECT * FROM resource_pools WHERE name = 'general';
-[ RECORD 1 ]------------+------------------
pool_id                  | 45035996273721212
name                     | general
is_internal              | t
memorysize               |
maxmemorysize            | 30G
executionparallelism     | AUTO
priority                 | 0
runtimepriority          | MEDIUM
runtimeprioritythreshold | 2
queuetimeout             | 00:05
plannedconcurrency       | 10
maxconcurrency           | 20
runtimecap               |
singleinitiator          | f
cpuaffinityset           |
cpuaffinitymode          | ANY
cascadeto                |

Расшифрую некоторые параметры:
  • memorysize — размер зарезервированной памяти пула, этот размер отрезается от пула General, уменьшая его размер доступной памяти, для General соответственно не указывается.
  • maxmemorysize — максимально разрешенный размер использования памяти пулом. В случае использования пулом памяти, более указанной memorysize, недостающая память временно забирается из пула General, если там есть конечно что забирать.
  • plannedconcurrency — делитель для установки размера памяти, выделяемой сессии при старте запроса в пуле, в данном случае для пула General maxmemorysize: 30 гб делить 10 plannedconcurrency = каждой сессии при старте выделяется 3 гб памяти пула, что мягко говоря жирновато.
  • maxconcurrency — максимальное количество выполняемых на пуле конкурентных сессий.

Такие «дефолтные» настройки дают фактически 100% гарантию тормозов работы Vertica:
  • 10 сессий запускает выполнение запросов
  • каждой сессии выделяется по 3 гб памяти пула, даже если столько и не нужно
  • Если сессии еще не успели отработать и новые сессии запустили еще запросы, то вместо памяти из 30 гб они получают работу в свапе
  • Если какая-то сессия в ходе работ съела всю память пула, то другие сессии так же оказываются в свапе

Давайте поможем «горю»:
ALTER RESOURCE POOL general PLANNEDCONCURRENCY 20 MAXCONCURRENCY 10;

Теперь каждой сессии при старте запроса в пуле выделяется 0.5 гб, а всего одновременно может выполнятся не более 10 сессий. При старте 10 сессий будет израсходовано 5 гб памяти пула, еще 25 гб останется как резерв для отдачи памяти тяжелым запросам и другим ресурсным пулам.

Хочу обратить внимание на параметр MAXCONCURRENCY — чем он ниже, тем быстрее будут работать ваши запросы. У каждой аппаратной части есть предел нагрузок, при превышении которого все «встает колом». Чем выше конкурентность, тем больше нагрузка на процессоры и дисковые массивы, тем ниже их скорость работы. Эффективнее выполнить 10 запросов и далее с очереди выполнить следующие 10 запросов, чем пытаться выполнить одновременно 20 запросов. Естественно, MAXCONCURRENCY будет в первую очередь зависеть от поставленных для решения задач пула и от характеристик железа кластера, Ваша задача выявить пределы и выставить его чуть ниже пределов, чтобы в случае пиковых нагрузок одновременного выполнения множества тяжелых запросов, кластер вдруг не затормозил для всех его пользователей.

Так что же с пулами? Пока мы только настроили General, однако держать в нем пользователей на самом деле дурная практика. Давайте сделаем типовые пулы по группам задач пользователей:

-- Пул для писателей
CREATE RESOURCE POOL writers
MEMORYSIZE '2G'
MAXMEMORYSIZE '10G'
PLANNEDCONCURRENCY 10
MAXCONCURRENCY 10
PRIORITY -50
RUNTIMECAP '3 MINUTE'
RUNTIMEPRIORITYTHRESHOLD 0;

-- Пул для тяжелых длинных запросов
CREATE RESOURCE POOL slowly
MEMORYSIZE '0%'
MAXMEMORYSIZE '20G'
MAXCONCURRENCY 7
RUNTIMEPRIORITY LOW
QUEUETIMEOUT '15 MINUTE'
RUNTIMEPRIORITYTHRESHOLD 0;

--  Пул для читателей
CREATE RESOURCE POOL readers
MEMORYSIZE '4G'
MAXMEMORYSIZE '10G'
PLANNEDCONCURRENCY 20
MAXCONCURRENCY 10
RUNTIMECAP '5 MINUTE'
PRIORITY 50
RUNTIMEPRIORITYTHRESHOLD 3
CASCADE TO slowly;

General теперь у нас «похудел»:

Что мы сделали:
  1. Раскидали по группам сессии пищушие, читающие и выполняющие длинные тяжелые запросы.
  2. Выделили начальную память пулам читателей и писателей, чтобы для большинства коротких запросов память бралась сразу из резервированной для пула без подкачки с General.
  3. Не стали выделять память пулу тяжелых запросов, все равно его сессии захотят много памяти и резервировать для них, отрезая драгоценную память из General, смысла нет, зато этому пулу разрешили забирать до 20 гб памяти от General в случае необходимости.
  4. Выставили для пула тяжелых запросов пониженный приоритет выполнения LOW.
  5. Для пула писателей и читателей выставили приоритет доступа к ресурсам так, чтобы по приоритету выполнения MEDIUM пул писателей был аутсайдером (-50 приоритет), пул General был посередине (нулевой приоритет) и пул для читателей был выше этих пулов (50 приоритет).
  6. Рационально выставили значения конкурентности пулам, где одновременно могут выполняться 10 запросов писателей, 10 запросов читателей и 7 тяжелых запросов.
  7. Для ситуаций, когда пользователь запустил тяжелый запрос в пуле читателей, который длиться более 5 минут, указали перевод каскадом таких запросов на пул тяжелых запросов. Это гарантирует, что пул читателей не просядет при выполнении на нем длинных запросов, которые забьют слоты выполнения конкурентов и замедлят конвеер выполнения из очереди быстрых запросов. Для пула писателей выставили ограничения выполнения запросов не более 3 минут, чтобы неоптимизированные запросы вставки или обновления данных сшибались.
  8. Для пула тяжелых запросов выставили время ожидания в очереди 15 минут. Если все конкурирующие слоты у пула заняты, то после 15 минут ожидания, стоящие в очереди запросы будут прекращены с ошибкой. Это даст понять пользователям, что сервер не висит, а просто в рамках их пула все занято.
  9. Для пула читателей выставили время в 3 секунды, в течении которых запрос после запуска имеет наивысший приоритет по ресурсам. Это позволит быстро выполнять короткие запросы, освобождая место в пуле для других запросов

Теперь назначаем пользователям нужные пулы и дело сделано:
ALTER USER user_writer RESOURCE POOL writers;
ALTER USER user_reader RESOURCE POOL readers;
ALTER USER user_analytical RESOURCE POOL slowly RUNTIMECAP '1 HOUR' TEMPSPACECAP '10G';

Здесь мы дополнительно, помимо пула, пользователю «user_analytical» ограничили для запросов время выполнения одним часом и разрешили использовать не более 10 гб пространства в TEMP.

Хочу заметить, что все вышеописанное в статье является действием «куда копать», а не примером «что настроить». Сколько и каких будет ресурсных пулов, с какими характеристиками — это все должны решить Вы сами. Можно начать с малого — создать по примеру подобные 3 пула и дальше смотреть по нагрузкам кластера, постепенно балансируя параметры пулов и выделяя группы пользователей по разным пулам. Главное помнить, что:

  1. Пул General является общим кладезем памяти для всех пулов и лучше его не использовать напрямую для работы пользовательских сессий
  2. Чем меньше конкурентов, тем меньше скорость проседания железа в пиковых нагрузках
  3. Сумма максимально разрешенной памяти всех пулов не должна перекрывать память General

Комментарии (0)

    Let's block ads! (Why?)

    Комментариев нет:

    Отправить комментарий