本文為您介紹基于SLS推出的ScheduledSQL功能,對歷史數據進行匯總壓縮,降低使用存儲成本。
背景
日志服務 SLS通過豐富靈活的方式將多種類型(日志、指標)的數據接入到服務中,并隨著時間不斷沉淀;之后,用戶就可以通過SLS強大的查詢分析能力對多個維度的數據進行搜索、分析。雖然歷史數據同樣有較高的查詢分析價值,但是大量歷史數據的存儲成本也不能忽視。因而SLS的用戶一般會給數據設置一個固定的保留日期,定期清理歷史數據,減輕成本壓力。為了解決這一問題,SLS近期推出了新功能ScheduledSQL,讓用戶定時保存SLS中的匯總數據,既保存了歷史數據供以后查詢分析,同時又減輕了存儲的成本壓力。
匯總數據
日志、指標類的數據都會隨著時間的推移不斷累積。例如一個系統每秒產生1000條日志,日志的平均大小為500byte,一小時就會有1.8GB的日志,一年就會產生15T的數據。雖然數據使用方希望能夠盡可能多的保存這15T數據以供查詢分析使用,但是這些歷史數據在提供分析價值的同時,也造成了較高的成本壓力。定期刪除歷史數據雖然能夠解決成本問題,但同時也給數據使用方帶來了不便。
數據價值的時間梯度
從使用頻率、數據權重等維度不難看出,數據的價值是隨著時間不斷降低的。例如用戶頁面查看日志,需要查看最近七天單個用戶每天的特定頁面的訪問數,最近一月單個用戶每天的訪問數,最近一年單個用戶每月的訪問數。假設有2萬用戶,20可供用戶訪問的頁面:
數據維度 |
時間梯度 |
保存時長 |
匯總數據量(條) |
原始數據量(條) |
匯總占比 |
user/page |
天 |
7天 |
2萬 * 20 * 7 = 280萬 |
2萬 * 20 * 7 = 280萬 |
100% |
user |
天 |
30天 |
2萬 * 30 = 60萬 |
2萬 * 20 * 30 = 1200萬 |
5% |
user |
月 |
1年 |
2萬* 12 = 24萬 |
2萬 * 20 * 365 = 1.4億 |
0.16% |
可以看到在上述場景下,隨著時間推移,數據具有極高的可壓縮比率。相對于直接刪除歷史數據,可以通過保存匯總數據來降低存儲成本。這樣即能夠查詢分析歷史數據,又不必花費極高的存儲成本。
匯總數據結構
在生成匯總數據的時候,首先需要評估數據的使用場景。不同場景、不同類型的數據的使用方式千差萬別,其評估方式也不盡相同。下面介紹下不同類型數據的評估方式。
數值型數據
指標數據是典型的數值型數據,一條典型的指標日志如下所示:
{
"bucket_location": "oss-cn-*****-h",
"bucket": "buc*****65",
"object": "245-***************.model",
"operation": "PostObject",
"time": "23/Jun/2021:10:23:50",
"object_size": "3188",
"__time__": 1624443830,
"key": "data-***************.txt",
"content_length_out": "22583527",
"content_length_in": "46803694",
"http_status": "200",
"response_time": "7339",
"__tag__:__receive_time__": "1624443838"
}
這條日志的字段可以分為時間,數值字段,分組字段三類,例如:
字段名稱 |
字段值 |
類型 |
bucket |
buc*****65 |
分組 |
object |
245-***************.model |
分組 |
operation |
PostObject |
分組 |
object_size |
3188 |
數值 |
content_length_in |
46803694 |
數值 |
content_length_out |
22583527 |
數值 |
__time__ |
1624443830 |
時間 |
__tag__:__receive_time__ |
1624443838 |
時間 |
數值字段即為具體的指標值,維度和時間字段一般用作分組值,在計算指標的聚合值時作為分組依據。例如,如果要計算OSS每個bucket每小時寫入的數據量,則需要使用維度字段operation和bucket,時間字段__time__,數值字段content_length_out:
operation: PostObject | select bucket, date_trunc("hour", __time__) as tm, sum(content_length_in) as total from log group by bucket, tm
如果使匯總數據支持上述場景,需要在匯總數據中保存分組字段operation和bucket,精確到小時級別的__time__字段,以及content_length_in的聚合值。所以可以通過如下sql語句計算匯總數據,支持上述場景:
operation: PostObject | select bucket, operation, date_trunc("hour", __time__) as tm, sum(content_length_in) as size from log group by bucket, operation, tm
如果還需要匯總數據同時支持計算每小時單次寫入數據量的平均值,則需要通過如下sql語句計算匯總數據:
operation: PostObject | select bucket, operation, date_trunc("hour", __time__) as tm, avg(content_length_in) as avg, count(1) as size from log group by bucket, operation, tm
得到如下所示的匯總數據:
字段名稱 |
字段樣例 |
字段說明 |
bucket |
buc*****65 |
bucket名稱 |
operation |
PostObject |
操作名稱 |
tm |
1624442400 |
取整到小時的時間戳 |
avg |
22583527 |
單次寫入數據大小的平均值 |
size |
65 |
寫入數據請求的次數 |
基于得到的匯總數據,可以通過如下sql語句進行計算
計算OSS每個bucket每小時寫入的數據量
operation: PostObject | select bucket, tm, sum(avg * size) as total from log
每小時單次寫入數據量的平均值
operation: PostObject | select bucket, tm, avg from log
可以看出,隨著場景的不同,計算匯總數據所需的sql語句也不盡相同。可以從以下幾個方面評估如何計算匯總數據:
選擇分組字段。
選擇數值字段的聚合值:計數、求和、平均、最大、最小。
選擇時間粒度:分鐘、小時、天。
采樣歷史數據
采樣歷史數據則較為簡單,在歷史數據中按照一定的規則挑選合適的數據存儲即可。例如對于系統日志,可以選擇存儲日志級別為WARNING或者ERROR的數據進行存儲,忽略INFO級別的日志。
匯總數據的限制
匯總數據本質上是對原始數據在更粗時間粒度的聚合,并且聚合分組、計算都是按照對匯總數據的預期使用方式來選擇的。
時間粒度
如果匯總數據的時間粒度是小時,則使用匯總數據進行數據分析只能夠得到以小時為單位的聚合結果,無法得到更細粒度的數據。
聚合函數
聚合函數只能夠使用匯總數據中聚合值支持的。如果匯總結果中不包含最小值,則基于匯總結果進行聚合計算的時候,是無法精確得到最小值的。
分組數據
由于匯總數據只保存了部分分組數據,在使用匯總數據進行數據分析時只能夠使用保存的部分。
日志服務中的匯總數據
下面以OSS訪問日志為例,說明如何基于SLS推出的ScheduledSQL功能,對歷史數據進行匯總壓縮,從而降低使用存儲成本。
評估使用場景
一條完整的OSS訪問日志如下:
{
"__topic__": "oss_access_log",
"bucket_location": "oss-cn-****-p",
"bucket": "bucket****",
"object": "245-************.model",
"client_ip": "127.0.0.1",
"operation": "PutObject",
"logging_flag": "false",
"time": "23/Jun/2021:13:07:30",
"server_cost_time": "8636",
"object_size": "7748",
"vpc_addr": "127.0.0.1",
"sync_request": "cdn",
"__time__": 1624453650,
"key": "data*****6958txt",
"delta_data_size": "3938",
"__source__": "127.0.0.1",
"error_code": "network disconnected",
"content_length_out": "79193322",
"response_body_length": "717233083",
"request_uri": "/request/path-2/file-9",
"content_length_in": "1823770",
"http_method": "GET",
"http_status": "200",
"request_length": "4099",
"response_time": "398",
"__tag__:__receive_time__": "1624453651",
"owner_id": "ln***v2",
"http_type": "https",
"bucket_storage_type": "archive"
}
需要基于OSS訪問數據構建如下的幾類關鍵結果:
名稱 |
時間粒度 |
分組依據 |
聚合函數 |
單位時間請求次數 |
小時 |
bucket, operation |
count |
單位時間請求錯誤 |
小時 |
bucket, operation, http_status |
count |
單位時間寫入數據量 |
小時 |
bucket, operation |
sum |
單位時間平均寫入數據量 |
小時 |
bucket, operation |
avg, count |
單位時間讀取數據量 |
小時 |
bucket, operation |
sum |
單位時間平均讀取數據量 |
小時 |
bucket, operation |
avg, count |
根據上面的使用場景,可以通過如下語句計算匯總數據:
operation: PostObject | select bucket, operation, http_status, date_trunc('hour', __time__) as tm, avg(content_length_out) as out_avg, avg(content_length_in) as in_avg, count(1) as size from log group by bucket, operation, http_status, tm
創建ScheduledSQL任務
執行查詢語句
在SLS的控制臺中執行上述查詢語句,隨后點擊創建ScheduledSQL。
計算配置
此處填入合適的作業名稱、以及目標庫即可。此處需要注意開啟目標庫的索引。
調度配置
這里調度間隔和時間窗口都選擇小時級別,點擊確認即可。關于調度配置的詳細信息,可以參考官方文檔。
在任務執行成功之后,就可以在目標庫中看到匯總數據。
匯總數據的使用
基于ScheduledSQL任務生成的匯總數據,可以為上述場景提供支撐。
名稱 |
查詢語句 |
單位時間請求次數 |
*| select bucket, tm, sum(1) as total group by bucket, tm |
單位時間請求錯誤 |
not http_status: 200 | select bucket, count(1) as cnt group by bucket |
單位時間寫入數據量 |
operation: PostObject | select bucket, tm, sum(avg_out * size) as total from log |
單位時間平均寫入數據量 |
operation: PostObject | select bucket, tm, sum(avg_out * size) as total from log |
單位時間讀取數據量 |
operation: GetObject | select bucket, tm, sum(avg_in * size) as total from log |
單位時間平均讀取數據量 |
operation: GetObject | select bucket, tm, sum(avg_in * size) as total from log |
總結
通過匯總數據支撐歷史數據分析,能夠較大的減輕存儲成本上的壓力。雖然同原始數據相比,其在使用場景以及靈活性方面都有所欠缺,但是如果能夠提前做好規劃,就能夠很好的支撐大部分的使用場景。