Sentry 監控 - Snuba 資料中臺架構(編寫和測試 Snuba 查詢)

語言: CN / TW / HK

系列

本指南將引導您完成編寫和測試 Snuba 查詢的過程。

探索 Snuba 資料模型

為了構建 Snuba 查詢,第一步是能夠知道您應該查詢哪個資料集,您應該選擇哪些實體以及每個實體schema 是什麼。

有關資料集實體的介紹,請參閱 Snuba 資料模型部分。 * https://getsentry.github.io/snuba/architecture/datamodel.html

資料集可以在這個模組中找到。每個資料集都是一個引用實體的類。 * https://github.com/getsentry/snuba/blob/master/snuba/datasets/factory.py

系統中的實體列表可以通過 snuba entity 命令找到:

sh snuba entities list

會返回如下內容:

sh Declared Entities: discover errors events groups groupassignee groupedmessage .....

一旦我們找到了我們感興趣的實體,我們就需要了解在該實體上宣告的 schemarelationship。 相同的命令描述了一個實體

sh snuba entities describe groupedmessage

會返回:

```python Entity groupedmessage Entity schema -------------------------------- offset UInt64 record_deleted UInt8 project_id UInt64 id UInt64 status Nullable(UInt8) last_seen Nullable(DateTime) first_seen Nullable(DateTime) active_at Nullable(DateTime) first_release_id Nullable(UInt64)

Relationships
--------------------------------
    groups
    --------------------------------
    Destination: events
    Type: LEFT
        Join keys
        --------------------------------
        project_id = LEFT.project_id
        id = LEFT.group_id

```

它提供列的列表及其型別以及與資料模型中定義的其他實體的關係。

準備對 Snuba 的查詢

Snuba 查詢語言稱為 SnQL。它記錄在 SnQL 查詢語言部分。所以本節不贅述。 * https://getsentry.github.io/snuba/language/snql.html

有一個 python sdk 可用於構建 Snuba 查詢,它可以用於任何 Python 客戶端,包括 Sentrysnuba-sdk。 * https://github.com/getsentry/snuba-sdk

查詢表示為一個 Query 物件,如: python query = Query( dataset="discover", match=Entity("events"), select=[ Column("title"), Function("uniq", [Column("event_id")], "uniq_events"), ], groupby=[Column("title")], where=[ Condition(Column("timestamp"), Op.GT, datetime.datetime(2021, 1, 1)), Condition(Column("project_id"), Op.IN, Function("tuple", [1, 2, 3])), ], limit=Limit(10), offset=Offset(0), granularity=Granularity(3600), )

有關如何構建查詢的更多詳細資訊,請參見 sdk 文件。 * https://getsentry.github.io/snuba-sdk/

一旦查詢物件準備就緒,它就可以傳送到 Snuba

使用 Sentry 向 Snuba 傳送查詢

查詢 Snuba 時最常見的用例是通過 Sentry。本節說明如何在 Sentry 程式碼庫中構建查詢並將其傳送到 Snuba

Sentry 匯入了上述的 Snuba sdk。這是構建 Snuba 查詢的推薦方法。

一旦建立了 Query 物件,Sentry 提供的 Snuba client api 就可以並且應該用於將查詢傳送到 Snuba

api 在這個模組中。 它負責快取、重試並允許批量查詢。 * https://github.com/getsentry/sentry/blob/master/src/sentry/utils/snuba.py#L667

該方法返回一個字典,其中包含響應中的資料和其他元資料:

json { "data": [ { "title": "very bad", "uniq_events": 2 } ], "meta": [ { "name": "title", "type": "String" }, { "name": "uniq_events", "type": "UInt64" } ], "timing": { ... details ... } }

data 部分是一個列表,每行一個字典。meta 包含響應中包含的的列表,其資料型別由 Clickhouse 推斷。

通過 Web UI 傳送測試查詢

Snuba 具有可用於傳送查詢的最小 Web UI。 您可以在本地執行 Snuba, 並且可以通過 http://localhost:1218/[DATASET NAME]/snql 訪問 Web UI

snubaUI.png

應該在 query 屬性中提供 SnQL 查詢,並且響應的結構與上一節中討論的相同。

通過 curl 傳送查詢

Web UI 僅將 payload 作為 POST 傳送。因此,使用 curl 或任何其他 HTTP 客戶端可以實現相同的結果。

請求和響應格式

請求格式在上面截圖中可見:

  • query 包含字串形式的 SnQL 查詢。
  • dataset 是資料集名稱(如果尚未在 url 中指定。
  • debug 使 Snuba 在響應中提供詳盡的統計資訊,包括 Clickhouse 查詢。
  • consistent 強制 Clickhouse 查詢以單執行緒模式執行,並且如果 Clickhouse 表被複制,它將強制 Snuba 始終命中同一個節點。可以保證順序一致性,因為這是消費者預設寫入的節點。這是通過設定為 in_order負載平衡 Clickhouse 屬性實現的。
  • https://clickhouse.tech/docs/en/operations/settings/settings/#load_balancing-in_order
  • turboTURBO_SAMPLE_RATE Snuba 設定中定義的查詢設定取樣率。它還可以防止 SnubaFINAL 模式應用於 Clickhouse 查詢,以防在替換後需要保證正確的結果。

Snuba 可以使用 4http code 進行響應。200 表示成功的查詢,如果查詢無法正確驗證,則為 400500 通常意味著與 Clickhouse 相關的問題(從超時到連線問題),儘管 Snuba 仍然無法提前識別一些無效查詢。Snuba 有一個內部速率限制器,所以 429 也是一個可能的返回碼。

成功查詢的響應格式與上面討論的相同。完整版本如下所示(在 debug 模式下)

json { "data": [], "meta": [ { "name": "title", "type": "String" } ], "timing": { "timestamp": 1621038379, "duration_ms": 95, "marks_ms": { "cache_get": 1, "cache_set": 4, "execute": 39, "get_configs": 0, "prepare_query": 10, "rate_limit": 4, "validate_schema": 34 } }, "stats": { "clickhouse_table": "errors_local", "final": false, "referrer": "http://localhost:1218/events/snql", "sample": null, "project_rate": 0, "project_concurrent": 1, "global_rate": 0, "global_concurrent": 1, "consistent": false, "result_rows": 0, "result_cols": 1, "query_id": "f09f3f9e1c632f395792c6a4bfe7c4fe" }, "sql": "SELECT (title AS _snuba_title) FROM errors_local PREWHERE equals((project_id AS _snuba_project_id), 1) WHERE equals(deleted, 0) AND greaterOrEquals((timestamp AS _snuba_timestamp), toDateTime('2021-05-01T00:00:00', 'Universal')) AND less(_snuba_timestamp, toDateTime('2021-05-11T00:00:00', 'Universal')) LIMIT 1000 OFFSET 0" }

timing 部分包含查詢的時間戳持續時間。有趣的是,持續時間被分解為幾個階段:marks_ms

sql 元素是 Clickhouse 查詢。

stats 字典包含以下 key * clickhouse_tablesnuba 在查詢處理過程中選取的表。 * final 表示 Snuba 是否決定向 Clickhouse 傳送 FINAL 查詢,這會迫使 Clickhouse 立即應用相關的合併(Merge Tree)。細節 * https://clickhouse.tech/docs/en/sql-reference/statements/select/from/#select-from-final * sample 是應用的取樣率。 * project_rate 是查詢時 Snuba 每秒收到的特定專案的請求數。 * project_concurrent 是查詢時涉及特定專案的併發查詢數。 * global_rateproject_rate 相同,但不專注於一個專案。 * global_concurrentproject_concurrent 相同,但不專注於一個專案。 * query_id 是此查詢的唯一識別符號。

查詢驗證問題通常採用以下格式:

json { "error": { "type": "invalid_query", "message": "missing >= condition on column timestamp for entity events" } }

Clickhouse 錯誤將具有類似的結構。type 欄位將顯示 clickhouse,該訊息將包含有關異常的詳細資訊。與查詢驗證錯誤相反,在 Clickhouse 錯誤的情況下,實際執行了查詢,因此存在為成功查詢描述的所有時間和統計資訊。