隨著多年微服務的發展,分布式追蹤系統已經成為云原生技術棧中非常引人注目的一個領域。隨著該技術的出現,你可以非常容易的去定位分布式系統中潛在的一些問題。在這篇文章之中,我會詳細為大家介紹什么是分布式追蹤系統,以及如何存儲分布式追蹤系統產生的數據。
我首先會沿著歷史的脈絡,介紹經典的大數據方案來解決分布式追蹤系統的數據存儲與分析的問題,而后會繼續分析目前業界常用的混合方案來解決相關問題。最后面向未來,我將提出一種混合的一體化方案來解決此類問題。
什么是分布式追蹤系統
在我們正式介紹分布式追蹤系統之前,我們需要探究一下分布式對于整個業界到底意味著什么。我們可以下這樣一個矛盾的結論:分布式把事情變得非常的簡單,同時也把它變得很復雜。我們聽過越來越多的案例,在使用分布式系統之后,雖然整個系統看起來結構清晰,路徑明確,并帶來了一定效率的提升。但越來越復雜的分布式結構增加了系統的復雜程度,同時給運維、管理、架構等等幾乎所有方面帶來了非常大的挑戰。
我們傾向于將越來越多的組件引入到已經很復雜的分布式系統之中來解決以上這些問題。這些組件和管理它們的組件一起組成了更加復雜的分布式系統。這些系統最終會反噬我們,并給我們帶來意想不到的問題。甚至于是非常重大的一些災難。
?
如圖是一個典型的電商類的系統。從這個結構圖上看,這個系統東西向和南北向都是非常的復雜的。它由一個前端的系統來承接用戶的訪問,其中包含了移動端和瀏覽器過來的流量。這些流量通過API的網關到達了賬戶系統、庫存系統和快遞系統。前端系統同時與后端系統進行相連,后端系統由各個子域所組成,它們共同構成了一個非常復雜的網絡拓撲結構。
在如此復雜的網絡拓撲結構,我們不能單單以傳統的運維方案去做監控,管理和觀測。而是需要引入一定的現代技術,特別是跟蹤技術,來將一條完整的調用鏈呈現到管理者和運維者面前。
通過跟蹤技術,我們可以觀測到系統的兩個重要的指標,一個是請求失敗,我們可以發現系統在哪個部分存在比較致命的問題,鏈路從何處斷開的。另一個就是延遲。它是無處不在的,即使你花費巨大的代價,也不可以避免延遲。
現在,讓我們深入到追蹤系統的內部,觀察追蹤數據的數據結構。如圖所示追蹤系統所產生的是一些點,這些點可以代表一個時間片段,它的英文是Span。Span描述的就是一次調用所跨越的一個時間范圍。
?
那么Span與Span之間是組成一個這樣的樹形的結構,這棵樹反映的是服務之間的一個調用過程。而另一張圖我們習慣于成為瀑布圖,它更加能夠反映Span之間的一個對應關系。
?
它與樹型圖最顯著的區別是,瀑布圖可以體現Span之間的隸屬關系。我們看到其中 SpanA是一個父節點,其包含其他三個Span。而其他Span之間有一定的并行關系。我們從中可以看到SpanB與SpanC之間是并行的,與SpanD也是并行的。而SpanE與其他Span之間是個串行關系。這張圖不僅可以告訴我們Span之間的對應關系,而且可以顯示這次調用它到底是一種并行調用還是串行調用。
既然Span是跟蹤系統的核心數據,同時這篇文章主要的目的是要探究如何去存儲跟蹤數據,那么探究如何去存儲Span就是我們需要研究的必要課題。
讓我們看看Span的一些具體結構,經典的Dapper論文所描述Span結構包括SpanId,父SpanId,還有它的Trace Id。而后是一組labels,這是一些key-value結構,類似于我們傳統的數據表的一行數據,它與傳統數據表不同點是:傳統數據表的列是預定義的,而這種key-value結構是根據數據動態定義的,所以它的整個長度是任意的,這一點對存儲來說是比較大的挑戰。
?
另外Span中還要存儲一些非結構化數據,所以它又帶有NoSQL數據的特點。同時它又具有典型的時間維度的特征,而這又是典型的時間序列數據的特點。這就是跟蹤數據的特點:一種混合的多模式結構。
經典的大數據存儲方案
經典的跟蹤系統存儲其實就來自經典的跟蹤系統論文:Dapper。這篇論文中還詳細描述了Google所采用的一種跟蹤系統的實現方案。這篇經典論文不僅描述了經典的以annotation為基礎的數據結構,而且它同時還提出了使用BigTable來作為整個跟蹤系統的存儲底層。
既然提到了BigTable,那就讓我們一起去探究目前BigTable的一些特性,看看為什么早期的跟蹤系統采用這種存儲結構。目前該產品已經云化了,我們可以很容易的去購買這個服務,去體驗它的功能特性。
BigTable有三種比較主要的特性:
l 第一個它是NoSQL數據庫。在上一節中我們提到,由于跟蹤系統內部存在著大量的非結構數據,而這些數據來源于用戶自定義。這里的用戶其實包括兩類,第一類就是跟蹤系統的設計者,它會增加多種字段來構成數據的底層。再此之上就是跟蹤系統的使用者,他們會根據自己的業務場景再添加另外一些動態的字段進來。故一個天然的NoSQL的非結構化數據庫是對這種任意字段類型的數據結構是有益的。
l 第二個特性就是存儲要支持高吞吐。在一個微服務場景之中,每一個子Span的粒度是代表一個服務內部的一個調用。但是這個調用可大可小,可以是對這個服務進程的調用,也可以是進程內部一個函數的調用。可以說,一次外部的業務調用可以產生海量的跟蹤數據。這就是跟蹤系統面臨的典型挑戰—數據放大。跟蹤系統需要極大的帶寬,同時對延遲也有非常敏感。綜上,一個可以支持大數據的數據庫對跟蹤系統是非常有利的。
l 第三個特性性能線性增長。由于業務系統是逐步接入到跟蹤系統之中的,就需要存儲方案支持系統平滑的提高吞吐量和存儲空間。不能因為新數據的接入,造成現有數據的寫入和查詢出現性能的劇烈下降。
以上就是BigTable作為第一代非常經典的分布式跟蹤存儲解決方案所提供的主要特性。
?
如圖所示一個跟蹤結構是如何進入到BigTable之中。第一個過程,跟蹤系統會生成一個本地的日志文件,日志文件包括了所有的Span,而后由一個搜集器將這些數據拉取到一個與之最近的BigTable節點之中。而后由Dapper的寫入器,將數據寫入到 Big Table的每個Cell中。其中,每行代表一個Trace ,也就是一次調用產生的全部Span可以一次性提取出來。
我們都知道BigTable是個商用的云數據庫。如果想自己去打造一個面向跟蹤場景的經典存儲方案,開源界也提供了有很多的選擇,比如說Cassandra,HBase等。
但是經典的分布式跟蹤系統非常大的問題就是投入產出比較低。因為我們知道跟蹤系統屬于二線系統,也是監控系統的一個延伸。雖然隨著微服務的產生,此類系統的地位有了比較顯著的提高,但其重要性依然低于一線生產系統。
那么采用這種經典的大數據方案的性價比是非常低的。你會投入很多的資源在跟蹤系統中,但是產生的效果并不能夠與你投入的資源相對稱。甚至是說你投入的非常多,產生效果是非常差的。這個時候你會對它的可用性和實際作用產生深深的懷疑。
現代的混合方案
這部分讓我們了解現代混合存儲方案。相比于傳統的大數據結構,現代混合存儲結構更強調于性價比和易用性。目前主流的有兩種典型的存儲方案:
第一種就是關系型數據庫,以MySQL為代表。
那么,首先讓我們了解一下MySQL。當然這其中包括其他的一些關系型數據庫。傳統的關系型數據庫是面向于查詢優化的,所以它的寫入性能相較于查詢性能是較低的。故傳統上它并不適合于做跟蹤類的存儲方案。
但是我們可以把關系數據庫進行一些改造。這里有兩個改造方面,第一點是使用一些Sharding中間件來增強MySQL吞吐量。如Apache ShardingSphere。
這樣就滿足了上文所提到的兩個關鍵點:高的吞吐和性能線性。
高吞吐很容易理解,這是sharding的主要策略。那么性能線性如何理解呢?
一個Trace 內部的Span是有一定的關聯關系的,但是Trace 和Trace 之間是相對于獨立的。那么通過sharding策略,整體的數據會較為離散的。這就可以滿足對性能線性增長的需求。因為我們知道影響sharding效果的一個最重要的原因就是關系的耦合。如果數據之間關系特別的緊密,那么你很難做到數據寫入性能的線性增長。
最后,對于數據的任寫入,我們可以通過預設冗余字段的方式來解決。當然任意數據并不能像大數據的存儲方案一樣可以無限寫入任意數據。但這種預設方案在性能上反而有更大的優勢。
剛才提到了兩種增強關系數據結構的方案,那么我們為什么一定要選擇這種關系數據庫作為跟蹤數據的存儲方案呢?
第一點就是像這種數據庫有大量的dba支持。所以我們很容易的將它的性能提到一個非常驚人的地步。甚至于有一些組織,比如說像TimeScale,就是利用關系數據庫來做時序數據庫的存儲跟蹤數據的。他們就是看中了這種關系數據庫優秀的成熟度。
那么如果要用MySQL去存儲關系數據,需要做額外哪些調整呢?
l 第一點,增強寫入性能。最簡單的方式是要增加buffer的大小。同時,對數據庫Engine做一相關的優化。比如增加buffer pool的一個大小,然后我們需要對數據塊的刷入策略進行一些調節。
l 第二點,增加數據的生命周期管理功能。因為一些老數據會出現隨著時間的流逝而價值降低的現象。需要增加數據生命周期管理功能來釋放磁盤空間。
l 第三點,分離流量。因為我們寫入量是巨大的,但讀取是相對少的。這與經典的關系數據庫場景是非常不同的,我們需要把寫入流量和讀取流量進行分離,以免讀取流量影響寫入流量。
第二個常用的存儲結構也是搜索引擎。以Elasticsearch為代表的搜索引擎對于日志搜集有比較好的支持,所以有相當一部分的跟蹤系統都會采用這種搜索引擎來存儲跟蹤數據。那么跟蹤數據本質上與log是非常相似的。因為log具有體量巨大,字段任意等跟蹤數據的顯著特點。它唯一與跟蹤數據的區別是 log沒有很強的關聯性。故如Elasticsearch和Loki這類系統都可以滿足存儲跟蹤數據的要求。
此類數據庫具有兩個相對優勢的特性:
l 第一,支持大量的非結構數據存儲。因為這種系統天生就是一個分布式數據庫,它不像關系數據庫需要一些中間件的加持。這種數據庫天然可以存儲大量的數據。而且他們對寫入有特殊優化,這樣就可以快速的存儲數據。
l 第二,高效的數據分析。數據之間的關系可以很容易的在此類系統中進行分析。因為它動態產生索引結構,非常適合于這種交互式的跟蹤數據分析場景。
如果你要使用Elasticsearch來存儲跟蹤數據。需要進行以下優化:
l 第一,需要實時的監控磁盤的使用情況。因為索引寫到一定程度,Elastcsearch就會將一些索引轉化為只讀索引,這樣的話會導致你的最新的高價值數據寫不進去。
l 第二,由于你的寫入量是非常大的,你要像關系數據庫一樣去增加它的Buffer,同時增加寫入的隊列的大小。
l 第三,Elasticsearch是分布式的數據庫,它自帶數據復制的功能。但是對于跟蹤數據,數據復制往往是多余的。因為這是一個寫多讀少的一個場景,所以你不需要通過副本來提高讀取性能。同時,跟蹤數據本身的價值也而且隨著時間流失而降低。故你也不需要對數據做高可用處理。綜合以上原因,經典的優化方案都會關閉它的復制功能。
以上就是兩種現代混合方案。之所以稱為混合,就是當代的跟蹤系統,如Apache SkyWalking,Zipkin等等都支持多種存儲方案。用戶必須根據自己的情況進行選擇,且每個方案都各有利弊,而并沒有一個一勞永逸的一體化解決方案。
面向未來的一體化方案
至此我們探究了什么是分布式跟蹤系統,經典的跟蹤系統數據存儲的方案,以及現代這種混合的跟蹤系統存儲方案。我們會發現目前并沒有一個非常完美的最佳實踐來解決跟蹤系統的存儲問題。其主要原因就是并沒有一個專用的跟蹤系統存儲的引擎,來幫助我們去同時解決那三個問題。
本文介紹的每種方案實際上只僅僅解決了部分的問題。傳統的經典結構,貌似解決了所有的問題,但是其代價是非常高的。所以我們需要的一個最佳跟蹤系統存儲方案,除了典型的三個特點之外,還需要加上性價比這個非技術特性。只有高性價比的跟蹤系統方案才能在生產實踐中得到廣泛的使用。
除了性價比之外,另一個附加特性也就是自我運維。跟蹤系統本質是一個運維工具,它的存儲系統如果需要運維人員花費更多的時間和精力來去管理和調優,那么必然會降低系統的使用率。因為專業的運維人員不希望特別關心工具自身的運維問題。但跟蹤系統本身會產生大量的數據,造成它的維護難度并不亞于高流量的業務系統。所以一個典型的或完美的跟蹤系統存儲方案,要能夠去自動識別和處理常見的運維問題,其最低限度是,保證系統能以一定的健康度來運行,而不至于完全的掛掉。
所以我們寄望存在一個從底層開始設計的面相跟蹤場景的數據庫。它應該從數據結構層到模型層完全按照跟蹤系統的特點進行構建的,并符合我們本文描述的此類數據庫的所有特點。很慶幸的是在我們這個時代有越來越多的獨立的底層引擎所涌現出來,我們可以利用它們去構建這么一個數據庫,而不需要完全從0開始。
同時由于RUM假說的出現,我們可以采用不同的數據庫訪問策略來實現跟蹤這個特定領域的數據庫。而這樣一款兼備各種跟蹤數據存儲所需要特點的數據庫其實也正在路上。
作者:
高洪濤——美國servicemesh服務商tetrate創始工程師。原華為軟件開發云技術專家,對云原生產品有豐富的設計,研發與實施經驗。對分布式數據庫,容器調度,微服務,ServicMesh等技術有深入的了解。前當當網系統架構師,開源達人,曾參與Elastic-Job等知名開源項目。目前為Apache ShardingSphere和Apache SkyWalking核心貢獻者,參與該開源項目在軟件開發云的商業化進程。
評論