Делаем метрики и мониторинг для Akka при помощи Kamon

24 декабря 2014

Когда вы работаете с Akka, и вообще акторами, очень многое может пойти не так. Очереди сообщений могут переполняться, актор может начать перемножать матрички, заняв собой трэд, или, наконец, где-то могут просто начать сыпаться эксепшены. Пока у вас одна нода и мало пользователей, можно, конечно, просто быть на телефоне 24/7 и разбираться в проблемах по логам, отладочным ручкам, ну или remsh, если вы пишите на Erlang. Как только нод становится больше и проект выходит из альфы, такой подход становится совершенно нерабочим. На помощь приходит Kamon.

Примечание: Кстати, если вдруг вам доводилось слышать про Typesafe Console, знайте, что эта штука умерла. Нечто похожее осталось в Activator UI (который вскользь упоминался в заметке про Play), но оно не особо удобно и применимо только во время разработки, и то с натяжкой. Интересно, что сам Typesafe не особо трубил о смерти Typesafe Console и даже в списке рассылки разместил соответствующую информацию 1-го апреля, чтобы окончательно всех запутать.

Kamon — эта такая штука для сбора метрик в проектах, использующих Akka, Play Framework или Spray. Вам лишь нужно сказать «использовать Kamon» и указать ему, куда нужно складывать метрики. Все остальное — дело техники. Kamon умеет писать метрики в StatsD, Datadog и New Relic. При этом Kamon очень гибок. В частности, вы можете сказать «собирай информацию обо всех акторах, кроме» или наоборот, «собирай метрики только для таких-то акторов».

На самом деле, помощью Kamon можно не только репортить метрики, но и пробрасывать трейсы-контексты, а также более правильно определять причину ask timeout. Библиотека постоянно развивается, и в будущих версиях может появится еще какой-нибудь полезный функционал. Однако в рамках этой заметки мы сосредоточимся именно на метриках.

Для определенности скажем, что мы решили использовать Datadog. В принципе, если вы решите использовать, например, StatsD, то настройка будет мало чем отличаться.

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

Запись метрик в Datadog происходит не напрямую, а через Datadog Agent. Это такой демон, выполняющий несколько функций, и разделенный на компоненты, каждый из которых выполняет только одну функцию:

  • Forwarder отвечает за отправку всех метрик в Datadog;
  • Collector собирает информацию о машине (память, cpu, диск, трафик);
  • Dogstatsd предоставляет StatsD API для записи метрик приложениями;
  • Supervisord рулит предыдущими тремя компонентами;

По умолчанию включены все компоненты, но при необходимости, например, можно отключить collector.

Информацию по установке агента вы можете найти здесь или, если вы уже зарегистрированы в системе, в разделе Integrations → Agent. В последнем предлагаются более быстрые варианты в стиле curl ... | sh.

В Ubuntu Linux после установки агента рулить им можно как-то так:

sudo service datadog-agent restart

Конфиг агента (api key, какой интерфейс слушать и тд):

/etc/dd-agent/datadog.conf

Логи агента с разбивкой по названным выше компонентам:

/var/log/datadog/

Описание протокола dogstatsd (который представляет собой расширенный протокол StatsD) вы можете найти здесь. Вот так, к примеру, можно записывать счетчики:

echo "test.counter:10|c" | nc -u -w0 127.0.0.1 8125

Хорошо, теперь нам есть, куда писать метрики. Осталось устроить все на стороне приложения. Пример того, как это делается, можно найти в этом репозитории. За основу мною был взять пример, который генерирует Typesafe Activator. Как оказалось, в этом примере многое нужно доводить до ума. Рассмотрим основные моменты.

Файл build.sbt:

val kamonVersion = "0.3.4"

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor" % "2.3.5",
  "io.kamon" %% "kamon-core" % kamonVersion,
  "io.kamon" %% "kamon-datadog" % kamonVersion,
  "io.kamon" %% "kamon-log-reporter" % kamonVersion,
  "io.kamon" %% "kamon-system-metrics" % kamonVersion,
  "org.aspectj" % "aspectjweaver" % "1.8.2"
)

aspectjSettings

javaOptions <++= AspectjKeys.weaverOptions in Aspectj

fork in run := true

Здесь самое главное — это прикручивание AspectJ, через который Kamon и делает всю свою магию. Также обратите внимание на используемый здесь пакет kamon-system-metrics. Он позволяет собирать разные полезные метрики о самой JVM, в том числе время, потраченное на сборку мусора.

Файл project/plugins.sbt:

resolvers += Resolver.typesafeRepo("releases")

addSbtPlugin("com.typesafe.sbt" % "sbt-aspectj" % "0.10.0")

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

Благодаря плагину sbt-aspectj Kamon будет работать при запуске приложения через sbt run.

Файл src/main/resources/application.conf:

akka {
  loglevel = INFO
  extensions = ["kamon.metric.Metrics", "kamon.datadog.Datadog",
                "kamon.system.SystemMetrics"]
}

kamon {
  metrics {
    filters = [
      {
        actor {
          includes = [ "user/*", "user/worker-*" ]
          excludes = [ "system/*" ]
        }
      },
      {
        trace {
          includes = [ "*" ]
          excludes = []
        }
      }
    ]
  }

  datadog {
    hostname = "127.0.0.1"
    port = 8125

    flush-interval = 1 second

    max-packet-size = 1024 bytes

    report-system-metrics = true

    includes {
      actor       = [ "*" ]
      trace       = [ "*" ]
      dispatcher  = [ "*" ]
    }

    application-name = "kamon_test"
  }
}

Здесь мы прикручиваем компоненты Kamon’а в виде расширений для Akka и настраиваем их — по каким акторам собирать метрики, куда и как часто эти метрики отправлять, и так далее.

Еще интересен файл src/main/scala/sample/kamon/RandomNumberActor.scala:

import kamon.Kamon
import kamon.metric.UserMetrics

// ...

val counter = Kamon(UserMetrics).registerCounter("generate-number")

// ...

counter.increment()

Как видите, здесь приводится пример использования пользовательских метрик.

Если все было сделано правильно, то при запуске приложения в Datadog посыпятся метрики, при помощи которых вы без труда сможете строить графики вроде следующих.

График времени обработки сообщения в DataDog

Здесь мы следим за временем обработки сообщений заданным актором (максимум и 95-ый процентиль). Заметьте, что все метрики называются одинаково для всех акторов. Но при этом мы можем фильтровать метрики по имени актора или хосту, на котором крутится нода, поскольку метрики идут вместе с тэгами (см {actor:... внизу графика). Кроме того, мы можем группировать метрики по множеству акторов, поскольку Kamon также снабжает метрики тэгами с префиксами, полученными из полного имени (пути) актора.

График длины очереди сообщений в DataDog

А этот график недвусмысленно намекает нам, что у актора копятся сообщения в очереди. Если вы недавно приступили к настройке Datadog, незамедлительно настройте алерты на эту ситуацию!

При использовании Kamon есть один важный нюанс. Допустим, вы собираете standalone jar. Тогда помимо этого jar вам придется включить в deb-пакет или чем вы там катите еще и aspectjweaver, а приложение запускать как-то так:

java -javaagent:aspectjweaver-1.8.2.jar -jar kamon-test.jar

Но упаковка в deb-пакеты — это уже тема для отдельной заметки.

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

Дополнение: Если вы вдруг используете Play, примите во внимание, что он инициализирует ActorSystem лениво, поэтому Kamon не будет слать никаких метрик до тех пор, пока кто-нибудь не пошлет первый HTTP-запрос. Для решения этой проблемы можно принудительно вычислить ActorSystem в onStart.

Дополнение: На момент написания этих строк Kamon репортил в качестве GC time суммарное время в миллисекундах, потраченное на сборку мусора с момента запуска приложения. Это поведение может измениться в будущем. А пока не пугайтесь, если увидите на графиках GC time в районе пятнадцати минут. Вообще, как оказалось, мониторинг GC time существенно усложняется, например, тем, что сборка мусора может происходить параллельно с работой кода самого приложения. Тем не менее, если вы полны решимости написать пользовательские метрики для наблюдения за GC, кое-какие примеры кода можно найти здесь и тут.

Дополнение: Вас также могут заинтересовать статьи Трассировка в Akka при помощи библиотеки Kamon и Устанавливаем связку из Prometheus и Grafana.

Метки: , , .


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