金越成
(上海金融期貨信息技術,上海 200122)
單體架構轉向微服務架構不只是部署的變化,其會從業務分析、業務域劃分、服務開發、上線部署、線上運維等多方面都帶來挑戰。微服務架構分布式軟件系統具有以下特點:節點規模龐大、系統結構與組件依賴關系復雜、規模不斷增長[1]。
尤其是在線上運維中,出現異常報警的時候如何快速定位故障問題,單體架構下直接查看日志分析就可以滿足,但是在微服務架構中,一項業務通常需要經過多個服務鏈條,如果依然沿用查看日志分析的方法,就需要登錄到不同的機器去查看日志,這無疑增加了工作難度,且如果有日志中心,看到的日志是多段的無法排序的。這樣就導致微服務架構下出現了比較典型的兩個問題:
(1)一個請求經過服務鏈條上的多項服務時,其中出現了一個調用失敗的問題,且只能判斷有異常,具體的異常是哪個服務引起的就需要進入每一個服務里面看日志,這樣的排障效率是非常低的;
(2)一個請求經過一系列服務之后最終返回錯誤或者超時,但各服務都正常運行,且無法判斷是哪個服務響應時間過長,因此需要查看每個服務的日志文件,但無法確定服務調用的時間和時長[2]。
谷歌在2010年4月發表了一篇論文Dapper, a Large-Scale Distributed Systems Tracing Infrastructure,介紹了分布式追蹤的幾個概念:
(1)追蹤Trace就是由分布的微服務協作所支撐的一個事務,一個追蹤包含為該事務提供服務的各個服務請求;
(2)跨度Span是事務中的一個工作流,一個Span包含了時間戳、日志和標簽信息,而Span之間包含父子關系或者主從關系;
(3)跨度上下文Span Context是支撐分布式追蹤的關鍵,它可以在調用的服務之間傳遞,上下文的內容包括諸如從一個服務傳遞到另一個服務的時間、追蹤的ID,還有其他需要從上游服務傳遞到下游服務的信息[3]。
(4)行業標準,OpenTracing是個標準化組織,提高了不同廠商間的互操作性,只要遵循OpenTracing標準,企業可以根據需要替換具體的追蹤產品。
(5)主流的分布式追蹤組件,zipkin、skywalking、jaeger都符合這個標準且具有很好的兼容性。
但這些產品的引入都對業務系統有侵入,需要應用重新發版本,而且無法滿足所有需求,需要進行二次開發。
設計目標:當出現問題的時候能夠快速地定位;對業務透明,業務不需要強依賴;可擴展,將來的運維需求可以放在里面。
場景及存在的問題如下。
(1)場景1:可以迅速發現日志異常并定位發生點。
當前問題:目前有HTTP層的應答碼規范、微服務框架層有明確的錯誤碼定義,但網關的錯誤信息不夠詳細。
(2)場景2:將調用鏈信息和日志信息結合起來,迅速還原異常發生時的分布式場景。
當前問題:微服務框架目前在Log記錄方面內容比較詳細,會自動記錄日志,但是在Trace方面存在短板。微服務框架埋點生成的trace日志,在排序方面難以滿足分布式需求(跨組件日志穿插),在深度方面不夠深入,存在引入的第三方組件沒有支持的問題。
(3)場景3:可以迅速發現并定位性能問題。
當前問題:目前最外層Controller層打印了耗時信息,但是內部的調用關系(模塊間調用、中間件調用)和耗時信息缺乏,導致只能定位接口級別的性能問題,定位粒度較粗。保障有工具進行了一些Metric的監控(例如Redis),但基本是以分鐘為粒度去監控,定位能力有限。
(4)場景4:希望能夠看到完整的線上依賴關系視圖。
當前問題:目前的日志能夠體現依賴關系,但是存在如下問題,即只有部分系統升級到了新的日志版本,依賴關系不全,依賴關系的粒度比較粗(服務→URL,服務->URL),無法形成端到端的URL級別的依賴關系(URL->URL)[4]。
(5)場景:對日志、追蹤等的完善版本盡快生效。
當前問題:業務系統目前對于日志等組件是強依賴關系(依賴于微服務框架的整體升級),由于業務系統本身的升級頻率不一、測試成本高等問題,很難推動業務系統進行微服務框架的整體升級,治理需求在線上系統的收斂速度慢、生效周期長。
(6)場景:避免應用的版本對日志等治理組件強依賴。
當前問題:目前由于是這種強依賴關系,導致應用升級日志組件需要整體升級微服務框架。
(7)場景:架構治理組件不能引起太多性能降低。
當前問題;目前性能影響不大。
(8)場景:使用標準的模型,避免在設計上擠牙膏,定位到容器pod。
當前問題:目前根據可見需求自己定義了一套trace體系,但是從演進過程來看較SkyWalking提煉過的模型差距較大[5]。
(1)對業務完全無侵入引入Agent的方式。官方的Skywalking Agent需要修改pom添加對應的包依賴及修改日志配置,應用需要重新發版本。
(2)支持日志模型擴展,通過日志中心能夠看出日志塊的調用順序。
利用Java Agent實現業務無侵入的目標,JVM1.5以后支持在主程序前運行Agent和主程序運行后運行Agent兩種模式。
(1)啟動時調用Instrumentation的loadClass AndCallPremain方法,在這個方法中會調用JavaAgent里MANIFEST.MF指定的Premain-Class類的premain方法。
(2)運行時修改主要是通過JVM的attach機制來請求目標JVM加載對應的Agent,調用InstrumentationImpl的loadClassAndCallAgentmain方法,在這個方法中會調用JavaAgent中MANIFEST.MF指定的Agentmain-Class類的Agentmain方法。
Skywalking是Apache孵化的產品,是專門為微服務架構和云原生架構系統而設計并且支持分布式鏈路追蹤的APM系統。其通過加載非侵入探針的方式收集應用中的調用鏈路信息,并對采集的調用鏈路信息進行分析,生成應用間關系、服務間關系以及服務指標。其支持多種語言,包括Java,.Net,PHP,Python,Node.js, C++。使用此系統需要在代碼的pom中顯示引入的依賴,然后在日志配置文件中使用相應的插件,最大的問題是需要應用升級發布新的版本。
自適應微服務追蹤插件的核心理念是業務無侵入,基于字節碼增強技術實現無侵入Agent服務治理能力,業務無需修改代碼即可實現服務追蹤、運維等需求。自定義Agent作為JVM層的切面,在進行跨組件調用的時候會記錄事件,在日志中打印調用鏈信息,然后異步上報到管理端。自定義Agent作為Skywalking Agent和業務代碼的橋梁,需要將應用中顯示的依賴放在自定義Agent中,日志配置插件也不用顯示修改,在運行時進行動態替換(圖1)。

圖1 Agent 示例
插件有以下核心優勢:
(1)代碼無侵入、業務無感知,即業務無需對程序代碼做任何修改,只需在應用啟動項添加Agent參數即可;
(2)運維需求下移,即運維上請求進出標志位,日志分層需求下移到基礎設施層;
(3)模塊化設計,使業務可按需加載、卸載功能模塊及升級。
(4)日志模型擴展,目的是實現通過日志中心查看日志能夠看出調用順序。
2.3.1 Trace 擴展模型在日志中的應用
TraceID:TraceID是一次請求唯一的標識,被應用日志和skywalking日志共用。
sqn:擴展字段,用來標識分布式環境下調用層級和調用順序。規則是從1開始順序遞增,每增減一個點號代表多一層調用,如1.1 是1.1.1的parent,2表示在1后面執行的(圖2)。

圖2 模型擴展
在傳統環境中,每臺虛機都部署一個Agent客戶端,在應用的啟動腳本中添加引用Agent的腳本。對開發測試人員無感知,運維人員線上運維變更只需一鍵就可開啟所有應用的追蹤。在容器環境中,Agent通過hostpath掛卷到node節點上,云平臺屏蔽了掛卷及啟動加載的細節,對開發應用透明。
實施步驟:
(1)啟動腳本修改,-javaagent:/java_agent/leo_agent/myAgent.jar -javaagent:/java_agent/skywalking_agent/skywalking-agent.jar=agent.service_name=serviceName;
(2)配置文件修改,增加默認skywalking collector的地址sky.coll.com:8080;
(3)選擇c o l l e c t o r 的存儲模式e s 7,配置elasticsearch的地址、用戶名、密碼;
(4)配置域名,在客戶端服務器上/etc/hosts配置域名sky.coll.com對應的IP。
傳統金融行業的特點是對安全性的要求特別高,這就導致了業務系統對升級基礎框架特別謹慎。由于應用使用各個框架版本不同,甚至跨度很大,通過在基礎框架中的埋點打印運維日志的功能實施難度太大,難以快速地在線上環境推動調用鏈跟蹤落地。使用這種自適應微服務追蹤技術可以解決以上問題,同時還可以提升線上環境排障效率,快速定位錯誤。