0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用Quickwit、Jaeger和Grafana监控您的Rust应用程序

jf_wN0SrCdH 来源:Rust语言中文社区 作者:Rust语言中文社区 2023-06-27 11:36 次阅读

使用Quickwit、Jaeger和Grafana监控您的Rust应用程序

你可能已经看过了Lucas Palmieri的博客文章Are we observable yet? An introduction to Rust telemetry。如果你还没有看过,我们建议阅读一下,因为它提供了一个全面的介绍,介绍了如何处理 Rust 代码中的日志。

然而,仅仅记录日志可能是不够的,特别是在分布式架构中。在 Quickwit 中,我们经常使用跟踪来理解性能瓶颈并提高速度。当我们遇到 Quickwit 的搜索响应缓慢时,我们经常会问自己:是什么导致了减速?是网络相关的问题,磁盘 I/O 还是过多的 CPU 使用?

在本博客文章中,我们将展示如何为 Rust 应用程序进行测量,并生成跟踪数据,从 DevOps 视角利用它们。我们的目标将是双重的:

使用广泛认可的 Jaeger UI 分析跟踪,以获取有关应用程序行为的见解。

从这些跟踪数据中派生 RED(速率、错误和持续时间)指标,并在 Grafana 中监视它们。如果您想进一步了解,我们建议参考以下资源:Weaveworks 的 RED 方法和 Google SRE 书籍中有关监控分布式系统的部分。

现在,让我们深入介绍步骤,其中我们将涵盖以下关键方面:

为使用 Actix 构建的简单 Web API 进行测量。

将您的跟踪和指标数据推送到 Quickwit。

在 Jaeger UI 中检测、诊断和解决问题。

在 Grafana 中监视您的应用程序的 RED 指标(速率、错误、持续时间)。

在深入了解之前,请确保您的系统上已安装并正确运行以下软件:

Rust 1.68+

Docker

如果您仍在运行旧版本的 Docker,则需要安装docker-compose。

构建并测量 Rust 应用

我们将使用 Actix Web 框架创建一个基本的 Rust 应用程序。这个应用程序是一个包含单个端点的 Web API。它将从受欢迎的 JSONPlaceholder 公共 Web API 获取帖子及其评论,并将它们显示为 JSON。为了更好地了解我们的应用程序生命周期并可能优化它,我们将确保测量以下例程:

从 /posts 获取帖子。

获取每个帖子的评论 /posts/1/comments

创建一个名为rust-app-tracing的新目录。在终端中切换到该目录,并运行以下命令初始化一个新的 Rust 项目。

cargo new web-api

让我们还要确保在web-api/Cargo.toml文件中拥有所需的依赖项。

actix-web:用于在 Rust 中构建 Web 应用程序的快速 Web 框架。

actix-web-opentelemetry:actix-web框架的 open-telemetry 扩展。

opentelemetry:Rust 的核心 open-telemetry SDK,包括跟踪和指标。

opentelemetry-otlp:提供各种 open-telemetry 导出器的 crate。

reqwest:提供一个直观的 API 来进行 HTTP 请求。

tokio:为我们的应用程序提供异步运行时。

Web API 应用程序代码

首先,让我们通过创建一个名为telemetry.rs的文件来配置应用程序跟踪,我们将在其中处理所有跟踪配置。


// 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 接下来,我们将实现我们的 API 端点,并在处理程序函数中添加一些测量代码。重要的是要注意,我们的重点不在于此应用程序的功能,而在于从应用程序生成有意义且可利用的跟踪数据。

首先,我们有一些模型文件,允许我们对post和comment进行序列化和反序列化。

//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 端点处理程序。请注意,某些函数上装饰有instrument属性。这是我们如何在处理程序函数和它用于执行任务的后续函数上启用跟踪的方法。


// 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 { let client = Client::new(); let url = format!("{}/posts", BASE_API_URL); let mut posts: Vec = request_url(&client, &url).await?; posts.truncate(limit); let post_idx_to_ids: Vec<(usize, i64)> = posts.iter().enumerate().map(|(idx, post)| (idx, post.id)).collect(); // fetch post comments one after another. for (index, post_id) in post_idx_to_ids { let comments = fetch_comments(&client, post_id).await?; posts[index].comments = comments } Ok(posts) } ...


在上面的片段中,我们仅发送跟踪。也可以使用可靠的日志收集器来收集日志并将其发送到Quickwit或其他后端。

使用 Quickwit 收集跟踪数据

现在我们已经构建了应用程序。让我们与 Quickwit 一起运行,并确保生成的跟踪被 Quickwit 索引。 与我们在之前的博客文章中所做的不同,我们将创建一个 docker-compose 文件来简化 Quickwit、Jaeger 和 Grafana 之间的设置。以下 docker-compose 文件包含所有必要的配置。

QW_ENABLE_OTLP_ENDPOINT:允许 Quickwit 接受和摄取跟踪和日志数据。

SPAN_STORAGE_TYPE、GRPC_STORAGE_SERVER、QW_ENABLE_JAEGER_ENDPOINT:允许 Jaeger 从 Quickwit 拉取跟踪和日志以进行分析。

GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS:允许我们在 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



有了这个 docker-compose 文件,让我们在项目目录中创建所需的目录以使服务正确运行。创建qwdata目录以存储 Quickwit 数据。 然后,下载并将 Quickwit Grafana 数据源插件放置在预期位置。

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



现在让我们通过运行以下命令启动所有服务(Quickwit、Jaeger、Grafana): 如果没有问题,现在我们可以运行 Web 应用程序并使用 cURL 几次命中http://localhost:9000/post端点,以生成一些跟踪。

curl -X GET http://localhost:9000/post 等待约 10 秒钟,新的跟踪将被索引并可供搜索。 您现在可以通过使用 cURL 搜索otel-traces-v0_6索引来检查 Quickwit 是否已索引跟踪数据。

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查看数据。76e0d844-104a-11ee-962d-dac502259ad0.png

Jaeger 容器已经在运行中了,可以转到http://localhost:16686查看我们的应用程序跟踪。

77395e92-104a-11ee-962d-dac502259ad0.png

从上面的截图可以看出,我们依次为每个帖子获取评论。也就是说,我们一个接一个地进行了二十次请求。这使得整个请求处理时间更长(上面为 4.39s)。 但我们能不能更好地做? 在 Rust 开发人员拥有的所有优秀工具中,答案是显而易见的 "是的!"。让我们利用 Tokio 和 Rustfutures crate的异步流特性,通过并行获取评论。 让我们更新我们的fetch_posts函数,以批量并行运行请求,每次同时进行十个请求。这应该可以进一步加速事情。

// Fetching posts with a limit. #[instrument(level = "info", name = "fetch_posts")] async fn fetch_posts(limit: usize) -> anyhow::Result { ... // fetch post comments concurrently. let tasks: Vec<_> = post_idx_to_ids .into_iter() .map(|(index, post_id)| { let moved_client = client.clone(); async move { let comments_fetch_result = fetch_comments(&moved_client, post_id).await; (index, comments_fetch_result) } }) .collect(); let mut stream = futures::iter(tasks) .buffer_unordered(10); // batch of 10 request at a time while let Some((index, comments_fetch_result)) = stream.next().await { let comments = comments_fetch_result?; posts[index].comments = comments; } ... }


通过这个改变,你会注意到我们现在处理请求的时间大约为2.46秒,同时你也可以直观地看到我们的请求处理程序在运行期间最多同时运行了十个fetch_comments请求。

778f2cb4-104a-11ee-962d-dac502259ad0.png

Jaeger 适用于对单个跟踪进行专注检查。但如果我们想要监视服务的延迟呢?如果我们想要计算具有给定跟踪元数据的错误或请求的数量呢? 这就是 Grafana 仪表板的用处。我们想要从我们的跟踪构建 RED 指标并在 Grafana 中可视化它们。 转到http://localhost:3000/login,使用admin作为用户名和密码登录。 登录后,我们可以使用新发布的Quickwit 数据源插件连接到 Quickwit 并查询我们的应用程序跟踪。

77d02642-104a-11ee-962d-dac502259ad0.png

为了使 RED 指标监控过程更加方便,我们准备了一个预配置的Grafana 仪表板供您下载并导入到您的 Grafana 实例中。 该仪表板作为一种强大的工具,用于可视化和理解性能。它包括三个面板:

第一个面板显示每分钟的请求数量。

第二个面板显示每分钟的错误数量。

第三个面板呈现每分钟请求的持续时间百分位数。

为了观察这些指标的运行情况,您可以使用 HTTP 基准测试工具,甚至可以使用本教程提供的此脚本发送多个并发请求到您的 Rust 应用程序。 现在让我们来看一下 Grafana 仪表板的截图,展示了运行脚本后的指标情况。7802395c-104a-11ee-962d-dac502259ad0.png

就是这样!在这篇博客文章中,我们超越了基本的日志记录,深入了解了分布式跟踪以及如何使用它来监视应用程序性能。 我们构建 Quickwit 的经验告诉我们,分布式跟踪对于了解由于调用 S3 或在本地磁盘上读取数据而失去时间的位置非常重要。我们希望它对您也有所帮助 :) 愉快的编码和观察!

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10447

    浏览量

    206576
  • Web
    Web
    +关注

    关注

    2

    文章

    1238

    浏览量

    68468
  • API
    API
    +关注

    关注

    2

    文章

    1383

    浏览量

    60994
  • 应用程序
    +关注

    关注

    37

    文章

    3136

    浏览量

    56405
  • Rust
    +关注

    关注

    1

    文章

    223

    浏览量

    6387

原文标题:【Rust日报】2023-06-20 使用Quickwit、Jaeger和Grafana监控您的Rust应用程序

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何在Rust中使用Memcached

    Memcached是一种高性能、分布式的内存对象缓存系统,可用于加速动态Web应用程序Rust是一种系统级编程语言,具有内存安全、高性能和并发性等特点。Rust语言的Memcached库提供
    的头像 发表于 09-19 16:30 885次阅读

    Rust GUI实践之Rust-Qt模块

    Rust-Qt 是 Rust 语言的一个 Qt 绑定库,它允许 Rust 开发者使用 Qt 框架来创建跨平台的图形界面应用程序。Qt 是一个跨平台的
    的头像 发表于 09-30 16:43 971次阅读

    开放分布式追踪(OpenTracing)入门与 Jaeger 实现

    应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。Agent - 它是一个监听在 UDP 端口
    发表于 03-07 16:27

    阿里云容器Kubernetes监控(二) - 使用Grafana展现Pod监控数据

    摘要: 简介 在kubernetes的监控方案中,Heapster+Influxdb+Grafana的组合相比prometheus等开源方案而言更为简单直接。而且Heapster在
    发表于 05-10 15:28

    使用PID调谐器应用程序分析的设计

    使用PID调谐器应用程序分析的设计
    发表于 07-31 14:16

    grafana使用方法

    grafana配置指南
    发表于 08-08 14:31

    只会用Python?教你在树莓派上开始使用Rust

    。出现提示时,选择默认安装。安装程序将在完成时通知,尽管安装可能会花费一些时间,具体取决于的连接。/p》 安装后安装成功,但是您还不能开始使用它。如果尝试按版本检查Rust和Car
    发表于 05-20 08:00

    怎样去使用Rust进行嵌入式编程呢

    使用Rust进行嵌入式编程Use Rust for embedded development篇首语:Rust的高性能、可靠性和生产力使其适合于嵌入式系统。在过去的几年里,Rust
    发表于 12-22 07:20

    简述linux-arm64 UOS安装开源Grafana的步骤

    (linux-arm64)UOS安装开源Grafana-7.2.0,和CentOS安装步骤一样Grafana是一款用Go语言开发的开源数据可视化工具,可以做数据监控和数据统计,带有告警功能,支持
    发表于 06-16 15:00

    多功能监控系统应用程序免费下载

    本文档的主要内容详细介绍的是多功能监控系统应用程序免费下载。
    发表于 03-29 08:00 2次下载
    多功能<b class='flag-5'>监控</b>系统<b class='flag-5'>应用程序</b>免费下载

    IPCamera Viewer网络摄像机监控应用程序免费下载

    本文档的主要内容详细介绍的是IPCamera Viewer网络摄像机监控应用程序免费下载。
    发表于 05-14 08:00 7次下载
    IPCamera Viewer网络摄像机<b class='flag-5'>监控</b><b class='flag-5'>应用程序</b>免费下载

    Jaeger Uber的分布式追踪系统

    jaeger.zip
    发表于 04-26 10:11 0次下载
    <b class='flag-5'>Jaeger</b> Uber的分布式追踪系统

    使用Thanos+Prometheus+Grafana构建监控系统

    对于弹性伸缩和高可用的系统来说,一般有大量的指标数据需要收集和存储,如何为这样的系统打造一个监控方案呢?本文介绍了如何使用 Thanos+Prometheus+Grafana 构建监控系统。
    的头像 发表于 05-05 21:14 2235次阅读

    Grafana 9泰酷了吧

    Grafana 9.0 的主要重点是改善 Grafana 的用户体验,使可观察性和数据可视化更易用也更容易获得。无论是通过 Prometheus 和 Loki 可视化查询生成器还是面板和仪表板搜索
    的头像 发表于 05-30 11:30 380次阅读
    <b class='flag-5'>Grafana</b> 9泰酷了吧

    基于Rust的Log日志库介绍

    Rust是一门系统级编程语言,因其安全性、高性能和并发性而备受欢迎。在Rust应用程序中,日志记录是一项非常重要的任务,因为它可以帮助开发人员了解应用程序的运行情况并解决问题。
    的头像 发表于 09-19 14:49 2150次阅读