Деревья
Вместе с метаданными, OpenTSDB 2.0 вводит понятие деревьев, иерархического метода организации временных рядов в легко навигационную структуру, которую можно просматривать, как файловую систему на компьютере. Пользователи могут определить несколько деревьев с различными наборами правил, которые организуют объекты TSMeta в структуру дерева. Затем пользователи могут просматривать полученное дерево через конечную точку HTTP API. Подробности см. в /api/tree.
Терминология деревьев
- Ветвь - Каждая ветвь — это один узел дерева. Она содержит список дочерних ветвей и листьев, а также список родительских ветвей.
- Лист - Конец ветви и представляет собой уникальный временной ряд. Лист будет содержать значение TSUID, которое можно использовать для генерации запроса TSD. Ветвь может, и скорее всего будет, иметь несколько листьев.
- Корень - Корневая ветвь — начало дерева, и все ветви расходятся от этого корня. Ее глубина равна 0.
- Глубина - Каждый раз, когда ветвь добавляется к другой ветви, глубина увеличивается.
- Строгое соответствие - При включенном режиме, временной ряд должен соответствовать правилу на каждом уровне набора правил. Если один или несколько уровней не соответствуют, временной ряд не будет включен в дерево.
- Путь - Название и уровень каждой ветви над текущей ветвью в иерархии.
Ветвь
Каждый узел дерева записывается как объект ветвь. Каждая ветвь содержит информацию, такую как:
- Идентификатор ветви - Идентификатор ветви. Это шестнадцатеричное значение, описанное ниже.
- Отображаемое имя - Имя ветви, полученное из объекта TSMeta набором правил дерева.
- Глубина - Насколько глубоко в иерархии находится ветвь.
- Путь - Глубина и имя каждой родительской ветви (включает локальную ветвь).
- Ветви - Дочерние ветви на один уровень ниже этой ветви.
- Листья - Листья, принадлежащие этой ветви.
Навигация по дереву начинается с корневой ветви, которая всегда имеет идентификатор, соответствующий идентификатору дерева, к которому принадлежит ветвь. Корень должен иметь одну или несколько дочерних ветвей, которые можно использовать для навигации на один уровень вниз по дереву. Каждая дочерняя ветвь может использоваться для навигации к ее дочерним ветвям и так далее. Корень не имеет родительских ветвей и всегда имеет глубину 0. Если дерево только что было определено или включено, у него может еще не быть корневой ветви, а следовательно, и дочерних ветвей.
Каждая ветвь часто будет содержать список дочерних ветвей. Однако, если ветвь находится в конце пути, у нее может не быть дочерних ветвей, но она должна иметь список листьев.
Идентификаторы и пути ветвей
Идентификаторы ветвей — это шестнадцатеричные кодированные массивы байтов, похожие на TSUID, но с другим форматом. Идентификаторы ветвей всегда начинаются с идентификатора дерева, закодированного в 2 байта. У корневых ветвей идентификатор ветви равен идентификатору дерева. Таким образом, корень для дерева 1 будет иметь идентификатор ветви 0001.
У каждой дочерней ветви есть DisplayName значение, и хеш этого значения используется для генерации 32-битного целого идентификатора ветви. Функция хеширования — это функция хеширования Java java.lang.String. Затем 4 байта целочисленного значения кодируются в 8 шестнадцатеричных символов. Например, если у нас есть отображаемое имя sys для ветви, возвращаемый хеш будет 102093. TSD преобразует это значение в шестнадцатеричное 0001BECD.
Идентификатор ветви состоит из идентификатора дерева, конкатенированного с идентификатором каждой родительской ветви над текущей ветвью, конкатенированного с идентификатором текущей ветви. Таким образом, если наша дочерняя ветвь sys является дочерней ветвью корня, у нас будет идентификатор ветви 00010001BECD.
Допустим, есть ветвь с отображаемым именем cpu от дочерней ветви sys. cpu возвращает хеш 98728, который преобразуется в 000181A8 в шестнадцатеричном формате. Идентификатор этой дочерней ветви будет 00010001BECD000181A8.
Идентификаторы создаются таким образом в первую очередь из-за метода хранения ветвей и листьев, но также и как способ навигации назад по дереву от ветви где-либо в структуре дерева. Это может быть особенно полезно, если вам известна конечная ветвь пути и вы хотите переместиться назад на один или несколько уровней. К сожалению, глубокое дерево может создавать очень длинные идентификаторы ветвей, но хорошо спроектированное дерево не должно быть глубже 5–10 уровней. Большинство запросов URI должны поддерживать ветви до 100 уровней глубины, прежде чем будут достигнуты ограничения символов URI.
Листья
Уникальный временной ряд представлен как лист на дереве. Лист может появляться на любой ветви структуры, включая корень. Но они обычно появляются в конце серии ветвей в ветви, которая имеет один или несколько листьев, но не имеет дочерних ветвей. Каждый лист содержит TSUID для временного ряда, который будет использоваться в запросе, а также имя и значения метрики и тега. Он также содержит отображаемое имя, полученное из набора правил, но может не совпадать ни с одним из имен метрики, имен тегов или значений тегов.
В идеале временной ряд будет появляться только один раз в дереве. Но если объект TSMeta для временного ряда, ИЛИ UIDMeta для метрики или тега изменены, он может быть обработан второй раз, и будет добавлен второй лист. Это может происходить особенно в ситуациях, когда дерево имеет пользовательское правило для метрики, имени тега или значения тега, где TSMeta был обработан, а затем пользователь добавляет пользовательское поле, которое соответствует набору правил. В таких ситуациях рекомендуется включить строгое соответствие для дерева, чтобы временной ряд не отображался до тех пор, пока пользовательские данные не будут добавлены.
Правила
Каждое дерево динамически строится из набора правил, определенных пользователем. Набор правил должен содержать как минимум одно правило и обычно содержит больше одного. Каждый набор имеет несколько уровней, определяющих порядок обработки правил. Правила, расположенные на уровне 0, обрабатываются первыми, затем правила на уровне 1 и так далее, пока все правила не будут применены к данному временному ряду. Каждый уровень в наборе правил может иметь несколько правил для обработки ситуаций, когда метрики и теги могут не быть спланированы заранее или могут случайно попасть какие-то произвольные данные. Если на уровне хранятся несколько правил, будет применено первое правило, которое успешно соответствует, а остальные будут проигнорированы. Эти правила также упорядочены по полю order, так что правило с порядком 0 обрабатывается первым, затем правило с порядком 1 и так далее. В логах и при использовании тестовой конечной точки правилам обычно присваиваются идентификаторы в формате "[<treeId>:<level>:<order>:<type>]", например, "[1:0:1:0]" указывает правило для дерева 1, на уровне 0, порядке 1 типа METRIC.
Типы правил
Каждое правило действует на один компонент данных временного ряда. В настоящее время доступны следующие типы:
| Тип | ID | Описание |
|---|---|---|
| METRIC | 0 | Обрабатывает имя метрики, связанной с временным рядом |
| METRIC_CUSTOM | 1 | Ищет в списке пользовательских тегов метаданных метрики заданное дополнительное имя. При совпадении, обрабатывается значение, связанное с именем тега. |
| TAGK | 2 | Ищет в списке tagk заданное имя. При совпадении, обрабатывается значение tagv, связанное с именем тега. |
| TAGK_CUSTOM | 3 | Ищет в списке tagk заданное имя. При совпадении, ищет в списке пользовательских тегов метаданных tagk заданное дополнительное имя. При совпадении, обрабатывается значение, связанное с пользовательским именем. |
| TAGV_CUSTOM | 4 | Ищет в списке tagv заданное имя. При совпадении, ищет в списке пользовательских тегов метаданных tagv заданное дополнительное имя. При совпадении, обрабатывается значение, связанное с пользовательским именем. |
Настройка правил
Одно правило может обрабатывать регулярное выражение, разделитель или ничего. Если для правила определены регулярное выражение и разделитель, будет обработано только регулярное выражение, а разделитель будет проигнорирован.
Все изменения в правиле проверяются для подтверждения заполнения соответствующих полей, чтобы правило могло обрабатывать данные. Для каждого типа правила необходимо заполнить следующие поля:
| Тип | Поле | Пользовательское поле |
|---|---|---|
| Метрика | ||
| Метрика_Пользовательская | X | X |
| TagK | X | |
| TagK_Пользовательская | X | X |
| TagV_Пользовательская | X | X |
Форматирование отображения
Иногда данные, извлеченные из тега или метрики, могут быть не очень описательными. Например, приложение может выводить временной ряд с парой тегов, такой как «порт=80» или «порт=443». С помощью стандартного правила, которое соответствовало значению tagk «порт», у нас будут две ветви с именами «80» и «443». Непосвященному лицу может быть непонятно, что эти числа означают. Поэтому пользователи могут определить форматировщик на основе маркеров, который изменит отображение ветви, чтобы отобразить полезную информацию. Например, мы можем объявить форматировщик «{имя_тега}: {значение}», и ветви теперь будут отображаться как «порт: 80» и «порт: 443».
Маркеры чувствительны к регистру и должны появляться только один раз в форматировщике. Они также должны точно совпадать с теми, что указаны в таблице ниже:
| Маркер | Описание | Применимый тип правила |
|---|---|---|
| {ovalue} | Исходное значение, обработанное правилом. Например, если правило использует регулярное выражение для извлечения части значения, но вы не хотите извлеченное значение, вы можете использовать его здесь. | Все |
| {value} | Обработанное значение. Если правило имеет извлеченную группу регулярных выражений или значение было разделено разделителем, это представляет собой значение после обработки. | Все |
| {имя_тега} | Имя tagk или пользовательского тега, связанного со значением. | METRIC_CUSTOM, TAGK_CUSTOM, TAGV_CUSTOM, TAGK |
| {tsuid} | TSUID временного ряда | Все |
Правила регулярных выражений
В некоторых ситуациях вам может потребоваться извлечь только компонент метрики, тега или пользовательского значения для группировки. Например, если у вас есть компьютеры в нескольких центрах обработки данных с полными доменными именами, которые включают имя ЦОД, но не все метрики включают тег ЦОД, вы можете использовать регулярное выражение для извлечения ЦОД для группировки.
Параметр правила regex должен быть установлен с допустимым регулярным выражением, которое включает один или несколько операторов извлечения, т. е. скобки. Если регулярное выражение совпадает со значением, предоставленным, извлеченные данные будут использованы для построения ветви или листа. Если в регулярном выражении предоставлено более одного извлечения, вы можете использовать параметр regex_group_index для выбора извлекаемого значения. Индекс отсчитывается от 0 и по умолчанию равен 0, поэтому, если вы хотите выбрать вывод второго извлечения, вы должны установить этот индекс в 1. Если регулярное выражение не совпадает со значением или извлечение не возвращает допустимую строку, правило будет считаться несовпадающим.
Например, если у нас есть тег хоста с тегом web01.nyc.mysite.com, мы можем использовать регулярное выражение, подобное .*\.(.*)\..*\..*, чтобы извлечь часть "nyc" из полного доменного имени и сгруппировать все серверы в центре обработки данных "nyc" под ветвью "nyc".
Правила разделителей
Метрики ряда систем обычно являются строками с разделителем, например, точкой, для обозначения компонентов метрики. Например, "sys.cpu.0.user". Для построения полезного дерева вы можете использовать правило разделителя, которое будет разделять строку на основе последовательности символов и создавать ветвь или лист из каждого отдельного значения. Установка разделителя "." для предыдущего примера даст три ветви "sys", "cpu", "0" и один лист "user".
Порядок приоритета
Каждое правило может обрабатывать только регулярное выражение, разделитель или ни то ни другое. Если правило содержит как значение "regex", так и "separator" в соответствующих полях, только "regex" будет выполняться над временными рядами. "separator" будет проигнорирован. Если ни "regex", ни "separator" не определены, то при совпадении правила с "field" все значение для этого поля будет обработано в ветвь или лист.
Построение дерева
Сначала необходимо создать таблицу tsdb-tree в HBase, если вы этого еще не сделали. Если вы включите обработку дерева, а таблица не существует, TSD не будут запускаться.
Дерево можно построить двумя способами. Настройка tsd.core.tree.enable_processing позволяет создавать дерево в реальном времени. Всякий раз, когда пользователь создает или редактирует новый объект TSMeta, объект TSMeta будет передан через каждое настроенное и включенное дерево. Результирующая ветвь будет записана в хранилище. Если произойдет конфликт или TSUID не совпадет с правилами, будет зарегистрировано предупреждение, и, если настроены параметры дерева, может быть записано в хранилище.
В качестве альтернативы вы можете периодически синхронизировать все объекты TSMeta через инструмент командной строки uid. Это позволит сканировать таблицу tsdb-uid и передавать каждый обнаруженный объект TSMeta через настроенные и включенные деревья. Подробности см. в uid.
Примечание
Для построения дерева в реальном времени необходимо также включить настройку tsd.core.meta.enable_tracking, чтобы объекты TSMeta создавались при получении временного ряда.
Общая процедура создания и построения дерева следующая:
- Создайте новое дерево через API HTTP
- Назначьте одно или несколько правил дереву через API HTTP
- Протестируйте правила с некоторыми объектами TSMeta через API HTTP
- После проверки правильности отображения ветвей установите флаг
enableдерева вtrue - Запустите инструмент
uidс подкомандойtreesyncдля синхронизации существующих объектов TSMeta в дереве
Примечание
При создании нового дерева оно по умолчанию будет отключено, поэтому объекты TSMeta не будут обрабатываться набором правил. Это даёт время для настройки набора правил и тестирования, чтобы убедиться, что дерево будет построено так, как вы ожидаете.
Порядок обработки правил
Дерево обычно имеет более одного правила, чтобы результирующее дерево было полезным. Как указано выше, правила организованы в уровни и порядки. Объект TSMeta обрабатывается набором правил, начиная с уровня 0 и порядка 0. Обработка происходит по правилам на уровне в порядке возрастания. После первого правила на уровне, успешно сопоставленного с данными TSMeta, обработка переходит к следующему уровню. Это означает, что правила на одном уровне фактически ``или``рованы. Если на уровне 0 есть правила с порядком 0, 1, 2 и 3, и TSMeta совпадает с правилом с порядком 1, правила с порядком 2 и 3 будут пропущены.
При редактировании правил может случиться, что некоторые уровни или порядки будут пропущены или оставлены пустыми. В этих ситуациях обработка просто пропускает пустые места. Вы должны сделать всё возможное, чтобы сохранить порядок, но процессор правил немного терпим.
Жесткое соответствие
Все объекты TSMeta обрабатываются через каждое дерево. Если вам нужно только одно, монолитное дерево для организации всех ваших временных рядов OpenTSDB, это не проблема. Но если вы хотите создать несколько деревьев для конкретных подмножеств информации, вы можете исключить некоторые записи временных рядов из создания листов. Флаг strictMatch дерева помогает отфильтровать временные ряды, которые относятся к одному дереву, но не к другому. При включённом жёстком соответствии временной ряд должен соответствовать правилу на каждом уровне (который содержит одно или несколько правил) в наборе правил, чтобы он был включен в дерево. Если метаданные не соответствуют ни одному из уровней с правилами, они будут записаны как несовпавшие, и лист не будет сгенерирован.
По умолчанию жёсткое соответствие отключено, чтобы можно было захватить как можно больше временных рядов в дереве. Если вы измените этот параметр в дереве, вам может потребоваться удалить существующие ветви и запустить повторную синхронизацию.
Коллизии
Из-за гибкости наборов правил и широкого разнообразия имён метрик, тегов и значений почти неизбежно, что две разные записи TSMeta будут пытаться создать один и тот же лист в дереве. Каждая ветвь может содержать только один лист с заданным отображаемым именем. Например, если ветвь содержит лист с именем user с TSUID 010101, но дерево пытается добавить новый лист с именем user с TSUID 020202, новый лист не будет добавлен в дерево. Вместо этого будет записана запись коллизии для дерева, указывающая, что TSUID 0202020 столкнулся с существующим листом для TSUID 010101. API HTTP можно использовать для запроса списка коллизий, чтобы проверить, не появился ли конкретный TSUID в дереве из-за коллизии.
Несовпадения
При включенном жестком соответствии для дерева TSMeta должен соответствовать правилу на каждом уровне набора правил, чтобы быть добавленным в дерево. Если одно или несколько уровней не совпадают, TSUID не будет добавлен. Подобно коллизиям, для каждого TSUID, который не был записан в дереве, будет записана запись о несоответствии. Запись будет содержать TSUID и краткое сообщение о том, какое правило и уровень не соответствовали.
Примеры
Предположим, что наш TSD хранит следующие временные ряды:
| TS# | Метрика | Теги | TSUID |
|---|---|---|---|
| 1 | cpu.system | dc=dal, host=web01.dal.mysite.com | 0102040101 |
| 2 | cpu.system | dc=dal, host=web02.dal.mysite.com | 0102040102 |
| 3 | cpu.system | dc=dal, host=web03.dal.mysite.com | 0102040103 |
| 4 | app.connections | host=web01.dal.mysite.com | 010101 |
| 5 | app.errors | host=web01.dal.mysite.com, owner=doe | 0101010306 |
| 6 | cpu.system | dc=lax, host=web01.lax.mysite.com | 0102050101 |
| 7 | cpu.system | dc=lax, host=web02.lax.mysite.com | 0102050102 |
| 8 | cpu.user | dc=dal, host=web01.dal.mysite.com | 0202040101 |
| 9 | cpu.user | dc=dal, host=web02.dal.mysite.com | 0202040102 |
Обратите внимание, что в этом примере мы не будем использовать правила пользовательских значений, поэтому нам не нужно показывать объекты TSMeta, но предположим, что эти значения заполняют TSMeta. Также TSUIDs усечены с 1 байтом на UID для иллюстративных целей.
Теперь давайте настроим дерево с отключенным strictMatching и следующими правилами:
| Уровень | Порядок | Тип правила | Поле (значение) | Регулярное выражение | Разделитель |
|---|---|---|---|---|---|
| 0 | 0 | TagK | dc | ||
| 0 | 1 | TagK | host | .*\.(.*)\.mysite\.com | |
| 1 | 0 | TagK | host | \\. | |
| 2 | 0 | Метрика | \\. |
Цель этого набора правил — упорядочить наши временные ряды по центрам обработки данных, затем по хостам, затем по метрикам. В нашей компании может быть тысячи серверов по всему миру, поэтому нет смысла отображать их все в одной ветви дерева, а нужно сгруппировать их по центрам обработки данных и позволить пользователям просматривать их по мере необходимости.
В наших примерах данных у нас были некоторые старые временные ряды, у которых не было тега dc. Однако тег host содержит полное доменное имя с именем центра обработки данных. Таким образом, первый уровень нашего набора правил содержит два правила. Первое будет искать тег dc, а если найдено, оно будет использовать значение этого тега, а второе правило пропустит. Если тег dc не существует, то второе правило будет сканировать значение тега host и попытаться извлечь имя центра обработки данных из полного доменного имени. Второй уровень имеет одно правило, и оно используется для группировки по значению тега host, чтобы все метрики, относящиеся к этому хосту, отображались в ветвях под ним. На последнем уровне есть правило метрики, которое включает разделитель для дальнейшей группировки временных рядов по содержанию. Поскольку у нас есть множество метрик CPU и приложений, все разделенные точкой, имеет смысл добавить разделитель на данном этапе.
Результат
Полученное дерево будет выглядеть следующим образом:
- dal
- web01.dal.mysite.com
- app
- connections (tsuid=010101)
- errors (tsuid=0101010306)
- cpu
- system (tsuid=0102040101)
- user (tsuid=0202040101)
- app
- web02.dal.mysite.com
- cpu
- system (tsuid=0102040102)
- user (tsuid=0202040102)
- cpu
- web03.dal.mysite.com
- cpu
- system (tsuid=0102040103)
- cpu
- web01.dal.mysite.com
- lax
- web01.lax.mysite.com
- cpu
- system (tsuid=0102050101)
- cpu
- web02.lax.mysite.com
- cpu
- system (tsuid=0102050102)
- cpu
- web01.lax.mysite.com
© 2010–2016 The OpenTSDB Authors
Licensed under the GNU LGPLv2.1+ and GPLv3+ licenses.
http://opentsdb.net/docs/build/html/user_guide/trees.html