Presto 在阿里云實時日志分析中的實踐和優化
一、業務背景
首先第一部分介紹一下我們的業務背景。阿里云 SLS 是一個云上一站式可觀測日志服務平臺。
SLS 提供了強大的數據采集、數據加工、消費投遞等能力,數據采集利器 ilogtail 目前也已經完全開源。數據采集上來后提供數據的統一存儲,包括熱存、智能冷存等,幫助用戶盡可能節省成本。在存儲之上,提供了數據處理與分析能力,包括即席查詢分析、關聯分析等。這兩塊構成了整個 SLS 產品的核心基礎能力。在這個基礎能力之上提供了豐富的工具和應用,最終服務于各種不同的角色和用戶。
本文將聚焦在存儲和分析基礎能力上面的建設,重點分享日志分析系統,以及在面對核心問題時的一些架構設計思路和經驗。
這是具體日志分析業務覆蓋和服務的能力,主要是圍繞日志場景去進行數據分析。日志數據的形態是多種多樣的,包括無結構的、半結構的以及結構化的。我們在數據源層面統一收集、存儲到存儲引擎當中,再通過 SQL 的分析引擎向上層提供數據分析服務。
具體業務,包括比如實時監控、實時大屏這一類基于日志數據分析去做的一些業務,其刷新率非常高,所以用戶的并發查詢請求量非常大;還有一些比如像基于日志的數據去做實時的告警、鏈路分析、交互式分析、AI 異常檢測等,這一類業務主要是對于數據的時效性要求非常高,要求查詢和分析延時要能夠做到秒級實時。
還有一類業務,比如像可視化工具、運營報表、schedule SQL 這一類的業務,數據量是非常大的,面臨超大數據規模的問題。就整體業務覆蓋而言,SLS 除了在阿里云上對外提供日志服務外,在集團內部也被眾多的 BU 所使用,同時也經歷了多年雙十一的挑戰。
分析引擎的整體能力方面,我們目前每天大概有數十億次的查詢,每天的行掃描規模大概在千萬億級別,吞吐大概在數十 PB 規模。而我們平均的查詢延時小于 300ms,在業務高峰時刻的并發峰值能夠達到 7.2 萬,屆時系統會面臨數十萬的 QPS 壓力。以上就是整體業務的情況。
二、核心問題
面對上述業務場景和需求,我們面臨的最核心問題主要包括四個方面。
首先,區別于傳統的離線數倉,我們是一個在線的實時分析服務,所以對于查詢的低延時要求非常高。我們要求秒級的查詢,并且數據要可見即可得、可得即可算。
第二,我們面對的數據處理規模是非常大的,數據的行掃描規模可能從百萬到千億級別不等,并且規模是彈性多變的。
第三,會面臨用戶高并發的查詢壓力,像雙十一這種業務高峰時刻能達到 7.2 萬的并發峰值,同時單點會有上千的并發查詢、數十萬的計算任務,所以如何去解決系統在面臨這種高并發查詢下的負載壓力,是我們面臨的又一個核心問題。
最后還要去解決整個云服務的高可用以及租戶間的隔離,由于云服務多、租戶是共享云上資源的,所以不可避免會有各種各樣的熱點資源爭用。怎樣去解決服務的治理以及壓力的防控,保障云服務的高可用,也是我們面臨的核心問題之一。
三、關鍵設計
接下來主要圍繞這四個核心的問題,分享在系統架構設計以及關鍵環節上面的思考和權衡。首先是 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,數千條業務線的日志分析需求。