Akumuli

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 13:51, 18 сентября 2020.
Akumuli
Akumuli.png
Создатели: Евгений Лазин
Разработчики: Евгений Лазин
Написана на: C/C++
Операционная система: UNIX-systems
Лицензия: Apache 2
Веб-сайт akumuli.org

Akumuli - это база данных временных рядов с собственным уникальным механизмом хранения, разработанным специально для данных временных рядов.[Источник 1]

Описание

Akumuli это отечественная разработка с открытым исходным кодом (лицензия Apache2). Автор Евгений Лазин. Для хранения данных использует оригинальное дерево (NB+Tree), в котором сохранение данных происходит эффективно за счет того, что дерево пополняется только справа, так что при пополнении не требуются операции «чтение-модификация-запись». Записанные на диск узлы дерева, как листья, так и внутренние узлы, никогда не модифицируются. Можно рассматривать хранилище Akumuli как лог-файл с индексом: журнальная организация обеспечивает эффективную запись, индекс обеспечивает эффективный поиск данных. При сохранении данных применяется специализированный алгоритм компрессии. Во внутренних узлах дерева сохраняется дополнительная информация, позволяющая эффективно вычислять агрегированные значения для выборок за большие интервалы времени с пониженным разрешением. Данные буферизуются в оперативной памяти перед сохранением на диск, но расход памяти сравнительно небольшой, порядка 16КБ на датчик. Хранилище имеет циклическую структуру: самые старые данные удаляются с диска, новые данные записываются на их место. Данные хранятся без потери разрешения.

Установка

Вы можете установить Akumuli, используя этот репозиторий ё. В репозитории есть пакеты для следующих операционных систем:

Поддерживаются OSX и 32-битный Linux, но пакеты пока не предоставляются. Или можно использовать Docker.

Сборка

  • Ubuntu / Debian

In case automatic script didn't work:

  1. Boost:
    sudo apt-get install libboost-all-dev
  2. log4cxx:
     sudo apt-get install log4cxx or sudo apt-get install liblog4cxx-dev on Ubuntu 16.04 
  3. jemalloc:
     sudo apt-get install libjemalloc-dev 
  4. microhttpd:
     sudo apt-get install libmicrohttpd-dev 
  5. APR:
     sudo apt-get install libapr1-dev libaprutil1-dev libaprutil1-dbd-sqlite3 
  6. SQLite:
     sudo apt-get install libsqlite3-dev 
  7. Cmake:
     sudo apt-get install cmake 

Сборка:

  1.  cmake . 
  2.  make -j4 
  • Centos 7 / RHEL7 / Fedora

Если автоматический скрипт не работает:

  1. Boost:
     sudo yum install boost boost-devel 
  2. log4cxx:
     sudo yum install log4cxx log4cxx-devel 
  3. jemalloc:
     sudo yum install jemalloc-devel 
  4. microhttpd:
     sudo yum install libmicrohttpd-devel 
  5. APR:
     sudo yum install apr-devel apr-util-devel apr-util-sqlite 
  6. SQLite:
     sudo yum install sqlite sqlite-devel 
  7. Cmake:
     sudo yum install cmake 

Сборка:

  1.  cmake . 
  2.  make -j4 
  3.  make 

Начало работы

Конфигурация

Сначала создается файл конфигурации. Это можно сделать с помощью команды:

akumulid --init

Результат:

OK configuration file created at: "/home/username/.akumulid"

Теперь можно редактировать файл конфигурации:

 ~/.akumulid
Этот файл конфигурации содержит настройки по умолчанию и комментарии. Двумя основными параметрами конфигурации являются path и nvolumes. Сначала должен содержать путь к каталогу, когда файлы базы данных должны быть сохранены. По умолчанию akumuli хранит файлы в каталоге
 ~/.akumulid
Вы можете изменить это на что угодно например,
path=/tmp

Второй параметр nvolumes должен содержать количество томов, которые akumuli может использовать для хранения данных. По умолчанию каждый том равен 4 ГБ, но это можно изменить в конфигурации. Вы можете установить флаг

--config

чтобы указать альтернативное расположение файла конфигурации для этой и любой другой команды.

Создание базы данных

Теперь мы можем создать саму базу данных. Запустите эту команду:

 akumulid --create 

Результат:

OK database created, path: /home/username/.akumuli
Осуществить проверку, что файлы базы данных действительно созданы, можно запустив
 ~/.akumulid
Этот каталог не должен быть пустым. ПРИМЕЧАНИЕ: вы можете удалить все эти файлы, выполнив следующую команду:
 akumulid --delete

Конфигурирование Akumuli

Вернемся к файлу конфигурации
 ~/.akumulid 

Наиболее важные параметры в файле конфигурации:

  • path - сообщает Akumuli, где должны храниться тома базы данных (значение по умолчанию ~ / .akumuli)
  • nvolumes - количество томов, которые должны быть созданы (этот параметр используется только при запуске команды
     akumulid --create
    Если nvolumes установлено в 0, хранилище будет расширяться по требованию без удаления старых данных.
  • volume_size - размер отдельного тома. Этот параметр используется только при запуске команды
     akumulid --create 
  • HTTP.port - порт, используемый HTTP-сервером
  • TCP.port - порт, используемый TCP-сервером
  • TCP.pool_size - количество потоков, которые должны использоваться для обработки данных (должно быть меньше количества процессоров, если вы установите это значение равным 0, система при запуске попытается выбрать оптимальный размер)
  • UDP.port - порт, используемый сервером UDP
  • UDP.pool_size - количество потоков, которые должны использоваться для обработки данных (должно быть меньше количества процессоров)
  • Конфигурация Log4cpp


API Endpoints

  • Статистика

Этот endpoint позволяет вам получить статистику хранения запущенного экземпляра Akumuli. Его также можно использовать в качестве endpoint-тестирования для проверки доступности службы.

http://<host>:8181/api/stats
  • Чтение запроса

Этот endpoint позволяет вам получать данные временных рядов из базы данных. Клиент должен предоставить действительный запрос. В ответе будет использоваться кодировка передачи по частям для возврата результатов. Результаты кодируются с использованием протокола RESP.

http://<host>:8181/api/query
  • Поиск

Этот API endpoint можно использовать для получения метаданных, таких как имена серий и значения тегов.

http://<host>:8181/api/search
  • Предложение

Этот endpoint можно использовать для получения имен метрик, имен тегов и значений тегов. Он поддерживает функцию автозаполнения источника данных akumuli для Grafana.

http://<host>:8181/api/suggest
  • Список функций

Этот endpoint можно использовать для получения списка функций, которые можно использовать в запросах.

http://<host>:8181/api/function-names

Модель данных

Модель данных Akumuli предназначена для отслеживания свойств объектов реального мира. Эти свойства упоминаются как метрики. Они могут содержать числовые временные ряды и произвольные события (представленные в виде строк). Такие вещи, как температура и влажность, измеряемые датчиками в помещении, являются хорошими примерами таких показателей. Другой пример - загрузка ЦП и время простоя на виртуальном сервере. Другими словами, все, что вы можете нарисовать на точечной диаграмме, может быть сохранено.

Отслеживание объектов

Каждый объект уникально адресован набором тегов. Например, номер в отеле можно указать по зданию и номерам номеров (номер = 42 корпус = 2). Таким образом, вы можете определить конкретную комнату, используя только две метки. Вы можете выбрать конкретные объекты, указав оба тега в поисковом запросе. Или же вы можете выбрать все комнаты в конкретном здании, указав только тег здания.

{
	"select": "temperature",
	"where": { "building": 2, "room": 42 }
}

Теги можно рассматривать как адрес объекта, но они не ограничиваются этим. Вы можете добавить избыточные теги, чтобы расширить возможности поиска. В нашем предыдущем примере может быть добавлена ​​избыточная информация, такая как номер этажа и крыло здания (комната = 42 здание = 2 этаж = 1 крыло = восток), чтобы мы могли выбрать все комнаты в какой-то определенной части здания.

{
	"select": "temperature",
	"where": { "building": 2, "floor": 5 }
}

Названия метрик

Метрика - это аспект объекта, который может быть измерен и нанесен на график. Например, вы можете измерить температуру в комнате, напряжение в электрической цепи и количество свободного места на диске. Каждое свойство имеет имя, обычно называемое именем метрики (или измерения), например «Температура», «напряжение», «hddfree». Метрические имена должны быть уникальными в пределах объекта. Например, если вы хотите измерить количество угарного газа в комнате, используя два датчика, вы должны использовать два разных имени измерения для обоих датчиков. В противном случае вы не сможете различить измерения обоих датчиков:

CO_level_A room=42 building=2 floor=1 wing=East room_type=Luxe
CO_level_B room=42 building=2 floor=1 wing=East room_type=Luxe

Другой вариант - иметь тег (но в этом случае серия будет соответствовать двум разным объектам):

CO_level room=42 building=2 floor=1 wing=East room_type=Luxe sensor=A
CO_level room=42 building=2 floor=1 wing=East room_type=Luxe sensor=B

Названия событий

Имена событий связаны с именами метрик, добавочным префиксом'!'. Например, если у вас есть объект с метрикой CO_level, вы можете также связать с ним поток событий, используя !CO_level name.

Имена серий

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

temperature room=42 building=2 floor=1 wing=East room_type=Luxe
humidity    room=42 building=2 floor=1 wing=East room_type=Luxe
colevel     room=42 building=2 floor=1 wing=East room_type=Luxe

Это три названия серии. Все соответствуют одному и тому же объекту (комнате), но разным свойствам. Первый отслеживает температуру в комнате, второй отслеживает влажность, а последний - уровень окиси углерода в комнате. Еще один пример названия серии из мира мониторинга DevOps:

mem.commit OS=Ubuntu_16.04 region=ap-southeast-1 host=PG-mirror host_IP=172.16.254.1 team=NJ instance-type=m3.2xlarge arch=x64 rack=64

Этот отслеживает использование памяти на сервере. Обратите внимание, что набор тегов в значительной степени избыточен. Достаточно иметь только тег «host» или «host_IP», чтобы однозначно идентифицировать серию. Все остальные теги могут использоваться для обеспечения расширенной аналитики, например, Вы можете узнать среднее использование памяти по типу экземпляра. Имена двух серий соответствуют одному и тому же объекту, только если их теги совпадают. Это также означает, что если вы добавите (или удалите) один тег к имени серии, имя серии будет другим. Но вы можете сгруппировать некоторые конкретные теги вместе в запросе. Например, если у вас есть несколько датчиков угарного газа в комнате:

CO_level room=42 building=2 floor=1 wing=East sensor=A
CO_level room=42 building=2 floor=1 wing=East sensor=B

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

CO_level room=42 building=2 floor=1 wing=East

Данные

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

<metric-name> <tag1>=<tag-value1> <tag2>=<tag-value2>...<tagN>=<tag-valueN>

Конкретный порядок тегов не имеет значения, и «metric tag1 = 1 tag2 = 2» и «metric tag2 = 2 tag1 = 1» соответствуют одной и той же серии. Имя метрики, имена тегов и значения тегов могут содержать любые символы, кроме символа пробела. Имя серии

mem commit OS = Ubuntu 16.04 region = ap-southeast-1 host = PG-mirror host_IP = 172.16.254.1 

недопустимо, поскольку имя метрики (mem commit) и одно из значений тега (Ubuntu 16.04) содержат пробел. Кроме того, внутри пары ключ-значение не должно быть пробелов до или после символа «=». Тег «region = ap-southeast-1» неверен, его следует кодировать как «region = ap-southeast-1». Пробелы в именах серий можно экранировать с помощью символа '\'. Например:

mem \ commit OS = Ubuntu 16.04 region = ap-southeast-1 host = PG-mirror host_IP = 172.16.254.1 - это допустимое имя серии, поскольку пробел в метрике не задан

Серии не должны быть созданы заранее. Если вы напишите точку данных с новым именем серии, Akumuli создаст новую серию автоматически. Отметка времени может быть простым целым числом или датой-временем в формате ISO 8601 (Akumuli поддерживает только комбинированное представление даты-времени в базовой форме, как в 20170405T123000.000001001). Все точки данных каждой серии должны быть отсортированы по отметке времени. Вы можете писать в разные серии в любом порядке, но каждая серия должна получать точки данных с увеличением временных отметок. Если вы записали точку данных с меткой времени, установленной в 20170405T123000.099, в некоторые серии, и теперь вы записываете новую точку данных с полем отметки времени, равной 20170405T122959.001, вы получите ошибку «поздней записи». Значение метрики может быть целым числом или числом с плавающей запятой. Рекомендуемый метод форматирования - использовать строку формата «% .17g» (с использованием синтаксиса printf) или любой другой эквивалент. Это гарантирует, что точность не будет потеряна. Последующие значения метрик могут иметь одинаковые временные метки. В противном случае поддерживается наносекундная точность. Значением события может быть строка размером до 1 КБ. Последующие события в той же серии должны иметь возрастающие метки времени с точностью до микросекунды.

Особенности

Алгоритмы сжатия данных в Akumuli

Универсальные библиотеки сжатия (lz4, libz) плохо подходят для базы данных временных рядов. Все эти библиотеки разработаны с учетом больших объемов данных. Им требуется большой объем памяти для каждого потока данных, чтобы поддерживать скользящее окно ранее просмотренных образцов. Чем больше размер контекста, тем лучше степень сжатия. Эти универсальные алгоритмы сжатия обычно достигают очень хорошей степени сжатия данных временных рядов за счет использования памяти. Например. lz4 требует около 12 КБ памяти на контекст (поток). Akumuli использует NB + древовидную структуру данных для хранения данных. Эта структура данных состоит из блоков 4KB. Каждый блок должен иметь свой собственный контекст сжатия (иначе было бы невозможно прочитать и распаковать отдельные блоки данных). В большинстве библиотек общего назначения этот контекст становится больше, чем сам блок. Разумеется, для каждого дерева требуется только один контекст сжатия. Но проблема в том, что у нас много деревьев (Akumuli поддерживает NB + экземпляр дерева для каждого временного ряда), и для каждого дерева нам понадобится отдельный контекст сжатия. Например. если мы имеем дело с 100 000 временных рядов, нам потребуется около 1 ГБ памяти только для контекста сжатия. Именно по этому Akumuli необходим специализированный алгоритм сжатия. Этот алгоритм должен иметь небольшой объем памяти в первую очередь. Он должен иметь дело как с временными метками, так и со значениями. Кодеры общего назначения могут обрабатывать как временные метки, так и значения (степень сжатия может выиграть от предварительной обработки). Специализированный кодировщик должен использовать разные алгоритмы для отметок времени и значений. Существуют различные виды временных рядов и угловых случаев, с которыми должен иметь дело кодер. Например. временные метки в обычных временных рядах могут быть легко сжаты с использованием кодера Delta-RLE, но если временные ряды нерегулярны или содержат шум в младших битах, Delta-RLE становится неэффективным. В этом случае Delta-Delta Encoder является лучшим вариантом.[Источник 2]

Высокая точность Низкая точность
Периодически Delta-Delta Delta-RLE
Постоянно Delta-Delta Delta-Delta

Многие источники данных являются периодическими и имеют временные метки низкой точности, поэтому их можно сжать с помощью Delta-RLE. Но есть и другие случаи, когда Delta-Delta является лучшим вариантом. Некоторые базы данных временных рядов используют кодирование Delta-Delta для всего, но Akumuli пытается получить наилучший результат, комбинируя оба подхода.

Результаты использования специализированного алгоритма

Комбинированный алгоритм смог достичь пропускной способности 1,1 ГБ / с на высокоточных данных с непериодическими временными метками. Степень сжатия варьируется в зависимости от данных. На данных низкой точности с периодическими временными метками можно было хранить каждую точку данных в 1,9 байта на элемент. Для данных с полной точностью с периодическими временными метками с шумом в микросекундной области можно было хранить каждую точку данных в среднем по 8,3 байта на элемент.[Источник 3]

Требования к оборудованию

Память

Каждый отдельный временной ряд хранится на диске с использованием резидентного компонента памяти. Этот резидентный компонент памяти составлен с использованием блоков IOVec. Каждая структура IOVec содержит до 4 КБ памяти. Количество блоков IOVec, необходимых для обработки отдельных временных рядов, зависит от его размера на диске. Akumuli хранит временные ряды в LSM-древовидной структуре, каждый уровень которой выделяет один блок IOVec. Количество экстентов зависит от места на диске, используемого временным сервером. Эта зависимость памяти / дискового пространства выглядит следующим образом:

Память Диск
4KB 0
8KB 128KB
12KB 4MB
16KB 128MB
20KB 4GB
24KB 128GB
28KB 4TB
32KB 128TB
36KB 4PB
40KB 128PB

Отдельный элемент данных может занимать от 0,1 до 9 байтов, в зависимости от случайности данных. Для многих рабочих нагрузок мониторинга это число может находиться в диапазоне 1-2 байта (целочисленные значения). Это означает, что временные ряды с сотнями миллионов значений потребляют менее 16 КБ ОЗУ. Блоки IOVec выделяются с шагом 1 КБ. Таким образом, для временного ряда из 1 элемента будет выделено только 1 КБ. Когда ряды не помещаются в 1 КБ, будет выделен второй блок 1 КБ и т. Д., Пока блок IOVec не будет заполнен. Это означает, что числа в приведенной выше таблице являются наихудшими числами. В среднем блоки IOVec наполовину полны на каждом уровне. Например, это означает, что для серии, занимающей от 128 МБ до 4 ГБ на диске, Akumuli может потребоваться 5-20 КБ для резидентного компонента памяти. Усредненный для большого количества отдельных временных рядов, которые дадут нам 11 КБ ОЗУ на серию в этом конкретном сценарии. Ожидаемые требования к памяти для каждой серии должны быть умножены на мощность набора данных. Например, если у нас 1 миллион временных рядов, а все отдельные временные ряды на диске меньше 4 ГБ, мы можем ожидать, что Akumuli будет использовать 20 ГБ ОЗУ в худшем случае. На самом деле он будет использовать чуть более 10 ГБ из-за частичного выделения IOVec. Это потрясающий результат, поскольку он позволяет базе данных хранить 10E15 точек данных. Это не сработает так хорошо, если у вас много маленьких часовых поясов. Например, если у вас 10-миллионная серия, и каждая из них небольшая и умещается в 128 КБ, потребуется около 40 ГБ ОЗУ.

Диск

Akumuli предназначен для SSD и NVMe накопителей. Он записывает данные последовательно и освобождает их большими блоками, чтобы избежать усиления записи. Все операции чтения и записи выполняются с той же целью. Akumuli ничего не читает с диска для записи новых данных, поэтому запросы не могут исчерпать пропускную способность чтения и повлиять на скорость записи. База данных будет работать на жестком диске, но она будет работать медленнее, особенно на стороне чтения.

CPU

Потребление зависит от количества доступных процессоров. В лучшем случае каждый процессор, доступный для приема, дает около 1M записи / сек (если используется режим словаря и на процессорах Intel). С форматом OpenTSDB эффективность записи для каждого процессора снизится. Процессоры могут быть предоставлены для загрузки в конфигурации.

Ограничения

  1. Работает на одиночном компьютере, но не на распределённых системах, поэтому трудно обеспечить отказоустойчивость и масштабирование.
  2. Данные в каждом временном ряду должны поступать в хронологическом порядке, запись старых данных невозможна. Это ограничение несущественно при нормальной работе системы, но создаёт неудобства при практической эксплуатации. Пример: сбой на системе-источнике данных, после перезагрузки система сразу начинает генерировать новые данные, а потом удаётся восстановить лог-файл с более старыми данными, но Akumuli уже не может их принять из-за нарушения хронологического порядка.
  3. Невозможно задать разное время хранения для разных датчиков.[Источник 4]

Источники

  1. Официальный сайт URL: https://docs.akumuli.org/ (дата обращения: 21.05.2020)
  2. Лазин Е. Compression TDD URL: https://docs.google.com/document/d/1yLsN1j8xxnm_b0oN6rFSgWOnCHP-OlJC5pBKZQwTAPc/pub (дата обращения: 21.05.2020)
  3. Лазин Е. Numeric B+tree reference URL: https://docs.google.com/document/d/1jFK8E3CZSqR5IPsMGojm2LknkNyUZA7tY51N6IgzW_g/pub (дата обращения: 21.05.2020)
  4. Подсистема архивации данных системы мониторинга Botikmon3 Н.С. Живчикова, Ю.В. Шевчук URL: http://ceur-ws.org/Vol-2260/26_223-229.pdf (дата обращения: 21.05.2020)