В нашей компании есть система для запуска PHP-скриптов по расписанию, которая позволяет распределять нагрузку на множество узлов и обеспечивать отказоустойвость. И в этой системе необходимо уметь собирать логи скриптов с сотен (и даже тысяч) машин, желательно в режиме реального времени. У нас раньше была система сбора логов, собранная «на коленке», и выдающая относительно невысокую производительность. Производительности стало не хватать, и мы переписали систему на Go. Новая система не использует scribe и обладает некоторыми уникальными фичами, например «вытесняющей многозадачностью» при доставке - если один из скриптов пишет столько логов, что мы не успеваем их всех доставить, логи всех остальных скриптов продолжают доставляться, с небольшой фиксированной задержкой. Система легко забивает гигабитную сетевую карту на нашем сервере-приемнике логов и не слишком «тормозит» доставку в случае, когда пропускной способности всё же не хваетает. В докладе я расскажу о том, как мы делали эту систему и про то, как она работает изнутри. Исходные тексты доступны на github: https://github.com/badoo/thunder
7. Пример скрипта: вывод на экран
[2015-10-12 09:53:57] INFO run started from /
home/nasretdinov/badoo/
[2015-10-12 09:53:57] INFO Hello, world!
[2015-10-12 09:53:57] INFO run script has
finished successfully (0.006 sec, 0.076 user, 0.012
sys, 0.034 loading)
8. Формат строки в лог-файле
[cloudstaging1,
74024107029]:
[2015-10-12 09:58:43]
INFO
Hello, world!
[hostname,
run_id]:
[YYYY-MM-DD HH:II:SS]
LOG_LEVEL
Message
10. Сбор логов
• Приложения могут писать отладочную
информацию — «логи»
• Логи пишутся на каждой машине «облака»,
оттуда их нужно уметь собирать
• Писать нужно много, чтобы можно было
понять причины проблем
11. Требования к системе
• Низкая latency (секунды)
• Высокая пропускная способность (десятки
Мб/сек)
• Возможность поиска («greppable»)
12. Старый сборщик логов: перенаправление вывода
• stdout | proxy >>
run_id.out.log
• stderr | proxy >>
run_id.err.log
proxy
process #1 process #2 process #3
process #1
STDIN
STDOUT
STDERR
1.out.log
/dev/null
1.err.log
proxy
13. Старый сборщик логов: перенаправление вывода
• имя файла: run_id.out.log[.offset]
• на каждый запуск создается 2 файла + в
имени файла хранится последнее
отправленное смещение
• опрашивается список файлов и всё
посылается в категорию «logs» в scribe
14.
15. Старый сборщик логов: достоинства
• Очень простая реализация
• Вполне надежная
• Позволяет легко отличать разные запуски
друг от друга — идентификатор запуска
находится в имени файла
16. Старый сборщик логов: недостатки
• Низкая скорость на приемнике (3 Мб/сек)
• Может накопиться очень много файлов
(миллион)
• Высокий CPU usage — опрос файлов
ресурсоемок
• Использование inotify делает только хуже
17. Старый сборщик логов: недостатки
• Неудобный перезапуск прокси
• Один «флудящий» класс вызывает «затор»
всей системы и задерживается доставка
всех логов
18. Новый сборщик логов: требования
• Управляемость (не создается миллион
файлов)
• Желательна real-time доставка
• Большой запас по пропускной способности
19. Новый сборщик логов: перенаправление вывода
• stdout >>
class.out.log
• stderr >>
class.err.log
proxy
process #1 process #2 process #3
process #1
STDIN
STDOUT
STDERR
test_class.out.log
/dev/null
test_class.err.log
23. Новый сборщик логов: достоинства
• Высокая скорость доставки (100+ Мб/сек)
• «Вытесняющая многозадачность»
• Отказоустойчивость (запись в файлы)
• Управляемость и гибкость — возможность
доставить файлы самостоятельно
• Real-time доставка
24. Новый сборщик логов: недостатки
• Возросшая сложность системы
• Высокий CPU usage на приемнике
• Не масштабируется (приемник — только 1
сервер)
• Подходит только для debug-логов, не
является заменой scribe
25. Выводы
• Начинайте с простого: старая система сделана
«на коленке» и прослужила целый год
• Используйте open-source инструменты — без
scribe нам было бы некуда отсылать логи
• Пишите свои системы, если нужно — новая
система решает наши проблемы, ваши
требования могут радикально отличаться