Трассировка в Akka при помощи библиотеки Kamon
17 декабря 2015
Ранее в заметке Делаем метрики и мониторинг для Akka при помощи Kamon мы уже познакомились с некоторыми возможностями Kamon. Правда, нельзя сказать, что возможности эти были особо впечатляющими, так как метрики можно вполне успешно писать и безо всякого Kamon. Сегодня же мы познакомимся с некоторыми другими средствами, предоставляемыми этой несколько спорной, но определенно очень мощной библиотекой.
Первая довольно часто встречающаяся на практике задача — неявное пробрасывание некоторого контекста между акторами. Допустим, актор A1 проставляет некоторый контест, например, информацию о пользователе, запросе, с которым он пришел в бэкенд, а также, возможно, некоторых параметрах этого запроса. Затем актор A1 шлет запрос A2, тот шлет A3, и так далее, до A42. Отметим, что если в проекте используется Akka Cluster, акторы эти могут быть на очень даже разных машинах. В какой-то момент мы решили, что в акторе A42 неплохо бы получить информацию о контексте, полученном в акторе A1. Можно, конечно, пробрасывать этот контекст явно во всех сообщениях между акторами. Или менее явно, если воспользоваться имплиситами. Но для этого нам понадобится поправить код как минимум в 42 местах! А возможно и больше, так как акторы могут обмениваться несколькими типам сообщений.
К счастью, с помощью Kamon эту проблему можно решить намного проще.
В акторе A1 пишем что-то вроде:
"TestContext",
traceToken = Some(s"dummy-trace-token"),
autoFinish = true) {
// ... тут обычный код с запросами к остальным акторам ...
}
Теперь в акторе A42 можно написать:
… и получить текущий контекст, в данном случае строчку «dummy-trace-token». Понятно, что в общем случае нам хотелось бы передавать что-то чуть более интересное, чем обычные строки. Это легко реализовать, создав новый case class с поддержкой сериализации в JSON. Работает такое пробрасывание контекста на магии AspectJ, поэтому в IntelliJ IDEA на забудьте в Run → Edit Configurations… → VM Options прописать -javaagent:/path/to/aspectjweaver-1.8.2.jar
. Также этот параметр требуется передавать JVM при запуске приложения в продакте, поэтому не забудьте поправить wrapper.conf или что вы там используете в проекте.
Не правда ли, приведенное выше решение лучше, чем внесение правок в 42 местах?
Рассмотрим еще пример. Когда в большом (и особенно — распределенном!) проекте что-то где-то начинает тормозить, определить, что именно, где именно и почему тормозит не всегда бывает просто. Kamon помогает нам и здесь.
Определим такой вот актор для сборки трейсов:
import akka.actor.{ActorLogging, Actor}
import kamon.trace.TraceInfo
class TraceSubscriber extends Actor with ActorLogging {
var traceNumber = 0
override def receive: Receive = {
case inf: TraceInfo =>
traceNumber = traceNumber + 1
val segmentsNumber = inf.segments.size
log.info(
s"""|Trace number $traceNumber ---
|Trace Name: ${inf.name},
|timestamp: ${inf.timestamp},
|elapsedTime: ${inf.elapsedTime},
|segmentsNumber: $segmentsNumber
|""".stripMargin.replace('\n', ' ')
)
}
}
Подпишем его на трейсы:
system.actorOf(Props(new TraceSubscriber), "traceSubscriber")
}
Kamon.tracer.subscribe(traceSubscriber)
Теперь внутри блока Tracer.withNewContext (см выше) мы можем определять так называемые «сегменты»:
"Main/sayHello",
"ask",
"me.eax.example") {
// ... тут обычный код ...
}
При выходе из блока Tracer.withNewContext в актор traceSubscriber магическим образом будет прилетать информация обо всех сегментах, выполненных в рамках контекста. Помимо информации, используемой в примере кода выше, можно также получить данные и о каждом отдельном сегменте, включая время, которое этот сегмент выполнялся:
Само собой разумеется, частоту, с которой прилетают сэмплы трейсов, можно настроить через конфиг.
Полную версию исходного кода к этой заметке можно найти на GitHub. Обратите особое внимание на использование плагина sbt-aspectj, подкладывание файла META-INF/aop.xml, а также настройки проекта в build.sbt. Следует понимать, что этот пост поверхностно описывает сравнительно простой пример, а больше подробной информации о представленном выше функционале вы найдете на официальном сайте Kamon.
А используете ли вы в своих проектах описанные возможности Kamon?
Метки: Akka, Scala, Функциональное программирование.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.