使用 SPL 高效實現 Flink SLS Connector 下推

作者:潘偉龍(豁朗)

背景

日誌服務 SLS 是雲原生觀測與分析平臺,爲 Log、Metric、Trace 等數據提供大規模、低成本、實時的平臺化服務,基於日誌服務的便捷的數據接入能力,可以將系統日誌、業務日誌等接入 SLS 進行存儲、分析;阿里雲 Flink 是阿里雲基於 Apache Flink 構建的大數據分析平臺,在實時數據分析、風控檢測等場景應用廣泛。阿里雲 Flink 原生支持阿里雲日誌服務 SLS 的 Connector,可以在阿里雲 Flink 平臺將 SLS 作爲源表或者結果表使用。

在阿里雲 Flink 配置 SLS 作爲源表時,默認會消費 SLS 的 Logstore 數據進行動態表的構建,在消費的過程中,可以指定起始時間點,消費的數據也是指定時間點以後的全量數據;在特定場景中,往往只需要對某類特徵的日誌或者日誌的某些字段進行分析處理,此類需求可以通過 Flink SQL 的 WHERE 和 SELECT 完成,這樣做有兩個問題:

1)Connector 從源頭拉取了過多不必要的數據行或者數據列造成了網絡的開銷;

2)這些不必要的數據需要在 Flink 中進行過濾投影計算,這些清洗工作並不是數據分析的關注的重點,造成了計算的浪費。

對於這種場景,有沒有更好的辦法呢?

答案是肯定的,SLS 推出了 SPL 語言, 可以高效的對日誌數據的清洗,加工。 這種能力也集成在了日誌消費場景,包括阿里雲 Flink 中 SLS Connector,通過配置 SLS SPL 即可實現對數據的清洗規則,在減少網絡傳輸的數據量的同時,也可以減少 Flink 端計算消耗。

接下來對 SPL 及 SPL 在阿里雲 Flink SLS Connector 中應用進行介紹及舉例。

SLS SPL 介紹

圖片

SLS SPL 是日誌服務推出的一款針對弱結構化的高性能日誌處理語言,可以同時在 Logtail 端、查詢掃描、流式消費場景使用,具有交互式、探索式、使用簡潔等特點。

SPL 基本語法如下:

<data-source> 
| <spl-cmd> -option=<option> -option ... <expression>, ... as <output>, ...
| <spl-cmd> ...
| <spl-cmd> ...

< spl-cmd > 是 SPL 指令,支持行過濾、列擴展、列裁剪、正則取值、字段投影、數值計算、JSON、CSV 等半結構化數據處理,具體參考 SPL 指令 [ 1] 介紹,具體來說包括:

結構化數據 SQL 計算指令:

支持行過濾、列擴展、數值計算、SQL 函數調用

  • extend 通過 SQL 表達式計算結果產生新字段
  • where 根據 SQL 表達式計算結果過濾數據條目
*
| extend latency=cast(latency as BIGINT)
| where status='200' AND latency>100

字段操作指令:

支持字段投影、字段重名、列裁剪

  • project 保留與給定模式相匹配的字段、重命名指定字段
  • project-away 保留與給定模式相匹配的字段、重命名指定字段
  • project-rename 重命名指定字段,並原樣保留其他所有字段
*
| project-away -wildcard "__tag__:*"
| project-rename __source__=remote_addr

非結構化數據提取指令:

支持 JSON、正則、CSV 等非結構化字段值處理

  • parse-regexp 提取指定字段中的正則表達式分組匹配信息
  • parse-json 提取指定字段中的第一層 JSON 信息
  • parse-csv 提取指定字段中的 CSV 格式信息
*
| parse-csv -delim='^_^' content as time, body
| parse-regexp body, '(\S+)\s+(\w+)' as msg, user

阿里雲 Flink 支持 SLS Connector,通過 SLS Connector 實時拉取 SLS 中 Logstore 的數據,分析後的數據也可以實時寫入 SLS,作爲一個高性能計算引擎,Flink SQL 也在越來越廣泛的應用在 Flink 計算中,藉助 SQL 語法可以對結構化的數據進行分析。

在 SLS Connector 中,可以配置日誌字段爲 Flink SQL 中的 Table 字段,然後基於 SQL 進行數據分析;在未支持 SPL 配置之前,SLS Connector 會實時消費全量的日誌數據到 Flink 計算平臺,當前消費方式有如下特點:

  • 在 Flink 中計算的往往不需要所有的日誌行,比如在安全場景中,可能僅需要符合某種特徵的數據,需要進行日誌進行過濾,事實上不需要的日誌行也會被拉取,造成網絡帶寬的浪費。
  • 在 Flink 中計算的一般是特定的字段列,比如在 Logstore 中有 30 個字段,真正需要在 Flink 計算的可能僅有 10 個字段,全字段的拉取造成了網絡帶寬的浪費。

在以上場景中,可能會增加並不需要的網絡流量和計算開銷,基於這些特點,SLS 將 SPL 的能力集成到 SLS Connector 的新版本中,可以實現數據在到達 Flink 之前已經進行了行過濾和列裁剪,這些預處理能力內置在 SLS 服務端,可以達到同時節省網絡流量與 Flink 計算(過濾、列裁剪)開銷的目的。

原理對比

  • 未配置 SPL 語句時:Flink 會拉取 SLS 的全量日誌數據(包含所有列、所有行)進行計算,如圖 1。
  • 配置 SPL 語句時:SPL 可以對拉取到的數據如果 SPL 語句包含過濾及列裁剪等,Flink 拉取到的是進行過濾和列裁剪後部分數據進行計算,如圖 2。

接下來以一個 Nginx 日誌爲例,來介紹基於 SLS SPL 的能力來使用 Flink。爲了便於演示,這裏在 Flink 控制檯配置 SLS 的源表,然後開啓一個連續查詢以觀察效果。在實際使用過程中,可以直接修改 SLS 源表,保留其餘分析和寫出邏輯。

接下來介紹下阿里雲 Flink 中使用 SPL 實現行過濾與列裁剪功能。

在 SLS 準備數據

  • 開通 SLS,在 SLS 創建 Project,Logstore,並創建具有消費 Logstore 的權限的賬號 AK/SK。
  • 當前 Logstore 數據使用 SLS 的的 SLB 七層日誌模擬接入方式產生模擬數據,其中包含 10 多個字段。

模擬接入會持續產生隨機的日誌數據,日誌內容示例如下:

{
  "__source__": "127.0.0.1",
  "__tag__:__receive_time__": "1706531737",
  "__time__": "1706531727",
  "__topic__": "slb_layer7",
  "body_bytes_sent": "3577",
  "client_ip": "114.137.195.189",
  "host": "www.pi.mock.com",
  "http_host": "www.cwj.mock.com",
  "http_user_agent": "Mozilla/5.0 (Windows NT 6.2; rv:22.0) Gecko/20130405 Firefox/23.0",
  "request_length": "1662",
  "request_method": "GET",
  "request_time": "31",
  "request_uri": "/request/path-0/file-3",
  "scheme": "https",
  "slbid": "slb-02",
  "status": "200",
  "upstream_addr": "42.63.187.102",
  "upstream_response_time": "32",
  "upstream_status": "200",
  "vip_addr": "223.18.47.239"
}

Logstore 中 slbid 字段有兩種值:slb-01 和 slb-02,對 15 分鐘的日誌數據進行 slbid 統計,可以發現 slb-01 與 slb-02 數量相當。

行過濾場景

在數據處理中過濾數據是一種常見需求,在 Flink 中可以使用 filter 算子或者 SQL 中的 where 條件進行過濾,使用非常方便;但是在 Flink 使用 filter 算子,往往意味着數據已經通過網絡進入 Flink 計算引擎中,全量的數據會消耗着網絡帶寬和 Flink 的計算性能,這種場景下,SLS SPL 爲 Flink SLS Connector 提供了一種支持過濾“下推”的能力,通過配置 SLS Connector 的 query 語句中,過濾條件,即可實現過濾條件下推。避免全量數據傳輸和全量數據過濾計算。

創建 SQL 作業

在阿里雲 Flink 控制檯創建一個空白的 SQL 的流作業草稿,點擊下一步,進入作業編寫。

在作業草稿中輸入如下創建臨時表的語句:

CREATE TEMPORARY TABLE sls_input(
  request_uri STRING,
  scheme STRING,
  slbid STRING,
  status STRING,
  `__topic__` STRING METADATA VIRTUAL,
  `__source__` STRING METADATA VIRTUAL,
  `__timestamp__` STRING METADATA VIRTUAL,
   __tag__ MAP<VARCHAR, VARCHAR> METADATA VIRTUAL,
  proctime as PROCTIME()
) WITH (
  'connector' = 'sls',
  'endpoint' ='cn-beijing-intranet.log.aliyuncs.com',
  'accessId' = '${ak}',
  'accessKey' = '${sk}',
  'starttime' = '2024-01-21 00:00:00',
  'project' ='${project}',
  'logstore' ='test-nginx-log',
  'query' = '* | where slbid = ''slb-01'''
);
  • 這裏爲了演示方便,僅設置 request_uri、scheme、slbid、status 和一些元數據字段作爲表字段。
  • ${ak}、${sk}、${project} 替換爲具有 Logstore 消費權限的賬號。
  • endpoint:填寫同地域的 SLS 的私網地址。
  • query:填寫 SLS 的 SPL 語句,這裏填寫了 SPL 的過濾語句:* | where slbid = ''slb-01'',注意在阿里雲 Flink 的 SQL 作業開發中,字符串需要使用英文單引號進行轉義。

連續查詢及效果

在作業中輸入分析語句,按照 slbid 進行聚合查詢,動態查詢會根據日誌的變化,實時刷新數字。

SELECT slbid, count(1) as slb_cnt FROM sls_input GROUP BY slbid

點擊右上角調試按鈕,進行調試,可以看到結果中 slbid 的字段值,始終是 slb-01。

可以看出設置了 SPL 語句後,sls_input 僅包含 slbid=‘slb-01’ 的數據,其他不符合條件的數據被過濾掉了。

流量對比

使用 SPL 後,可以看出在 SLS 的寫流量不變的情況下,Flink 對 SLS 的讀流量有大幅度下降;同時在過濾佔主要很多 Flink CU 的場景下,經過過濾後,Flink CU 也會有相應的降低。

列裁剪場景

在數據處理中列裁剪也是一種常見需求,在原始數據中,往往會有全量的字段,但是實際的計算只需要特定的字段;類似需要在 Flink 中可以使用 project 算子或者 SQL 中的 select 進行列裁剪與變換,使用 Flink 使用 project 算子,往往意味着數據已經通過網絡進入 Flink 計算引擎中,全量的數據會消耗着網絡帶寬和 Flink 的計算性能,這種場景下,SLS SPL 爲 Flink SLS Connector 提供了一種支持投影下推的能力,通過配置 SLS Connector 的 query 參數,即可實現投影字段下推。避免全量數據傳輸和全量數據過濾計算。

創建 SQL 作業

創建步驟同行過濾場景,在作業草稿中輸入如下創建臨時表的語句,這裏 query 參數配置進行了修改,在過濾的基礎上增加了投影語句,可以實現從 SLS 服務端僅拉取特定字段的內容。

CREATE TEMPORARY TABLE sls_input(
  request_uri STRING,
  scheme STRING,
  slbid STRING,
  status STRING,
  `__topic__` STRING METADATA VIRTUAL,
  `__source__` STRING METADATA VIRTUAL,
  `__timestamp__` STRING METADATA VIRTUAL,
   __tag__ MAP<VARCHAR, VARCHAR> METADATA VIRTUAL,
  proctime as PROCTIME()
) WITH (
  'connector' = 'sls',
  'endpoint' ='cn-beijing-intranet.log.aliyuncs.com',
  'accessId' = '${ak}',
  'accessKey' = '${sk}',
  'starttime' = '2024-01-21 00:00:00',
  'project' ='${project}',
  'logstore' ='test-nginx-log',
  'query' = '* | where slbid = ''slb-01'' | project request_uri, scheme, slbid, status, __topic__, __source__, "__tag__:__receive_time__"'
);

爲了效果,下面分行展示語句中配置,在 Flink 語句中任然需要單行配置。

* 
| where slbid = ''slb-01'' 
| project request_uri, scheme, slbid, status, __topic__, __source__, "__tag__:__receive_time__"

上面使用了 SLS SPL 的管道式語法來實現數據過濾後投影的操作,類似 Unix 管道,使用|符號將不同指令進行分割,上一條指令的輸出作爲下一條指令的輸入,最後的指令的輸出表示整個管道的輸出。

連續查詢及效果

在作業中輸入分析語句,可以看到,結果與行過濾場景結果類似。

SELECT slbid, count(1) as slb_cnt FROM sls_input_project GROUP BY slbid

🔔 注意: 這裏與行過濾不同的是,上面的行過濾場景會返回全量的字段,而當前的語句令 SLS Connector 只返回特定的字段,再次減少了數據的網絡傳輸。

SPL 還可以做什麼

  • 上述實例中演示了使用 SLS SPL 的過濾和投影功能來實現 SLS Connector 的“下推”功能,可以有效地減少網絡流量和 Flink CU 的使用。可以避免在 Flink 進行計算之前,進行額外的過濾和投影計算消耗。
  • SLS SPL 的功能不止於過濾與投影,SLS SPL 完整支持的語法可以參考文檔:SPL 指令 [ 1] 。同時,SPL管道式語法已全面支持在 Flink Connector 中進行配置。
  • SLS SPL 支持對於數據進行預處理,比如正則字段、JSON 字段,CSV 字段展開;數據格式轉換,列的增加和減少;過濾等。除了用於消費場景,在 SLS 的 Scan 模式與採集端都會應用場景,以便用戶在採集端、消費端都可以使用 SPL 的能力。

相關鏈接:

[1] SPL 指令

https://help.aliyun.com/zh/sls/user-guide/spl-instruction?spm=a2c4g.11186623.0.0.33f35a3dl8g8KD

[2] 日誌服務概述

https://help.aliyun.com/zh/sls/product-overview/what-is-log-service

[3] SPL 概述

https://help.aliyun.com/zh/sls/user-guide/spl-overview

[4] 阿里雲 Flink Connector SLS

https://help.aliyun.com/zh/flink/developer-reference/log-service-connector

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章