В этой статье мы расскажем о том, какие компоненты используются для сбора, обработки и хранения метрик виртуальных машин, приведем примеры настройки использования этих компонентов в проекте VPC.
За получение метрик и их первичную обработку, отвечает компонент OpenStack Ceilometer.
На протяжении долгого времени он был единственным компонентом OpenStack предоставляющим все базовые возможности телеметрии.
В дальнейшем разработчики разделили функции Ceilometer между несколькими продуктами:
- Aodh — сервис оповещений;
- Gnocchi — сервис хранения агрегированных измерений;
- Panko — сервис хранения информации о событиях;
- Ceilometer — сервис сбора измерений.
Aodh и Panko останутся за рамками этой статьи.
Сбор измерений — OpenStack Ceilometer
Ceilometer может собирать измерения об использовании CPU, RAM, сетевых интерфейсов, дисков, значений температуры из различных источников:
- напрямую из гипервизоров (KVM, Hyper-V, XEN, VMware);
- из очереди сообщений (RabbitMQ, ZeroMQ, Kafka);
- посредством опроса других компонентов OpenStack через REST API;
- посредством опроса оборудования по протоколам SNMP или IPMI.
Ранее Ceilometer также предоставлял API для работы с собранными измерениями, метриками и ресурсами. Но начиная с релиза OpenStack Ocata соответствующая функциональность была убрана из этого компонента, так как основным бэкендом для Ceilometer стал Gnocchi, имеющий собственный полнофункциональный API для работы со всеми этими объектами.
Мы пробовали использовать Ceilometer из релиза OpenStack Juno несколько лет назад.
Наша первая версия биллинга для проекта VPC отправляла в него отчёты, где они были доступны и служебным программам и пользователям, авторизованным с помощью стандартного токена OpenStack Keystone.
Основными бэкендами для Ceilometer в те времена были SQL база данных и MongoDB. К сожалению, оба варианта после полугода использования переставали справляться с нагрузкой. Это происходило из-за того, что структура собираемых данных была слишком свободной, неиндексируемой и излишне подробной.
Каждое измерение хранилось в первоначальном виде, без каких либо агрегаций и изменений. На больших объемах данных простые операции выборки измерений за заданный временной период начинали выполняться очень долго и сервисом становилось невозможно пользоваться.
Для преодоления архитектурных проблем в 2014 году команда разработчиков сервисов телеметрии для OpenStack основала новый проект под названием Gnocchi. Подробное описание причин и выбранного способа решения можно прочитать в обзорной заметке в блоге основного разработчика Gnocchi – Жульена Данжу: OpenStack Ceilometer and the Gnocchi experiment.
Архитектура Ceilometer
Архитектура Ceilometer наглядно показана на схеме:
На каждом хосте, где установлен гипервизор, присутствует компонент Ceilometer Agent Compute, который собирает данные с виртуальных машин. Собранные данные в таком случае передаются центральному агенту Ceilometer Agent Notification через очередь сообщений.
Если нужно собирать данные о загрузке физических хостов, то на них можно установить и использовать SNMP-агент. В таком случае, сбор данных будет осуществляться центральным агентом Ceilometer Agent Central.
После обработки эти данные будут переданы агенту Ceilometer Agent Notification, который отправит их в выбранный бэкенд для хранения.
Ещё центральный агент Ceilometer Agent Notification может собирать информацию о событиях других компонентов OpenStack, прослушивая очередь сообщений. Это может быть полезно, если требуется отслеживать и сохранять информацию о создании, изменении или удалении серверов, дисков или портов.
До недавних пор (а более точно — до релиза OpenStack Ocata, который состоялся в феврале этого года) наряду с Ceilometer Agent Notification и Ceilometer Agent Central, на управляющие хосты требовалось устанавливать еще один компонент — Ceilometer Collector.
Сейчас этот компонент уже не используется. Все его функции выполняет Ceilometer Agent Notification.
Настройка Ceilometer
Основными конфигурационными файлами Ceilometer являются:
- ceilometer.conf — файл, описывающий все базовые параметры Ceilometer (логирование, использование очереди сообщений, аутентификация, координация процессов Ceilometer, и прочее);
- pipeline.yaml — файл, описывающий, какую информацию и откуда необходимо собирать;
- gnocchi_resources.yaml — описание соответствия объектов Ceilometer и Gnocchi (об этом мы поговорим позднее).
Шаблон файла ceilometer.conf со всеми доступными опциями можно скачать или сгенерировать, используя официальную документацию: Ceilometer Configuration Options.
Файл pipeline.yaml требуется заполнить самостоятельно.
Пример:
---
sources: #Источники данных
- interval: 600 # Интервал получения данных (секунды)
meters: # Список метрик
- memory.usage # Используемая память внутри виртуальной машины (МБ)
- memory.resident # Память, используемая виртуальной машиной на хосте (МБ)
name: memory_meters # Имя источника измерений
sinks: # Список получателей данных
- memory.sink # Имя получателя данных
- interval: 600 # Интервал получения данных (секунды)
meters: # Список метрик
- disk.device.read.bytes # Суммарное количество прочитанных байт на диске
- disk.device.write.bytes # Суммарное количество записанных байт на диске
name: disk_meters # Имя источника измерений
sinks: # Список потребителей измерений
- disk_sink # Имя потребителя измерений
sinks: # Потребители измерений
- name: memory_sink # Имя получателя данных (используется источником "memory_meters")
publishers: # Список бэкендов хранения, в которые будут записаны измерения
- gnocchi:// # Используется только бэкенд Gnocchi
- name: disk_sink # Имя получателя данных (используется источником "memory_meters")
publishers: # Список бэкендов для хранения измерений
- gnocchi:// # Используется только бэкенд Gnocchi (об этом речь пойдёт ниже)
В этом файле мы можем дополнительно указать трансформации для собираемых данных. К примеру, мы можем преобразовать все полученные значения метрик memory.usage и memory.resident из мегабайт в килобайты. Заодно переименуем эти метрики и добавим им единицы измерения.
Для этого нам потребуется отредактировать потребителя memory_sink таким образом:
sinks:
- name: memory_sink
transformers:
- name: "unit_conversion" # Используем встроенный метод unit_conversion
parameters:
source:
map_from:
name: "memory\\.(usage|resident)" # Что переименовать
target:
map_to:
name: "memory.\\1.kilobytes" # Как переименовать
scale: "volume * 1024.0" # Как преобразовать значения
unit: "KB" # Добавление единицы измерения
publishers:
- gnocchi://
Подробную информацию о формате данного файла и применении других преобразований можно узнать в официальной документации: Data processing and pipelines.
Далее мы рассмотрим проект Gnocchi, который позволяет хранить собираемые измерения в агрегированном виде и предоставляет API для работы с ними.
Хранение данных — Gnocchi
Проект Gnocchi представляет из себя базу данных временных рядов (time-series database).
Следует отметить, что, в начале мая 2017г., разработчики Gnocchi решили вывести этот проект из инфраструктуры OpenStack.
Кодовая база была перенесена в GitHub, а в качестве багтрекера используется механизм GitHub Issues. Одна из основных причин — желание позиционировать Gnocchi не только как бэкенд к Ceilometer, но как более универсальный продукт, подходящий под другие решения. К примеру, в репозитории Gnocchi уже сейчас имеется плагин для сохранения данных из Collectd и плагин для построения графиков в Grafana.
Рассмотрим устройство и особенности работы Gnocchi более подробно.
Архитектура Gnocchi
Gnocchi состоит из 2х основных компонентов:
- API, через который происходит сохранение и обновление данных (например от Ceilometer, или вручную), а также получение агрегированных данных;
- Metricd — демон, который обрабатывает только-что полученные и еще не отсортированные данные, и сохраняет их в нужном виде в выбранное хранилище (Ceph, Redis, OpenStack Swift или на локальную файловую систему).
Начиная с версии 3.1 в Gnocchi появилась поддержка разных типов хранилищ для обработанных и необработанных данных. Такое разделение позволяет размещать «горячие» неагрегированные данные на быстром хранилище (например, Redis, поддержка которого появилась в Gnocchi версии 4.0), а данные в агрегированном виде сохранять уже в более надежный, масштабируемый бэкенд (например, Ceph, поддержка которого была еще в самой первой версии Gnocchi).
Помимо непосредственного хранилища данных, для Gnocchi дополнительно требуется SQL-база данных, где хранятся индексы метрик и их метаданные. Для этого можно использовать MySQL или PostgreSQL. Gnocchi использует собственных подход к сохранению измерений, так как все перечисленные технологии не предоставляют возможность хранить данные в виде временных рядов.
Сохранение данных в Gnocchi
При получении новых данных значения не сохраняются в исходном виде. Вместо этого они агрегируются при помощи выбранных пользователем методами (в нашем примере — методами минимум, максимум, среднее) и сохраняются с указанной точностью (в нашем примере — 3600 секунд), в соответствии с созданной архивной политикой.
Мы можем создать архивную политику при помощи консольного клиента python-gnocchiclient. Для примера создадим политику с именем memory_policy, которая содержит 3 метода агрегации — минимум, максимум и среднее, и 2 определения того, как данные будут храниться. Первое определение говорит о том, что мы будем хранить данные с точностью 1 час на протяжении 7 дней. Второе говорит о том, что мы будем хранить данные с точностью 1 день на протяжении 1 года.
Помимо этого укажем значение back window равное 72, что позволит нам сохранять не только метрики, созданные сейчас, но и старые, по какой-то причине зависшие метрики, сроком не более 72 дней.
controller:~# gnocchi archive-policy create memory_policy > -b 72 > -m min -m max -m mean > -d 'granularity:1h,timespan:7d' > -d 'granularity:1d,timespan:365d'
В ответ мы получим описание созданной политики:
+---------------------+-------------------------------------------------------------------------+
| Field | Value |
+---------------------+-------------------------------------------------------------------------+
| aggregation_methods | max, min, mean |
| back_window | 72 |
| definition | - points: 168, granularity: 1:00:00, timespan: 7 days, 0:00:00 |
| | - points: 365, granularity: 1 day, 0:00:00, timespan: 365 days, 0:00:00 |
| name | memory_policy |
+---------------------+-------------------------------------------------------------------------+
Обратите внимание на то, что для определений также было автоматически рассчитано значение points. Эта величина считается по формуле:
Points = Timespan / Granularity
Она требуется для расчета места, которое будут занимать значения сохраняемых метрик.
Разработчики Gnocchi предлагают использовать следующую формулу для расчета требуемого места:
Size (in bytes) = 8 * points * aggregation methods
Указанная формула является расчетом места для худшего случая, так как информация всегда хранится в сжатом виде. Используя эту формулу, мы можем рассчитать объем места для архивной политики memory_policy. Для первого определения (точность 1 час в течение 7 дней) мы получаем 4032 байта:
4032 (байт) = 8 * 168 * 3
А для второго определения (точность 1 день на протяжении года) получаем 8760 байт:
8760 (байт) = 8 * 365 * 3
Полученные значения отображают используемое место для одной метрики, хранимой согласно политике memory_policy.
Если мы, к примеру, начнем собирать 2 метрики — memory.usage и memory.resident для 2000 виртуальных машин, то нам потребуется:
2000 * 2 * 4032 (байт) = 16.128 Мбайт (для 7 дней)
2000 * 2 * 8760 (байт) = 35.04 Мбайт (для 1 года)
Ресурсы Gnocchi
Все метрики, сохраняемые в Gnocchi, относятся к каким либо ресурсам. Ресурс — это абстрактный объект, который может содержать несколько метрик и также может иметь дополнительные поля, описанные в типе этого ресурса.
Взаимоотношение объектов метрика — ресурс — тип ресурса выглядит так:
К примеру, мы имеем набор ресурсов типа instance_memory. Каждый ресурс этого типа будет содержать метрики memory.usage и memory.resident.
Если мы собираем метрики с 2000 виртуальных машин, то число ресурсов instance_memory также будет равно 2000.
Для таких ресурсов может быть полезно сохранять дополнительную информацию, например, имя хоста гипервизора, на котором запущена виртуальная машина или идентификатор образа операционной системы (хранящегося в сервисе OpenStack Glance), из которого виртуальная машина была создана.
Создадим тип ресурса instance_memory при помощи консольной команды. Укажем описанные дополнительные поля host, image_ref, для хранения имени хоста и идентификатора образа, сделаем при этом поле host обязательным:
controller:~# gnocchi resource-type create instance_memory > -a host:string:true:min_length=0:max_length=255 > -a image_ref:string:false:min_length=0:max_length=255
В ответ мы получим описание созданного типа ресурса:
+----------------------+-----------------------------------------------------------+
| Field | Value |
+----------------------+-----------------------------------------------------------+
| attributes/host | max_length=255, min_length=0, required=True, type=string |
| attributes/image_ref | max_length=255, min_length=0, required=False, type=string |
| name | instance_memory |
| state | active |
+----------------------+-----------------------------------------------------------+
Аналогичным образом создадим типы ресурсов instance_cpu и instance_disk. Первый будет иметь такие же дополнительные поля, как и instance_memory, а второй будет иметь поле instance_id, указывающий идентификатор сервера, к которому подключен диск:
controller:~# gnocchi resource-type create instance_cpu > -a host:string:true:min_length=0:max_length=255 > -a image_ref:string:false:min_length=0:max_length=255
+----------------------+-----------------------------------------------------------+
| Field | Value |
+----------------------+-----------------------------------------------------------+
| attributes/host | max_length=255, min_length=0, required=True, type=string |
| attributes/image_ref | max_length=255, min_length=0, required=False, type=string |
| name | instance_cpu |
| state | active |
+----------------------+-----------------------------------------------------------+
controller:~# gnocchi resource-type create instance_disk > -a instance_id:uuid:true
+------------------------+--------------------------+
| Field | Value |
+------------------------+--------------------------+
| attributes/instance_id | required=True, type=uuid |
| name | instance_disk |
| state | active |
+------------------------+--------------------------+
Теперь разберемся, как нам начать сохранять метрики Ceilometer в Gnocchi, используя созданные типы ресурсов.
Конфигурация Ceilometer + Gnocchi
Для того, чтобы Ceilometer начал использовать Gnocchi в качестве бэкенда, требуется:
1. Добавить опцию meter_dispatchers в файл ceilometer.conf:
[DEFAULT]
meter_dispatchers = gnocchi
2. Создать файл gnocchi_resources.yaml, который описывает соответствия метрик Ceilometer и типов ресурсов Gnocchi, а также указывает дополнительные поля типов ресурсов:
---
resources:
- resource_type: instance_memory # Тип ресурса для выбранных метрик
metrics:
- 'memory.usage' # Метрика используемой памяти внутри виртуальной машины
- 'memory.resident' # Метрика используемой памяти виртуальной машиной на хосте
attributes:
host: resource_metadata.instance_host # Метаданные о хосте виртуальной машины
image_ref: resource_metadata.image_ref # Метаданные об образе виртуальной машины
- resource_type: instance_disk # Тип ресурса для выбранных метрик
metrics:
- 'disk.device.read.bytes' # Метрика суммарного количества прочитанных байт на диске
- 'disk.device.write.bytes' # Метрика суммарного количества записанных байт на диске
attributes:
instance_id: resource_metadata.instance_id # Метаданные с id виртуальной машины
- resource_type: instance_cpu # Тип ресурса для выбранной метрики
metrics:
- 'cpu_util' # Метрика утилизации процессора внутри виртуальной машины
attributes:
host: resource_metadata.instance_host # Метаданные о хосте виртуальной машины
image_ref: resource_metadata.image_ref # Метаданные об образе виртуальной машины
После запуска Ceilometer, начнется сбор данных и их отправка в Gnocchi (при условии что он был настроен согласно документации).
Вы можете следить за статусом обработки новых данных и сохранением их в агрегированном виде в выбранное хранилище при помощи команды:
controller:~# gnocchi status
+-----------------------------------------------------+-------+
| Field | Value |
+-----------------------------------------------------+-------+
| storage/number of metric having measures to process | 93 |
| storage/total number of measures to process | 93 |
+-----------------------------------------------------+-------+
В приведенном выводе можно увидеть, что сейчас процессы Gnocchi-metricd обрабатывают 93 измерения, распределенные по 93 метрикам.
При помощи этой команды можно следить, справляется ли компонент Gnocchi-metricd с поступающими метриками.
Скорость обработки будет напрямую зависеть от количества процессов Gnocchi-metricd и производительности выбранного хранилища данных.
Вывод агрегированной информации
После того, как полученные измерения будут обработаны и сохранены, можно будет получить доступ к ресурсам и измерениям Gnocchi.
Выведем ресурсы с типом instance_memory, ограничим вывод тремя ресурсами, и отобразим только 4 колонки — идентификатор самого ресурса его тип, имя хоста виртуальной машины и идентификатор ее образа:
controller:~# gnocchi resource list --type instance_memory --limit 3 --column id --column type --column host --column image_ref
+--------------------------------------+-----------------+-----------+--------------------------------------+
| id | type | host | image_ref |
+--------------------------------------+-----------------+-----------+--------------------------------------+
| 945ad3cc-2617-4b19-a681-5a1cb96d71e1 | instance_memory | compute00 | 3456e843-b7fe-42be-8c4c-0c7d1c2d09c7 |
| e33c895f-e38a-4f8e-be07-8fe0d7c8275f | instance_memory | compute02 | 27bbfeb7-0706-4d11-bb59-f98d6b08dc1c |
| 023fed66-3fdd-43b6-b02e-325da55b62cc | instance_memory | compute04 | f0f5e0aa-4615-462e-8340-b8258aae90e2 |
+--------------------------------------+-----------------+-----------+--------------------------------------+
Отобразим колонки с метриками и типом для ресурса 945ad3cc-2617-4b19-a681-5a1cb96d71e1:
controller:~# gnocchi resource show --column metrics --column type 945ad3cc-2617-4b19-a681-5a1cb96d71e1
+---------+-------------------------------------------------------+
| Field | Value |
+---------+-------------------------------------------------------+
| metrics | memory.resident: f56b76ad-5ce8-49fe-975f-6e5da412df31 |
| | memory.usage: aa757f46-52b9-40de-898c-524dfe29b7bc |
| type | sel_instance |
+---------+-------------------------------------------------------+
Посмотрим на средние значения для измерений метрики aa757f46-52b9-40de-898c-524dfe29b7bc, в интервале 12:00 — 18:00 для даты 25.08.2017, и точностью равной одному часу:
controller:~# gnocchi measures show --aggregation mean --granularity 3600 --start 2017-08-25T12:00 --stop 2017-08-25T18:00 aa757f46-52b9-40de-898c-524dfe29b7bc
+---------------------------+-------------+---------------+
| timestamp | granularity | value | |
+---------------------------+-------------+---------------+
| 2017-08-25T12:00:00+00:00 | 3600.0 | 2231.75 |
| 2017-08-25T13:00:00+00:00 | 3600.0 | 2238.66666667 |
| 2017-08-25T14:00:00+00:00 | 3600.0 | 2248.58333333 |
| 2017-08-25T15:00:00+00:00 | 3600.0 | 2259.08333333 |
| 2017-08-25T16:00:00+00:00 | 3600.0 | 2240.41666667 |
| 2017-08-25T17:00:00+00:00 | 3600.0 | 2249.66666667 |
+---------------------------+-------------+---------------+
Агрегированную информацию можно получать не только с помощью консольной утилиты, но и через REST API. Рассмотрим несколько примеров:
Получение значений метрики memory.usage для ресурса типа instance_memory, с точностью 24 часа, начиная с даты 28.08.2017:
controller:~# curl -XGET > -H 'Content-Type: application/json' > -H 'X-Auth-Token: KEYSTONE_TOKEN' > 'controller:8041/v1/resource/instance_memory/684f5b56-2c06-485a-ae1a-66ab5c4175fb/metric/memory.usage/measures?start=2017-08-28&granularity=86400' > | python -m json.tool
[
[
"2017-08-28T00:00:00+00:00",
86400.0,
2645.9444444444443
],
[
"2017-08-29T00:00:00+00:00",
86400.0,
2671.625
],
[
"2017-08-30T00:00:00+00:00",
86400.0,
2681.5438596491226
]
]
Поиск ресурса с типом instance_memory, созданного после 29.08.2017, со значением «compute19» в поле host:
controller:~# curl -XPOST > -H 'Content-Type: application/json' > -H 'X-Auth-Token: KEYSTONE_TOKEN' > 'controller:8041/v1/search/resource/instance_memory > -d '{
> "and": [
> {
> "=": {
> "host": "compute19"
> }
> },
> {
> ">": {
> "started_at": "2017-08-29"
> }
> }
> ]
> }' > | python -m json.tool
[
{
"created_by_project_id": "99288fd3d178459f808c1e8bc2cf9e49",
"created_by_user_id": "7dd0582d38aa471bbe8995f63a1293a9",
"creator": "7dd0582d38aa471bbe8995f63a1293a9:99288fd3d178459f808c1e8bc2cf9e49",
"ended_at": null,
"host": "compute19",
"id": "9052e237-ad17-47be-8aa5-10aacbf6717f",
"image_ref": "e12ef13d-783c-4030-9251-ad2c8e270453",
"metrics": {
"memory.resident": "365db8ce-f4f7-4e59-ac9f-03dcdfe81195",
"memory.usage": "084157b7-09d3-45e7-a869-fad62062025a"
},
"original_resource_id": "9052e237-ad17-47be-8aa5-10aacbf6717f",
"project_id": "99288fd3d178459f808c1e8bc2cf9e49",
"revision_end": null,
"revision_start": "2017-08-30T20:35:19.214598+00:00",
"started_at": "2017-08-30T20:35:19.214577+00:00",
"type": "instance_memory",
"user_id": "7dd0582d38aa471bbe8995f63a1293a9"
}
]
Получение агрегации по максимальным значениям метрик memory.resident с точность до одного часа для виртуальных машин, запущенных на хосте compute19; метрики систематизированы по идентификаторам проектов:
controller:~# curl -XPOST > -H 'Content-Type: application/json' > -H 'X-Auth-Token: KEYSTONE_TOKEN' > 'controller:8041/v1/aggregation/resource/instance_memory/metric/memory.resident&aggregation=max&granularity=3600&groupby=project_id' > -d '{
> "=": {
> "host": "compute19"
> }
> }' > | python -m json.tool
[
{
"group": {
"project_id": "eef577b17cfe4432b7769d0078dbb625"
},
"measures": [
[
"2017-08-29T09:00:00+00:00",
3600,
735
],
[
"2017-08-30T11:00:00+00:00",
3600,
949
]
]
},
{
"group": {
"project_id": "b998dbbb9b02474c9dc49ffc289eae8c"
},
"measures": [
[
"2017-08-29T09:00:00+00:00",
3600,
612
],
[
"2017-08-30T11:00:00+00:00",
3600,
642
]
]
}
]
Другие примеры использования REST API доступны в официальной документации.
Статистика в сервисе VPC
В настоящее время мы используем описанные компоненты в сервисе VPC.
Пользователям доступны следующие метрики для виртуальных машин:
- утилизация процессора, в % (cpu_util);
- использование оперативной памяти, в МБ (memory.usage).
Метрики для дисков:
- количество байт/c на чтение и запись (disk.device.read.bytes, disk.device.write.bytes);
- количество запросов на чтение и запись в секунду (disk.device.read.requests, disk.device.write.requests).
И метрики для сетевых интерфейсов:
- количество бит/c входящего и исходящего трафика (network.incoming.bits, network.outgoing.bits);
- количество пакетов входящего и исходящего трафика в секунду (network.incoming.packets, network.outgoing.packets).
Все данные можно получать как через REST API или консольный клиент Gnocchi, так и в виде встроенных графиков в панели управления серверами.
Графики использования процессора
Графики использования оперативной памяти
Графики нагрузки дисков
Графики нагрузки сетевых интерфейсов
Заключение
В этой статье мы рассмотрели два компонента для сбора, хранения и отображения статистики об объектах OpenStack.
Если у вас возникли вопросы, добро пожаловать в комментарии.
Если вам интересно было бы попробовать gnocchi в качестве сервиса, в который вы смогли бы писать собственные данные — напишите нам об этом.
Также будем рады, если вы поделитесь собственным опытом использования Ceilometer или Gnocchi.