Graylog как альтернатива ELK для централизованного сбора логов: опыт телеком-оператора

Исходная ситуация

Телеком-оператор «ТелекомПро» обслуживает 200 000 абонентов и управляет инфраструктурой из 1 200 устройств: маршрутизаторы, коммутаторы, серверы биллинга, BRAS, DNS-серверы, RADIUS, голосовые шлюзы. Суммарный поток логов — 500 GB в день, 15 000 сообщений в секунду в пиках.

До нас компания использовала rsyslog с записью в файлы на центральном сервере. Проблемы:

  • Поиск по логам — grep по 500 GB файлам занимал от 10 до 40 минут. При аварии инженеры тратили больше времени на поиск логов, чем на устранение проблемы.
  • Корреляция событий — сопоставить событие на BRAS с логом RADIUS и записью биллинга вручную практически невозможно. Для расследования абонентской жалобы уходило 2-3 часа.
  • Отсутствие алертинга — о проблемах узнавали от абонентов, а не из логов. Критическая ошибка BGP-сессии могла оставаться незамеченной часами.
  • Хранение — логи старше 7 дней удалялись из-за нехватки дискового пространства, хотя регулятор требует хранение 6 месяцев.

Нам нужна была система, которая справится с 500 GB/день, обеспечит поиск за секунды, умеет алертить и будет проще в эксплуатации, чем полноценный ELK-стек.

Почему Graylog, а не ELK или Loki

Мы рассмотрели три варианта: ELK (Elasticsearch + Logstash + Kibana), Grafana Loki и Graylog. Вот результат сравнения для нашего сценария (500 GB/день):

КритерийELKGraylogGrafana Loki
RAM (500 GB/day)96-128 GB64-96 GB32-48 GB
Сложность настройкиВысокая (3 компонента)Средняя (единый UI)Низкая
Syslog из коробкиЧерез Logstash/FilebeatНативный inputЧерез Promtail
Pipeline обработкиLogstash (Grok, Ruby)Встроенные (правила)LogQL
AlertingKibana Alerting (платный)ВстроенныйЧерез Grafana
LDAP/AD authПлатный (X-Pack)БесплатныйЧерез Grafana
Полнотекстовый поискОтличныйОтличный (тот же ES)Ограниченный
СтоимостьБесплатный / Elastic LicenseOpen Source / EnterpriseБесплатный

Loki привлекает экономией RAM (не индексирует содержимое логов, только метки), но для телекома полнотекстовый поиск критичен: инженеру нужно найти конкретный IP абонента или MAC-адрес за секунды. Loki для этого потребует сканирование chunks, что при 500 GB/день будет медленным.

ELK проиграл по двум причинам: платный LDAP/AD (у ТелекомПро Active Directory с 150 пользователями) и сложность эксплуатации — три отдельных компонента, каждый со своей конфигурацией. Graylog даёт единый веб-интерфейс для всего: inputs, обработка, поиск, дашборды, алертинг.

Архитектура и установка

Graylog состоит из трёх компонентов: Graylog Server (Java-приложение), MongoDB (хранение конфигурации и метаданных), OpenSearch/Elasticsearch (индексация и хранение логов).

Для 500 GB/день мы спроектировали кластер:

  • 2 × Graylog Server (8 vCPU, 16 GB RAM) — за HAProxy для HA
  • 3 × OpenSearch Data Nodes (16 vCPU, 64 GB RAM, 8 TB NVMe)
  • 3 × OpenSearch Master Nodes (4 vCPU, 8 GB RAM)
  • 3 × MongoDB (Replica Set) (4 vCPU, 8 GB RAM)

Docker-compose для Graylog-ноды (production-ready):

# docker-compose.yml для Graylog Server
version: '3.8'

services:
  graylog:
    image: graylog/graylog:6.0
    environment:
      GRAYLOG_PASSWORD_SECRET: "somepasswordpepper-atleast16chars!!"
      GRAYLOG_ROOT_PASSWORD_SHA2: "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"
      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
      GRAYLOG_HTTP_EXTERNAL_URI: "https://graylog.telecompro.local/"
      GRAYLOG_ELASTICSEARCH_HOSTS: "https://opensearch1:9200,https://opensearch2:9200,https://opensearch3:9200"
      GRAYLOG_MONGODB_URI: "mongodb://mongo1:27017,mongo2:27017,mongo3:27017/graylog?replicaSet=rs0"
      GRAYLOG_IS_LEADER: "true"
      GRAYLOG_MESSAGE_JOURNAL_MAX_SIZE: "10gb"
      GRAYLOG_INPUTBUFFER_PROCESSORS: "4"
      GRAYLOG_PROCESSBUFFER_PROCESSORS: "8"
      GRAYLOG_OUTPUTBUFFER_PROCESSORS: "4"
    ports:
      - "9000:9000"     # Web UI
      - "1514:1514/tcp" # Syslog TCP
      - "1514:1514/udp" # Syslog UDP
      - "12201:12201"   # GELF TCP
      - "12201:12201/udp" # GELF UDP
      - "5044:5044"     # Beats
    volumes:
      - graylog_data:/usr/share/graylog/data
      - graylog_journal:/usr/share/graylog/data/journal
    restart: always
    ulimits:
      nofile:
        soft: 65536
        hard: 65536

volumes:
  graylog_data:
  graylog_journal:

OpenSearch настраиваем отдельно с оптимизациями для log storage:

# opensearch.yml — конфигурация data node
cluster.name: graylog-cluster
node.name: opensearch-data-1
node.roles: [data, ingest]

network.host: 0.0.0.0
discovery.seed_hosts:
  - opensearch-master-1
  - opensearch-master-2
  - opensearch-master-3

# Оптимизации для лог-хранилища
indices.memory.index_buffer_size: 25%
indices.queries.cache.size: 10%
thread_pool.write.queue_size: 1000

# JVM heap = 50% RAM, но не более 31 GB
# opensearch-data: 32 GB heap при 64 GB RAM

Inputs, Extractors и Pipelines

В Graylog input — это точка приёма логов. Мы создали несколько inputs для разных источников:

  • Syslog UDP (порт 1514) — сетевое оборудование (маршрутизаторы, коммутаторы), отправляет логи по syslog
  • Syslog TCP (порт 1514) — серверы Linux (rsyslog с TCP для гарантированной доставки)
  • GELF TCP (порт 12201) — приложения (Docker-контейнеры через GELF driver)
  • Beats (порт 5044) — Windows-серверы через Winlogbeat

Extractors извлекают структурированные данные из неструктурированных логов. Пример для RADIUS-логов:

# Pipeline Rule: парсинг RADIUS accounting
rule "parse radius accounting"
when
  has_field("message") AND
  contains(to_string($message.message), "Acct-Status-Type")
then
  let msg = to_string($message.message);

  // Извлекаем поля через regex
  let username = regex("User-Name = \"(.+?)\"", msg);
  let nasip = regex("NAS-IP-Address = (\\d+\\.\\d+\\.\\d+\\.\\d+)", msg);
  let framedip = regex("Framed-IP-Address = (\\d+\\.\\d+\\.\\d+\\.\\d+)", msg);
  let accttype = regex("Acct-Status-Type = (\\w+)", msg);
  let sessionid = regex("Acct-Session-Id = \"(.+?)\"", msg);

  set_field("radius_username", username["0"]);
  set_field("radius_nas_ip", nasip["0"]);
  set_field("radius_framed_ip", framedip["0"]);
  set_field("radius_acct_type", accttype["0"]);
  set_field("radius_session_id", sessionid["0"]);

  // Устанавливаем stream для RADIUS
  route_to_stream("RADIUS Accounting");
end

Pipelines в Graylog выполняются в определённом порядке (stages). Наш pipeline для сетевого оборудования:

# Stage 0: Определение типа устройства
rule "classify network device"
when
  has_field("source")
then
  // Определяем тип устройства по hostname или IP
  let src = to_string($message.source);
  let device_type = lookup("netbox-lookup", src);

  set_field("device_type", device_type);
  set_field("facility_name", syslog_facility($message.facility));
end

# Stage 1: Парсинг в зависимости от типа
rule "parse cisco ios"
when
  has_field("device_type") AND
  to_string($message.device_type) == "cisco_ios"
then
  let parsed = grok("%{CISCOTIMESTAMP:cisco_ts}: %%{CISCO_REASON:facility}-%{INT:severity}-%{CISCO_REASON:mnemonic}: %{GREEDYDATA:cisco_message}",
    to_string($message.message));

  set_fields(parsed);
  set_field("severity_label", syslog_severity($message.severity));
end

Streams, Alerting и Dashboards

Streams в Graylog — механизм маршрутизации сообщений. Каждый лог попадает в один или несколько streams на основе правил. Мы создали потоки:

  • Network Equipment — все логи от маршрутизаторов и коммутаторов
  • RADIUS — аутентификация и учёт абонентов
  • Billing — логи биллинговой системы
  • DNS — запросы DNS-серверов
  • Security — события безопасности (failed login, firewall drops)

Каждый stream привязан к своему индексу в OpenSearch с собственной политикой ротации:

# Index Set конфигурация через Graylog API
curl -u admin:password -H "Content-Type: application/json" \
  -X POST http://graylog:9000/api/system/indices/index_sets \
  -d '{
    "title": "Network Equipment Logs",
    "description": "Logs from routers and switches",
    "index_prefix": "network",
    "shards": 4,
    "replicas": 1,
    "rotation_strategy_class": "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategy",
    "rotation_strategy": {
      "type": "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategyConfig",
      "max_size": 30000000000
    },
    "retention_strategy_class": "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategy",
    "retention_strategy": {
      "type": "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategyConfig",
      "max_number_of_indices": 180
    },
    "index_analyzer": "standard",
    "field_type_refresh_interval": 5000
  }'

Alerting — одна из сильных сторон Graylog. Пример alert condition для обнаружения BGP-flapping:

# Event Definition: BGP Session Flap Detection
# Тип: Aggregation
# Условие: более 3 событий BGP_NOTIFICATION за 5 минут от одного устройства

# Graylog Event Definition (JSON)
{
  "title": "BGP Session Flap",
  "description": "BGP session flapping detected on network device",
  "priority": 1,
  "config": {
    "type": "aggregation-v1",
    "query": "mnemonic:BGP_NOTIFICATION OR mnemonic:BGP-5-ADJCHANGE",
    "streams": ["network-equipment-stream-id"],
    "group_by": ["source"],
    "series": [{
      "id": "count",
      "function": "count",
      "field": "message"
    }],
    "conditions": {
      "expression": {
        "expr": ">",
        "left": {"ref": "count"},
        "right": {"value": 3}
      }
    },
    "search_within_ms": 300000,
    "execute_every_ms": 60000
  },
  "notifications": [{
    "notification_id": "telegram-notification-id"
  }]
}

Dashboards мы создали для каждой команды: NOC видит состояние сетевого оборудования, abuse-отдел — Security stream, биллинг — свои логи. Всё разграничено через роли Graylog, привязанные к LDAP-группам.

LDAP-аутентификация и Content Packs

Интеграция с Active Directory — бесплатная фича Graylog (в отличие от ELK, где это требует платный X-Pack):

# Настройка LDAP через Graylog API
curl -u admin:password -H "Content-Type: application/json" \
  -X PUT http://graylog:9000/api/system/authentication/services/backends \
  -d '{
    "title": "TelecomPro AD",
    "description": "Active Directory",
    "config": {
      "type": "active-directory",
      "servers": [
        {"host": "dc1.telecompro.local", "port": 636, "security": "tls"}
      ],
      "system_user_dn": "CN=graylog-svc,OU=ServiceAccounts,DC=telecompro,DC=local",
      "system_user_password": {"is_set": true},
      "user_search_base": "OU=Users,DC=telecompro,DC=local",
      "user_search_pattern": "(&(objectClass=user)(sAMAccountName={0}))",
      "user_name_attribute": "sAMAccountName",
      "user_full_name_attribute": "displayName",
      "user_email_attribute": "mail"
    }
  }'

Content Packs — готовые наборы конфигураций (inputs, extractors, dashboards, streams) для типовых задач. Graylog Marketplace предлагает пакеты для Cisco, Palo Alto, Windows Event Log и других. Мы установили:

  • Cisco IOS/IOS-XE Content Pack — парсинг syslog, дашборды для BGP/OSPF/interface errors
  • Linux SSH Content Pack — детекция brute-force, failed logins
  • DNS Query Logging — парсинг и визуализация DNS-запросов

Свой Content Pack для RADIUS мы создали и опубликовали на Marketplace — сообщество оценило, 340 установок за первый месяц.

Результаты и сравнение ресурсов

После 4 месяцев эксплуатации Graylog на 500 GB логов/день:

МетрикаДо (rsyslog + grep)После (Graylog)
Время поиска по логам10-40 минут2-5 секунд
Время расследования инцидента2-3 часа15-30 минут
Обнаружение BGP-проблемОт абонентов (30-60 мин)Автоматический алерт (< 1 мин)
Хранение логов7 дней180 дней
Корреляция событийРучная (невозможна)Автоматическая (streams + lookup)

Потребление ресурсов кластера:

  • OpenSearch: 192 GB RAM, 24 TB NVMe (180 дней хранения с компрессией)
  • Graylog Server: 32 GB RAM (2 ноды)
  • MongoDB: 24 GB RAM (3 ноды Replica Set)
  • Итого: 248 GB RAM, 24 TB SSD

Для сравнения: аналогичный ELK-стек потребовал бы ~320 GB RAM из-за дополнительных компонентов (Logstash, Kibana) и более прожорливого Elasticsearch. Loki справился бы с 96 GB RAM, но полнотекстовый поиск по 500 GB был бы в 10-100 раз медленнее.

Главный вывод: Graylog — золотая середина между мощью ELK и простотой Loki. Единый интерфейс для всего, встроенный алертинг, бесплатный LDAP и приемлемое потребление ресурсов делают его оптимальным выбором для среднего и крупного бизнеса.

Часто задаваемые вопросы

Graylog 5.x+ перешёл на OpenSearch как рекомендуемый бэкенд после изменения лицензии Elasticsearch. Graylog 6.0 поддерживает OpenSearch 2.x. Elasticsearch 7.x тоже работает, но официальная поддержка прекращена. Для новых установок рекомендуется OpenSearch.
Нет, MongoDB — обязательный компонент Graylog для хранения конфигурации, пользователей, alert definitions, dashboards. Объём данных в MongoDB минимален (обычно < 1 GB), нагрузка низкая. Достаточно небольшого Replica Set из 3 нод с 8 GB RAM каждая.
Для 100 GB/день достаточно: 1 Graylog Server (8 vCPU, 16 GB RAM), 3 OpenSearch Data Nodes (8 vCPU, 32 GB RAM, 2 TB SSD каждая), 1 MongoDB (4 vCPU, 8 GB RAM). При хранении 90 дней потребуется ~5 TB дискового пространства с учётом компрессии OpenSearch (коэффициент ~0.55).
Graylog использует Journal (на основе Apache Kafka) как буфер между входящими сообщениями и обработкой. При пиковой нагрузке сообщения буферизуются в Journal на диске. Мы настроили GRAYLOG_MESSAGE_JOURNAL_MAX_SIZE=10gb, что позволяет буферизовать ~2 часа пиковой нагрузки без потери логов.
Если у вас уже настроенный ELK с Logstash pipelines и Kibana dashboards — миграция может не окупиться. Graylog имеет смысл при новой установке или если вы столкнулись с ограничениями бесплатного ELK: отсутствие LDAP, базового алертинга, сложность эксплуатации трёх отдельных компонентов. Graylog может использовать существующий OpenSearch/Elasticsearch кластер.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#graylog#elk#opensearch#log management#syslog#gelf#pipeline#alerting
Комментарии 0

Оставить комментарий

загрузка...