Почему свободного места в мониторинге недостаточно
Хранилище на 50 ТБ с 40 млн изображений может неделю отдавать картинки за 8 мс, а потом за 200 мс при том же объёме данных и 30% свободного места. Причина в очереди на одном узле, разросшемся индексе метаданных или SSD, который начал перевыделять сектора. График занятости диска в такой ситуации выглядит ровным, и дежурный узнаёт о проблеме от пользователей.
Хранилище изображений отличается от обычной файловой шары тремя свойствами. Миллионы мелких объектов, миниатюры по 20-150 КБ и оригиналы по 1-5 МБ, поэтому нагрузка ложится на метаданные и количество операций, а не на объём. Высокая чувствительность к задержке чтения: изображение участвует в отрисовке страницы, и лишние 100 мс видны в метриках фронтенда. Деградация накопителя проявляется постепенно, через рост latency и ошибок, задолго до полного отказа.
Прямой ответ на вопрос «что мониторить»: latency отдачи и записи (p50, p95, p99 отдельно для GET и PUT), throughput в МБ/с, IOPS и средний размер блока, заполнение в байтах и в inode, ошибки бэкенда (5xx, таймауты, ошибки целостности), состояние дисков через SMART, трафик репликации и ребалансировки. К этому набору добавляются алерты с продуманными порогами и регламентные работы: scrub, балансировка, обновление версий.
Экономика проста. Если p95 отдачи выросло с 120 до 180 мс, страница каталога с 30 изображениями добавляет почти 2 секунды к загрузке. При SLA p95 меньше 200 мс запас остаётся небольшим, и следующий пик трафика выводит сервис за границу. Подробный разбор метрик накопителей, SMART-атрибутов и состояния пулов собран в материале про мониторинг систем хранения: ключевые метрики и инструменты для администратора.
Отдельный источник нагрузки, о котором часто забывают: генерация изображений. Если хранилище наполняется не только загрузками пользователей, но и работой моделей, доступ к ним удобно держать через единый шлюз, например через агрегатор API AiTunnel, а на стороне хранилища измерять всплески записи и рост числа объектов по префиксам.
Ключевые метрики системы хранения изображений и их интерпретация
Latency, throughput и IOPS: как связаны и на что влияют
Latency это время от одной операции. Throughput это объём данных за секунду. IOPS это число операций за секунду. Связь между ними задаёт закон Литтла: при фиксированной глубине очереди рост IOPS упирается в потолок, и дальше растёт только задержка. Хранилище, которое держит 10 000 IOPS при latency 10 мс, после роста нагрузки до 15 000 IOPS отдаёт уже 50 мс, потому что очередь выросла, а не потому что диски стали медленнее.
Для изображений важно разделять операции чтения и записи. PUT миниатюры размером 40 КБ и GET оригинала на 4 МБ нагружают разные подсистемы. Мелкие объекты упираются в IOPS и метаданные, крупные в пропускную способность сети и диска. Средний размер блока в iostat или node_exporter показывает, какая из двух проблем у вас: 4-8 КБ означает давление на IOPS, 128 КБ и выше означает давление на полосу.
Смотрите на перцентили, а не на среднее. Среднее по выборке из миллионов запросов скрывает хвост, а именно хвост портит пользовательский опыт. p50 показывает типичный запрос, p95 ловит деградацию под нагрузкой, p99 вскрывает редкие, но дорогие случаи: попадание в холодный кэш, чтение с ремонтируемого OSD, ожидание блокировки метаданных.
| Метрика | Что показывает | Ориентир для картинок | Порог алерта |
|---|---|---|---|
| Latency p95 | Отдача объекта под обычной нагрузкой | менее 200 мс | более 300 мс в течение 10 минут |
| Latency p99 | Хвост запросов, холодный кэш | менее 500 мс | более 500 мс в течение 10 минут |
| Throughput | Пропускная способность чтения и записи | 60-70% от полки канала | устойчиво выше 90% |
| IOPS | Число операций, нагрузка на метаданные | до 70% от измеренного максимума | устойчиво выше 85% |
| Заполнение | Занятое место и inode | до 80% | warning 85%, critical 90% |
| Ошибки S3 API | 5xx, отказы, таймауты | менее 0,1% запросов | рост на 10% за 5 минут |
Нормы зависят от железа. На NVMe-пулах реальны p99 в 20-30 мс, на SATA-массивах с шардированием те же 200 мс уже хороший результат. Снимайте baseline на своём стенде под целевой нагрузкой и сравнивайте текущие значения с ним, а не с чужой таблицей.
Заполнение дисков и ошибки бэкенда: пороги и тренды
Порог 80% удобен как точка внимания для локальных ФС и объектных шлюзов. В Ceph граница жёстче: при заполнении пула выше 70-75% кластер начинает ребалансировать размещение, растёт recovery-трафик, и latency чтения картинок подскакивает вместе с ним. Поэтому для Ceph имеет смысл ставить warning на 70%, critical на 80%, и держать отдельный алерт на полный nearfull кластера.
Inode не менее важны, чем байты. Каталог с десятками миллионов миниатюр в одной директории съедает inode быстрее, чем место, а ext4 по умолчанию создаёт один inode примерно на 16 КБ, что для мелких изображений даёт неожиданно жёсткий лимит. Проверяйте node_filesystem_files_free наравне с node_filesystem_avail_bytes, а раскладку объектов по префиксам проектируйте заранее: хеш от ключа или дата в первых символах пути разгружает метаданные и ускоряет листинг.
Ошибки бэкенда делятся на три группы. Транспортные: таймауты, обрывы соединений, недоступность узла. Прикладные: 5xx от S3 API, отказ записи из-за нехватки места. Ошибки целостности: несовпадение контрольных сумм, повреждённые объекты, ошибки чтения с диска. Третья группа самая опасная, потому что не влияет на доступность, но означает потерю данных. В ZFS это ошибки checksum в zpool status, в Ceph ошибки deep scrub и значение ceph_health_status выше OK.
Тренд полезнее текущего значения. Функция predict_linear в Prometheus по шестичасовому окну показывает, когда закончится место: predict_linear(node_filesystem_avail_bytes[6h], 7*24*3600) меньше нуля означает заполнение за неделю при текущем темпе. Такой алерт даёт время договориться о закупке дисков или почистить старые производные изображения, а не разбираться с инцидентом в три часа ночи.
Настройка Prometheus и Grafana для MinIO, Ceph и TrueNAS
Схема одна для всех трёх систем: экспортер отдаёт метрики по HTTP, Prometheus собирает их по расписанию, Grafana рисует дашборды, Alertmanager рассылает уведомления. Разница в источнике данных. MinIO отдаёт метрики сам, Ceph публикует их через mgr-модуль, TrueNAS требует поставить node_exporter и smartctl_exporter в jail или на сам хост. Конфигурации ниже проверялись на Prometheus 3.x, Grafana 11.x, node_exporter 1.8, smartctl_exporter 0.13, MinIO RELEASE.2025, Ceph 19.2 Squid и TrueNAS SCALE 25.04. Перед переносом в продакшен сверьте имена метрик и флаги с версией, которая стоит у вас.
Если стек мониторинга удобнее держать вне своего железа,Prometheus с Grafana и Alertmanager поднимаются на облачных серверах или в managed Kubernetes, например в Timeweb Cloud. Тогда хранилище остаётся на месте, а сбор и хранение метрик живут отдельно и переживают падение площадки.
MinIO: экспортер, scrape-конфиг и дашборд
Встроенный endpoint включается одной командой: mc admin prometheus generate myminio выдаёт JWT и готовый блок scrape-конфига. Метрики кластера доступны по пути /minio/v2/metrics/cluster, метрики узла по /minio/v2/metrics/node, бакета по /minio/v2/metrics/bucket. Токен лучше положить в файл, а не в командную строку Prometheus.
scrape_configs:
- job_name: minio-cluster
metrics_path: /minio/v2/metrics/cluster
scheme: http
bearer_token_file: /etc/prometheus/minio-token
static_configs:
- targets: ['minio-1:9000', 'minio-2:9000', 'minio-3:9000']
- job_name: minio-bucket
metrics_path: /minio/v2/metrics/bucket
bearer_token_file: /etc/prometheus/minio-token
static_configs:
- targets: ['minio-1:9000']
Ключевые метрики для дашборда: minio_cluster_capacity_usable_free_bytes и minio_cluster_usage_total_bytes для заполнения, minio_bucket_usage_total_bytes для разбивки по бакетам, minio_s3_requests_total и minio_s3_errors_total для нагрузки и ошибок, minio_node_disk_used_bytes и minio_node_disk_free_bytes для состояния дисков, minio_cluster_nodes_offline_total для доступности узлов. Гистограмма времени до первого байта minio_s3_requests_ttfb_seconds_distribution даёт перцентили latency через histogram_quantile.
Готовый дашборд MinIO Dashboard импортируется по ID 13502, для детального разбора дисков подойдёт Node Exporter Full с ID 1860. Обе панели требуют правки под свои job-имена.
Ceph: мониторинг кластера через Prometheus
Модуль prometheus входит в состав Ceph и включается командой ceph mgr module enable prometheus. По умолчанию он слушает порт 9283 и отдаёт метрики на /metrics, дополнительно можно поднять на всех mgr-узлах. Альтернатива для старых кластеров, ceph_exporter от DigitalOcean, требует доступа к сокету и отдельного сервиса.
scrape_configs:
- job_name: ceph
metrics_path: /metrics
static_configs:
- targets: ['ceph-mgr-1:9283', 'ceph-mgr-2:9283']
relabel_configs:
- source_labels: [__address__]
regex: '([^:]+):(\d+)'
target_label: instance
replacement: '$1'
Смотрите на ceph_health_status (0 означает HEALTH_OK), ceph_osd_up для упавших OSD, ceph_pool_used_bytes и ceph_pool_max_avail для заполнения пулов, ceph_pool_percent_used для порогов nearfull, ceph_osd_apply_latency_ms и ceph_osd_commit_latency_ms для задержек операций, ceph_pg_degraded и ceph_pg_undersized для состояния размещения, ceph_cluster_total_recovering_bytes_per_sec для трафика восстановления. Рост recovery-трафика объясняет всплеск latency без внешней нагрузки, и это нормальное поведение, а не инцидент.
Дашборд Ceph Cluster импортируется по ID 2842. Расширенный набор панелей для кластерной инфраструктуры, включая Ceph и Pacemaker, разобран в статье про мониторинг кластеров серверов с Prometheus и Grafana.
TrueNAS: мониторинг дисков и ZFS через node_exporter и smartctl_exporter
TrueNAS SCALE не отдаёт метрики ZFS и SMART из коробки в формате Prometheus. Практичный путь: создать jail или виртуальную машину, поставить туда node_exporter с включённым коллектором zfs и smartctl_exporter, дать им доступ к /dev и к команде smartctl, а затем добавить job в Prometheus.
scrape_configs:
- job_name: truenas-node
static_configs:
- targets: ['truenas:9100']
- job_name: truenas-smart
static_configs:
- targets: ['truenas:9633']
Полезные метрики: node_zfs_zpool_state (значение 0 для ONLINE), node_zfs_zpool_used_bytes и node_zfs_zpool_free_bytes, node_disk_io_time_seconds_total и node_disk_read_bytes_total для нагрузки на диски, node_filesystem_avail_bytes и node_filesystem_files_free для места и inode. От smartctl_exporter нужны smartctl_device_smart_status, smartctl_device_attribute_raw_value с attribute_id 5 и 197 (перевыделенные и ожидающие сектора), smartctl_device_temperature. Показатель температуры дисков выше 50 градусов в стойке с плохой продувкой объясняет скачки latency лучше, чем очередь запросов.
Для TrueNAS удобны общий дашборд Node Exporter Full (ID 1860) и дашборды SMART-атрибутов (например, Smartctl Exporter, ID 19841), дополненные самодельной панелью по состоянию пулов.
Алерты на деградацию дисков и критическое заполнение
Алерт полезен, если по нему есть действие. Уведомление «диск заполнен» в момент, когда запись уже упала, бесполезно, а правило «заполнение выше 85% в течение 10 минут» даёт часы на реакцию. Для каждого правила фиксируйте порог, длительность (for), уровень важности и текст с указанием узла и метрики. Группировку и маршрутизацию держите в Alertmanager, а сами условия в Prometheus.
Правила алертов для деградации дисков
Основу дают SMART-правила и проверка состояния кластера. Дополнительно полезно ловить не только смену статуса, но и медленное накопление дефектов, потому что диск с растущим числом перевыделенных секторов продолжает работать месяцами и деградирует по скорости.
groups:
- name: storage-images-disks
rules:
- alert: SmartStatusFailed
expr: smartctl_device_smart_status != 1
for: 5m
labels:
severity: critical
team: storage
annotations:
summary: "SMART-статус диска не PASSED"
description: "{{ $labels.instance }} диск {{ $labels.device }}"
- alert: SmartReallocatedGrowing
expr: increase(smartctl_device_attribute_raw_value{attribute_id="5"}[24h]) > 0
for: 10m
labels:
severity: warning
annotations:
summary: "Растёт число перевыделенных секторов"
- alert: CephOsdDown
expr: ceph_osd_up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "OSD {{ $labels.ceph_daemon }} недоступен"
- alert: CephOsdApplyLatencyHigh
expr: ceph_osd_apply_latency_ms > 100
for: 10m
labels:
severity: warning
annotations:
summary: "Задержка применения операций на OSD выше 100 мс"
Для RAID-массивов на TrueNAS и Linux отдельно следите за состоянием через метрики mdstat или node_md_disks: деградация зеркала до одного диска означает нулевой запас по отказоустойчивости. Порог ceph_osd_apply_latency_ms в 100 мс исторически считается признаком проблемного OSD, но на NVMe-кластерах его стоит опустить до 10-20 мс, ориентируясь на свой baseline.
Алерты на критическое заполнение и ошибки бэкенда
Правила заполнения делайте двухуровневыми, а прогноз выносите в отдельный алерт. Он срабатывает раньше остальных и обычно превращает инцидент в плановую задачу.
- alert: DiskFillWarning
expr: (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs"} /
node_filesystem_size_bytes{fstype!~"tmpfs|overlay|squashfs"}) * 100 > 85
for: 10m
labels:
severity: warning
annotations:
summary: "Раздел {{ $labels.mountpoint }} заполнен более чем на 85%"
- alert: DiskFillCritical
expr: (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs"} /
node_filesystem_size_bytes{fstype!~"tmpfs|overlay|squashfs"}) * 100 > 90
for: 5m
labels:
severity: critical
- alert: InodesAlmostExhausted
expr: (1 - node_filesystem_files_free / node_filesystem_files) * 100 > 85
for: 15m
labels:
severity: warning
annotations:
summary: "Свободных inode меньше 15%"
- alert: DiskWillFillIn7Days
expr: predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[6h], 7*24*3600) < 0
for: 1h
labels:
severity: warning
annotations:
summary: "При текущем темпе раздел заполнится за неделю"
- alert: MinioS3ErrorsGrowing
expr: sum by (bucket) (rate(minio_s3_errors_total[5m])) > 1
for: 5m
labels:
severity: critical
annotations:
summary: "Рост ошибок S3 API в бакете {{ $labels.bucket }}"
- alert: MinioTtfbP99High
expr: histogram_quantile(0.99, sum by (le) (rate(minio_s3_requests_ttfb_seconds_distribution_bucket[5m]))) > 0.5
for: 10m
labels:
severity: warning
annotations:
summary: "p99 отдачи объектов выше 500 мс"
- alert: CephPoolNearFull
expr: ceph_pool_percent_used > 80
for: 15m
labels:
severity: critical
Чтобы правила не спамили, используйте group_by по кластеру и типу проблемы, repeat_interval не меньше 4 часов для warning и 30 минут для critical, а также inhibition: пока активен алерт о недоступности узла, правила по его дискам и latency молчат. Каналы уведомлений подбирайте по скорости реакции: Telegram или Slack для critical, email или тикет для warning. Ошибки целостности, которые приходят из zpool status и deep scrub, стоит отправлять в тот же канал, что и отказ диска, даже если сервис продолжает работать.
Регламентное обслуживание: scrub, балансировка и обновление версий
Регулярные работы предотвращают сбои не хуже алертов, но требуют окна обслуживания и плана отката. Ниже периодичность, проверенная на практике для хранилищ изображений среднего размера, и команды для каждой системы.
Scrub и проверка целостности данных
Scrub читает все блоки, сверяет контрольные суммы и восстанавливает повреждённые данные из избыточности. В ZFS это zpool scrub tank, статус смотрится командой zpool status -v, ошибки показываются в секции errors. В Ceph обычный scrub запускается автоматически, а deep scrub раз в неделю проверяет контрольные суммы объектов: ceph osd deep-scrub osd.5 для конкретного OSD и ceph osd scrub all для запуска вручную.
Scrub конкурирует за дисковый ввод-вывод. На массиве из 12 дисков полный проход ZFS по 40 ТБ занимает от нескольких часов до суток, и всё это время latency отдачи картинок растёт. Планируйте задачу через cron на ночь или выходные, ограничивайте скорость: в ZFS параметр zfs_scrub_delay добавляет паузы между блоками, в Ceph параметры osd_scrub_begin_hour и osd_scrub_end_hour задают окно, а osd_scrub_load_threshold не даёт запускать scrub при высокой нагрузке. Для Ceph разумный ритм: deep scrub раз в неделю в ночном окне, для ZFS: scrub раз в месяц, а также после замены диска или сбоя питания.
Балансировка и обновление версий
Дисбаланс в Ceph возникает после добавления или замены OSD: одни диски заполнены под 90%, другие под 60%. Команда ceph osd reweight-by-utilization 110 корректирует вес OSD с отклонением от среднего и запускает перемещение данных. На время ребалансировки полезно выставить ceph osd set norebalance, если нужно сначала освободить ресурсы под пиковую нагрузку, и снять флаг в окне. Помните, что миграция данных сама создаёт нагрузку на сеть и диски, поэтому выполнять её в час пик не стоит.
Обновление версий проходит по-разному. MinIO обновляется командой mc admin update, при этом rolling-рестарт узлов в кластере идёт по одному и сервис остаётся доступен. Ceph обновляется управляемо через ceph orch upgrade start --image, который переводит демонов по одному и позволяет остановиться на любом шаге при появлении ошибок. TrueNAS обновляется через веб-интерфейс с возможностью откатить системный датасет, но перед обновлением проверяйте примечания к версии: смена схемы ZFS или поведения плагинов иногда требует ручных шагов.
Чек-лист перед любым обновлением: свежий бэкап конфигураций и данных, проверенный на восстановление; тестовый стенд с той же версией, на котором прогнано обновление; окно обслуживания с уведомлением пользователей; известный способ отката; мониторинг latency и ошибок, включённый до старта работ. Автоматизировать снапшоты и проверку восстановления помогают готовые скрипты, разобранные в статье про автоматизацию резервного копирования и восстановления.
Примеры дашбордов и готовые конфигурации
Набор, который закрывает задачи мониторинга хранилища изображений без написания панелей с нуля: MinIO Dashboard (ID 13502), Ceph Cluster (ID 2842), Node Exporter Full (ID 1860) для узлов и ZFS, Smartctl Exporter (ID 19841) для атрибутов дисков, а также дашборд Alertmanager Overview (ID 9578) для контроля самих уведомлений. Публичные дашборды рассчитаны на стандартные имена метрик, поэтому после импорта проверьте, что панели не пустые, и поправьте фильтры instance и job.
Минимальный JSON-фрагмент панели для латентности, который можно вставить в дашборд через Import JSON и адаптировать под свои метрики:
{
"type": "timeseries",
"title": "MinIO TTFB p95 / p99",
"datasource": "Prometheus",
"targets": [
{
"expr": "histogram_quantile(0.95, sum by (le) (rate(minio_s3_requests_ttfb_seconds_distribution_bucket[5m])))",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.99, sum by (le) (rate(minio_s3_requests_ttfb_seconds_distribution_bucket[5m])))",
"legendFormat": "p99"
}
],
"fieldConfig": {
"defaults": { "unit": "s" }
}
}
Конфигурацию Alertmanager для дежурной смены удобно строить на маршрутах: critical уходит в голосовой канал илиTelegram, warning в тикет-систему, а правила по дискам одного узла собираются в одно уведомление через group_by: ['alertname', 'instance']. Отдельно проверьте, что алерты доходят: создайте тестовое правило с искусственным условием и убедитесь, что уведомление пришло за ожидаемое время.
Похожий подход применим и в медицинских хранилищах, где важна не только доступность, но и целостность самих файлов: разбор контроля DICOM-изображений и алертов по потере данных собран в статье про мониторинг PACS-серверов.
Как выстроить систему мониторинга, которая предотвращает сбои
Порядок запуска выглядит так. Сначала выпишите критичные метрики и снимите baseline на целевом профиле нагрузки: latency чтения и записи по перцентилям, IOPS, throughput, заполнение в байтах и inode, ошибки API. Затем поднимите сбор: endpoint MinIO, mgr-модуль Ceph, node_exporter и smartctl_exporter на TrueNAS, и убедитесь, что метрики приходят без пропусков. После этого импортируйте дашборды и правьте их под свои job-имена, чтобы дежурный видел картину за 10 секунд. Следующий шаг: правила алертов с порогами, длительностью и понятными текстами, плюс маршрутизация в Alertmanager. И последний: регламент работ с расписанием scrub, окнами для балансировки и процедурой обновления с проверкой на стенде.
Мониторинг не заканчивается запуском. Раз в квартал пересматривайте пороги: после перехода на NVMe алерт по latency в 500 мс перестаёт быть полезным, а после роста числа изображений прежний порог заполнения может срабатывать слишком поздно. Раз в месяц проверяйте, что каждый активный алерт кто-то действительно обработал, и удаляйте правила, которые только шумят. Если разбираетесь с уже случившейся деградацией, начните с поиска узкого места по метрикам, а не с закупки железа: методика разбора описана в материале про поиск узкого места в системе.