company_banner

Loghouse 0.3 — долгожданное обновление нашей системы работы с логами в Kubernetes

    У компании «Флант» есть ряд Open Source-разработок, преимущественно для Kubernetes, и loghouse — одна из самых популярных. Это наш инструмент для централизованного логирования в K8s, который был представлен более 2 лет назад.



    Как мы упоминали в недавней статье про логи, он требовал доработки, и актуальность её со временем только росла. Сегодня мы рады представить новую версию loghouse — v0.3.0. Подробности о ней — под катом.

    Недостатки


    Мы используем loghouse во множестве Kubernetes-кластеров всё это время, и в целом такое решение устраивает как нас самих, так и различных клиентов, которым мы тоже предоставляем доступ.

    Главные его плюсы — простой и понятный интерфейс, возможность исполнения SQL-запросов, хорошее сжатие и низкое потребление ресурсов при вставке данных в базу, а также низкие накладные ресурсы при хранении.

    Самые наболевшие проблемы в loghouse за время эксплуатации:

    • использование таблиц-партиций, объединённых merge-таблицей;
    • отсутствие буфера, который бы сглаживал всплески логов;
    • устаревшие и потенциально уязвимые gem в веб-панели;
    • устаревший fluentd (loghouse-fluentd:latest не стартовал из-за проблемного gemset'а).

    Кроме того, накопилось значительное количество issues на GitHub, которые тоже хотелось бы решить.

    Главные изменения в loghouse 0.3.0


    На самом деле, изменений у нас накопилось достаточное количество, но мы осветим самые важные. Их можно разделить на 3 основные группы:

    • улучшение хранения логов и схемы БД;
    • улучшение сбора логов;
    • появление мониторинга.

    1. Улучшения в хранении логов и схеме базы


    Ключевые новшества:

    • Изменились схемы хранения логов, осуществлён переход на работу с единой таблицей и отказ от таблиц-партиций.
    • Начал применяться механизм очистки базы, встроенный в ClickHouse последних версий.
    • Появилась возможность использования внешней инсталляции ClickHouse, даже в режиме кластера.

    Сравним производительность старой и новой схем в реальном проекте. Вот пример поиска уникальных URL в логах приложения популярного онлайн-ресурса dtf.ru:

    SELECT 
        string_fields.values[indexOf(string_fields.names, 'path')] AS path, 
        count(*) AS count
    FROM logs
    WHERE (namespace = 'kube-nginx-ingress') AND ((string_fields.values[indexOf(string_fields.names, 'vhost')]) LIKE '%foobar.baz%') AND (date = '2020-02-29')
    GROUP BY string_fields.values[indexOf(string_fields.names, 'path')]
    ORDER BY count DESC
    LIMIT 20

    Отбор происходит по десяткам миллионов записей. Старая схема отрабатывала за 20 секунд:



    Новая — за 14:



    Если вы используете наш Helm-чарт, то при обновлении loghouse будет автоматически произведена миграция базы на новый формат. В противном случае — придётся сделать миграцию вручную. Процесс описан в документации. Если вкратце, то достаточно запустить:

    DO_DB_DEPLOY=true rake create_logs_tables

    Кроме того, мы начали использовать TTL для таблиц ClickHouse. Это позволяет автоматически удалять из БД данные, которые старше, чем заданный временной интервал:

    CREATE TABLE logs
    (
    ....
    )
      ENGINE = MergeTree()
      PARTITION BY (date)
      ORDER BY (timestamp, nsec, namespace, container_name)
      TTL date + toIntervalDay(14)
      SETTINGS index_granularity = 32768;

    Примеры схем баз данных и конфигов для ClickHouse, включая пример работы с кластером CH, можно найти в документации.

    Улучшение сбора логов


    Основные новшества:

    • Добавлен буфер, который призван сгладить всплески при появлении большого числа логов.
    • Реализована возможность отправлять логи в loghouse напрямую из приложения: по TCP и UDP, в формате JSON.

    Аккумулятором логов в loghouse стала новая таблица logs_buffer, добавленная в схему БД. Эта таблица — in-memory, т.е. хранится в RAM (имеет специальный тип Buffer); именно она и должна сгладить нагрузку на базу. За совет по её добавлению благодарим Sovigod!

    Реализованная отправка логов напрямую в loghouse из приложения позволяет делать это даже через netcat:

    echo '{"log": {"level": "info", "msg": "hello world"}}' | nc fluentd.loghouse 5170

    Данные логи можно посмотреть в пространстве имён, куда установлен loghouse, в потоке net:



    Требования к отправляемым данным минимальны: сообщение должно быть корректным JSON с полем log. Поле log, в свою очередь, может быть как строкой, так и nested JSON.

    Мониторинг работы подсистемы логирования


    Важным улучшением стал мониторинг fluentd через Prometheus. Теперь в комплекте к loghouse идёт панель для Grafana, которая отображает все основные метрики, такие как:

    • количество работающих fluentd;
    • количество отправляемых событий в ClickHouse;
    • размер свободного буфера в процентах.

    Код панели для Grafana можно увидеть в документации.

    Панель для ClickHouse сделана на основе уже готового продукта — от f1yegor, за что автору большое спасибо.

    Как видно, в панели отображается количество подключений к ClickHouse, использование буфера, активность фоновых задач и количество слияний. Этого вполне достаточно для понимания состояния системы:



    Панель для fluentd показывает активные экземпляры fluentd. Это особенно критично для тех, кто совсем не хочет/не может терять логи:



    Кроме статуса pod'ов, в панели видна нагрузка на очередь отправки логов в ClickHouse. По очередям можно понять, справляется ClickHouse с нагрузкой или уже нет. В случаях, когда лог нельзя терять, этот параметр тоже становится критичным.

    Примеры панелей заточены под нашу поставку Prometheus Operator, однако легко модифицируются через переменные в настройках.

    Наконец, в рамках работ по мониторингу loghouse мы собрали актуальный Docker-образ с релизом clickhouse_exporter 0.1.0 от Percona Labs, так как автор оригинального clickhouse_exporter забросил свой репозиторий.

    Планы на будущее


    • Сделать возможным развертывание кластера ClickHouse в Kubernetes.
    • Сделать работу с выборкой логов асинхронной и вынести её из Ruby-части бэкенда.
    • В Ruby-приложении есть известные узкие места, над исправлением которых мы работаем.
    • Возможно, частично переписать бэкенд на Go.
    • Сделать фильтрацию логов.

    Вместо заключения


    Приятно видеть, что проект loghouse нашёл свою аудиторию, не только завоевав звёздочки в GitHub (600+), но и побудив реальных пользователей рассказывать о своих успехах и проблемах.

    Создав loghouse более 2 лет назад, мы не были уверены в его перспективах, ожидая, что рынок и/или Open Source-сообщество предложат лучшие решения. Однако на сегодняшний день видим, что это жизнеспособный путь, который мы сами по-прежнему выбираем и используем на множестве обслуживаемых Kubernetes-кластеров.

    Будем рады любому содействию в улучшении и развитии loghouse. Если вам чего-то не хватает в loghouse — пишите в комментариях. Также мы, конечно, будем рады активности на GitHub.

    P.S.


    Читайте также в нашем блоге:

    Флант
    Специалисты по DevOps и Kubernetes

    Комментарии 20

      +1
      Есть ли шанс у Loghouse против (читать «в среде») cloud провайдера? GCP/AWS/Azure/AliCloud/yandex.cloud против StackDriver logs/Azure monitoring и прочее? Могут ли быть причины строит систему на нем (loghouse) и почему?
        0
        За всех (потенциальных пользователей loghouse) не скажу, т.к. продукт изначально появился как ответ на нашу внутреннюю потребность и отсутствие подходящих решений. Если кого-то устраивает завязка на конкретного провайдера — это нормальная ситуация, пусть отчасти и убивающая красоту K8s (cloud agnostic); специфика и выбор есть у каждого.
        В нашей компании мы стараемся создать для себя базовую универсальную инфраструктуру и использовать у всех клиентов унифицированные решения. Это облегчает поддержку. Соответственно, мы хотели иметь относительно легковесную систему сбора логов для себя, которая бы покрывала наши потребности и требовала минимальных навыков от наших инженеров. Поэтому и появился loghouse.
        Теперь к вопросу. Если коротко, то всё зависит от сложившейся ситуации в проекте. Проще пояснить на примерах:
        1. Клиент пришел к нас с legacy-инфраструктурой, которая умещалась в 1-2 сервера, и ему требуется развитие, чтобы его приложение соответствовало запросам бизнеса — в этом случае мы попробуем поставить loghouse и использовать его.
        2. Клиент собирает только ошибки и имеет обширный мониторинг. Такому клиенту логи особо и не нужны. Тут мы точно согласуем и поставим loghouse с минимальным размером диска, чтобы иметь возможность вести расследования проблем.
        3. Например, у клиента есть желание использовать EFK стэк или Graylog — мы не будем мешать клиенту и будем вместе с ним использовать этот стек, loghouse в кластере не будет.
        4. Клиент пользуется стеком от datadog, соответственно проще и логичнее подключить datadog к логам кластера при переезде в k8s, а не городить loghouse.
          0
          почему пункт 1 не мы поможем понять как перенести бизнес клиента в облачного провайдера <тут любимый провайдер>, чтобы рост/цена/что-то еще… удовлетворяли требования клиент. Права не понимаю какой смысл заниматься придумыванием велосипедов, когда уже везде есть десяток производителей «со всеми свистелками»? Не беру во внимание когда ваш клиент это NASA или госдеп или вы и ваш клиент живете на необитаемом острове?
          PS. я не критикую, сам люблю изобрести что-то изученное, но сугубо в некоммерческих целях.
            +4
            С нашей стороны: удобно иметь единое централизованное решение, потому что у разных клиентов разный выбор/возможности по провайдерам, а нам с ними всеми работать. Существующие решения нам не подходят (есть ответ ниже конкретно про Loki, который появился позже loghouse'а, но так не заставил нас забросить свою разработку, хотя мы в чем-то даже «надеялись» на это). Поэтому по умолчанию* предлагаем так.

            Со стороны клиента (небольшого и/или тому, кому не нужен cloud agnostic): все базовые потребности по логам закрываются, с уверенным запасом. Больше гибкости по выбору (и ценам) провайдеров, т.к. можно его делать без учета таких деталей — потребность уже закрыта «на стороне», вне зависимости от фич облака (а некоторым и облако не нужно, на своем железе развернуть тоже можно… в отличие от). Плюс, если речь про обслуживание у нас — поддержка осуществляется, а на случай чего — это Open Source.

            * Именно по умолчанию. Когда нужно нечто большее/специфичное, мы готовы браться и за другие варианты для логов, об этом писал выше.

            TL;DR: мы не за велосипеды. Нам самим было бы лучше иметь классное Open Source-решение, поддерживаемое большим сообществом (вне Фланта) и попросту интегрированное в наши инсталляции. Но это не то, что предлагают облачные сервисы, у них всё само-в-себе.

            P.S. И, конечно, всегда остается вкусовщина :-)
        +1

        Расскажите зачем там вообще backend, если clickhouse имеет http интерфейс и можно засылать SQL прямо с фронта?

          0
          В loghouse есть свой язык запросов, кроме того можно делать быстрые шаблоны запросов и сохранять их в базу. Но вам никто не мешает делать SQL запросы напрямую. Вы можете использовать tabix.io, он есть в поставке loghouse.
            0

            Это не камень в чей-то огород, просто я собирался (но скорее всего никогда не сделаю) делать такую морду для своих логов. Я понимаю, что у loghouse язык запросов по типу papertrail, но такие запросы можно и на фронте трансформировать в SQL. Остается только "сохранять запросы".

              0
              Так может стоит попробовать tabix?
                0

                papertrail синтаксис аналогично хочется + drilldown в выводe

          +1
          Берите loghouse-acceptor гошный вместо флюента. Правда, он новый 0.3 не поддерживает, получается.
            0
            Мы смотрим немного на другую схему, но пока не пришли к консенсусу.

            Кроме того, loghouse-acceptor не очень подходит для k8s
            Daemon accepts log only in syslog RFC5424 format from rsyslog. Later may be will be added some additinal protocols support.
              +1

              vectore.dev не пробовали? Хотелось бы его видеть вместо fluentd.

              0
              Кстати, loghouse-acceptor сделан так, что работать он будет и с новой версией. Всё в этом плане замечательно.
              0

              Спасибо за новую версию! Где можно найти документацию по запуску логхауса с внешним кластером кликхауса? Как-то не очень получается запустить helm chart с clickhouse.external true.


              Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(Endpoints.subsets[0].ports[0]): unknown field "targetPort" in io.k8s.api.core.v1.EndpointPort, ValidationError(Endpoints.subsets[0].ports[1]): unknown field "targetPort" in io.k8s.api.core.v1.EndpointPort]
              helm.go:75: [debug] error validating "": error validating data: [ValidationError(Endpoints.subsets[0].ports[0]): unknown field "targetPort" in io.k8s.api.core.v1.EndpointPort, ValidationError(Endpoints.subsets[0].ports[1]): unknown field "targetPort" in io.k8s.api.core.v1.EndpointPort]

              Или лучше на гитхаб?

                0
                Да, есть ошибка в объекте endpoint. Завтра сделаю hotfix chart
                  0
                  PR уже готов. В ближайшее время выкатим в резил.
                  0
                  Все просто классно, но уже появился стабильные loki с promtail и все свалили на них…
                    +1
                    Никто не спорит, что loki хорошее решение, однако нам видится у него ряд минусов:
                    • он не разворачивает json, поэтому часто он не удобен для аналитики
                    • наши клиенты и инженеры знают SQL и им удобно пользоваться такими инструментами как balerter
                    • С появившемся внешним clickhouse можно обеспечить любую скорость работы с логами. Да, loki умеет использовать внешнее хранилище, но оно не добавит скорости.


                    Дело в том, что на рынке cейчас много разных решений и все они имеют право на жизнь. При этом промышленный стандарт, типо helm, еще не появился
                    +1
                    CREATE TABLE logs
                    (
                    ....
                    )
                      ENGINE = MergeTree()
                      PARTITION BY (date, toHour(timestamp))
                      ORDER BY (timestamp, nsec,namespace, container_name)
                      TTL date + toIntervalDay(14)
                      SETTINGS index_granularity = 32768;

                    Почасовые партиции?
                    Сложно угадать сколько у вас в среднем падает логов ежедневно, но можно допустить что несколько сотен лямов в день, а с таким кол-вом можно спокойной жить и с партициями по месяцу.
                    Но учитывая ваш TTL подневные может вам и сойдут, но даже они далеко не всем нужны.
                    ORDER BY (timestamp, nsec, namespace, container_name)
                    Сомнительный ORDER BY, вообще по всем канонам в начало ORDER BY идут те поля, которые учавствуют в подавляющем большинстве запросов, что бы отбрасывать ненужные нам гранулы. С вашим ORDER BY так не выйдет.
                    timestamp и date вполне можно объединить в 1 столбец, тогда для партицирования использовать toYYYYMMDD(timestamp).
                    А для особенно смелых, можно использовать DateTime64, тогда и nsec можно там хранить.
                    Еще не видно никаких Codecs, они могут очень значительно повлиять на объем хранимых данных.
                    count(*)
                    Звездочка в count() ненужна, возможно может даже негативно влиять на скорость сканирования.

                    Вообще я бы в вашем случае попробовал, что то вроде
                    ORDER BY (namespace, container_name,timestamp, nsec)
                    И возможно, задал бы PRIMARY KEY покороче, допустим (namespace, container_name,timestamp)
                      +1
                      PARTITION BY (date, toHour(timestamp))
                      

                      У нас используются дневные партиции. Почасовые партиции мы тестировали, но в итоге отказались. Они есть в одном из коммитов. Спасибо, что заметили ошибку в статье.
                      Сложно угадать сколько у вас в среднем падает логов ежедневно, но можно допустить что несколько сотен лямов в день, а с таким кол-вом можно спокойной жить и с партициями по месяцу.

                      Дело в том, что мы искали вариант, который позволит бить данные на относительно не большие куски, которые, в случае чего, можно было бы легко удалить. Да и логи мы не храним месяцами. Так что разбиение по дням нас устраивает. Однако никто не мешает использовать свою кастомную схему.
                      ORDER BY (timestamp, nsec, namespace, container_name)

                      Очень часто мы ищем логи во временном промежутке в каком-то namespace. Переход на другую сортировку значительно замедлял просмотрщик логов.
                      Еще не видно никаких Codecs

                      Да, мы знаем про кодеки, однако сильная переработка схемы данных не была целью этого релиза.

                      Если у вас есть еще какие-то предложения — вы можете всегда их оформить issue на github.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое