唐文



摘要:分布式系統對高性能、高可用性、可伸縮要求越來越高,消息中間件是重要的技術之一,解決應用解耦、異步消息、流量削峰等問題。消息中間件松耦合交互方式在系統整體實現層面會呈現出復雜度,多應用間業務流無法跟蹤、無法定位問題,需要耗費大量的時間來查找定位問題。該文實現一種基于消息中間件的調用鏈跟蹤方法,可視化業務流完整的調用鏈,同時統計分析各階段耗時,而且方法對應用程序實現“零侵入”。
關鍵詞:分布式系統;消息中間件;調用鏈跟蹤;服務跟蹤
中圖分類號:TP311 文獻標識碼:A
文章編號:1009-3044(2019)30-0054-02
1概述
分布式系統中應用部署在不同節點中,不同的應用之間通過傳遞消息來激活對方的事件觸發相應的操作,發送者將消息發布到主題中,消費者通過訂閱主題來獲取關注的消息,消息中間件能在不同平臺之間通信,屏蔽掉各種平臺及協議之間的特性,實現應用程序之間的協同。發布/訂閱者不相互感知,由此帶來一些問題:消息在應用程序之間傳遞丟失,無法快速定位出丟失消息的應用嘲;業務流過程中如果出現性能問題,無法快速確定哪個應用耗時長。以上問題往往需要將各個應用日志打開,耗費大量人力才能找出問題。
分布式消息跟蹤業界已有成熟的實現方案,代表是GoogleDapper,其實現原理是:對于每次用戶發起的請求,使用一個TRACE ID作為標識,每個服務組件使用SPAN ID作為標識,服務組件對于到達的請求記錄跟蹤日志,跟蹤日志中包含TRACE,ID、SPAN ID和PARENT,ID(消息發送上游組件的SPAN加),組件通過PARENT ID找到上游組件,用戶發起的請求涉及的所有組件調用關系可視出來。Dapper已有實現主要在遠程過程調用(RPC)場景,對應用開發者未完全實現“零侵入”嘲。
2設計實現
2.1方案
消息中間件(MOM)采用發布/訂閱模式,生產者將消息發送到主題中,中間件將主題中消息發送給訂閱者,將Dapper的TRACE,ID、SPAN,ID和PARENT ID在發布訂閱消息中傳遞,應用將ID持久化到日志中,通過日志則可分析出調用鏈。
如圖1所示,業務流由APPl發起消息,消息APP2和APP3訂閱處理,APP2處理之后發布新消息,新消息APP4訂閱處理,一次完整的業務流經過APP1、APP2、APP3、APP4和中間件5個組件,參照Dapper原理過程如下:
1)APP1業務流發起來,生成一個Traceid假若為1,Parentid等于自身Moduleid為1,兩個id攜帶在發布的消息中,同時id持久化到日志中;
2)APP2訂閱到消息,首先將接收到消息的Traceid=1、Parentid=1持久化到日志中,消息處理完成后生成新消息,新消息Traceid繼承已處理消息的Traceid為1,Parentid等于自身Moduleid為2;
3)APP4訂閱到消息,將接收到消息的Traceid=1、Parentid=2持久化到日志中;
41 APP3訂閱到消息,將接收到消息的Traceid=1、Parentid=2持久化到日志中。
步驟2中APP2發布新消息繼承Traceid對應用程序“零侵人”原理在消息處理進程/線程上下文未改變。日志文件命名與Moduleid一致,通過日志文件中的Traceid、Parentid則可以將業務流調用鏈識別出來。APP發送/接收端記錄日志信息,同樣中間件接收,發送端也記錄日志信息,日志信息加上時間戳,不僅是調用鏈,業務流完整耗時、分段耗時、應用耗時占比、熱點應用都可識別出來,幫助運維者管理和決策。
方案實現存在以下幾個問題需要考慮:
1)Traceid和Moduleid確保系統全局唯一,需要有一個ID生成策略;
2)調用鏈跟蹤影響系統正常運行,涉及組件眾多,如何動態開關功能;
3)調用鏈生成大量的日志需要機器分析,日志規格化便于機器分析。
2.2ID生成策略
Traceid代表一次業務流,不能出現兩個一樣的Traceid,使用時間戳是一個很好的辦法,Linux時間戳精確到微妙/納秒,如果在APP端生成Traceid,同一個時間精度點上可能小概率出現兩個APP生成相同的Traceid。中間件為單線程處理,單次處理耗時小于一個時間戳精度不會發生,因此在中間件中生成更合理,Traceid規則如下:
考慮到中間件是多實例多進程,Traceid中加人中間件ID。由于0號Traceid在系統中中約定為不存在ID號,需要保證生成的Traceid不為0,因此將最后12bit最后一位設置為1。
Moduleid需要考慮應用進程在多實例的情況下也能夠識別,Moduleid組成格式-。Moduleid采用字符串構成,使用Pid來區分業務進程多實例的情況。考慮到服務鏈跟蹤需要做到應用“零侵入”,新增功能不需要修改代碼,Moduleid不能夠由業務來進行設置,應用使用中間件時注冊了Moduleid,因此可由中間件直接將Moduleid加入到消息通告中,應用無需感知。
2.3功能開關
服務鏈跟蹤功能默認開啟,一個是影響正常業務性能,一個是產生大量log,兩個都浪費系統資源,因此需要支持動態開關。一次業務流涉及的所有應用很難提前知曉,發起應用則很容易知道,在業務流發起應用打開功能更合理的,同時能支持指定消息主題打開。
業務流發起應用打開功能后,中間件以及所有的下游應用如何識別。發起應用可通過特定命令告訴中間件該次消息需要使用調用鏈跟蹤,中間件識別到則生成一個新的Traceid,并在消息通告中攜帶上Traceid和Parentid,下流應用接收到攜帶ID的消息則認為功能開啟,這樣鏈式傳遞將所有涉及的應用功能開啟。實現上將Traceid=O作為功能開啟,這也是上小節為什么將0號視為不存在的Traceid。業務流執行完成功能同時關閉,因此功能關閉不需要額外處理。
2.4日志分析
為支持機器分析日志,日志首先需要支持規格化,XML/JSON是常用的規格化方式,嵌入式系統中資源受限使用最簡單的規格化方式,在日志將增加標簽。單條日志包含的信息如下:其中:
Traceid標識本條日志屬于哪條跟蹤鏈;CMod標識本條日志屬于哪個應用;
LMod標識本條日志Parentid是哪個應用;
Key標識觸發本次消息的主題;
Act標識觸發本次消息的增/刪/改行為。
跟蹤日志具有固定的格式,因此可以使用正則表達式從中分析出所有信息,通過CMod和LMod找出調用父子關系,構造出調用鏈樹形圖。另外,耗時可以是日志生成的時間戳中分析獲取。
3測試
下圖2展示了系統中一次業務流調用鏈圖,上下流應用調用關系、消息傳遞的主題Key、業務流完整耗時、各階段耗時及占比全部可顯示出來,達到了系統設計預期。
4結論
本文基于Google Dapper原理實現了基于消息中間的調用鏈跟蹤,解決了分布式系統中應用之間調用關系難于跟蹤定位問題,對于業務流時延性能分析能夠顯著的幫助,優化只需要關注各個應用,完整視圖由機器來自動化生產,節省人力資源投入。本文實現還存在下一步優化點:1)應用消息處理更改上下文,如采用異步處理方式;2)分布式節點中時間戳存在不一致,耗時分析增加這部分考慮。