Статьи

Оптимизация Graylog2 для сред с высоким логом

Рич Макдоно является автором этой статьи.

По мере превращения организации из стартапа с несколькими системами в сложную среду, состоящую из сотен серверов, десятков подсетей и множества точек интеграции, преимущества автоматизации становятся крайне очевидными. В частности, как только система выросла до нескольких хостов, необходимо решить ряд проблем, связанных с журналами:

• Перемещение журналов в безопасное удаленное местоположение (например, вне исходного хоста)
• Разрешение неадминистраторам на поиск журналов с использованием контроля доступа на основе ролей
• Фильтрация, запутывание и очистка сообщений журналов
• Анализ журналов на нескольких хостах

Возьмем, к примеру, покупку, сделанную в одном из наших веб-приложений конечным пользователем. Как правило, они попадают на нашу целевую страницу, входят в систему, возможно, просматривают несколько профилей и отправляют сообщения другим пользователям, покупают продление подписки и затем выходят. В это время их действия будут создавать сообщения журнала на нескольких веб-серверах, обновлять записи базы данных в нашей главной базе данных и нескольких ведомых только для чтения, передавать задачи в фоновые очереди для последующей обработки, отправлять электронную почту, и несколько хостов взаимодействовали бы с наши платежные системы и другие сторонние интеграции.

Если во всем этом наборе действий что-то идет не так, как можно выполнить поиск по более чем дюжине хостов, чтобы определить, какие действия вызвали события на каждом хосте? Как вы соотносите пакеты данных с осмысленными событиями, которые соответствуют этому единственному пользователю?

Splunk — это один из коммерческих продуктов, который отвечает потребностям нашей организации. Однако Splunk, в частности, позиционируется как хороший выбор для небольших сред с небольшим бюджетом или больших сред с большим бюджетом для этих типов инструментов. Объем регистрируемых нами данных регистрации является чрезмерно дорогим для установки Spunk.

В Avid Life Media мы являемся потребителями и сторонниками ценности программного обеспечения с открытым исходным кодом. Наши приложения почти исключительно написаны с использованием свободно доступных инструментов, и мы продолжаем получать огромные положительные результаты, стратегически выбирая инструменты, которые получают поддержку и развитие от сообщества OSS. Естественно, наше внимание обратилось на Graylog2.

GrayLog2 — это бесплатная система сбора и корреляции журналов с открытым исходным кодом. Хотя он не соответствует списку функций Splunk, он предоставляет все основные возможности корреляции журналов, которые нам нужны.

Шаги для установки Graylog2 хорошо документированы в другом месте. Здесь я остановлюсь на некоторых из мер, которые были необходимы для дальнейшей эксплуатации системы для производственного использования. Поскольку наша среда получает от 2000 до 6000 журнальных сообщений в минуту (со случайными пиками до 40000!), Мы обнаруживаем, что наш набор данных растет очень быстро. В результате мы обнаружили, что наш сервер для хранения этих сообщений заполнялся очень быстро. Нам нужно было решение для сохранения диска с данными в виде плоских файлов — функция, которая в настоящее время не является частью приложения. Поэтому обсуждается архивация данных из MongoDB, как и наш собственный скрипт пересылки журналов, удобный инструмент Python для отправки сообщений из любого файла журнала на вашем сервере, основанный на совпадении или несоответствии регулярного выражения.

Эта статья посвящена версии Graylog2 0.9.5p2. Наше обновление до 0.9.6 было отложено до более поздней даты по причинам, о которых я расскажу позже в этом посте.

Стек приложений

Стек приложения состоит из следующих компонентов:

заявка функция
graylog2-сервер Системный журнал Graylog / GELF сервер
graylog2-веб-интерфейс Графический интерфейс Rails 3 для доступа к базе данных Graylog2
Монго БД Механизм персистентности для приложения Graylog2. Mongo — это база данных NOSQL, которая хорошо подходит для хранения данных журналов.
GELF Daemon Сценарий Python, который привязывает файлы журналов и пересылает их на сервер GELF

Из них только GELF Daemon написан собственными силами, с источником, обсужденным немного позже.

Все серверы в этой конкретной производственной среде работают под управлением версий RHEL 5 и RHEL 6, однако ничто не мешает этим технологиям работать в любой другой системе * NIX.

Архитектура

Вход / Back-конец

Все клиенты в среде пересылают свои журналы, используя либо собственную конфигурацию системного журнала, либо используя GELF. В то время как первый из них легко доступен для большинства сервисов UNIX, GELF — это более многофункциональный протокол, разработанный сообществом Graylog2, который может предоставить отдельные поля для индексации Graylog2.

Это требует, чтобы два порта были открыты для хоста регистрации от всех клиентов в среде.

Данные анализируются сервером Graylog2 и немедленно сохраняются в базе данных MongoDB. В нашем случае мы используем выделенный том NFS с нашего NetApp NAS, однако нет никаких причин, по которым локальное хранилище не будет работать так же хорошо.

Внимательно рассмотрите требования к оперативной памяти вашего сервера! MongoDB использует файлы с отображением в памяти, поэтому вам нужно иметь как минимум размер вашей коллекции баз данных * свободной в ОЗУ * на вашем хосте, в противном случае вы рискуете обменяться! В нашем случае у нас 8 ГБ ОЗУ на одном хосте с ограниченным набором 5 ГБ.

Фронтальный / Web

В отличие от большинства приложений на Rails, требования MySQL отсутствуют. Все данные для всего приложения хранятся в MongoDB. Кроме этого, веб-интерфейс является очень типичным проектом Rails, работающим под управлением Passenger. Производительность никогда не является серьезной проблемой, даже если приложение Rails работает на том же хосте, что и сервер Graylog2, которому, кстати, назначено 8 виртуальных процессорных ядер. Это оказалось более чем достаточным для нужд обработки информации журнала из нескольких сотен систем.

Закрытое хранилище

GrayLog2 использует ограниченные возможности хранения MongoDB. Ограниченная коллекция — это, по сути, таблица базы данных, которая использует механизм FIFO для ограничения использования хранилища. Для нашей таблицы журналов мы ограничены 5 ГБ общей памяти, которая должна быть способна хранить более недели журналов. Мы архивируем данные в файл через 24 часа и позволяем MongoDB удалять данные без помех.

Архивирование

Данные передаются из базы данных сообщений Graylog2 довольно быстро в нашей среде. Следовательно, мы активно архивируем данные в файл. MongoDB * очень * поддается такому подходу. Ниже приведен наш сценарий архивации, который выполняется каждый вечер на хосте Graylog2.

Обратите внимание, что пакет pymongo доступен в EPEL. Пожалуйста, сначала проверьте, как ваш пробег может отличаться!

#!/usr/bin/env python
from pymongo import Connection
import gzip
import time
import traceback
connection = Connection('localhost', 27017)
db = connection.graylog2
collection = db.messages
now = int(time.time())
today = time.localtime(time.time())
yesterday = time.localtime(now - 86400)
fileName = ('/data/dumps/messages_%s_%s.gz' % (yesterday[1], yesterday[2]))
handle = gzip.open(fileName, 'wb')
for doc in collection.find():
  if (now - (int(doc['created_at'])) > 0) and
     (now - int(doc['created_at']) < 86400):
    try:
      handle.write(u'%s %s %s "%s" message: "%s" full_message: "%s"\n' % (doc[u'host'],
       doc[u'facility'],
       doc[u'level'],
       time.ctime(int(doc['created_at'])),
       str(doc[u'message']).strip(),
       str(doc[u'full_message']).strip()))
    except:
      traceback.print_exc()
print "all done"
handle.close()

Запуск этого скрипта так же прост, как добавление в ваш локальный crontab.

Настройка клиента

Мы * сильно * верим в автоматизацию. По этой причине мы используем Puppet для * подавляющего большинства конфигураций наших серверов. Настроить несколько сотен серверов с новым хостом журнала так же просто, как добавить несколько строк в нашу конфигурацию Puppet

class graylog_clients {
  file { "/etc/syslog.conf":
    owner => root,
    group => root,
    mode => 644,
    source => "puppet://puppet/puppetfiles/graylog_clients/etc/syslog.conf"
  }
  service { syslog:
    ensure => running,
    subscribe => File["/etc/syslog.conf"]
  }
  file { "/etc/gelfDaemon.conf":
    owner => root,
    group => root,
    mode => 644,
    source => "puppet://puppet/puppetfiles/graylog_clients/etc/gelfDaemon.conf"
  }
  file { "/usr/local/bin/gelfDaemon.py":
    owner => root,
    group => root,
    mode => 755,
    source => "puppet://puppet/puppetfiles/graylog_clients/usr/local/bin/gelfDaemon.py"
  }
  file { "/etc/init.d/gelfDaemon":
    owner => root,
    group => root,
    mode => 750,
    source => "puppet://puppet/puppetfiles/graylog_clients/etc/init.d/gelfDaemon"
  }
}
node /.*awesome-host-[0-9]$/ {
  include all_clients, app_servers, snort_servers, prod_servers, graylog_clients
}

Конфигурация для наших локальных серверов системного журнала, предоставляемых классом graylog_clients, очень проста:

# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none    /var/log/messages
# The authpriv file has restricted access.
authpriv.*            /var/log/secure
# Log cron stuff
cron.*              /var/log/cron
# Everybody gets emergency messages
*.emerg             *
# Save news errors of level crit and higher in a special file.
uucp,news.crit            /var/log/spooler
# Save boot messages also to boot.log
local7.*            /var/log/boot.log
*.emerg         @awesome-graylog2-host
*.alert         @awesome-graylog2-host
*.crit          @awesome-graylog2-host
*.warning       @awesome-graylog2-host

Как видите, мы сделали очень мало в плане модификаций. Наш «Awesome Graylog2 Host» теперь получает все сообщения системного журнала, как и любой другой стандартный сервер системного журнала.

GELF Daemon

Наш демон GELF — это скрипт сбора журналов, который отслеживает журналы в режиме реального времени и передает их слушателю Graylog2 GELF, если они удовлетворяют определенным критериям. Мы написали это, чтобы решить некоторые проблемы, которые нелегко решить с помощью стандартного процесса syslog:

  • Пересылка журналов, которые соответствуют регулярному выражению (и пропуск тех, которые не соответствуют)
  • Объединение множества строк из одного события в одно сообщение журнала
  • Создание нескольких хвостов в одном файле

Система, которая спровоцировала создание этого сценария, является одним из наших основных веб-приложений — очень, * очень * шумное приложение, которое любит создавать бесконечный поток отдельных строк журнала для одного запроса. Используя этот сценарий, мы можем получить краткую, единственную запись в Graylog2, когда возникают определенные исключения, вместо того, чтобы получать поток из множества отдельных записей журнала, как это было бы с простым перенаправителем системного журнала, не обрабатывающим символы новой строки.

Этот подход также творит чудеса для таких вещей, как медленные журналы MySQL. Мы можем включить это:

# Time: 120201 18:53:33
# User@Host: avidlifemedia_db[avidlifemedia_db] @ amazing-server [10.0.10.199]
# Thread_id: 1668392  Schema: awesome_production
# Query_time: 7.728352  Lock_time: 0.000049  Rows_sent: 1
# Rows_examined: 2475275  Rows_affected: 0  Rows_read: 1
SELECT things.* FROM blah...

Into this:
Time: 120201 18:53:33
User@Host: avidlifemedia_db[avidlifemedia_db] @ amazing-server [10.0.10.199]
Thread_id: 1668392  Schema: awesome_production
Query_time: 7.728352  Lock_time: 0.000049  Rows_sent: 1
Rows_examined: 2475275  Rows_affected: 0  Rows_read: 1
SELECT things.* FROM blah...

… И отправлять его только в том случае, если время медленного запроса превышает значение, которое мы заботимся об этом конкретном хосте.

Демон GELF устанавливается Puppet, как и файл конфигурации для него. Единственное дополнительное действие — включить и запустить этот скрипт после установки модуля python-json.

yum install python-json -y
chkconfig gelfDaemon on
service gelfDaemon start

Эти задачи также могут быть выполнены Puppet, или одним из ваших собственных сценариев развертывания, или одним из ста различных способов автоматизации процессов в вашей собственной среде.

Обратите внимание, что сценарий gelfDaemon.py безопасно выполнять из командной строки. Это полезно, если у вас есть какие-либо проблемы и вам необходимо отладить то, что процесс GELF перенаправляет на сервер Graylog2 (все сообщения журнала, отправляемые на сервер Graylog, выводятся на консоль).

Обратите внимание, что представленный здесь скрипт использует версию модуля python-json для RHEL 5.x.

Настройка GELF Daemon

Настроить демона GELF очень просто. Конфиг-файл, не называемый /etc/gelfDaemon.conf, управляет его поведением. Пример кода должен сделать его понятным:

# /etc/gelfDaemon.conf
#
# levels are defined as these:
#            CRITICAL: 2
#            ERROR: 3
#            WARNING: 4
#            NOTICE: 5
#            INFO: 6
#            DEBUG: 7
[default]
gelfServer = amazing-graylog2-server
gelfPort = 12201
gelfMaxChunkSize = 8154
[awesome-app]
path = /data/awesome-app/current/log/production.log
level = 3
regex = .*[eE]xception.*
facility = awesome-app
short_message_regex = ^.{1,60}
concatenate_on = ^\ \~$
[sphinx]
path = /data/awesome-app/sphinx/log/searchd.log
level = 5
regex = .*
facility = searchd_log
short_message_regex = ^.{1,60}

Из двух приведенных здесь примеров один явно более сложный. Раздел awesome-app будет принимать строки, содержащие слово «исключение», и объединять все последующие строки, начинающиеся с «~», в конце, а затем отправлять их на сервер Graylog2 в виде одного сообщения. Любые строки, в которых нет слова «исключение», просто пропускаются.

Наш пример Sphinx здесь берет все строки (. *, Чтобы соответствовать каждой строке) и передает их без какой-либо конкатенации.

Обратите внимание, что «средство» является * произвольным *. Средства журнала GELF не идентичны средствам системного журнала и могут быть такими, какими вы хотите их видеть. Это делает работу с Graylog2 намного, намного проще и позволяет вам создавать свои потоки более разумно.

Источник Github для демона GELF находится здесь:

https://github.com/rmcdonough/GELF-Daemon/

Обновление до Graylog2 версии 0.9.6

В прошлом месяце мы попытались перейти на последнюю версию Graylog2. К сожалению, в последней сборке graylog2-сервера есть критическая ошибка, которая заставляет его молча отбрасывать сообщения системного журнала, с которых он не может проанализировать дату.

http://jira.graylog2.org/browse/SERVER-90

Проблема была решена, но исправление доступно только в 0.9.6p1-RC (версия-кандидат). Мы ждем, пока это выйдет в стабильный релиз, прежде чем мы попробуем снова.

Кроме того, с отказом от MongoDB для механизма персистентности необходимо было создать новый сценарий архивации. Извлечь данные из Elasticsearch, к сожалению, не так просто, и приложение наверняка получит выгоду от механизма архивирования. Мы запустили новый сценарий для этого, однако он еще не завершен.

О Рич Макдоно

Моя элегантность и остроумие превосходят только мое смирение.