Presto 在阿里雲實時日誌分析中的實踐和優化
導讀 本文將分享阿里雲千億規模實時日誌分析的架構設計和實踐。
文章將圍繞下面四點展開:
-
業務背景
-
核心問題
-
關鍵設計
-
未來展望
分享嘉賓|顧漢傑 阿里巴巴 技術專家
編輯整理|李科
出品社區|DataFun
01 業務背景
首先第一部分介紹一下我們的業務背景。阿里雲 SLS 是一個雲上一站式可觀測日誌服務平臺。
SLS 提供了強大的數據採集、數據加工、消費投遞等能力,數據採集利器 ilogtail 目前也已經完全開源。數據採集上來後提供數據的統一存儲,包括熱存、智能冷存等,幫助用戶儘可能節省成本。在存儲之上,提供了數據處理與分析能力,包括即席查詢分析、關聯分析等。這兩塊構成了整個 SLS 產品的核心基礎能力。在這個基礎能力之上提供了豐富的工具和應用,最終服務於各種不同的角色和用戶。
本文將聚焦在存儲和分析基礎能力上面的建設,重點分享日誌分析系統,以及在面對核心問題時的一些架構設計思路和經驗。
這是具體日誌分析業務覆蓋和服務的能力,主要是圍繞日誌場景去進行數據分析。日誌數據的形態是多種多樣的,包括無結構的、半結構的以及結構化的。我們在數據源層面統一收集、存儲到存儲引擎當中,再通過 SQL 的分析引擎向上層提供數據分析服務。
具體業務,包括比如實時監控、實時大屏這一類基於日誌數據分析去做的一些業務,其刷新率非常高,所以用戶的併發查詢請求量非常大;還有一些比如像基於日誌的數據去做實時的告警、鏈路分析、交互式分析、AI 異常檢測等,這一類業務主要是對於數據的時效性要求非常高,要求查詢和分析延時要能夠做到秒級實時。
還有一類業務,比如像可視化工具、運營報表、schedule SQL 這一類的業務,數據量是非常大的,面臨超大數據規模的問題。就整體業務覆蓋而言,SLS 除了在阿里雲上對外提供日誌服務外,在集團內部也被衆多的 BU 所使用,同時也經歷了多年雙十一的挑戰。
分析引擎的整體能力方面,我們目前每天大概有數十億次的查詢,每天的行掃描規模大概在千萬億級別,吞吐大概在數十 PB 規模。而我們平均的查詢延時小於 300ms,在業務高峯時刻的併發峯值能夠達到 7.2 萬,屆時系統會面臨數十萬的 QPS 壓力。以上就是整體業務的情況。
02 核心問題
面對上述業務場景和需求,我們面臨的最核心問題主要包括四個方面。
首先, 區別於傳統的離線數倉,我們是一個在線的實時分析服務,所以對於查詢的低延時要求非常高。我們要求秒級的查詢,並且數據要可見即可得、可得即可算。
第二, 我們面對的數據處理規模是非常大的,數據的行掃描規模可能從百萬到千億級別不等,並且規模是彈性多變的。
第三, 會面臨用戶高併發的查詢壓力,像雙十一這種業務高峯時刻能達到 7.2 萬的併發峯值,同時單點會有上千的併發查詢、數十萬的計算任務,所以如何去解決系統在面臨這種高併發查詢下的負載壓力,是我們面臨的又一個核心問題。
最後 還要去解決整個雲服務的高可用以及租戶間的隔離,由於雲服務多、租戶是共享雲上資源的,所以不可避免會有各種各樣的熱點資源爭用。怎樣去解決服務的治理以及壓力的防控,保障雲服務的高可用,也是我們面臨的核心問題之一。
03 關鍵設計
接下來主要圍繞這四個核心的問題,分享在系統架構設計以及關鍵環節上面的思考和權衡。首先是 SLS 日誌查詢分析範式,主要是由三部分因素組成:第一部分是查詢語句,類似於搜索引擎,可以根據相關的關鍵字或者是一些過濾查詢條件,將特徵數據檢索出來。第二部分是分析語句,也就是標準的 SQL 語句,可以針對檢索出來的一些特徵數據,進行靈活的統計和分析。第三部分是時間範圍,可以指定任意的時間範圍,在這個範圍內進行日誌數據的分析。所以這三個要素構成了 SLS 整個日誌查詢分析的範式。
日誌數據有它自己的一些特點。首先時間是日誌數據的一個天然屬性。其次日誌分析 99% 的場景是面向特徵的,比如像上圖中的示例,服務訪問日誌中包含時間、日誌級別、地域、訪問域名、http status、延時等多個字段,我們可能就想分析來自 cn-shanghai 地域的訪問情況,那我們可以通過關鍵詞檢索過濾出需要分析的數據。第三,分析的數據往往具有局部性,比如對於上面的服務日誌,我們可能就想分析 status 字段,那對於每一條檢索出來的日誌,並不需要將整行日誌的數據全部加載。這些日誌數據的特點是實時、低延時查詢分析的關鍵所在。
實時計算、低延遲的關鍵,我認爲首先是快速定位數據,其次是高效加載數據,最後是如何執行高效計算。在這裏**索引和列存是關鍵。**首先介紹一下我們的存儲模型,這是一個三級結構,最外層是 project,實現了用戶級別的隔離;在 project 內可以有多個 logstore,它是日誌數據的存儲單元,實現了生命週期 TTL 的管理;在一個 logstore 內部是由多個數據分片(我們叫它 Shard)組成。Shard 間是按照 Range 粒度進行切分,日誌數據的寫入,是類似於一個隊列的形式進行追加,然後按照 hash 均衡負載到各個 Shard 分片上。最終是以 LSM-Tree(log structure merge Tree)的寫入模型將數據存儲下來。
前面我們剛剛提到了日誌的一個天然屬性是時間,這裏我們基於 LSM 追加寫入模型,其實日誌數據在一個 Shard 內都是按照時間進行分佈的。所以第一個關鍵點是基於時間檢索模型,根據 From 和 To 的時間範圍可以快速地定位到某一個 Shard 在某一段時間內的數據。同時根據查詢分析範式,對於前面的查詢條件,我們可以利用索引倒排技術,高效檢索出來我們需要的特徵數據。同時,剛剛還提到分析數據可能是局部的,用戶可能只需要分析日誌數據中的某些字段,所以我們實現了列存,對於索引字段進行列式存儲,分析時將指定列的列存數據加載上來進行分析即可。
所以,最終在 LSM 寫入之後,會進行異步的索引和列存構建過程,最終統一存儲到我們的分佈式存儲。這就構成了我們整體的存儲模型。總體來說,通過索引和列存,以空間來換時間,減少了 IO 次數和無效的數據掃描,提升了數據讀取和計算效率。
再來看計算和存儲架構,首先無論是存儲還是計算,都是分佈式架構。 日誌數據的寫入基於 LSM 模型,在寫入節點上面,一部分熱數據在 memory 裏面,另一部分則已經 Dump 下去,最終寫到分佈式存儲中,這部分是數據寫入。而查詢分析時需要加載數據,我們希望能高效利用 LSM 模型特性,儘可能地從 memory 中加載數據,減少不必要的網絡和磁盤 IO,因此在存儲和計算架構上,我們進行了數據本地性的設計,將計算節點和存儲節點放在同一個機器上面,同時因爲計算節點和存儲節點是跨進程的,所以涉及到數據的交互,這裏是通過 domain socket 進行控制面的通信,通過 share memory 完成數據交接。
通過數據本地性的設計,我們利用了 LSM 裏面本地的 mem cache,同時利用分佈式存儲節點上面的 page cache,減少了不必要的磁盤 IO;同時也避免了節點間跨網絡的 IO 開銷,最終有效地提升了 IO 效率。
有了前面這兩點,要實現實時低延遲計算,仍然存在不少挑戰。這裏引用計算機領域一個大佬的話 “所有計算機領域的問題都可以通過另外一層抽象來解決”。我們其實也是借鑑了這一思想,在整個系統裏面實現了一個分層緩存。
在數據層面, 利用了分佈式存儲節點上面的 page cache,利用寫入節點上面的 memory cache 這樣的一些緩存能力。
在索引層面, 緩存了倒排數值、字典等等一些索引塊的信息,減少反覆索引數據的加載以及解碼開銷。
在分析引擎層面, 對元數據進行緩存,將索引字段信息、Shard 分片信息,還有數據分佈等這些信息進行緩存,來加速 SQL 語義的解析以及物理執行計劃的生成過程。同時,對於相同 SQL 的邏輯執行計劃進行了緩存,來減少分析引擎核心節點 coordinator 上面的重複 SQL 解析的開銷。
在調度層面, 對數據的分片以及任務執行的調度歷史進行緩存,這樣做的好處是可能有一些節點上面已經加載過一部分的數據,它已經執行過一些歷史任務,對這些調度歷史進行緩存之後,可以基於親和力的調度,下次再計算的時候,可以再調度到這個節點上,最大化的利用數據的本地性以及下層緩存的一些收益。
在計算緩存層面, 實現了一個 partial agg operator 的算子。它主要是緩存相同數據在相同算子上的部分聚合計算結果,來避免相同數據反覆加載和計算的開銷。
最終在結果緩存層面, 會緩存完全相同的查詢的最終計算結果,來減少無效的查詢開銷。基本上通過這三個層面,在查詢的實時性以及低延時上面,可以做到較好的表現。
第二個核心問題就是超大數據規模的問題。 我們剛剛所講的存儲模型,由於用戶的日誌數據越寫越多,數據塊可能越來越多。按照我們前面數據本地性這樣的設計,所有的計算要在這樣的一個存儲節點上面去走,隨着單 Shard 上數據規模越來越大,單節點的數據讀取和計算能力可能是不夠的。所以整體來說,我們會將 LSM 落到分佈式存儲裏面的一些 block 的數據塊,把它散列到更多的存儲節點上面,分派給上層更多的計算節點,這樣整體再交給上面的計算匯聚層,去做相關的計算的匯聚。這樣一來,在存儲層面我們的 IO 壓力可以得到水平散列,在計算層面,我們的計算並行度能夠得到大幅的提升,在計算節點上面的內存、CPU 這些資源也能夠得到水平擴展。這個是我們在整體架構上面做的調整(即存儲計算分離)。
但是我們會面臨新的挑戰。由於剛剛所說的數據本地性的設計,就是爲了避免網絡開銷來高效地利用數據的本地的緩存,這種存算分離的模式,可能會丟失一部分數據的本地性,可能會導致延時的增高。另外,雖然我們去做了水平的擴展,但是由於數據的一些熱點或者是一些傾斜,可能會造成一些局部的熱點的負載壓力。
針對數據本地性丟失問題,我們的應對方式是基於親和力的調度,再去調度到這個節點上,利用這個節點上的數據的本地性,儘可能減少數據加載以及延時的開銷。另外一個就是去對負載進行實時的感知,通過均衡調度的一些策略,儘量去減少系統的負載的一些熱點。所以整體來說,我們是在速度和規模之間進行一個權衡。通過水平擴展,我們可以實現 IO、內存以及 CPU 等資源的橫向擴展能力。同時通過存算分離的架構,可以提升存算的並行度,解決超大數據規模的問題。並通過親和力的調度,以及負載均衡來應對新的挑戰。
第三個核心問題,系統會面臨一些高併發的查詢壓力。 整體來說,分析引擎的架構是非常簡單的,前面會有一個 coordinator,也就是一個協調節點。具體工作的 worker 節點,統一由 coordinator 節點來負責整體任務的調度。所以當用戶的併發查詢請求越來越高的時候,coordinator 上面的負載就會非常大,因爲它既要承接前面用戶的查詢請求,同時還要負責 SQL 的整體的解析任務,同時還要負責整體的計算過程當中的任務調度。我們在實際線上也進行了採樣分析,發現 SQL 解析部分,包括詞法分析、語法分析,還有 planner 生成以及優化改寫這些步驟,對於 CPU 的消耗開銷是非常大的,尤其是 plan 生成和優化改寫這兩步。
另一方面,我們也分析了我們線上的一些業務,發現很多業務來自於儀表盤、智能告警,還有 schedule SQL 這樣一些業務。這類業務查詢是固定不變的,只變動一些時間。所以這樣的查詢所對應的邏輯執行計劃是不變的,我們就在這個層面去做了查詢 plan 這樣的一個緩存,通過 plan 的 cache 來減少系統關鍵節點上面的關鍵負載的開銷。最終的效果是緩存命中率能夠達到 75%,同時關鍵節點上 CPU 的消耗能夠降低 20% 到 30%,而且我們的 JVM 的 GC 壓力和次數也有明顯的降低。
另外一個高併發的問題就是我們的 coordinator 節點上可能會存在這種網絡連接數爆炸式的增長。因爲 coordinator 在整個分析系統中,是核心協調節點,它要和集羣裏面所有的 worker 節點進行通信,任務上面進行節點上面的調度交互。所以當集羣裏面的節點規模越來越大,單個 coordinator 節點網絡通信的量是非常大的。面臨的挑戰是單秒就可能達到 10 萬以上的併發任務數。原來是 HTTP 短連接這種通信模式,單個 coordinator 作爲一個客戶端,要去和所有的 worker 節點進行通信。我們的應對方案就是複用信道,將 HTTP 短連接改造成 RPC 長連。通過複用信道來減少反覆建連的開銷。同時可以有效控制連接的規模,在集羣內把連接數做到恆定可控。
第四個核心問題是服務的高可用以及租戶之間的隔離, 這也是我們作爲雲服務不得不解決的一個核心問題。雲上多租戶的一個核心挑戰在於如何在共享資源的前提下去做好租戶之間的隔離,做好服務的可用性。我們的思路跟 Linux 的多租戶分時複用的思路是相似的,分成若干的時間片去給用戶使用相關的資源。重點在於我們怎麼去做隔離,以及怎麼保證系統的可用性,我們通過限流的方式來做自我的保護,限制用戶的使用。首先我們實現了分佈式的用戶查詢隊列,基於一致性哈希可以將具體的用戶落到具體的 coordinator 節點上,在 coordinator 節點上來統一管控用戶的資源使用情況,控制用戶的併發查詢數。同時在執行過程當中,去監控用戶的內存以及查詢時間的情況來限定其使用。
在具體的執行層面,我們會對 task 的時間片進行有效的限定,這裏麪包括計算層面的,還有查詢檢索層面的,以及 IO 層面的各種任務時間片。最後,在存儲層面,我們會對整體的數據掃描量進行一個限定,避免一下打爆我們的網絡帶寬。整體來說,通過這樣的一個分層的限流措施,我們可以比較好地做到在共享資源情況下的租戶隔離,也做到一個比較好的系統的自我防護,保證服務的高可用。
這裏還帶來另外一個問題,由於我們做了各種限定,可能用戶的數據在計算的過程當中沒有加載完整,這就會導致查詢不精確。針對這種情況,我們的解決思路是並沒有直接去返回,查詢失敗了會把本次查詢的一個已經計算出來的結果返回,並且會標記這個結果是不精確的。同時由於我們分層緩存的設計,通過讓用戶進一步地去查詢,可以漸進式地去逼近一個精確的結果。整體來說,我們是通過分層的保護和限流,來實現租戶資源之間的隔離和服務的穩定可用。同時我們要在速度、規模還有穩定性上面去做一些權衡和取捨。
總結一下前面所介紹的實踐經驗。
首先, 通過索引列存、數據本地性,以及分級的緩存,解決了第一個核心問題——查詢的實時性以及低延時問題;
第二, 通過水平的擴展、存算分離等架構上的改造,解決了第二個核心問題;
第三, 通過一些關鍵節點上面的性能提升,以及網絡上的優化,解決了系統高併發上的壓力。我們目前能夠支持雲上的海量用戶的在線併發查詢。同時我們經受住了多年雙 11 大促業務高峯併發峯值的考驗。
最後, 通過分層的限流以及調度隔離,實現了整體的服務的高可用以及多租戶的隔離,可以穩定支撐阿里集團數十個 BU,數千條業務線的日誌分析需求。
04 未來展望
最後展望一下我們目前正在做的,以及未來將開展的一些工作。首先,雲上多租戶的資源調度方面,我們還有非常大的優化空間。另外,在計算節點上,我們希望通過一些向量化等方案去做計算的加速。最後,我們還希望能夠去做一些創新性的探索,進一步提升用戶體驗。
05 問答環節
Q1:倒排索引和內存是怎麼進行高效關聯的?
A1:剛剛提到的查詢範式,是由三個要素組成,**時間、查詢和分析。**在查詢的時候,我們在 SQL 層面去做了一個改造,把前面的過濾條件,前面的查詢條件帶過來之後,把查詢進行了一個下推到存儲層裏面,利用存儲層面的存儲節點上面的索引能力,根據查詢條件可以檢出我需要的一些特徵數據,其他不需要的數據就不需要去加載。對於需要的數據我們再去利用,因爲我可能需要的數據是行存的這種日誌的形式,需要去分析一些局部的數據,這個地方我們又利用到列存的方式,我們將列存的數據加載到 SQL 的分析系統裏面,進行相關的分析和計算。這就是整體關聯的路徑。
Q2:數據的分析時延是指對熱數據有效還是冷數據?這兩邊怎麼進行考慮?
A2:我們在存儲層面去做了一個冷熱的分層。對於冷數據,會歸檔到更低頻的一些介質上面,對於用戶的體驗來說,其實可能就是冷數據的查詢和分析的延時會有一定的增高,但是成本上面會有減少。
Q3:block 是怎麼進行的劃分,比如根據什麼原則劃分 block?
A3:我們有多種策略,比如基於文件塊的大小,包括索引的一些條目數,去做切分。針對數據膨脹的情況,我們在產品層面的設計是,支持自動切分,達到一定的閾值,可以去做自動的切分。
今天的分享就到這裏,謝謝大家。
分享嘉賓
顧漢傑
阿里巴巴
技術專家
九年分佈式系統研發經驗,主要專注於大數據分析和存儲領域,先後參與過 HBase、Presto 等存儲和計算引擎的系統研發。目前在阿里雲日誌服務從事實時日誌分析系統的研發和性能優化等工作。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/B4p9NYjGg-yVLXW-oVsgig