初探分佈式鏈路追蹤

本篇文章,主要介紹應用如何正確使用日誌系統,幫助用戶從依賴、輸出、清理、問題排查、報警等各方面全面掌握。

可觀測性

可觀察性不單是一套理論框架,而且並不強制具體的技術規格。其核心在於鼓勵團隊內化可觀察性的理念,並確保由研發人員構建的應用程序具備可觀察性。在學術領域中,儘管 “可觀測性” 這一術語是近年來從控制理論中引進的新詞,但實際上,它在計算機科學領域已有深厚的實踐基礎。學者們通常會把可觀測性細化爲三個更具體的研究方向:事件日誌、鏈路追蹤和聚合度量。這三個領域雖然各有側重點,但並非完全孤立,它們之間存在着天然的交集與互補性。

  1. 日誌 (Logging),展現的是應用運行而產生的事件或者程序在執行的過程中間產生的一些日誌,可以詳細解釋系統的運行狀態,但是存儲和查詢需要消耗大量的資源。所以往往使用過濾器減少數據量。

  2. 度量 (Metrics),是一種聚合數值,存儲空間很小,可以觀察系統的狀態和趨勢,但對於問題定位缺乏細節展示。這個時候使用等高線指標等多維數據結構來增強對於細節的表現力。例如統計一個服務的 TBS 的正確率、成功率、流量等,這是常見的針對單個指標或者某一個數據庫的。

  3. 追蹤 (Tracing),面向的是請求,可以輕鬆分析出請求中異常點,但與日誌有相同的問題就是資源消耗較大。通常也需要通過採樣的方式減少數據量。比如一次請求的範圍,也就是從瀏覽器或者手機端發起的任何一次調用,一個流程化的東西,需要軌跡去追蹤。

在工業界,歷經長期的競爭,日誌和度量領域的主導技術已逐漸明朗。日誌收集與分析方面,Elastic Stack(亦稱爲 ELK Stack)已成爲廣泛採納的技術選擇。然而,追蹤技術的發展路徑與日誌和度量領域顯然不同。追蹤技術高度依賴於特定的網絡協議和編程語言。服務間是通過 HTTP 還是 gRPC 通信,會直接決定追蹤實施的具體方法。同樣,服務是否採用 Java、Golang、還是 Node.js 編寫,也會影響到如何追蹤進程內調用堆棧。這種依賴性使得追蹤工具通常需要以插件或探針的形式進行深度集成,因而具有一定的侵入性。此外,由於追蹤技術需要適應不同的語言和網絡環境,追蹤領域很難形成單一的主導者。相反,市場上存在多樣化的產品,旨在滿足各種不同技術棧的追蹤需求。

本文主要探討其中的追蹤下日誌內容。

鏈路追蹤

分佈式鏈路追蹤公認的起源是 Google 在 2010 年發表的論文《Dapper : a Large-Scale Distributed Systems Tracing Infrastructure》,這篇論文介紹了 Google 從 2004 年開始使用的分佈式追蹤系統 Dapper 的實現原理。

論文《Dapper : a Large-Scale Distributed Systems Tracing Infrastructure》地址:https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/papers/dapper-2010-1.pdf

▐基本原理

分佈式鏈路追蹤的基本原理就是在分佈式應用的接口方法上設置一些觀察點,然後在入口節點給每個請求分配一個全局唯一的標識 TraceId。當請求流經這些觀察點時就會記錄一行對應的鏈路日誌(包含鏈路唯一標識,接口名稱,時間戳,主機信息等)。最後通過 TraceId 將一次請求的所有鏈路日誌進行組裝,就可以還原出該次請求的鏈路軌跡。

分佈式鏈路追蹤實現請求回溯的關鍵點有兩個:一是低成本、高質量的觀察點設置,也就是鏈路插樁,確保追蹤的信息足夠豐富,能夠快速定位異常根因;二是保證鏈路上下文在不同環境下都能夠完整透傳,避免出現上下文丟失導致的斷鏈現象。

▐基礎術語

雖然分佈式鏈路追蹤的實現方式多種多樣,但是仍然有一些基礎術語在業界具備廣泛的共識。

一條 Trace 代表一次入口請求在 IT 系統內的完整調用軌跡及其關聯數據集合。其中,全局唯一的鏈路標識 TraceId,是最具代表的一個屬性。通過 TraceId 才能將同一個請求分散在不同節點的鏈路數據準確的關聯起來,實現請求粒度的 “確定性關聯” 價值。

以集團的 Eagleeye 設計的 traceId 設計爲例,根據這個 id,可以知道這個請求在 2022-10-18 10:10:40 發出,被 11.15.148.83 機器上進程號爲 14031 的 Nginx(對應標識位 e)接收到。其中的四位原子遞增數從 0-9999,目的是爲了防止單機併發造成 traceId 碰撞。

Span 是一個操作,它代表系統中一個邏輯運行單元。Span 之間通過嵌套或者順序排列建立因果關係。Span 包含以下對象

  1. Operation Name:描述了當前接口的行爲語義,比如 /api/createOrder 代表執行了一次創建訂單的動作。

  2. SpanId/ParentSpanId:接口調用的層級標識,用於還原 Trace 內部的層次調用關係。

  3. Start/FinishTime:接口調用的開始和結束時間,二者相減就是該次調用的耗時。

  4. StatusCode:響應狀態,標識當次調用是成功或失敗。

  5. Tags & Events:調用附加信息,詳見下面的描述。

其中最重要的是 SpanId 的設計。同樣以阿里的 Eagleeye 的 spanId(rpcId)設計爲例,Eagleeye 設計了 RpcId 來區別同一個調用鏈下多個網絡調用的順序和嵌套層次,用 0.X1.X2.X3.....Xi 來表示,根節點的 RpcId 固定從 0 開始,id 的位數("." 的數量)表示了 Span 在這棵樹中的層級,Id 最後一位表示了 Span 在這一層級中的順序。那麼給定同一個 Trace 中的所有 RpcId,便可以很容易還原出一個完成的調用鏈:

- 0
  - 0.1
    - 0.1.1
    - 0.1.2
      - 0.1.2.1
  - 0.2
    - 0.2.1
  - 0.3
    - 0.3.1
      - 0.3.1.1
    - 0.3.2

如果需要進一步記錄請求的行爲特徵,可以使用 Tags 來擴展語義。Tags 是一組由 {Key:Value} 組成的鍵值對集合,描述這一次接口調用的具體屬性。比如 Eagleeye 裏就有「Tags」的實現(UserData),阿里的全鏈路壓測標識就是通過 UserData 裏傳遞實現的。

在分佈式追蹤的上下文中,一個 Trace 可被視爲一個有向無環圖,其中每個 Span 代表圖中的一個節點,而節點之間的連接則表示爲鏈接。觀察這樣的圖表,我們可以看到一個單獨的 Span 節點可能擁有多條鏈接,這表明它具有多個子 Span。這種結構揭示了各個操作間的父子或者因果關係,從而使得追蹤整個請求的流程成爲可能。

Trace 定義了 Span 間兩種基本關係:

  1. ChildOf:表示父 Span 在一定程度上依賴子 Span。

  2. FollowsFrom:表示父 Span 完全不依賴其子 Span 的結果。

▐鏈路追蹤的挑戰

本地存儲埋點數據涉及磁盤操作,而磁盤 I/O 速度通常較慢。在高併發的環境中,如果採用同步刷新磁盤的方式,可能會對原有業務的性能造成顯著影響。因此,在鏈路追蹤系統中進行數據埋點時,應當儘量減少對系統的性能損耗,確保對原業務的邏輯和性能具有無侵入性。這意味着追蹤系統的設計需要儘量輕量化,並採取策略如異步處理、緩存等方法來降低對業務性能的影響。

併發環形隊列

集團的 Eagleeye 採用併發環形隊列存儲 Trace 數據,如下圖所示:

環形隊列確實是日誌框架中實現異步日誌寫入的一種常用技術。在這種隊列中,存在兩個關鍵的指針,即讀指針(take)和寫指針(put)。

  1. 讀指針(take): 它指向隊列中的最舊數據,即下一條待消費的數據。

  2. 寫指針(put): 它指向隊列中下一個將要存放新數據的位置。

這個隊列被設計爲支持原子性的讀寫操作,以保證在多線程環境中數據的一致性。這意味着,當一個線程在執行讀或寫操作時,其他線程不能同時修改被操作的數據項。

讀指針和寫指針按同一方向(如時鐘方向)移動,隨着數據的不斷生產和消費,這兩個指針在隊列中循環前進。然而,如果生產數據的速度持續超過消費速度,寫指針最終會 “追上” 讀指針,這種情況被稱爲“套圈”。

當出現套圈現象時,隊列將根據預設的策略來處理新產生的數據。常見的處理策略包括:

  1. 丟棄即將寫入的新數據,以保護隊列中已存在的數據不被覆蓋。

  2. 覆蓋隊列中最舊的數據,這意味着最先入隊的數據將被新數據取代,這種策略適用於對最新數據保持最高優先級的場景。

選擇哪種策略取決於具體應用場景的需求和對數據丟失的容忍度。環形隊列的這種設計使得它在處理高併發日誌數據時非常高效,能夠在保證性能的同時減少資源佔用。

Skywalking 在實現上有所區別,採用分區的 QueueBuffer 存儲 Trace 數據,多個消費線程通過 Driver 平均分配到各個 QueueBuffer 上進行數據消費:

在高性能的應用場景中,隊列的實現方式對於整體性能有顯著的影響。QueueBuffer 通常有兩種不同的實現方式:

  1. 基於 JDK 的阻塞隊列:這種實現方式利用了 Java 標準庫中的 java.util.concurrent 包下的阻塞隊列,例如 ArrayBlockingQueue 或 LinkedBlockingQueue。這些隊列內部處理了線程同步的邏輯,使得在多線程環境下生產者和消費者可以安全地進行併發操作。基於 JDK 的阻塞隊列通常用於服務端,因爲服務端可以承受相對較重的負載,並且更注重於穩定性和線程安全。

  2. 普通數組 + 原子下標:這種實現方式使用了一個普通的數組,並結合了原子操作的下標(如 AtomicInteger)用於記錄讀寫的位置。這種隊列不是阻塞的,因此,當隊列滿時,它需要顯式地處理生產者的等待邏輯,當隊列空時,需要處理消費者的等待邏輯。SkyWalking 的 Agent 端採用這種方式,因爲它相對更輕量級,且在高吞吐量場景下提供了更高的性能。Agent 端的性能尤其重要,因爲它直接運行在應用程序內部,性能的任何抖動都可能影響到應用程序本身的性能。

在普通數組 + 原子下標的實現中,有一些值得關注的點:

  1. 原子性操作:通過使用原子類(如 AtomicInteger),可以確保在併發場景下修改下標時的線程安全性,避免了鎖的開銷。

  2. 非阻塞算法:由於不使用阻塞隊列,這種實現可以採用非阻塞算法來優化性能,尤其是在高併發的生產者 - 消費者模型中。

  3. 迴繞邏輯:當數組達到其末端時,讀寫下標需要回繞到數組的開始,形成一個環狀結構,這就是所謂的環形緩衝區。

  4. 飽和策略:需要定義當隊列滿時的行爲,是等待、丟棄數據還是覆蓋舊數據。

  5. 總的來說,不同的 QueueBuffer 實現方式適用於不同的使用場景

鷹眼(EagleEye)和 SkyWalking 採用了不同的數據採集及傳輸策略,每種方法都有其適用場景和相應的權衡。

鷹眼系統首先將數據存儲到本地日誌文件中,然後利用一個代理(agent)來收集這些日誌並將其傳輸到服務端。這種基於日誌加邊車代理的方法使得數據採集可以在不直接干擾主應用邏輯的情況下進行,但這也意味着需要處理日誌文件的管理和代理的維護。

相比之下,SkyWalking 提供了 gRPC 和 Kafka 兩種基於服務的數據傳輸方式,這使得數據可以更實時地傳輸到處理後端。gRPC 是一種高性能的遠程過程調用(RPC)框架,Kafka 是一個分佈式流處理平臺,兩者都能有效地處理大量的數據流。

從架構上看,SkyWalking 採取了分離應用層埋點和中間件代碼的策略,這在某種程度上實現了應用級別的透明性。用戶不需要在應用代碼中直接管理追蹤邏輯,而是依賴中間件層的插件來自動完成數據的採集。然而,這種方式意味着當中間件需要升級時,相關的插件也可能需要更新,這可能在維護方面引入一些挑戰。

鷹眼的埋點方法由專門的中間件團隊來維護,對於上層應用來說同樣是透明的,這意味着應用開發者不需要關心數據採集的具體實現細節。這種方法非常適合阿里巴巴集團內部的環境,因爲它能夠提供統一的標準和容易控制的集成點。

總的來說,這兩種系統提供了不同的解決方案,各自的優點和挑戰都值得在選擇和實施追蹤系統時予以考慮。

在分佈式鏈路追蹤系統中,方法增強(通常稱爲 “埋點”)指的是在代碼中插入額外的邏輯來捕獲和記錄執行信息,這是實現追蹤的核心技術。Dapper,谷歌的分佈式追蹤系統,提出的設計原則要求方法增強必須同時滿足應用級透明性和低開銷這兩個關鍵條件:

  1. 應用級透明:開發者不需要修改業務代碼或僅需要極少的修改即可實現埋點,這意味着追蹤邏輯對應用層是不可見或幾乎不可見的。

  2. 低開銷:埋點操作對系統的性能影響應當儘可能小,以避免追蹤邏輯本身成爲系統性能的瓶頸。

現在,我們來比較阿里巴巴的 EagleEye 與開源項目 SkyWalking 在埋點技術上的不同做法:

硬編碼

EagleEye:阿里巴巴的 EagleEye 通過中間件層進行數據採集和追蹤,通常這由集團的中間件團隊負責維護。這種中間件集成方式允許上層應用無需知曉具體的追蹤邏輯,因此在應用級別上保持了較高的透明度。然而,這種方法可能會在中間件升級時需要同步更新埋點邏輯,增加了維護的複雜度。

字節碼增強

SkyWalking:SkyWalking 提供了自動插樁的能力,通常通過 Java Agent 技術在運行時不侵入地修改字節碼,插入追蹤代碼。這種方式對業務代碼完全透明,開發者無需修改任何業務邏輯即可實現埋點。同時,SkyWalking 旨在保持低開銷,以減少對應用性能的影響。由於它是一個開源項目,SkyWalking 更容易適應多樣化的技術棧和快速發展的生態。

兩種方法各有優勢和劣勢,EagleEye 的中間件集成方式適合阿里巴巴這樣擁有統一技術棧和強大內部支持的大型企業環境。而 SkyWalking 的自動插樁技術則提供了靈活性和廣泛的社區支持,更適合多變的技術環境和需要快速適應新技術的公司。選擇哪種埋點方式取決於企業的具體需求、技術棧的複雜性以及維護能力。

在多線程併發調用環境下的數據鏈路埋點也是一個值得關注問題,當一個服務考慮性能問題可能會起多個線程同時調用其他不同的模塊。鏈路系統如何保證這些調用還是符合 openTrace 規範,保證 traceId 和 spanId 有序。

目前 Java 生態下,普遍的思路是用父線程的 ThreadLocal 中拿到保存的 trace 信息,然後作爲參數傳遞給子線程,子線程在初始化的時候設置 trace 信息來避免丟失。

值得關注的是,集團提供了 InheritableThreadLocals 的子類 TransmittableThreadLocal,解決了 InheritableThreadLocal 只能再 new Thread 的時候傳遞本地變量,無法應用到線程池的問題。可以應用來作鏈路追蹤,傳遞變量等用途。美團也實現了類似的子類 TransmissibleThreadLocal。

日誌收集和分析

日誌用來記錄系統運行期間發生過的離散事件,在目前複雜的分佈式系統中,很難只依靠 tail、grep、awk 來從單臺機器的日誌中挖掘信息了,往往還要有專門的全局查詢和可視化功能。此時,從打印日誌到分析查詢之間,還隔着收集、緩衝、聚合、加工、索引、存儲等若干個步驟,如下圖所示:

提到日誌實時分析,大部分人第一想到是社區很火 ELK Stack。ELK 方案上手難度小、開源材料衆多、在社區中有大量的使用案例。於此同時,阿里巴巴集團也推出了對日誌場景的解決方案產品日誌服務 (SLS/Log) 。下面將先後介紹這兩種框架並分析優劣。

▐開源的 ELK 方案

ELK Stack 是一個縮略詞,用來描述由三個常見項目組成的堆棧:Elasticsearch、Logstash 和 Kibana。ELK Stack 通常被稱爲 Elasticsearch,作用是聚合來自所有系統和應用程序的日誌,分析這些日誌,並創建可視化來進行應用程序和基礎設施監控、更快的故障排除、安全分析等。

E = Elasticsearch 

Elasticsearch 是在 Apache Lucene 上構建的分佈式搜索和分析引擎。對各種語言、高性能和無架構 JSON 文檔的支持使 Elasticsearch 成爲各種日誌分析和搜索使用案例的理想選擇。 

L = Logstash

Logstash 是一個開源數據攝取工具,允許從各種來源收集數據,轉換數據,並將數據發送到希望的目標。

K = Kibana

Kibana 是一種數據可視化和挖掘工具,可以用於日誌和時間序列分析、應用程序監控和運營智能使用案例。

寫日誌是在服務節點中進行的,但我們不可能在每個節點都單獨建設日誌查詢功能。這不是資源或工作量的問題,而是分佈式系統處理一個請求要跨越多個服務節點,爲了能看到跨節點的全部日誌,就要有能覆蓋整個鏈路的全局日誌系統。這個需求決定了每個節點輸出日誌到文件後,必須將日誌文件統一收集起來集中存儲、索引,由此便催生了專門的日誌收集器。

最初,ELK 中日誌收集與下一節要講的加工聚合的職責都是由 Logstash 來承擔的,Logstash 除了部署在各個節點中作爲收集的客戶端(Shipper)以外,它還同時設有獨立部署的節點,扮演歸集轉換日誌的服務端(Master)角色。Logstash 有良好的插件化設計,收集、轉換、輸出都支持插件化定製,應對多重角色本身並沒有什麼困難。但是 Logstash 與它的插件是基於 JRuby 編寫的,要跑在單獨的 Java 虛擬機進程上,而且 Logstash 的默認的堆大小就到了 1GB。對於歸集部分(Master)這種消耗並不是什麼問題,但作爲每個節點都要部署的日誌收集器就顯得太過負重了。後來,Elastic.co 公司將所有需要在服務節點中處理的工作整理成以 Libbeat 爲核心的 Beats 框架,並使用 Golang 重寫了一個功能較少,卻更輕量高效的日誌收集器 Filebeat。

日誌不追求絕對的完整精確,只追求在代價可承受的範圍內保證儘可能地保證較高的數據質量。一種最常用的緩解壓力的做法是將日誌接收者從 Logstash 和 Elasticsearch 轉移至抗壓能力更強的隊列緩存,譬如在 Logstash 之前架設一個 Kafka 或者 Redis 作爲緩衝層,面對突發流量,Logstash 或 Elasticsearch 處理能力出現瓶頸時自動削峯填谷,甚至當它們短時間停頓,也不會丟失日誌數據。

將日誌集中收集之後,存入 Elasticsearch 之前,一般還要對它們進行加工轉換和聚合處理。這是因爲日誌是非結構化數據,一行日誌中通常會包含多項信息,如果不做處理,那在 Elasticsearch 就只能以全文檢索的原始方式去使用日誌,既不利於統計對比,也不利於條件過濾。

Logstash 的基本職能是把日誌行中的非結構化數據,通過 Grok 表達式語法轉換爲上面表格那樣的結構化數據,進行結構化的同時,還可能會根據需要,調用其他插件來完成時間處理(統一時間格式)、類型轉換(如字符串、數值的轉換)、查詢歸類(譬如將 IP 地址根據地理信息庫按省市歸類)等額外處理工作,然後以 JSON 格式輸出到 Elasticsearch 中(這是最普遍的輸出形式,Logstash 輸出也有很多插件可以具體定製不同的格式)。有了這些經過 Logstash 轉換,已經結構化的日誌,Elasticsearch 便可針對不同的數據項來建立索引,進行條件查詢、統計、聚合等操作的了。

Elasticsearch 是整個 Elastic Stack 技術棧的核心,其他步驟的工具,如 Filebeat、Logstash、Kibana 都有替代品,有自由選擇的餘地,唯獨 Elasticsearch 在日誌分析這方面完全沒有什麼值得一提的競爭者,幾乎就是解決此問題的唯一答案。核心原因是 Elasticsearch 的優勢正好與日誌分析的需求完美契合:

  1. 數據特徵的角度看,日誌是典型的基於時間的數據流。日誌雖然增長速度很快,但已寫入的數據幾乎沒有再發生變動的可能。以按日索引爲例,由於你能準確地預知明天、後天的日期,因此全部索引都可以預先創建,這免去了動態創建的尋找節點、創建分片、在集羣中廣播變動信息等開銷

  2. 從數據價值的角度看,日誌基本上只會以最近的數據爲檢索目標,隨着時間推移,早期的數據將逐漸失去價值。這點決定了可以很容易區分出冷數據和熱數據,進而對不同數據採用不一樣的硬件策略。

  3. 從數據使用的角度看,分析日誌很依賴全文檢索和即席查詢,對實時性的要求是處於實時與離線兩者之間的 “近實時”,即不強求日誌產生後立刻能查到,但也不能接受日誌產生之後按小時甚至按天的頻率來更新,這些檢索能力和近實時性,也正好都是 Elasticsearch 的強項。

Elasticsearch 只提供了 API 層面的查詢能力,它通常搭配同樣出自 Elastic.co 公司的 Kibana 一起使用,可以將 Kibana 視爲 Elastic Stack 的 GUI 部分。Kibana 儘管只負責圖形界面和展示,但它提供的能力遠不止讓你能在界面上執行 Elasticsearch 的查詢那麼簡單。Kibana 宣傳的核心能力是 “探索數據並可視化”,即把存儲在 Elasticsearch 中的數據被檢索、聚合、統計後,定製形成各種圖形、表格、指標、統計,以此觀察系統的運行狀態,找出日誌事件中潛藏的規律和隱患。

▐阿里的 SLS 方案

阿里雲日誌服務 SLS 基於阿里雲自研靈活索引的一站式雲原生可觀測數據分析平臺。爲 Log/Metric/Trace 等數據提供大規模、低成本、實時平臺化服務。一站式提供數據採集、加工、分析、告警可視化與投遞功能。

Logtail 是集團雲提供的日誌服務(SLS)的一個組件,它作爲日誌採集客戶端,提供了一種高效且易於配置的方式來接入日誌數據。由於 Logtail 是用 C++ 語言編寫的,它具有較高的性能和較低的資源消耗,適合在各種環境下運行,包括資源受限的環境。

Logtail 的主要功能包括:

  1. 無侵入式採集:Logtail 能夠監視指定的日誌文件,實時採集更新的日誌數據,而無需修改現有的應用程序代碼。

  2. 多種日誌格式支持:除了採集標準的文本日誌文件,Logtail 還能夠採集其他類型的日誌,如 MySQL 的二進制日誌(binlog)、HTTP 數據、以及容器日誌等。

  3. 容器化環境支持:Logtail 提供對容器友好的支持,無論是標準容器還是處於 Kubernetes 集羣中的容器,Logtail 都能夠靈活地採集日誌數據。

  4. 異常處理:Logtail 有一套完備的機制來處理在日誌採集過程中可能出現的異常,如當遇到網絡故障或服務端異常時,它可以通過主動重試或將數據緩存到本地等方式來確保數據的安全和完整性。

由於 Logtail 的這些特性,它成爲了一個非常強大且可靠的日誌採集工具,特別是在需要確保日誌數據不丟失的情況下。它的無侵入性質意味着開發者或運維人員可以在不影響現有應用程序的情況下部署日誌採集,而其對容器和微服務架構的友好支持則使其非常適合現代雲原生應用。

Logtail 作爲日誌採集客戶端,其文件採集流程設計得非常全面,涵蓋了從日誌生成到傳輸的多個關鍵環節。以下是 Logtail 文件採集流程的六個主要步驟:

  1. 文件監聽:Logtail 監控配置中指定的日誌文件或目錄,以便於檢測文件的創建、更新或者刪除事件。這通常通過文件系統的通知機制來實現,如 Linux 上的 inotify。

  2. 文件讀取:一旦文件發生變化,Logtail 會讀取文件內容。對於更新的文件,Logtail 保持追蹤當前的讀取進度,確保從上次停止的地方繼續讀取,避免重複或遺漏。

  3. 日誌處理:讀取到的原始日誌數據會經過初步處理,比如分割日誌行、解析字段等,將原始文本轉換爲結構化的日誌記錄。

  4. 日誌過濾:用戶可以定義過濾規則,根據日誌內容或屬性決定哪些日誌記錄應該被採集,哪些應該被忽略。這一步可以減少無用數據的傳輸和存儲,優化成本和性能。

  5. 日誌聚合:在發送之前,Logtail 可以對日誌進行批處理,合併多個日誌記錄爲一個數據包,減少網絡請求的次數,提高數據傳輸效率。

  6. 數據發送:聚合後的日誌數據會被髮送到配置的目標,例如阿里雲日誌服務 SLS 的服務器。數據發送過程中,Logtail 會處理網絡異常等問題,確保數據的可靠傳輸。

以上六個環節構成了 Logtail 文件採集的完整流程,每個步驟都是爲了確保日誌數據的準確、高效、可靠採集。在高可用性和高性能的要求下,Logtail 的設計使得日誌數據能夠從源頭到目的地的遷移過程中保持完整性和一致性。

對比開源的 logstash,和 logtail 的對比如下:

moXTiO

總體來說,logstash 支持所有主流日誌類型,插件支持最豐富,可以靈活 DIY,但性能較差,JVM 容易導致內存使用量高。logtail 佔用機器 cpu、內存資源最少,結合阿里雲日誌服務的 E2E 體驗良好,但目前對特定日誌類型解析的支持較弱。

阿里雲日誌服務(SLS)提供的數據加工功能是一項強大的特性,使得用戶能夠在日誌數據進入存儲和分析階段之前對其進行預處理。這些功能對於數據的清洗、轉換、安全保護和增強都非常關鍵,尤其是在構建複雜的數據處理流水線時。以下是數據加工功能的幾個關鍵點和它們的應用場景。

  1. 數據規整:這個功能允許用戶對無結構或半結構化的日誌進行字段提取和格式轉換,從而得到結構化數據。這對於後續的實時處理、分析和數據倉庫計算來說是非常重要的,因爲結構化數據更容易進行查詢和分析。

  2. 數據富化:數據富化功能可以通過字段連接(JOIN)操作,將日誌數據(如訂單日誌)和其他維度數據(如用戶信息表)相結合。這樣可以爲原始日誌添加更豐富的上下文信息,提高數據分析的深度和準確性。

  3. 數據流轉:流轉功能支持跨地域的數據傳輸,允許用戶將數據從一個地域轉移到另一個地域。例如,可以將海外地域的日誌數據傳輸到中心地域,實現日誌的集中化管理和分析。

  4. 數據脫敏:數據脫敏對於符合隱私法規和公司政策是必不可少的。SLS 可以在日誌數據中識別並隱藏或替換敏感信息,比如密碼、手機號或地址等,來保護用戶隱私。

  5. 數據過濾:數據過濾允許用戶基於特定條件選擇性地提取日誌條目。這可以用來隔離關鍵服務的日誌,以便進行重點監控和分析。

應用場景:

  1. 數據規整(一對一):從單個源 Logstore 讀取數據,經過加工處理後,輸出到單個目標 Logstore,適用於簡單的加工任務。

  2. 數據分派(一對多):從單個源 Logstore 讀取數據,根據不同的規則或條件將數據加工後分發到多個目標 Logstore 中,適用於需要將日誌按類型或用途分開處理的場景。

  3. 數據融合(多對一):從多個源 Logstore 讀取數據,將它們合併或加工後輸出到一個目標 Logstore 中,適用於需要綜合多個數據源進行統一分析的場景。

通過這些數據加工功能,SLS 能夠提供靈活、強大的數據處理能力,幫助用戶更好地管理和分析日誌數據,同時保護敏感信息。這對於需要實時數據洞察和快速響應的企業來說是非常有價值的。

阿里雲日誌服務(SLS)的存儲引擎專門爲處理可觀測數據而設計,包括日誌、指標和追蹤數據。它旨在提供一個統一和高效的解決方案,用以滿足大規模數據存儲和快速查詢的需求。下面是對這個存儲引擎的兩個關鍵特性的進一步解讀:

統一性(Unified)

  1. 多類型數據支持:統一的存儲引擎意味着它能夠存儲和處理多種類型的可觀測數據,無論是結構化的日誌數據、時間序列的指標數據還是分佈式追蹤的信息。這樣的設計減少了需要使用和管理多個存儲系統的複雜性。

  2. 統一查詢接口:有了統一的存儲引擎,用戶可以通過一個共同的查詢接口訪問不同類型的數據,這提高了使用效率,並允許跨數據類型的分析和關聯。

  3. 統一的管理和運維:統一存儲引擎也簡化了數據的管理和運維任務,因爲它減少了需要學習和監控的工具和接口的數量。

性能(Fast)

  1. 高速寫入:SLS 的存儲引擎針對高速數據寫入進行了優化,以支持大數據量的實時採集。這對於高流量網站、大型分佈式應用和 IoT 設備等場合至關重要。

  2. 高效查詢:SLS 存儲引擎還針對快速查詢進行了優化,確保即使在涉及大規模數據集時,也能夠快速返回結果。

  3. 適應大規模場景:阿里雲天然服務於各種規模的企業,包括那些擁有超大規模數據場景的企業。SLS 的存儲引擎設計考慮了這些場景的需求,保證了擴展性和穩定性。

總體來說,SLS 的存儲引擎通過統一和快速的寫入與查詢功能,爲處理大規模的可觀測數據提供了一個強大、高效且易於管理的解決方案。整體架構如下:

接入層協議支持:

  1. 接入層的設計非常靈活,支持多種數據寫入協議,這意味着無論數據來源是什麼(如應用程序、服務器、網絡設備等),都能夠順利與 SLS 集成。

  2. 寫入的數據首先被放入一個先進先出(FIFO)的管道中,這個管道模型類似於 Apache Kafka 的消息隊列(MQ)模型,提供了高吞吐量和可靠性。

管道和數據消費:

  1. 管道不僅存儲數據,還支持數據消費,允許各類下游系統(如實時分析、告警、可視化工具等)接入並處理數據。

  2. 這種設計實現了數據的異步處理,增強了系統的整體擴展性和彈性。

索引結構和存儲優化:

  1. 在管道之上,存儲引擎爲不同類型的數據(Traces/Logs 和 Metrics)構建了兩套索引結構。

  2. 利用倒排索引(Inverted Index)、列式存儲(Columnar Storage)以及壓縮(Compaction)等技術,SLS 能夠提供快速的查詢性能,同時優化存儲空間的使用效率。

統一的進程架構:

  1. 上述所有功能都在一個統一的進程內實現,這意味着可以在單一的系統中處理日誌、指標和追蹤數據,大大簡化了運維和部署的複雜性和成本。

純分佈式框架:

  1. SLS 的存儲引擎基於純分佈式架構構建,支持水平擴展,可以隨着數據量的增長而增加更多的存儲節點。

  2. 單個存儲節點(Store)能夠處理極高的數據量,最多支持每天處理 PB 級別的數據寫入,適合大規模的數據中心和雲環境。

在查詢方面,SLS 的查詢和分析引擎整合了多種查詢語法和分析能力,提供了一個強大的查詢環境:

  1. 關鍵詞查詢:支持對存儲在 SLS 中的日誌數據進行全文搜索,類似於其他日誌管理系統中的關鍵詞查詢功能。這主要用於快速查找特定日誌條目或篩選日誌信息。

  2. PromQL 的語法兼容:PromQL 是 Prometheus 查詢語言,專門用於時間序列數據的查詢。SLS 兼容 PromQL 語法,使得用戶能夠利用 PromQL 進行指標數據的查詢和分析。

  3. SQL 作爲頂層分析語言:1、爲了實現對可觀測數據的深入分析,SLS 擴展了 SQL 語言的能力,使其能夠支持連接關鍵詞查詢、PromQL 等語法;2、通過 SQL,用戶可以執行更復雜的數據操作,如聚合、排序、聯接和子查詢等,這爲數據分析提供了極大的靈活性。

  4. 外部數據源和機器學習模型的集成:SLS 的 SQL 擴展還允許用戶連接外部數據庫和機器學習模型。這意味着用戶可以將 SLS 中的數據與其他數據源相結合,或使用機器學習算法進行高級分析。

  5. 可觀測數據的融合分析:SLS 使得日誌、指標和追蹤數據能夠在一個統一的分析環境中進行關聯和分析。這種融合分析能力使用戶能夠以多維度來理解和分析系統的行爲和性能。

通過這樣的設計,SLS 提供了一個功能全面的查詢和分析環境,可以滿足從簡單的文本搜索到複雜的數據挖掘和分析的各種需求。對於開發人員、運維人員和數據分析師來說,SLS 的查詢功能極大地提高了他們處理和分析可觀測數據的效率和準確性。

▐ELK 對比 SLS

ELK 的核心 ElasticSearch 基於 Lucene 全文索引實現,面向 Document 類型,構建一套完整的可觀測分析平臺需要組合多款服務,這其中包括 logstash、Kibana、Kafka、Flink、TSDB、Prometheus 等服務,對於規模、查詢能力等方面存在一定限制,整體成本較高。

日誌服務 SLS 基於阿里雲自研靈活索引,支持一站式雲原生可觀測性,多規格多場景支持。

詳細對比下兩者在以下方面的差異:

  1. 性能:在同樣成本的介質上部署,SLS 能夠提供更低的延時、以及更穩定的查詢性能。

  2. 成本:這裏的成本不光是部署成本,還需要包括使用成本。要維護良好狀態的 ELK 集羣,需要從容量規劃、穩定性保障、性能調優、數據高可用,數據如何在不同系統間關聯等多個方面下功夫。SLS 全託管免運維無需花費額外人力投入。百 TB 規模下,SLS 綜合成本是 ELK 的 44%。

  3. 易用性:SLS 對開源協議及組件相比 ELK 有更好的兼容性。利用 ELK 構建完整可觀測分析平臺需組合多款服務,這其中包括 Logstash、Kibana、Kafka、Flink、TSDB、Prometheus 等。SLS 在這個場景上無需多個組件搭配,支持一站式數據監控分析平臺能力。

  4. 互聯互通與二次開發:在可觀測場景中,我們需要跨多個數據源進行關聯分析 SLS 可觀測數據統一存儲支持 log metric trace 數據存儲,打通數據孤島,並且提供開源友好的 API 接口進行使用。

  5. 附加能力(新算子、告警等):開源 ELK 僅支持指標分析聚合、分桶聚合、管道分析、矩陣分析有限的聚合算法。SLS 針對數據分析場景支持 30+ 聚合計算函數,豐富的機器學習函數以及多渠道數據源,是 ELK 提供操作符的 5 倍,充分發掘數據分析能力。除此之外,SLS 內置告警功能可以快速開箱即用,無需搭建系統。

參考文章

  1. https://icyfenix.cn/distribution/observability/tracing.html

  2. https://tech.meituan.com/2023/04/20/traceid-google-dapper-mtrace.html

  3. https://tech.meituan.com/2022/07/21/visualized-log-tracing.html

  4. https://developer.aliyun.com/article/1065820#slide-4

  5. https://aws.amazon.com/cn/what-is/elk-stack/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/0l-y-24UT3AB98H_1jhFHQ