Следующие шаги с Tracing

Tokio-console

tokio-console - это утилита, похожая на htop, которая позволяет вам видеть представление в реальном времени спэнов (span) и событий приложения. Она также может представлять "ресурсы", которые создала среда выполнения Tokio, такие как Задачи (Tasks). Это важно для понимания проблем производительности в процессе разработки.

Например, чтобы использовать tokio-console в проекте mini-redis, вам нужно включить функцию tracing для пакета Tokio:

# Обновите импорт tokio в вашем Cargo.toml
tokio = { version = "1", features = ["full", "tracing"] }

Примечание: Функция full не включает tracing.

Вам также нужно добавить зависимость от пакета console-subscriber. Этот крейт предоставляет реализацию Subscriber, которая заменит текущую, используемую mini-redis:

# Добавьте это в раздел dependencies вашего Cargo.toml
console-subscriber = "0.1.5"

Наконец, в src/bin/server.rs замените вызов tracing_subscriber на вызов console-subscriber:

Замените это:

#![allow(unused)]
fn main() {
use std::error::Error;
tracing_subscriber::fmt::try_init()?;
Ok::<(), Box<dyn Error + Send + Sync + 'static>>(())
}

...на это:

#![allow(unused)]
fn main() {
console_subscriber::init();
}

Это включит console_subscriber, что означает, что любая инструментация, относящаяся к tokio-console, будет записываться. Логирование в stdout все равно будет происходить (на основе значения переменной окружения RUST_LOG).

Теперь мы должны быть готовы снова запустить mini-redis, на этот раз используя флаг tokio_unstable (который необходим для включения tracing):

RUSTFLAGS="--cfg tokio_unstable" cargo run --bin mini-redis-server

Флаг tokio_unstable позволяет нам использовать дополнительные API, предоставляемые Tokio, которые в настоящее время не имеют гарантии стабильности (другими словами, для этих API допускаются критические изменения).

Осталось только запустить саму консоль в другом терминале. Самый простой способ сделать это - установить ее из crates.io:

cargo install --locked tokio-console

и затем запустить ее с помощью:

tokio-console

Первоначальный вид, который вы увидите, - это Задачи (Tasks) Tokio, которые в настоящее время выполняются. Пример: Представление Задач tokio-console

Она также может показывать Задачи в течение некоторого времени после их завершения (цвет для них будет серым). Вы можете сгенерировать некоторые трассировки, запустив пример hello world для mini-redis (это доступно в репозитории mini-redis):

cargo run --example hello_world

Если вы нажмете r, вы можете переключиться на представление Ресурсов (Resources). Это отображает семафоры, мьютексы и другие конструкции, которые используются средой выполнения Tokio. Пример: Представление Ресурсов tokio-console

Всякий раз, когда вам нужно проанализировать среду выполнения Tokio, чтобы лучше понять производительность вашего приложения, вы можете использовать tokio-console для просмотра того, что происходит в реальном времени, помогая вам обнаружить взаимные блокировки и другие проблемы.

Чтобы узнать больше о том, как использовать tokio-console, посетите ее страницу документации.

Интеграция с OpenTelemetry

OpenTelemetry (OTel) означает несколько вещей; во-первых, это открытая спецификация, определяющая модель данных для трассировок (traces) и метрик (metrics), которая может удовлетворить потребности большинства пользователей. Это также набор SDK для конкретных языков, предоставляющих инструментацию, чтобы трассировки и метрики могли отправляться из приложения. В-третьих, есть OpenTelemetry Collector - бинарный файл, который работает вместе с вашим приложением для сбора трассировок и метрик, в конечном итоге отправляя их поставщику телеметрии, такому как DataDog, Honeycomb или AWS X-Ray. Он также может отправлять данные в такие инструменты, как Prometheus.

Крейт opentelemetry предоставляет SDK OpenTelemetry для Rust, и мы будем использовать его для этого руководства.

В этом руководстве мы настроим mini-redis для отправки данных в Jaeger, который представляет собой пользовательский интерфейс для визуализации трассировок.

Чтобы запустить экземпляр Jaeger, вы можете использовать Docker:

docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest

Вы можете посетить страницу Jaeger, перейдя по адресу http://localhost:16686. Она будет выглядеть так: Пользовательский интерфейс Jaeger

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

Чтобы настроить mini-redis, нам сначала нужно добавить несколько зависимостей. Обновите ваш Cargo.toml следующим образом:

# Реализует типы, определенные в спецификации Otel
opentelemetry = "0.17.0"
# Интеграция между крейтом tracing и крейтом opentelemetry
tracing-opentelemetry = "0.17.2" 
# Позволяет экспортировать данные в Jaeger
opentelemetry-jaeger = "0.16.0"

Теперь в src/bin/server.rs добавьте следующие импорты:

#![allow(unused)]
fn main() {
use opentelemetry::global;
use tracing_subscriber::{
    fmt, layer::SubscriberExt, util::SubscriberInitExt,
};
}

Мы рассмотрим, что делает каждый из них, через мгновение.

Следующий шаг - заменить вызов tracing_subscriber на настройку OTel.

Замените это:

#![allow(unused)]
fn main() {
use std::error::Error;
tracing_subscriber::fmt::try_init()?;
Ok::<(), Box<dyn Error + Send + Sync + 'static>>(())
}

...на это:

#![allow(unused)]
fn main() {
use std::error::Error;
use opentelemetry::global;
use tracing_subscriber::{
    fmt, layer::SubscriberExt, util::SubscriberInitExt,
};
// Позволяет передавать контекст (т.е., идентификаторы трассировок) между сервисами
global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());
// Настраивает механизм, необходимый для экспорта данных в Jaeger
// Есть другие крейты OTel, которые предоставляют конвейеры для поставщиков,
// упомянутых ранее.
let tracer = opentelemetry_jaeger::new_pipeline()
    .with_service_name("mini-redis")
    .install_simple()?;

// Создаем слой tracing с настроенным трассировщиком
let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer);

// Трейты SubscriberExt и SubscriberInitExt необходимы для расширения
// Registry для принятия `opentelemetry` (типа OpenTelemetryLayer).
tracing_subscriber::registry()
    .with(opentelemetry)
    // Продолжаем логировать в stdout
    .with(fmt::Layer::default())
    .try_init()?;
Ok::<(), Box<dyn Error + Send + Sync + 'static>>(())
}

Теперь вы должны быть able to запустить mini-redis:

cargo run --bin mini-redis-server

В другом терминале запустите пример hello world (это доступно в репозитории mini-redis):

cargo run --example hello_world

Теперь обновите пользовательский интерфейс Jaeger, который у нас был открыт, и на главной странице поиска найдите "mini-redis" как один из вариантов в выпадающем списке Service.

Выберите этот вариант и нажмите кнопку "Find Traces". Это должно показать запрос, который мы только что сделали, запустив пример. Пользовательский интерфейс Jaeger, обзор mini-redis

Нажатие на трассировку должно показать вам детальное представление спэнов, которые были отправлены во время обработки примера hello world. Пользовательский интерфейс Jaeger, детали запроса mini-redis

На этом пока все! Вы можете исследовать это дальше, отправляя больше запросов, добавляя дополнительную инструментацию для mini-redis или настраивая OTel с поставщиком телеметрии (вместо экземпляра Jaeger, который мы запускаем локально). Для последнего вам может понадобиться подключить дополнительный крейт (например, для отправки данных в OTel Collector вам понадобится крейт opentelemetry-otlp). Есть много примеров, доступных в репозитории opentelemetry-rust.

Примечание: Репозиторий mini-redis уже содержит полный пример OpenTelemetry с AWS X-Ray, подробности которого можно найти в README, а также в файлах Cargo.toml и src/bin/server.rs.