Databend 全鏈路追蹤

全鏈路追蹤意味着能夠追蹤到每一個調用請求的完整調用鏈路、收集性能數據並反饋異常。Databend 使用 tracing 賦能可觀測性,實現全鏈路追蹤。

Databend 與 Tracing

Databend 與 Tracing

初步瞭解 Databend 怎麼實現全鏈路追蹤。

初識 Tracing

Tracing 是由 Tokio 團隊維護的 Rust 應用跟蹤框架,用來收集結構化的、基於事件的診斷信息。

項目地址:https://github.com/tokio-rs/tracing

示例:

use tracing::{info, Level};
use tracing_subscriber;

fn main() {
    let collector = tracing_subscriber::fmt()
        // filter spans/events with level TRACE or higher.
        .with_max_level(Level::TRACE)
        // build but do not install the subscriber.
        .finish();

    tracing::collect::with_default(collector, || {
        info!("This will be logged to stdout");
    });
    info!("This will _not_ be logged to stdout");
}




use tracing::{info, Level};
use tracing_subscriber;

fn main() {
    let collector = tracing_subscriber::fmt()
        // filter spans/events with level TRACE or higher.
        .with_max_level(Level::TRACE)
        // build but do not install the subscriber.
        .finish();

    tracing::collect::with_default(collector, || {
        info!("This will be logged to stdout");
    });
    info!("This will _not_ be logged to stdout");
}

Databend 中的 Tracing

Databend 的 tracing-subscriber 被統一整合在 common/tracing,由 query 和 meta 共用。

// Use env RUST_LOG to initialize log if present.
// Otherwise use the specified level.
let directives = env::var(EnvFilter::DEFAULT_ENV).unwrap_or_else(|_x| level.to_string());
let env_filter = EnvFilter::new(directives);
let subscriber = Registry::default()
    .with(env_filter)                # 根據環境變量過濾
    .with(JsonStorageLayer)          # 利用 tracing-bunyan-formatter 格式化爲 json
    .with(stdout_logging_layer)      # 標準輸出
    .with(file_logging_layer)        # 輸出到文件,默認位於 `_logs` 目錄下
    .with(jaeger_layer);             # opentelemetry-jaeger

#[cfg(feature = "console")]
let subscriber = subscriber.with(console_subscriber::spawn()); # tokio console

tracing::subscriber::set_global_default(subscriber)
    .expect("error setting global tracing subscriber");
// Use env RUST_LOG to initialize log if present.
// Otherwise use the specified level.
let directives = env::var(EnvFilter::DEFAULT_ENV).unwrap_or_else(|_x| level.to_string());
let env_filter = EnvFilter::new(directives);
let subscriber = Registry::default()
    .with(env_filter)                # 根據環境變量過濾
    .with(JsonStorageLayer)          # 利用 tracing-bunyan-formatter 格式化爲 json
    .with(stdout_logging_layer)      # 標準輸出
    .with(file_logging_layer)        # 輸出到文件,默認位於 `_logs` 目錄下
    .with(jaeger_layer);             # opentelemetry-jaeger

#[cfg(feature = "console")]
let subscriber = subscriber.with(console_subscriber::spawn()); # tokio console

tracing::subscriber::set_global_default(subscriber)
    .expect("error setting global tracing subscriber");

具體到內部的 tracing 記錄,大致有兩類:

use common_tracing::tracing;

tracing::info!("{:?}", conf);
tracing::info!("DatabendQuery {}", *databend_query::DATABEND_COMMIT_VERSION);
use common_tracing::tracing;

tracing::info!("{:?}", conf);
tracing::info!("DatabendQuery {}", *databend_query::DATABEND_COMMIT_VERSION);
use common_tracing::tracing::debug_span;
#[tracing::instrument(level = "debug", skip_all)]
async fn read(&mut self) -> Result<Option<DataBlock>> {
    ...
        fetched_metadata = read_metadata_async(&mut self.reader)
            .instrument(debug_span!("parquet_source_read_meta"))
            .await
            .map_err(|e| ErrorCode::ParquetError(e.to_string()))?;
    ...
}
use common_tracing::tracing::debug_span;
#[tracing::instrument(level = "debug", skip_all)]
async fn read(&mut self) -> Result<Option<DataBlock>> {
    ...
        fetched_metadata = read_metadata_async(&mut self.reader)
            .instrument(debug_span!("parquet_source_read_meta"))
            .await
            .map_err(|e| ErrorCode::ParquetError(e.to_string()))?;
    ...
}

示例:

{
  "v": 0,
  "name""databend-query-test_cluster@0.0.0.0:3307",
  "msg""Shutdown server.",
  "level": 30,
  "hostname""dataslime",
  "pid": 53341,
  "time""2022-05-11T00:51:56.374807359Z",
  "target""databend_query",
  "line": 153,
  "file""query/src/bin/databend-query.rs"
}
{
  "v": 0,
  "name""databend-query-test_cluster@0.0.0.0:3307",
  "msg""Shutdown server.",
  "level": 30,
  "hostname""dataslime",
  "pid": 53341,
  "time""2022-05-11T00:51:56.374807359Z",
  "target""databend_query",
  "line": 153,
  "file""query/src/bin/databend-query.rs"
}

觀測 Databend 追蹤的方式

Databend 原生提供了多種觀測方式,以方便診斷和調試:

Jaeger 分佈式追蹤

使用 Jaeger 對 Databend 進行全鏈路追蹤。

Opentelemetry & Jaeger

OpenTelemetry 是工具、API 和 SDK 的集合。使用它來檢測、生成、收集和導出遙測數據(度量、日誌和追蹤),以幫助您分析軟件的性能和行爲。

Jaeger 是一個開源的端到端分佈式追蹤系統。由 Uber 捐贈給 CNCF 。它可以用於監視基於微服務的分佈式系統,提供以下能力:

Step by Step

遵循下述步驟,即可使用 Jaeger 探索 Databend :

結果探索

x 軸是執行時刻,y 軸是持續的時間,圓點反映 span 的聚集程度。

執行下述語句即可得到上圖所示追蹤結果:

CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 SELECT * FROM t1;




CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 SELECT * FROM t1;

Timeline

下圖是點擊最大的圓點得到的追蹤情況:

使用 timeline 模式來展現 tracing 的各個跨度之間的關係。以時間爲主線進行分析, 方便使用者觀看在某個時間點觀看程序信息。

點開第一個跨度,可以看到這是執行 INSERT INTO t1 SELECT *FROM t1 查詢時的情況。

Graph

切換到 graph 模式,可以看到各個 span 之間的調用鏈,每個 span 具體用時 , 以及百分比。

通過這個視圖使用者很容易知道系統瓶頸, 快速定位問題。

Compare

連起來的各個部分形成整個 trace 的調用鏈。因爲比較時一般會比較兩個相同類型的調用,所以看到的會是重合後的視圖。

對於顏色的一個說明:

tokio-console 診斷

tokio-console 診斷

tokio-rs 團隊出品的診斷和調試工具,可以幫助我們診斷與 tokio 運行時相關的問題。

console 是什麼

tokio-console 是專爲異步程序設計的調試與診斷工具,能夠列出 tokio 的任務,提供對程序的任務和資源的實時、易於導航的視圖,總結了它們的當前狀態和歷史行爲。主要包含以下組件:

項目地址:https://github.com/tokio-rs/console

Step by Step

結果探索

任務

先看什麼是 tokio 任務:

基礎視圖

通過左右切換,可以得到總忙時間或輪詢次數等指標對任務進行排序。控制檯通過高亮來提示較大差異,比如從毫秒到秒的切換。

控制檯還實現了一個 “警告” 系統。通過監視應用程序中任務的運行時操作,控制檯可以檢測可能提示 bug 或性能問題的行爲模式,並突出顯示這些行爲模式供用戶分析。比如已經運行了很長時間而沒有讓步的任務,喚醒的次數比被其他任務喚醒的次數還要多的任務。

任務視圖

上下切換選中任務,enter 查看關於每個任務的翔實數據,比如輪詢持續時間的直方圖。

不僅列出任務。console 還會插入異步互斥和信號量等資源。Tokio Console 的資源詳細信息視圖顯示了哪些任務已經進入臨界區,哪些任務正在等待獲得訪問權限。

還能做什麼

還能做什麼

與分佈式追蹤和日誌系統相關的一些其他內容。

可觀測性 + +

目前還有一系列關於可觀測性和 Tracing 的 Issue 有待解決:

另外,更進一步的考量是,如何基於可觀測性來自動 / 半自動地發現問題並對系統進行調優。

瞭解更多

瞭解更多

Tracing

Jaeger

tokio-console

關於 Databend

Databend 是一款開源、彈性、低成本,基於對象存儲也可以做實時分析的新式數倉。期待您的關注,一起探索雲原生數倉解決方案,打造新一代開源 Data Cloud。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/NJi92jg2Egoi-kK3HFXPEA