Logtail技術分享(二) : 多租戶隔離技術+雙十一實戰效果
日益增長的數據采集需求
上一篇中我們分享了日誌采集中基於Polling+Notify組合的日誌保序采集技術,Logtail基於Polling+Notify的組合方案以及日誌輪轉隊列等相關技術實現了單一配置下的日誌保序、高效、可靠采集問題。
然而日誌采集並不僅僅是單一用戶/應用需要完成的工作,例如一個典型的服務器上需要采集的日誌數據有:資源類Metric數據、係統監控日誌、Nginx訪問數據、中間件請求數據、安全審計日誌、各類應用中各個不同組件的日誌等等;如果應用docker話,保守估計一個docker內的應用有6-7類日誌,一台物理機運行50個docker,那即使采集docker內的日誌就有300多種配置。
而現在涉及需要獲取數據的角色上到看交易大盤的CEO下到查詢日誌的debug小弟,幾乎所有人都會和日誌相關。正是這些寶貴的數據才讓我們真正成為一家數據型公司。因此,保障各種日誌的有效采集是一款合格的日誌采集Agent必須要解決的問題。
多租戶隔離的特性與挑戰
多租戶隔離技術早在20世紀60年代的大型主機中就已經開始使用,發展到今天非常多的應用/係統都應用了該技術。在每種不同的應用/係統中對於多租戶隔離都有不同的詮釋,本文中我們僅僅對應用在日誌采集中的多租戶隔離進行探討。
多租戶隔離特性
首先需要搞清楚日誌采集場景下的多租戶隔離需具備哪些特性,這裏我們總結以下5點:隔離性、公平性、可靠性、可控性、性價比
- 隔離性: 多租戶隔離最基本特性,多個采集工作之間互不影響,部分采集配置阻塞不影響其他正常采集
- 公平性: 保證各個階段(讀取、處理、發送)多個配置之間的公平性,不能因為某個配置下日誌寫入量大而導致其他配置被處理的概率降低
- 可靠性: 無論在何種場景,可靠性都至關重要,多租戶隔離下,如果部分采集阻塞,agent可以暫停該配置采集,但恢複時需盡可能保證數據不丟失
- 可控性: 可控性主要體現在資源和行為的可控,agent需要具備控製各個配置的資源占用在合理範圍,並且具備控製采集速率、暫停/開啟等行為
- 性價比: 以上特性最終方案實現時最需要關注的就是性價比,如何在盡可能少的資源占用情況下實現盡可能優的多租戶隔離方案才是技術可行性與適用性的關鍵
多租戶隔離挑戰
目前logtail正逐步成為集團的基礎設施之一,在集團內部一台服務存在數百個采集配置屬於常態,每個配置的優先級、日誌產生速度、處理方式、上傳目的地址等都有可能不同,如何有效隔離各種自定義配置,保證采集配置QoS不因部分配置異常而受到影響?
一台服務器的數百個配置涉及不同應用的不同層麵日誌,其中部分日誌優先級高而部分優先級低,關鍵時刻需要對低優先級日誌降級停采,但又希望降級期間過後還能夠將之前的數據追回,如何有效地限製低優先級配置以及動態降級且極可能保證日誌不丟失?
目前Logtail在整個集團以及公有雲的部署量近百萬,如果logtail能夠節省1MB內存使用,那整體將能夠減少近1TB的內存,同時日誌采集Agent的定位是服務的輔助應用,一台服務器並不能將主要資源提供給日誌采集。如何在盡可能低的資源占用情況下盡可能、盡量公平以及盡量有效地調度各個配置?
業界采集Agent多租戶隔離方案
首先我們來看一下業界的采集agent對於多租戶隔離方麵主要采用的技術,這裏主要關注Logstash、Fluentd以及最近較火的Filebeat,我們分別從以上5個特性對這三款產品進行對比和分析。
logstash | fluentd | filebeat | |
---|---|---|---|
隔離性 | 每個配置至少1個線程,獨立的可持久化隊列 | 每個配置至少1個線程,獨立的可持久化隊列 | 每個配置若幹go runtime,獨立隊列 |
公平性 | 各配置間無協調,基於多線程調度 | 各配置間無協調,基於多線程調度 | 各配置間無協調,基於go runtime調度 |
可靠性 | 基於可持久化隊列緩存保證 | 基於可持久化隊列緩存保證 | 隊列滿後停止采集 |
可控性 | 可控製持久化隊列資源,刪除配置停采,支持遠程配置 | 可控製持久化隊列資源,刪除配置停采,本地配置 | 可控製隊列資源占用,刪除配置停采 |
性價比 | 較低 | 較低 | 較高 |
Logstash、Fluentd和Filebeat都屬於pipeline的架構,根據語言不同,分別使用獨立的線程/go runtime實現了pipeline功能,每個pipeline內部順序執行,各個pipeline間互相獨立運行,此種方式隔離性較好,實現較為簡單,在小規模場景下較為適用。然而隨著配置數量增長,相應的線程數/go runtime呈等比上升,在采集配置較多的情況下資源難以控製;而且由於各個pipeline間完全依賴底層(操作係統/go runtime)調度,當CPU資源無法全部滿足時,數據量較高的配置會占用較多的執行時間,導致其他數據較少的配置獲取資源的概率降低。
Logtail多租戶隔離方案
整體架構
不同於當前主流的開源采集agent實現,logtail采用的是更加複雜的架構,事件發現、數據讀取、解析、發送等都采用固定數量的線程(解析線程可配置),線程規模不會隨配置數增多。雖然所有配置都運行在同一執行環境,但我們采取了一係列的措施保障各個配置處理流程的互相隔離、配置間調度的公平、數據采集可靠性、可控性以及非常高的資源性價比。
下麵我們主要介紹該方案中一些實現多租戶隔離的較為關鍵性的技術
基於時間片的采集調度
業界主流的Agent對於每個配置會分配獨立的線程/go runtime來進行數據讀取,而logtail數據的讀取隻配置了一個線程,主要原因是:
- 單線程足以完成所有配置的事件處理以及數據讀取,數據讀取的瓶頸並不在於計算而是磁盤,對於正常的服務器,每秒基本不可能產生超過100MB的日誌,而logtail數據讀取線程可完成每秒200MB以上的數據讀取(SSD速率可以更高)
- 單線程的另一個優勢是可以使事件處理和數據讀取在無鎖環境下運行,相對多線程處理性價比較高
但單線程的情況下會存在多個配置間資源分配不均的問題,如果使用簡單的FCFS方式,一旦一個寫入速度極高的文件占據了處理單元,它就一直運行下去,直到該文件被處理完成並主動釋放資源,此方式很有可能造成其他采集的文件被餓死。因此我們采用了基於時間片的采集調度方案,使各個配置間盡可能公平的調度。
- Logtail會將Polling以及Inotify事件合並到無鎖的事件隊列中(參見上一篇),每個文件的修改事件會觸發日誌讀取;
- 日誌讀取將從上一次讀取的偏移量LastReadOffset處開始,嚐試在固定的時間片內將文讀取到EOF處;
- 如果時間片內讀取完畢,則認為該事件處理完畢,刪除該事件;
- 如果時間片內讀取未完成,則將該時間重新push到隊列尾部,等待下一次調度。
該方案使得每個采集目標得到公平地對待,所有文件都有被調度運行的機會,很好地解決了采集目標的餓死現象。
多級高低水位反饋隊列
基於時間片的采集調度保證了各個配置的日誌在數據讀取時得到公平的調度,滿足了多租戶隔離中基本的公平性,但對於隔離性並未起到幫助作用。例如當部分采集配置因處理複雜或網絡異常等原因阻塞時,阻塞配置依然會進行處理,最終會導致隊列到達上限而阻塞數據讀取線程,影響其他正常配置。
為此我們設計了一套多級高低水位反饋隊列用以實現多個采集配置間以及讀取、解析、發送各個步驟間有效的協調和調度。雖然和進程調度中Multilevel feedback queue命名較為類似,但隊列實現以及適用場景有很大區別。
- 多級
- 這裏的多級指的是處理過程的多級,即各個處理過程間會有一個這樣的隊列且相鄰隊列互相關聯
- 例如在Logtail的數據讀取、處理、發送流程中需要在讀取->解析以及解析->發送間各自設置一個這樣的隊列
- 高低水位:
- 單一隊列中設置了高低兩個水位
- 當隊列增長到高水位時,停止非緊急數據寫入(例如進程重啟時、數據拆分等特殊情況允許寫入)
- 當隊列從高水位消費到低水位時,再次允許寫入
- 反饋:
- 反饋分為同步和異步兩種
- 在準備讀取當前隊列數據時會同步檢查下一級隊列狀態,當下級隊列到達高水位時跳過此隊列
- 當前隊列從高水位消費到低水位時,異步通知關聯的前一級隊列
由於多個配置存在,所以我們會為每個配置創建一組隊列,每個隊列使用指針數組實現,每一級中所有配置隊列公用一個鎖,對於性能以及內存消耗較為友好。Logtail中的多級高低水位反饋隊列結構如下:
我們以日誌解析這個步驟的工作方式來觀察多級反饋隊列的行為:
- 初始狀態下解析線程處理Wait狀態,當有數據到達或下一級發送線程某一配置的隊列從高水位消費到低水位時,進入FindJob狀態
- FindJob會從上一次處理的隊列位置順序查找當前有數據且下一級隊列可以寫入的隊列,若查找到則進行Process狀態,否則進行Wait狀態
- Process對於當前job解析完後,判斷該job所屬隊列是否從高水位到達低水位,若是則進入Feedback狀態,否則回到FindJob查找下一個有效job
- Feedback狀態會向關聯的上一級隊列發送信號,參數攜帶當前隊列ID,用以觸發上一級流程運行,信號發送完畢後進入FindJob狀態
基於多級高低水位反饋隊列的處理過程中,當遇到下一級阻塞的隊列時直接跳過,防止因阻塞Job的處理導致線程阻塞,具有較高的隔離性;FindJob會記錄上一次查找的隊列ID,下次查找時會從該ID之後的隊列開始,保證了各個配置間調度的公平性。
流控以及阻塞處理
上一節的多級高低水位反饋隊列解決了多配置間的隔離性和公平性問題,但對於可控性以及可靠性方麵還存在一些問題。例如:
1. 無法精確控製每個配置的的采集流量,隻能通過刪除采集配置停止采集
2. 如果某一配置完全阻塞時,當該配置關聯日誌文件輪轉,恢複阻塞時將丟失輪轉前的數據
這裏主要包括三個部分:事件處理、數據讀取邏輯以及數據發送控製:
- 事件處理與數據讀取無關,即使讀取關聯的隊列滿也照常處理,這裏的處理主要是更新文件meta、將輪轉文件放入輪轉隊列,具體可查看上一篇文章;此種方式可保證即使在配置阻塞/暫停的情況下依然保證及時文件輪轉也不會丟失數據;
- 當配置關聯的解析隊列滿時,如果將事件重新放回隊列尾,則會造成較多的無效調度,使CPU空轉。因此我們在遇到解析隊列滿時,將該事件放到一個專門的blocked隊列中,當解析隊列異步反饋時重新將blocked隊列中的數據放回事件隊列;
- Sender中每個配置的隊列關聯一個SenderInfo,SenderInfo中記錄該配置當前網絡是否正常、Quota是否正常以及最大允許的發送速率。每次Sender會根據SenderInfo中的狀從隊列中取數據,這裏包括:網絡失敗重試、Quota超限重試、狀態更新、流控等邏輯
整體流程梳理
現在讓我們回顧一下logtail在多租戶隔離中使用的相關技術,具體如下圖:
- 通過時間片采集調度保證各個配置數據入口的隔離性和公平性
- 通過多級高低水位反饋隊列保證在極低的資源占用下依然可以保證各處理流程間以及多個配置間的隔離性和公平性,
- 通過事件處理不阻塞的機製保證即使在配置阻塞/停采期間發生文件輪轉依然具有較高的可靠性
- 通過各個配置不同的流控/停采策略以及配置動態更新保證數據采集具備較高的可控性
通過以上幾點設計的組合,我們使用極低的資源構建出了虛擬的多租戶Pipleline結構:
實戰見真知
多租戶隔離中的性價比問題隻靠語言描述是蒼白無力的,最好的方式還是拿數據說話:
雙11背後的日誌采集
目前logtail已承載阿裏雲全站、所有雲產品服務、全球各Region部署、阿裏巴巴集團(淘寶、天貓、菜鳥等)上重要服務的數據采集。每天采集接近百萬服務器上的實時數據,對接數千個應用與消費者。今年雙十一螞蟻金服(支付寶)幾乎所有應用、用戶及服務器產生的數據都由Logtail采集。
目前logtail在螞蟻安裝了24萬多台,平均每台機器上存在近百個采集配置,每天采集上千個應用數PB的日誌。在雙11期間,為了保證核心應用數據采集正常,雙11零點前對300多個應用提前降級停采,零點高峰過後逐批恢複日誌采集,logtail在3個小時追完了300多個應用5小時的高峰數據並且保證停采期間日誌即使輪轉/刪除也不會丟失。下圖是追數據期間logtail的CPU、內存占用:
可以看到即使在雙11期間logtail的平均cpu占用也隻有單核的1.7%,平均內存最高也隻有42M。追數據期間cpu相對隻上升0.4%、內存隻升高7M。拋開功能不談,logtail對於資源的控製是開源采集Agent無法達到的。
性能對比
在logstash、fluentd和filebeat中,多租戶實現最好且性能最高的是filebeat,所以這裏我們拿filebeat進行對比。
測試機配置:
CPU : 16核 Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz
MEM : 64GB
DISK: 4塊1TB SSD(日誌寫入單獨一塊SSD)filebeat配置優化
網上filebeat的benchmark約為30K/s(日誌條數每秒),這裏為了盡可能提高filebeat性能,我們把filebeat讀文件緩存設置為512k,將輸出配置到一塊單獨的SSD中並將日誌rotate的size設為4GB(相對網上benchmark性能提升一倍左右)
配置數較少情況
下麵是logtail與filebeat在極簡模式(單行日誌,不對日誌解析)分別在1、2、4、8個配置下、日誌寫入速度分別為0.1、1、5 MB/s的CPU和內存占用
0.1 M/s | 1M/s | 5M/s | |
---|---|---|---|
1配置 | FB:1.8% 22M LT: 0.5% 34M | FB:15.9% 22M LT: 1.3% 36M | FB: 76.3% 26M LT: 5.5% 42M |
2配置 | FB:3.0% 22M LT: 0.6% 35M | FB:27.5% 24M LT: 2.5% 44M | FB: 137.9% 31M LT: 8.3% 50M |
4配置 | FB:6.3% 30M LT: 0.8% 35M | FB:52.4% 30M LT: 4.3% 59M | FB: 190.4% 31M(丟數據) LT: 15.3% 69M |
8配置 | FB:10.9% 36M LT: 1.1% 46M | FB:103% 37M LT: 6.5% 82M | FB: (丟數據) LT: 30.5% 83M |
filebeat對於內存控製較優,但性能相對logtail有一定差距:filebeat處理能力約為18MB/s,測試中一條日誌約為300字節,換算成日誌條數約為60K/s(網上benchmark約為30K/s)。
可以看出filebeat相對logstash和fluentd有一定的優勢(快10倍左右);logtail的極簡模式(不對日誌解析,和filebeat類似)下的處理能力約為150M/s,相對優化後的filebeat有8倍左右的性能提升。由於filebeat達到18MB/s耗費了200%左右的cpu,logtail達到150MB/s隻需消耗100%的cpu,所以如果從cpu的性價比上logtail相比filebeat有十多倍的優勢。
配置數量較多
下麵對比100個配置情況下filebeat和logtail的性能:
0.01 M/s | 0.1M/s | 1M/s | |
---|---|---|---|
Logtail | 2.7% 60M | 8.0% 65M | 65.4% 98M |
filebeat | 13.3% 236M | 102.5% 238M | 210.3% 238M(丟數據) |
當配置上升至100個時,filebeat 內存占用明顯升高,而logtail的內存相對增長較低;100個配置下logtail的cpu消耗與相同數據量情況下2配置的基本無區別。同時觀察filebeat cpu消耗情況,可以看到約20%的cpu消耗在涉及和調度相關的futex調用,可見當配置數增多時即使依賴go的協程調度方式也會消耗較多的cpu。
總結
一個數據采集軟件看起來很微小很簡單,但當遇到超大的規模、超多的用戶、超級的數據量時一切都需要重新考慮。阿裏雲日誌服務的logtail就是這樣一款曆經上百萬的部署量、每天數PB的數據、近萬個應用洗禮的日誌采集Agent。
相對開源軟件,我們最大的優勢是有阿裏、有雙11這樣的環境給我們練兵、采坑。今天分享的多租戶隔離技術,對於開源agent或許都不會考慮這個問題,但相信未來業務規模上升到一定體量肯定會遇到,希望到時候我們的分享能給大家一定的幫助。
展望
改進
- 目前logtail雖然在多租戶的公平性上做的比較好,但對於配置的優先級上麵並沒有做太多的優化,未來我們需要在這方麵多下功夫,畢竟不同類型的數據重要程度是不一致的,采集的優先級也需要更精確。
- 當前logtail的監控功能對於用戶的可見度太低,未來我們考慮會將logtail的運行數據、錯誤數據等打包成一套Agent監控報警方案,將logtail的一體化采集方案做的更加完備。
新功能
logtail即將推出的新版本中還將支持http、mysql binlog以及mysql sql輸入源,歡迎大家體驗:
- 支持http作為輸入源,用戶可以配置特定的url,logtail會定期請求並將請求數據處理並上傳到日誌服務。此方式能支持采集nginx、haproxy、docker daemon等能提供http接口的數據。
- 支持mysql binlog作為輸入源(包括RDS),以binlog形式同步數據到日誌服務中,類似canal
- 支持mysql sql作為輸入源,可通過select語句自定義將數據采集到日誌服務中,支持增量采集
同誌們有更多輸入源的需求或其他問題請加釘釘群11775223聯係:
掃我進群
參考資料
Multilevel feedback queue
cpu scheduling
log service
logtail vs logstash, flunetd
logstash
filebeat
fluentd
最後更新:2017-11-16 09:34:07