使用Quickwit、Jaeger和Grafana監(jiān)控您的Rust應(yīng)用程序
你可能已經(jīng)看過了Lucas Palmieri的博客文章Are we observable yet? An introduction to Rust telemetry。如果你還沒有看過,我們建議閱讀一下,因?yàn)樗峁┝艘粋€(gè)全面的介紹,介紹了如何處理 Rust 代碼中的日志。
然而,僅僅記錄日志可能是不夠的,特別是在分布式架構(gòu)中。在 Quickwit 中,我們經(jīng)常使用跟蹤來理解性能瓶頸并提高速度。當(dāng)我們遇到 Quickwit 的搜索響應(yīng)緩慢時(shí),我們經(jīng)常會(huì)問自己:是什么導(dǎo)致了減速?是網(wǎng)絡(luò)相關(guān)的問題,磁盤 I/O 還是過多的 CPU 使用?
在本博客文章中,我們將展示如何為 Rust 應(yīng)用程序進(jìn)行測(cè)量,并生成跟蹤數(shù)據(jù),從 DevOps 視角利用它們。我們的目標(biāo)將是雙重的:
使用廣泛認(rèn)可的 Jaeger UI 分析跟蹤,以獲取有關(guān)應(yīng)用程序行為的見解。
從這些跟蹤數(shù)據(jù)中派生 RED(速率、錯(cuò)誤和持續(xù)時(shí)間)指標(biāo),并在 Grafana 中監(jiān)視它們。如果您想進(jìn)一步了解,我們建議參考以下資源:Weaveworks 的 RED 方法和 Google SRE 書籍中有關(guān)監(jiān)控分布式系統(tǒng)的部分。
現(xiàn)在,讓我們深入介紹步驟,其中我們將涵蓋以下關(guān)鍵方面:
為使用 Actix 構(gòu)建的簡(jiǎn)單 Web API 進(jìn)行測(cè)量。
將您的跟蹤和指標(biāo)數(shù)據(jù)推送到 Quickwit。
在 Jaeger UI 中檢測(cè)、診斷和解決問題。
在 Grafana 中監(jiān)視您的應(yīng)用程序的 RED 指標(biāo)(速率、錯(cuò)誤、持續(xù)時(shí)間)。
在深入了解之前,請(qǐng)確保您的系統(tǒng)上已安裝并正確運(yùn)行以下軟件:
Rust 1.68+
Docker
如果您仍在運(yùn)行舊版本的 Docker,則需要安裝docker-compose。
構(gòu)建并測(cè)量 Rust 應(yīng)用
我們將使用 Actix Web 框架創(chuàng)建一個(gè)基本的 Rust 應(yīng)用程序。這個(gè)應(yīng)用程序是一個(gè)包含單個(gè)端點(diǎn)的 Web API。它將從受歡迎的 JSONPlaceholder 公共 Web API 獲取帖子及其評(píng)論,并將它們顯示為 JSON。為了更好地了解我們的應(yīng)用程序生命周期并可能優(yōu)化它,我們將確保測(cè)量以下例程:
從 /posts 獲取帖子。
獲取每個(gè)帖子的評(píng)論 /posts/1/comments
創(chuàng)建一個(gè)名為rust-app-tracing的新目錄。在終端中切換到該目錄,并運(yùn)行以下命令初始化一個(gè)新的 Rust 項(xiàng)目。
cargo new web-api
讓我們還要確保在web-api/Cargo.toml文件中擁有所需的依賴項(xiàng)。
actix-web:用于在 Rust 中構(gòu)建 Web 應(yīng)用程序的快速 Web 框架。
actix-web-opentelemetry:actix-web框架的 open-telemetry 擴(kuò)展。
opentelemetry:Rust 的核心 open-telemetry SDK,包括跟蹤和指標(biāo)。
opentelemetry-otlp:提供各種 open-telemetry 導(dǎo)出器的 crate。
reqwest:提供一個(gè)直觀的 API 來進(jìn)行 HTTP 請(qǐng)求。
tokio:為我們的應(yīng)用程序提供異步運(yùn)行時(shí)。
Web API 應(yīng)用程序代碼
首先,讓我們通過創(chuàng)建一個(gè)名為telemetry.rs的文件來配置應(yīng)用程序跟蹤,我們將在其中處理所有跟蹤配置。
// telemetry.rs ... const SERVICE_NAME: &'static str = "quickwit-jaeger-demo"; pub fn init_telemetry(exporter_endpoint: &str) { // Create a gRPC exporter let exporter = opentelemetry_otlp::new_exporter() .tonic() .with_endpoint(exporter_endpoint); // Define a tracer let tracer = opentelemetry_otlp::new_pipeline() .tracing() .with_exporter(exporter) .with_trace_config( trace::new(vec![KeyValue::new( opentelemetry_semantic_conventions::SERVICE_NAME, SERVICE_NAME.to_string(), )])), ) .install_batch(opentelemetry::Tokio) .expect("Error: Failed to initialize the tracer."); // Define a subscriber. let subscriber = Registry::default(); // Level filter layer to filter traces based on level (trace, debug, info, warn, error). let level_filter_layer = EnvFilter::new("INFO")); // Layer for adding our configured tracer. let tracing_layer = tracing_opentelemetry::layer().with_tracer(tracer); // Layer for printing spans to stdout let formatting_layer = BunyanFormattingLayer::new( SERVICE_NAME.to_string(), std::stdout, ); global::new()); subscriber .with(level_filter_layer) .with(tracing_layer) .with(JsonStorageLayer) .with(formatting_layer) .init() }
Copy 接下來,我們將實(shí)現(xiàn)我們的 API 端點(diǎn),并在處理程序函數(shù)中添加一些測(cè)量代碼。重要的是要注意,我們的重點(diǎn)不在于此應(yīng)用程序的功能,而在于從應(yīng)用程序生成有意義且可利用的跟蹤數(shù)據(jù)。
首先,我們有一些模型文件,允許我們對(duì)post和comment進(jìn)行序列化和反序列化。
//models.rs ... #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Post { pub user_id: i64, pub id: i64, pub title: String, pub body: String, #[serde(default)] pub comments: Vec, } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Comment { pub post_id: i64, pub id: i64, pub name: String, pub email: String, pub body: String, }
接下來,讓我們處理 API 端點(diǎn)處理程序。請(qǐng)注意,某些函數(shù)上裝飾有instrument屬性。這是我們?nèi)绾卧谔幚沓绦蚝瘮?shù)和它用于執(zhí)行任務(wù)的后續(xù)函數(shù)上啟用跟蹤的方法。
// lib.rs ... const BASE_API_URL: &'static str = "https://jsonplaceholder.typicode.com"; // The get_post handler #[instrument(level = "info", name = "get_posts", skip_all)] #[get("")] async fn get_posts() -> Result { // Randomly simulate errors in request handling let choices = [200, 400, 401, 200, 500, 501, 200, 500]; let mut rng = rand::thread_rng(); let choice = choices.choose(&mut rng) .unwrap() .clone(); match choice { 400..=401 => Ok(HttpResponse::from_u16(choice).unwrap())), 500..=501 => Ok(HttpResponse::from_u16(choice).unwrap())), _ => { let posts = fetch_posts(20) .await .map_err(actix_web::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(posts)) } } } // Fetching posts with a limit. #[instrument(level = "info", name = "fetch_posts")] async fn fetch_posts(limit: usize) -> anyhow::Result
在上面的片段中,我們僅發(fā)送跟蹤。也可以使用可靠的日志收集器來收集日志并將其發(fā)送到Quickwit或其他后端。
使用 Quickwit 收集跟蹤數(shù)據(jù)
現(xiàn)在我們已經(jīng)構(gòu)建了應(yīng)用程序。讓我們與 Quickwit 一起運(yùn)行,并確保生成的跟蹤被 Quickwit 索引。 與我們?cè)谥暗牟┛臀恼轮兴龅牟煌覀儗?chuàng)建一個(gè) docker-compose 文件來簡(jiǎn)化 Quickwit、Jaeger 和 Grafana 之間的設(shè)置。以下 docker-compose 文件包含所有必要的配置。
QW_ENABLE_OTLP_ENDPOINT:允許 Quickwit 接受和攝取跟蹤和日志數(shù)據(jù)。
SPAN_STORAGE_TYPE、GRPC_STORAGE_SERVER、QW_ENABLE_JAEGER_ENDPOINT:允許 Jaeger 從 Quickwit 拉取跟蹤和日志以進(jìn)行分析。
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS:允許我們?cè)?Grafana 中加載特定的插件。
# docker-compose.yaml version: '3' services: quickwit: image: quickwit/quickwit:latest command: run restart: always environment: QW_ENABLE_OTLP_ENDPOINT: true QW_ENABLE_JAEGER_ENDPOINT: true ports: - '7280:7280' - '7281:7281' volumes: - ./qwdata:/quickwit/qwdata jaeger: image: jaegertracing/jaeger-query:latest restart: always depends_on: - quickwit environment: SPAN_STORAGE_TYPE: 'grpc-plugin' GRPC_STORAGE_SERVER: 'quickwit:7281' ports: - '16686:16686' grafana: image: grafana/grafana-enterprise:latest restart: always user: root depends_on: - quickwit environment: GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: 'quickwit-quickwit-datasource' ports: - '3000:3000' volumes: - ./grafana-storage:/var/lib/grafana
有了這個(gè) docker-compose 文件,讓我們?cè)陧?xiàng)目目錄中創(chuàng)建所需的目錄以使服務(wù)正確運(yùn)行。創(chuàng)建qwdata目錄以存儲(chǔ) Quickwit 數(shù)據(jù)。 然后,下載并將 Quickwit Grafana 數(shù)據(jù)源插件放置在預(yù)期位置。
wget https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.2.0/quickwit-quickwit-datasource-0.2.0.zip && mkdir -p grafana-storage/plugins && unzip quickwit-quickwit-datasource-0.2.0.zip -d grafana-storage/plugins
現(xiàn)在讓我們通過運(yùn)行以下命令啟動(dòng)所有服務(wù)(Quickwit、Jaeger、Grafana): 如果沒有問題,現(xiàn)在我們可以運(yùn)行 Web 應(yīng)用程序并使用 cURL 幾次命中http://localhost:9000/post端點(diǎn),以生成一些跟蹤。
curl -X GET http://localhost:9000/post 等待約 10 秒鐘,新的跟蹤將被索引并可供搜索。 您現(xiàn)在可以通過使用 cURL 搜索otel-traces-v0_6索引來檢查 Quickwit 是否已索引跟蹤數(shù)據(jù)。
curl -X POST http://localhost:7280/api/v1/otel-traces-v0_6/search -H 'Content-Type: application/json' -d '{ "query": "service_name:quickwit-jaeger-demo" }'
您也可以使用 Quickwit UIhttp://localhost:7280/ui/search查看數(shù)據(jù)。
Jaeger 容器已經(jīng)在運(yùn)行中了,可以轉(zhuǎn)到http://localhost:16686查看我們的應(yīng)用程序跟蹤。
從上面的截圖可以看出,我們依次為每個(gè)帖子獲取評(píng)論。也就是說,我們一個(gè)接一個(gè)地進(jìn)行了二十次請(qǐng)求。這使得整個(gè)請(qǐng)求處理時(shí)間更長(zhǎng)(上面為 4.39s)。 但我們能不能更好地做? 在 Rust 開發(fā)人員擁有的所有優(yōu)秀工具中,答案是顯而易見的 "是的!"。讓我們利用 Tokio 和 Rustfutures crate的異步流特性,通過并行獲取評(píng)論。 讓我們更新我們的fetch_posts函數(shù),以批量并行運(yùn)行請(qǐng)求,每次同時(shí)進(jìn)行十個(gè)請(qǐng)求。這應(yīng)該可以進(jìn)一步加速事情。
// Fetching posts with a limit. #[instrument(level = "info", name = "fetch_posts")] async fn fetch_posts(limit: usize) -> anyhow::Result
通過這個(gè)改變,你會(huì)注意到我們現(xiàn)在處理請(qǐng)求的時(shí)間大約為2.46秒,同時(shí)你也可以直觀地看到我們的請(qǐng)求處理程序在運(yùn)行期間最多同時(shí)運(yùn)行了十個(gè)fetch_comments請(qǐng)求。
Jaeger 適用于對(duì)單個(gè)跟蹤進(jìn)行專注檢查。但如果我們想要監(jiān)視服務(wù)的延遲呢?如果我們想要計(jì)算具有給定跟蹤元數(shù)據(jù)的錯(cuò)誤或請(qǐng)求的數(shù)量呢? 這就是 Grafana 儀表板的用處。我們想要從我們的跟蹤構(gòu)建 RED 指標(biāo)并在 Grafana 中可視化它們。 轉(zhuǎn)到http://localhost:3000/login,使用admin作為用戶名和密碼登錄。 登錄后,我們可以使用新發(fā)布的Quickwit 數(shù)據(jù)源插件連接到 Quickwit 并查詢我們的應(yīng)用程序跟蹤。
為了使 RED 指標(biāo)監(jiān)控過程更加方便,我們準(zhǔn)備了一個(gè)預(yù)配置的Grafana 儀表板供您下載并導(dǎo)入到您的 Grafana 實(shí)例中。 該儀表板作為一種強(qiáng)大的工具,用于可視化和理解性能。它包括三個(gè)面板:
第一個(gè)面板顯示每分鐘的請(qǐng)求數(shù)量。
第二個(gè)面板顯示每分鐘的錯(cuò)誤數(shù)量。
第三個(gè)面板呈現(xiàn)每分鐘請(qǐng)求的持續(xù)時(shí)間百分位數(shù)。
為了觀察這些指標(biāo)的運(yùn)行情況,您可以使用 HTTP 基準(zhǔn)測(cè)試工具,甚至可以使用本教程提供的此腳本發(fā)送多個(gè)并發(fā)請(qǐng)求到您的 Rust 應(yīng)用程序。 現(xiàn)在讓我們來看一下 Grafana 儀表板的截圖,展示了運(yùn)行腳本后的指標(biāo)情況。
就是這樣!在這篇博客文章中,我們超越了基本的日志記錄,深入了解了分布式跟蹤以及如何使用它來監(jiān)視應(yīng)用程序性能。 我們構(gòu)建 Quickwit 的經(jīng)驗(yàn)告訴我們,分布式跟蹤對(duì)于了解由于調(diào)用 S3 或在本地磁盤上讀取數(shù)據(jù)而失去時(shí)間的位置非常重要。我們希望它對(duì)您也有所幫助 :) 愉快的編碼和觀察!
審核編輯:湯梓紅
-
cpu
+關(guān)注
關(guān)注
68文章
10829瀏覽量
211196 -
Web
+關(guān)注
關(guān)注
2文章
1257瀏覽量
69368 -
API
+關(guān)注
關(guān)注
2文章
1487瀏覽量
61833 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3245瀏覽量
57615 -
Rust
+關(guān)注
關(guān)注
1文章
228瀏覽量
6574
原文標(biāo)題:【Rust日?qǐng)?bào)】2023-06-20 使用Quickwit、Jaeger和Grafana監(jiān)控您的Rust應(yīng)用程序
文章出處:【微信號(hào):Rust語言中文社區(qū),微信公眾號(hào):Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論