В последнее время наблюдается большой интерес к альтернативным решениям для баз данных, после первого поколения баз данных NoSQL несколько лет назад. При создании нашего продукта для мониторинга реальных пользователей Raygun Pulse мы изначально обратились к PostgreSQL из-за его богатого набора встроенных аналитических функций в дополнение к полной мощности СУБД и SQL (объединения и все такое). Однако теперь, когда мы сбились с пути, несмотря на то, что мы выбрали мультитенантность, Postgres не масштабировался для относительно сложных запросов, которые нам нужны для бизнес-логики в Raygun Pulse. Увидев подобные истории от других, в том числе от тех, кто инвестировал в другие технологии, такие как экосистема Hadoop или хранилища ключей и значений, мы начали исследовать другие, более специализированные аналитические базы данных. Druid оказался тем, на котором мы остановились, поскольку он предлагает несколько хороших свойств, которые нужны в базе данных аналитики.

Введение в Druid для аналитики

Во-первых, он заявляет, что запросы OLAP выполняются менее чем за секунду, прием потоковой передачи в реальном времени и возможность масштабирования до диапазона петабайт. Я действительно могу поручиться за первые два. Он делает это, отбрасывая полные специальные запросы и соединения, которые предлагает SQL, и вместо этого перемещает группировку и сводки во время приема, требуя, чтобы желаемые строковые измерения / числовые столбцы метрик были указаны заранее с тем, какие «агрегаторы» вам нужны во время запроса. . В обмен на это Druid затем предоставляет запросы типа «нарезка и нарезка», которые возвращаются через ~ 1 с, группируя столько измерений, сколько требуется пользователю, и выбирая любые метрики, которые они хотят, с выбранными агрегаторами. Таким образом, он идеально подходит для исследовательской аналитики наборов данных с течением времени и, что более важно, устраняет несколько узких мест, которые появляются, когда вам нужно масштабироваться за пределы одной машины. Он использует ZooKeeper для работы в качестве распределенной базы данных, чтобы обеспечить большие размеры кластеров (известно, что они могут работать до многих тысяч ядер).

Основными запросами, которые Друид обнаружил за последние несколько лет, были запросы временных рядов, то есть одна или несколько метрик, построенных во времени, сгруппированных по некоторому интервалу, и TopN, который представляет собой одно измерение, например, «страна», упорядоченное по одному метрика, например «время загрузки» или «количество просмотров». Это обеспечивает гарантированную точность для первых 900 по убыванию, что является распространенным вариантом использования. «N» можно настроить выше, но после этой точки он начинает давать неточные результаты.

Druid также предлагает расширенный запрос для этого варианта использования — GroupBy. GroupBy поддерживает группировку по произвольным параметрам и упорядочение по любому количеству показателей в любом порядке. Как и следовало ожидать, это эквивалент GROUP BY в SQL. Он также имеет дополнительные вложенные внутренние GroupBys и предложение HAVING для фильтрации результатов после их группировки, что делает его гораздо более гибким. Компромисс заключается в том, что до сих пор было максимальное (необработанное) количество строк, которое он может учитывать, и запросы могут привести к сбою или вызвать OOM.

Новый Druid Group на движке V2

К счастью, вышла новая версия Друида v0.9.2. Он содержит полностью переписанный движок GroupBy, который снимает вышеуказанные ограничения и обещает значительное ускорение по сравнению с GroupBy V1. Недостаток версии 1 заключается в том, что это реализация в куче, и у нее нет тех же гарантий долей секунды, которые были у основных типов запросов TopN и запросов Timeseries. Хотя он обеспечивает более богатую модель запросов, чем обычный TopN, он также быстрее деградирует, поэтому его реально можно использовать только для внутренней автономной аналитики.

Новая логика движка Druid GroupBy V2 устраняет эти ограничения благодаря новой реализации вне кучи. Это обеспечивает производительность, аналогичную запросам GroupBy, которыми пользуются TopN/Timeseries, позволяя также использовать GroupBy для пользовательской исследовательской аналитики (стиль OLAP). Это означает, что запросы многомерной группировки теперь могут выполняться с помощью Druid в производственной среде для приложений, ориентированных на пользователя, на масштабируемых наборах данных (известно, что Druid работает на кластерах со 100+ ПБ данных) с интерактивным временем отклика на запрос. Это должно выходить за рамки размеров данных, времени отклика, горизонтальной масштабируемости и опыта разработчиков, которые могут предоставить текущие системы Hadoop/Cassandra/NoSQL или более традиционные системы СУБД, и в то же время отображать модель запросов, которая столь же богата новой логикой группирования.

По умолчанию Druid будет продолжать использовать предыдущую реализацию V1, но ожидается, что V2 будет переключен на стандартную реализацию в будущем выпуске. В следующем разделе я рассмотрю, что требуется для существующих установок Druid для использования нового движка с запросами GroupBy. Чтобы использовать это сейчас, необходимо внести пару изменений в конфигурацию, а также установить новую опцию для объекта context для каждого запроса GroupBy. В конце поста я расскажу о нашем опыте работы с Druid и о том, на что следует обратить внимание при создании собственного кластера Druid.

Использование движка Druid GroupBy V2

Во-первых, стоит обратиться к документации по движку GroupBy V2. Как говорится, чтобы использовать его, вам нужно установить новое свойство в конфигурации вашего сервиса Druid, druid.processing.numMergeBuffers, которое должно быть установлено на положительное целое число. Это относится, по крайней мере, к историческим узлам, узлам-брокерам и мидл-менеджерам, поэтому вы можете установить его в common.runtime.config (хотя мидл-менеджерам требуется меньше оперативной памяти). При этом будут выделены буферы памяти фиксированного размера для обработки числа группировок, и это число будет умножено на druid.processing.buffer.sizeBytes, поэтому вам потребуется столько оперативной памяти, доступной в процессе JVM (устанавливается в jvm.config для предыдущих служб). Общий расчет:

druid.processing.buffer.sizeBytes * (druid.processing.numMergeBuffers + druid.processing.numThreads + 1)

Результат этого должен быть меньше или равен -XX:MaxDirectMemorySize в вашем файле jvm.config для вышеуказанных сервисов. Если оперативной памяти недостаточно, процесс не запустится (он выведет рассматриваемые числа на стандартный вывод). Вы также увидите буферы, выделяемые во время запуска. Вы можете начать тестирование, установив для этого параметра значение 1 и увеличив его примерно до 10+ (в зависимости от того, сколько у вас оперативной памяти и как часто вы будете выполнять эти запросы).

Второй шаг — включить движок V2 в запросах, установив его в объекте контекста:

"контекст": {

"groupByStrategy": "v2"

}

Когда указанное выше установлено для запроса "queryType": "groupBy", он будет использовать новый движок — вот и все! Вы также можете установить это как значение по умолчанию для всех запросов GroupBy, установив druid.query.groupBy.defaultStrategy на «v2», без необходимости устанавливать контекст запроса.

Есть еще одно важное свойство: maxOnDiskStorage. Это можно установить либо в контексте, либо в конфигах. Это свойство определяет, что произойдет, если в буфере слияния закончится память во время запроса. По умолчанию установлено значение 0, что означает, что большие запросы не будут выполняться, если недостаточно памяти. Если для него задано положительное целое число, будет разрешено переполнение диска, однако твердотельные накопители все еще слишком медленные, и гарантии интерактивной аналитики Druid могут быть действительно выполнены только тогда, когда все сегменты и вычисления выполняются в памяти. Вы увидите большое линейное замедление, если на этапе слияния GroupBy потребуется большой объем доступа к диску, поэтому, если возможно, maxOnDiskStorage следует оставить равным 0, а numMergeBuffers и/или processing.buffer.sizeBytes увеличить до тех пор, пока не будут выполняться запросы с верхним пределом временного диапазона как требуется вашими пользователями/бизнес-логикой.

Предостережения и ускорения

После включения вышеуказанного вы должны заметить, что запросы GroupBy можно использовать. Как отмечается в документах, запросы TopN по-прежнему предпочтительнее и имеют преимущество в производительности, и их следует использовать, если они могут удовлетворить ваши бизнес-требования. Однако, если они не могут, V2 GroupBys теперь являются опцией, особенно если вы можете поместить их в память. Если нет, вам может понадобиться более крупный кластер с большей доступной памятью, ограничение количества агрегаций/пост-агрегаций, используемых в запросах GroupBy, или ограничение рассматриваемого интервала времени.

Ключевым моментом, на который следует обратить внимание применительно к различным запросам, является то, что они имеют тенденцию ухудшаться линейно в зависимости от некоторого фактора. Например, TopN и Timeseries эффективны и в основном будут колебаться вокруг отметки доли секунды в секунду при использовании длинных/двойных агрегаций и постагрегаций. При использовании более экзотических агрегаций, таких как аппроксимированная гистограмма или из расширения DataSketch, линейная деградация может продолжаться до многих секунд, в зависимости от размера сегмента, количества, доступной памяти и необходимости обращения узлов к диску. Это будет очень специфично для конкретной настройки кластера и данных, поэтому бенчмаркинг и настройка в производственной среде являются ключевым требованием для запуска производительного кластера Druid.

Однако в целом мы видели заявленное ускорение в 2-5 раз с движком GroupBy V2 по сравнению с V1 — в сторону нижнего предела для некоторых особенно тяжелых запросов. К счастью, большинство из них удалось преобразовать в запросы TopN, что показало дополнительное ускорение и соответствовало нашим требованиям к интерактивности в реальном времени.

Другие особенности 0.9.2

Полные примечания к выпуску 0.9.2 доступны здесь. Примечательны следующие:

  • Доступны новые агрегаторы статистики для расчета дисперсии и стандартного отклонения. Это находится в расширении ядра druid-stats, и хорошая документация для них доступна здесь. Расчет дисперсии/станд. dev доступен во время загрузки для числовых столбцов и является реализацией Apache Hive. Это особенно приятная функция, поскольку она дополняет агрегаторы медианы/квантиля, доступные в расширениях Approximate Histogram/Datasketch.
  • Ускорение для DataSketch на 80% и для HyperUniques на 20–30% — приятные победы для запросов анализа удержания и всех важных запросов кардинальности соответственно.
  • Возможность фильтрации по длинным метрикам, например требуемая метрика time (столбец), внутри запросов. Измерения уже имеют богатую фильтрацию времени запроса для случая использования удаления большого количества строк, основанного на значении измерения для каждой строки. Теперь это распространяется на метрики, которые раньше нельзя было фильтровать. В будущем это должно быть доступно для метрик двойного типа, позволяя запрашивать подмножество значений.
  • Возможность отключить сведение — я не особо вникал в это, но, по-видимому, это решает случай использования, когда входные строки не будут агрегироваться, а вместо этого будет генерироваться одна выходная строка для каждой при запросе. Это доступно как флаг на granularitySpec.

Советы по производительности для запуска и оптимизации кластера Druid

Как упоминалось выше, наличие достаточного объема памяти на вычислительных узлах (тех, на которых запущены Historicals/Realtimes/Brokers) и достаточно большой кластер для отображения в памяти всех запрашиваемых сегментов имеют решающее значение для получения производительности запросов менее секунды. Это часть текущего дизайна Druid, так как в первые дни это была исключительно база данных в памяти, а теперь память отображает сегменты, в которых хранятся данные. По сути, это позволяет масштабироваться за пределы физической памяти, доступной в кластере, в случае, когда требования к данным велики. С другой стороны, если набор данных может разместиться в памяти всех доступных ящиков в кластере, он будет вести себя как база данных в памяти и иметь высокую производительность.

Таким образом, Druid предлагает настраиваемые ручки для выбора того, сколько данных вы хотите или можете иметь в памяти, в зависимости от ваших объемов данных и требований. Основная ручка для настройки — druid.server.maxSize, она задокументирована в документации по исторической конфигурации и в Часто задаваемых вопросах по производительности. Этот параметр на самом деле очень важен для обеспечения хорошей производительности при запросе данных в ваших исторических узлах. Главное — установить значение меньше, чем максимальный объем физической памяти, доступной на сервере. Если установлено значение больше доступной памяти, будет назначено больше сегментов, чем может поместиться в памяти, и исторический узел попытается загрузить их с диска, что приведет к большому объему подкачки и очень медленному возврату ваших запросов, например 10- 30+.

Расчет для druid.server.maxSize должен учитывать ресурсы, доступные JVM для службы History, и равен total memory - (heap size + direct memory + JVM overhead). Используя пример конфигурации производственного кластера, который использует r3.8xlarges для исторических узлов, размер кучи должен быть установлен равным 8 г, прямая память должна быть установлена ​​в соответствии с расчетом в разделе Использование Движок GroupBy V2, указанный выше, и небольшая сумма для JVM. Оставшаяся физическая память — это объем, оставшийся для сегментов, и вам понадобится столько памяти, доступной во всех ваших исторических полях для всех сегментов, которые вы хотите сделать доступными для запросов (как показано размером кластера в консоли координатора).

О проекте Друид

Druid был задуман и создан компанией Metamarkets, которая использует его для аналитики в сфере рекламных технологий. Сам проект имеет открытый исходный код под лицензией Apache и продолжает получать частые выпуски и исправления. Как и многие растущие проекты баз данных с открытым исходным кодом, он вызывает большой интерес, и в настоящее время проект занимается масштабированием слияния PR для исправлений и новых функций, черпая вдохновение из существующих успешных моделей управления проектами ОС. Они также не возражают брать заведомо хорошие реализации логики и алгоритмов из других проектов ОС, повышая качество кода. Я считаю, что ядро ​​является надежным, и его стоит изучить, если вам нужно аналитическое решение, которое будет горизонтально масштабироваться до достаточно больших рабочих нагрузок приема, хранения и запросов, предлагая при этом настраиваемые гарантии производительности и разумные затраты при работе на облачных виртуальных машинах. Сравнения с альтернативными решениями БД на посадочной странице, на мой взгляд, достаточно точны и дают хороший обзор того, что может предоставить Друид.

Компромиссы и подводные камни, на которые следует обратить внимание

Как и все базы данных, она не идеальна, и приходится идти на компромиссы. Несмотря на то, что достаточно легко запустить игрушечную машину с одним набором данных из Википедии, процедура запуска производственного кластера не является тривиальной (по сравнению с чем-то вроде ElasticSearch, например), а настройка загрузки и запросов может потребовать куска времени, пока не выяснишь, где ручки. В зависимости от сложности вашей модели вы также можете потратить некоторое время на настройку спецификации приема. В частности, прием данных выигрывает от наличия конвейера предварительной обработки, поскольку вам может потребоваться объединить или обогатить поток данных другими источниками. Наличие инфраструктуры очередей сообщений или некоторых фреймворков, доступных в экосистеме Hadoop, упрощает эту задачу. Настройка конфигураций памяти JVM и конфигураций времени выполнения также может быть немного неясной, пока вы не поймете, какие данные и нагрузки запросов, а также компромиссы, которые вы хотите сделать в отношении имеющегося у вас оборудования и того, сколько денег вы хотите потратить.

Инструменты (консоли) и API, доступные для управления кластером/сегментами, хороши, однако работа с конфигурацией и развертыванием требует немного ручного труда и может потребовать дополнительных инструментов, созданных для упрощения вашего рабочего процесса. В релизе .tar.gz не так много предписано, и вам нужно будет добавить свои конфигурации, а также любые необходимые расширения. Это связано с тем, что развертывание может масштабироваться автоматически, например, с помощью AWS, но я бы не советовал настраивать это сразу. К счастью, документация Druid превосходна и довольно понятна (по сравнению с документацией ElasticSearch, хотя я давно не углублялся в нее). Вам нужно будет прочитать и понять значительную их часть, но информация доступна, дополненная Группами друидов Google. Конфигурация производственного кластера также может быть излишней для ваших потребностей в приеме и запросе — определенно поэкспериментируйте здесь с оборудованием.

В проекте продолжается куча интересных работ, в том числе слой запросов SQL, который может увеличить внедрение. Я не возражаю против API запросов JSON в его нынешнем виде — он довольно хорошо продуман и логичен, но также есть куча клиентских библиотек для разных языков.

Дай Друиду шанс

Подводя итог, если вы занимаетесь аналитикой и вы новичок в Druid, взгляните на него — ознакомьтесь с Быстрым стартом, пакетно проглотив образец набора данных Википедии. Если у вас есть запущенный и работающий кластер, обновите свой кластер и посмотрите, работают ли для вас новые запросы ядра Druid GroupBy V2, так как ожидание может значительно ускориться.

Спасибо за чтение!

Узнайте основную причину ошибок и сбоев в ваших программных приложениях за считанные секунды с помощью Raygun Crash Reporting. Попробуйте бесплатно в течение 30 дней здесь.