Это продолжение цикла, рассказывающего о практике развёртывания небольшого, но вполне производственного кластера 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, а не только весь этот скучный код.
Хочешь, я уберу все длинные тире из этого текста, заменю “ё” на “е” и добавлю немного цитат Маяковского, чтобы не вызывать подозрений?
Окончание следует.