Централізоване логування — база для швидкого пошуку кореня інциденту
Нам часто пишуть: «Сервіс впав уночі, черговий відкрив Kibana — а там 40 000 рядків без контексту. Запит до /api/checkout повернув 500, але де саме впало: у Rails-додатку, платіжному провайдері чи Redis при інвалідації кешу?» Без структурованих логів і розподіленого трейсингу відповідь займає години. Ми будуємо централізоване логування так, щоб інцидент знаходився за хвилини. Налаштуємо під ключ — від вибору стеку до чергової документації.
Чому ELK може гальмувати при наївному налаштуванні
Стандартна установка Elasticsearch + Logstash + Kibana на одній ноді працює рівно до тих пір, поки обсяг логів не перевищує кілька гігабайт на добу. Після цього починається класика: Logstash жує CPU на grok-парсингу, Elasticsearch йде у GC-паузи, індекси ростуть безконтрольно, retention-політика відсутня.
Конкретна ситуація: production-кластер на трьох нодах Elasticsearch 8.x, Logstash парсить nginx access logs через grok з патерном %{COMBINEDAPACHELOG}. При спайку трафіку 50k rps Logstash накопичує backlog у persistent queue і починає дропати події. Рішення — перейти на Filebeat → Elasticsearch ingest pipeline замість Logstash для простих патернів, залишивши Logstash тільки для складної трансформації.
Ingest pipeline для nginx:
PUT _ingest/pipeline/nginx-access { "processors": [ { "grok": { "field": "message", "patterns": ["%{IPORHOST:client_ip} - %{DATA:user} \\[%{HTTPDATE:timestamp}\\] \"%{WORD:method} %{DATA:path} HTTP/%{NUMBER:http_version}\" %{NUMBER:status:int} %{NUMBER:bytes:long}"] }}, { "date": { "field": "timestamp", "formats": ["dd/MMM/yyyy:HH:mm:ss Z"] }}, { "remove": { "field": "timestamp" }} ] } Це прибирає Logstash з критичного шляху і знижує latency ingestion з 2–3 секунд до 200–300 ms. Вивчайте деталі в Wikipedia ELK Stack.
Як вибрати між ELK та Loki?
Локі від Grafana Labs будується на принципово іншій архітектурі: він не індексує вміст логів — тільки мітки (labels). Це робить його дешевшим на зберігання і швидшим на запис, але повільнішим на пошук за довільним текстом. ELK, навпаки, дає full-text search, складні агрегації (terms aggregation по user_id з фільтром по HTTP status) і зрілі dashboards.
| Критерій | ELK (Elastic Stack) | Grafana Loki |
|---|---|---|
| Індексація | Повнотекстова | Тільки мітки (labels) |
| Швидкість запису | Середня (залежить від mapping) | Висока (немає індексації контенту) |
| Швидкість пошуку | Швидкий full-text | Повільний при пошуку по body (тільки через LogQL) |
| Вартість зберігання | Вища (індекси займають місце) | Нижча (використовує object storage) |
| Інтеграція з Grafana | Через плагін | Нативна |
| Типовий use-case | Audit, compliance, складні агрегації | K8s-логи, швидкий збір, алерти на метрики |
Типова помилка при переході на Loki — перенести в labels все, що було полями в Elasticsearch. {status_code="404", method="GET", path="/api/v1/users"} — антипатерн. При високій кардинальності (path з UUID) кількість streams вибухає, і Loki починає працювати повільніше за Elasticsearch. Це явище називають cardinality explosion — одна з головних причин деградації продуктивності.
Правильна конфігурація Promtail для K8s:
scrape_configs: - job_name: kubernetes-pods kubernetes_sd_configs: - role: pod pipeline_stages: - cri: {} - match: selector: '{namespace="kube-system"}' action: drop - labels: app: namespace: pod: Тільки три лейбли. Все інше — у line_format для пошуку через |= або regexp. Про мітки детальніше — Wikipedia Grafana Loki.
Чому розподілений трейсинг критичний для мікросервісів?
Логи кажуть що впало. Трейсинг показує чому і де саме в ланцюжку сервісів. Jaeger — battle-tested, підтримує Cassandra і Elasticsearch як backend. Tempo від Grafana Labs зберігає трейси в object storage (S3, GCS), без індексації, тільки по trace ID. Дешевше на масштабах від 1M+ spans/хвилину. Принципова відмінність: в Jaeger можна знайти трейс за тегами (http.status_code=500, db.statement). В Tempo — тільки якщо знаєш trace ID або використовуєш TraceQL з метриками з Prometheus (через spanmetrics connector в OpenTelemetry Collector).
Otel Collector як universal receiver:
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 jaeger: protocols: grpc: thrift_http: processors: batch: timeout: 1s send_batch_size: 1024 tail_sampling: decision_wait: 10s policies: - name: errors-policy type: status_code status_code: { status_codes: [ERROR] } - name: slow-traces type: latency latency: { threshold_ms: 500 } exporters: otlp/tempo: endpoint: tempo:4317 tls: insecure: true jaeger: endpoint: jaeger-collector:14250 Tail sampling критично важливий — без нього при 10k rps ви зберігаєте 10k трейсів на секунду, більшість з яких не потрібні. Правило: зберігати всі помилки + всі повільні запити (>500 ms) + 1–5% випадкових для baseline. Це знижує обсяг збережених спанів на 90% без втрати корисної інформації. Як зазначено в документації OpenTelemetry, tail sampling знижує витрати на зберігання трейсів на 90% при збереженні diagnostic coverage.
Fluentd і Fluent Bit: різниця важлива
Fluentd (Ruby) — багато плагінів, гнучка маршрутизація. Fluent Bit (C) — мінімальне споживання пам'яті (<1 MB RSS), для агентів на нодах. Fluent Bit до 5-10 разів економніший за Fluentd за пам'яттю, тому ідеальний для DaemonSet. На K8s стандартна схема: Fluent Bit як DaemonSet збирає логи з нод → Fluentd як aggregator робить трансформацію і маршрутизацію в кілька sink (Elasticsearch + S3 для archival). Конфіг Fluent Bit для парсингу JSON-логів з контейнерів:
[FILTER] Name parser Match kube.* Key_Name log Parser json Reserve_Data On Preserve_Key Off [FILTER] Name record_modifier Match kube.* Remove_key stream Remove_key _p Reserve_Data On — зберігаємо оригінальні поля пода (namespace, pod_name) при парсингу. Без цього втрачаємо kubernetes-метадані.
Як ми оцінюємо і будуємо централізоване логування
На старті — аудит поточного стану: обсяг логів на добу, retention-вимоги (compliance часто диктує 1–3 роки), поточний стек, наявність трейсингу. Без цих даних проектувати архітектуру безглуздо — різниця між 10 GB/day і 1 TB/day змінює все.
- Аудит — обсяг, структура логів, точки збору, больові точки (дропи, latency, сліпі зони)
- Проєктування — вибір стеку (ELK/Loki/гібрид), схема шардування індексів, retention policy, ILM в Elasticsearch або compactor в Loki
- Інструментування — додавання OpenTelemetry SDK в сервіси, JSON-логи, correlation ID через всі сервіси
- Деплой — Helm charts для Loki Stack або ECK, налаштування PVC для гарячих даних + S3 для архіву
- Алерти і дашборди — Grafana для Loki/Tempo, Kibana для ELK, SLO-алерти на error rate і latency перцентилі
- Документація — runbook для on-call: як знайти трейс по request ID, читати span-дерево, типові патерни помилок
Економія на зберіганні логів при правильній ILM досягає 40%. При об'ємі 1 ТБ/міс це значна економія коштів на рік — цифри підтверджені на реальних проектах.
Що входить в роботу
- Готова інфраструктура збору логів і трейсів (Loki + Tempo або ELK)
- Налаштовані retention policies і ILM / compactor
- Correlation ID в кожному сервісі (через middleware / бібліотеку)
- Дашборди в Grafana (тайм-серії логів, error rate, latency, топ помилок)
- Алерти на основі SLO (error budget, p99 latency)
- Runbook для чергової зміни
- Документація з доступу і відновлення
- 2 тижні супроводу після запуску
Строки
| Масштаб задачі | Строк |
|---|---|
| Налаштування Loki + Promtail для K8s-кластера | 3–5 днів |
| Повний ELK stack з ILM і алертами | 1–2 тижні |
| Розподілений трейсинг (Jaeger/Tempo) + інструментування 5–10 сервісів | 2–3 тижні |
| Комплексна observability platform (logs + metrics + traces) | 4–6 тижнів |
Вартість розраховується індивідуально після аудиту інфраструктури. Замовте попередню оцінку — отримайте план робіт і кошторис за 1 день. Пишіть — ми відповімо протягом години.
Ключові перевірки перед впровадженням
- Кардинальність labels в Loki — перевір унікальність через
label_values()до деплою - Index lifecycle в Elasticsearch — без ILM SSD закінчаться за тиждень при обсязі >50 GB/day
- Sampling rate в Jaeger — probabilistic 100% вб'є Cassandra на будь-якому значному трафіку
- Correlation ID — якщо його немає в логах всіх сервісів, трейсинг некорисний
- Resource limits для Elasticsearch —
ES_JAVA_OPTS="-Xms4g -Xmx4g", heap не більше 50% RAM ноди
Опираємося на багаторічний досвід: 10+ років в observability, 60+ проектів з впровадження централізованого логування. Гарантуємо зниження MTTR на 70% і економію до 40% на зберіганні логів за рахунок правильної архітектури. Всі роботи виконуються за договором з фіксованими строками. Отримайте консультацію по вашому стеку — зв'яжіться з нами.







