Это продолжение цикла, рассказывающего о практике развёртывания небольшого, но вполне производственного кластера Cassandra. В первой, второй и третьей частях мы продвинулись вперед вот по такому плану:
Анализ рабочей нагрузки и требований
Разработка схемы данных
Настройка хостовых машин
Настройка конфигурации Cassandra
Настройка топологии кластера
= ВЫ НАХОДИТЕСЬ ЗДЕСЬ =Подключение Prometheus Cassandra Exporter
Подключение Prometheus Node Exporter
Вывод всех метрик в Grafana
Проведение нагрузочного тестирования
Дополнительный тюнинг по результатам теста
В этой части мы интегрируем сразу два экспортера метрик: Первый нативный, снимающий показатели непосредственно с Cassandra, и второй для мониторинга состояния хостовых машин нод. Поскольку Cassandra — это история про highload, то мониторинг состояния серверов нод можно считать обязательным.
После этого материала у нас должны появиться два дашборда Grafana для обоих экспортеров. Традиционно забегая вперед скажу, что во время нагрузочного теста постоянно переключаться между парой вкладок браузера с дашбордами Cassandra и Node Monitor мне порядком надоело, поэтому я завёл 3 наиболее показательные метрики из Node Exporter’a (а именно: CPU Usage, Disk I/O Throughput, Disk I/O Utilization) непосредственно в дашборд Cassandra. Это оказалось очень удобно для мониторинга и вы можете поступить так же.
6. Подключение Prometheus Cassandra Exporter
При выборе этого экспортера появляются следующие муки выбора варианты:
Нативный экспортер именно для Cassandra
JVM Exporter, Grafana-дашборд которого “допиливается” до состояния, так сказать, “Cassandra Ready”
С первым всё понятно, а вот зачем может понадобиться второй вариант? А потому что именно он показывает подробности работы Garbage Collector’а JVM, что может очень пригодиться для тонкого тюнинга производительности Cassandra. Соответствующие настройки мы как раз обсуждали во 2-й статье цикла в разделе “Сборщик мусора”.
Идея тонкого тюнинга производственных деплоев мне очень близка, но есть нюанс: Небольшой рисёрч в каталоге дашбордов Grafana показал, что убить двух зайцев одним выстрелом не получится и нужно выбирать. Вариант с допиливанием подходящего JVM дашборда до состояния “Cassandra Ready” выглядел настолько трудоёмким, что я вздохнул и решил, что мне не очень-то и нужны графики с миллисекундами Garbage Collector по цене кропотливой недельной работы.
Замечу, что сделанный выбор оправдан только для текущего кейса, и в вашем случае (например, с кластером на петабайт+ данных) анализ метрик сборщика мусора JVM может иметь решающее значение для тюнинга производительности.
Короче говоря, я выбрал Bitnami Cassandra Exporter как наиболее обновляемый и поддерживаемый.
Правим настройки Cassandra Exporter
Вначале нам нужно забрать из выбранного образа исходный файл конфигурации экспортера, чтобы внести нужные правки. Например, так:
docker pull bitnamilegacy/cassandra-exporter:2-debian-11
docker run -d --name cassandra-exporter bitnami/cassandra-exporter:2-debian-11
docker cp cassandra-exporter:/opt/bitnami/cassandra-exporter/config.yml cassandra-exporter-config.yml
В этом небольшом конфиге потребуется поправить буквально несколько строк в самом начале файла. Должно получиться:
# deploy/templates/cassandra-exporter-config.yml
host: 127.0.0.1:7199
ssl: False
user:
password:
listenPort: 9103
...
Прочие строки оставьте как есть. Конфиг не использует подстановку Ansible-значений, поэтому здесь расширение файла yml
(вместо j2
).
Опции для экспортера
Подготовьте этот файл в указанном расположении:
# deploy/templates/jvm.options
# JMX options for Cassandra Exporter
-Dcom.sun.management.jmxremote.port=7199
-Dcom.sun.management.jmxremote.rmi.port=7199
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false
Есть большой соблазн (которому я и поддался вначале) вместо еще одного отдельного конфига просто добавить нужные переменные среды в docker-compose.j2
внутрь секции services.cassandra.environment
, но не делайте так!
Потому что переменные среды будут применяться ко всем компонентам Cassandra, включая утилиту nodetool
, которой такая оптимизация не понравится. Поэтому фабрики рабочим, земля крестьянам конфиг — экспортеру, окружение — Кассандре!
А доступы?
Проверьте, что ваш Prometheus доступен по нужному порту с каждой ноды. Здесь пример для случая с iptables
— проделайте то же самое по аналогии с тем firewall, который фактически используется на хост-машинах всех нод:
sudo iptables -A INPUT -p tcp -s --dport 9103 -j ACCEPT
sudo iptables -L -n | grep 9103
# Сохраним конфиг iptables, чтобы правки применялись при перезагрузке
sudo netfilter-persistent save
sudo cat /etc/iptables/rules.v4 | grep 9103
Обновляем docker-compose
Теперь добавим контейнер Cassandra Exporter в docker-compose.j2
и смонтируем пару только что подготовленных конфигов (показаны только вновь добавляемые строки):
# deploy/templates/docker-compose.j2
services:
cassandra:
volumes:
- ./jvm.options:/etc/cassandra/jvm.options
cassandra-exporter:
image: bitnamilegacy/cassandra-exporter:2-debian-11
container_name: cassandra-exporter
restart: unless-stopped
network_mode: "host"
volumes:
- ./cassandra-exporter-config.yml:/opt/bitnami/cassandra-exporter/config.yml
depends_on:
- cassandra
Можно сразу добавить Node Exporter, чтобы затем развернуть всё вместе.
7. Подключение Prometheus Node Exporter
К счастью, экспортер метрик с хост-машины Linux не требует таких мук выбора, как предыдущий.
Всё что нужно сделать — это смонтировать информацию о процессах, ядре, системе, устройствах, драйверах, а также всю корневую файловую систему хоста внутрь контейнера в режиме “только для чтения", чтобы Алиса экспортер мог получать эти данные и потом передавать куда следует.
Регулярка исключает из мониторинга служебные точки монтирования Docker и его внутренние /sys
, /proc
, /dev
и прочие, чтобы не засорять метрики ненужными данными.
Давайте добавим всё это в docker-compose.j2
(показаны добавляемые строки):
# deploy/templates/docker-compose.j2
services:
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: node-exporter
restart: unless-stopped
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)'
ports:
- "9100:9100"
pid: "host"
Удобнее всего сначала настроить оба экспортера на какой-то одной выбранной ноде. Поскольку все нужные конфиги уже смонтированы на хост-машину, то в процессе отладки просто правим их “на лету” и перезапускаем ноду, чтобы изменения применились.
Если же ваш кластер под нагрузкой, то эксперименты только на одной ноде за раз — вообще единственный верный вариант. У вас же выставлен RF>1 для всех важных keyspaces, да? Да? (популярный_мем.jpg)
Если мы всё сделали правильно, то метрики на ноде уже должны появиться:
curl -s http://localhost:9103/metrics 2>/dev/null | head -n 10
curl -s http://localhost:9103/metrics | wc -l
Разворачиваем на весь кластер
Давайте обновим наш Ansible-плейбук:
# deploy/main.yml
- name: deploy
hosts: all
tasks:
# ...
- name: Copy all needed templates
template:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
owner: '{{ item.owner | default("root") }}'
group: '{{ item.group | default("root") }}'
mode: '{{ item.mode | default("0644") }}'
loop:
- {src: 'templates/docker-compose.j2',
dest: '{{ ansible_env.HOME }}/cassandra/docker-compose.yml',
owner: 'root',
group: 'root',
mode: '0644'}
- {src: 'templates/cassandra.j2',
dest: '{{ ansible_env.HOME }}/cassandra/cassandra.yaml',
owner: 'cassandra',
group: 'cassandra',
mode: '0644'}
- {src: 'templates/jvm11-server.options.j2',
dest: '{{ ansible_env.HOME }}/cassandra/jvm11-server.options',
owner: 'cassandra',
group: 'cassandra',
mode: '0644'}
- {src: 'templates/cassandra-rackdc.properties.j2',
dest: '{{ ansible_env.HOME }}/cassandra/cassandra-rackdc.properties',
owner: 'cassandra',
group: 'cassandra',
mode: '0644'}
- {src: 'templates/jvm.options',
dest: '{{ ansible_env.HOME }}/cassandra/jvm.options',
owner: 'cassandra',
group: 'cassandra',
mode: '0600'}
- {src: 'templates/cassandra-exporter-config.yml',
dest: '{{ ansible_env.HOME }}/cassandra/cassandra-exporter-config.yml',
owner: 'root',
group: 'root',
mode: '0644'}
become: true
- name: Create and start services
docker_compose:
project_src: '{{ ansible_env.HOME }}/cassandra'
Здесь еще появился файл cassandra-rackdc.properties.j2
с топологией кластера, который я неосмотрительно позабыл в прошлой статье цикла.
8. Вывод всех метрик в Grafana
Пожалуй, можно уже добавить в scrape configs существующего Prometheus вот такую секцию для Cassandra Exporter:
# prometheus.yml
scrape_configs:
...
- job_name: "cassandra"
static_configs:
- targets: ["192.168.0.1:9103"]
labels:
instance: cassandra1
environment: production
service: cassandra
datacenter: NIRS
rack: rack1
- targets: ["192.168.0.2:9103"]
labels:
instance: cassandra2
environment: production
service: cassandra
datacenter: NIRS
rack: rack1
- targets: ["192.168.32.3:9103"]
labels:
instance: cassandra3
environment: production
service: cassandra
datacenter: NIRS
rack: rack2
- targets: ["192.168.32.4:9103"]
labels:
instance: cassandra4
environment: production
service: cassandra
datacenter: NIRS
rack: rack2
- targets: ["192.168.64.0:9103"]
labels:
instance: cassandra5
environment: production
service: cassandra
datacenter: NIRS
rack: rack2
И похожую секцию для Node Exporter туда же:
scrape_configs:
...
- job_name: "cassandra_hosts"
static_configs:
- targets: ["192.168.0.1:9100"]
labels:
instance: cassandra1 # Same instance label as the Cassandra section
environment: production
service: cassandra-host
datacenter: NIRS
rack: rack1
- targets: ["192.168.0.2:9100"]
labels:
instance: cassandra2
environment: production
service: cassandra-host
datacenter: NIRS
rack: rack1
- targets: ["192.168.32.3:9100"]
labels:
instance: cassandra3
environment: production
service: cassandra-host
datacenter: NIRS
rack: rack2
- targets: ["192.168.32.4:9100"]
labels:
instance: cassandra4
environment: production
service: cassandra-host
datacenter: NIRS
rack: rack2
- targets: ["192.168.64.0:9100"]
labels:
instance: cassandra5
environment: production
service: cassandra-host
datacenter: NIRS
rack: rack2
Инстансы в метках есть смысл сделать одинаковыми в обеих секциях.
IP-адреса в примере взяты из предыдущей статьи, где мы настраивали топологию кластера, чтобы, так сказать, сохранить преемственность. А вот датацентр мы уже успели поменять, поскольку предыдущий сгорел. Новый ДЦ будет понадёжнее, как-никак.
Теперь добавьте в Grafana пару новых панелей из этих шаблонов ниже и настройте источники данных:
Дашборд для Cassandra Exporter
Дашборд для Node Exporter
Подводим итог
Кластер в целом настроен и работает, а Grafana рисует графики с плоскими линиями, демонстрирующими, что ничего не происходит. Но мы уже на финишной прямой и скоро это исправим: в нагрузочном тесте всё пойдет куда интереснее, графики порадуют пиками в самых неожиданных местах, а кластер весело упадёт! В заключительной статье цикла наконец-то появятся интересные картинки из Playboy, а не только весь этот скучный код.
Хочешь, я уберу все длинные тире из этого текста, заменю “ё” на “е” и добавлю немного цитат Маяковского, чтобы не вызывать подозрений?
Окончание следует.