【經(jīng)驗談】微服務日志的七種優(yōu)秀實踐
譯文【51CTO.com快譯】微服務架構是一種全新的應用結構,它能夠幫助您通過松耦合的系統(tǒng),開發(fā)、測試、部署和發(fā)布彼此相互獨立的各種服務。因此微服務背后的理念是:將大型系統(tǒng)分解成多個獨立的小部分。
通常情況下,每個服務都能通過HTTP的端點與其他服務交互。它們在隱藏技術棧細節(jié)的同時,會暴露自己的契約(contract)給其對應的消費者(consumer)角色。例如:服務A可以在調(diào)用服務B的同時,也去調(diào)用服務C,而只要整個請求鏈是完整的,那么服務A就能夠?qū)Πl(fā)起請求的客戶端做出響應。
微服務架構能夠給我們的系統(tǒng)帶來很多方面的好處,其主要能力包括:使用不同的技術棧、獨立地進行部署、一次只解決一個小問題等。但是,由于它在通信和管理上的復雜性,一般使用微服務的成本會比較高。而且在一個或多個服務出現(xiàn)問題時,微服務會變得更加復雜。如果沒有掌握良好的、且有意義的日志的話,你都無法回答諸如:哪個服務、為什么、和在什么情況下失敗了等問題。
老實說,我本人最憎恨那些由于糟糕的日志策略,所導致的一些“未知”的系統(tǒng)錯誤。下面我們和您分享一些,自己在與微服務打交道時總結出的七種優(yōu)秀實踐。
1.用唯一性ID來關聯(lián)各個請求
請回想一下我們上面提到的服務A、B、C之間的請求調(diào)用鏈。在實踐中,我們應當給每一個調(diào)用分配一個唯一性的ID,以便標識出每一個請求。
設想您正在記錄每個服務的訪問與錯誤日志。如果您發(fā)現(xiàn)在服務B上有錯誤,那么您就能知道該錯誤是來自于服務A、還是服務C。
如果錯誤信息足夠詳細的話,您也許不必去重現(xiàn)錯誤。但是多數(shù)情況并非如此,您必須通過正確的方式,將各個服務(如服務B)中的所有請求進行錯誤重現(xiàn)。因此,如果您發(fā)現(xiàn)了某個與之相關聯(lián)的請求,那么您只需要在日志中尋找出它所對應的ID便可。
隨后,您可以順藤摸瓜地從系統(tǒng)中將那些主要請求的某個部分,從服務的全量日志中截取出來。接著,您就可以知道是哪項服務的主請求花費了最多的時間。其可能性包括:可能是某項服務使用到了緩存、或是某項服務不止一次調(diào)用了其他服務、以及其他有趣的細節(jié)。
2.在響應中包含唯一性ID
微服務的用戶可能會不止一次地碰到同一個錯誤。面對這樣的情況,您應該乘機對客戶端可能接收到的響應進行編碼,以便它能夠?qū)⒁粋€唯一性的ID,連同與該錯誤相關的任何其他有用的信息都傳遞出來。當然,這個唯一性的ID完全可以和我們在上面所提到的相關請求保持一致。
因此,在響應的有效載荷中包含與請求相關的唯一性ID,將有助于您和您的客戶更迅速地發(fā)現(xiàn)各類問題。同時,您也可以獲悉請求日期、時間和其他細節(jié)上的參數(shù),以便您能夠更好地理解自己所碰到的問題。另外,您還可以將請求的ID,添加到諸如“請聯(lián)系服務管理員,并報告該問題。”之類的常見補充性錯誤信息之中,以便深入了解到底是什么原因引起該錯誤,進而防止它在未來再次發(fā)生。
3.發(fā)送日志到集中的位置
在此,讓我們假設您已經(jīng)對各種有用的日志信息進行了分類。下一步,我們就需要將各類日志發(fā)送到一個集中化的位置。
試想一下:如果您每次都需要登錄到各個相互單獨的服務器上,以來讀取不同的日志信息,那么您將不得不花費更多的時間去試圖關聯(lián)這些問題。這遠不如您登錄到某一個位置,并一站式地訪問到所有的日志,以定位問題。
此外,您的系統(tǒng)通常會隨著時間的推移,而變得日趨復雜,而各項微服務的數(shù)量也會節(jié)節(jié)攀升。同時,您的各種服務可能會分處不同的服務器或提供商,這都會讓形勢變得更為復雜。
因此,集中式存放日志正在成為業(yè)界的常規(guī)方法,特別是當您的服務工作在云端、容器、或其他混合環(huán)境之中,而某些服務器可能會在無任何通知的情況下下線的時候。例如,在出現(xiàn)異常錯誤,或是內(nèi)存的消耗水平已經(jīng)達到100%時,某些容器就會被終止運行。
您可以在服務器中斷之前,通過設置代理,每五分鐘推/拉一次日志,來解決此類問題。您也可以在服務器上配置一個cronjob(定時任務)、sidecar container、或是一個與其他進程共享的文件位置,來集中化各種日志。為了避免日志被篡改,您還可以自行構建一套解決方案,具體請參見鏈接:https://blog.scalyr.com/2017/11/log-management-need/。
可見,將所有服務的日志都集中到一處,會有助于您更容易、且有效地定位各種關聯(lián)問題。
4.結構化您的日志數(shù)據(jù)
在具體實踐中,我們很難為所有的日志數(shù)據(jù)預先定義好格式。有些日志可能需要比其他日志更多的字段,相反這些字段可能會對那些不需要的日志來說不但多余、而且浪費字節(jié)數(shù)。
微服務架構是通過使用不同的技術堆棧,來解決此類問題的。不過,這會影響每個服務的日志格式。例如:某一個服務可能是用逗號來分隔不同的字段,而其他日志則使用的是管道或命名空間。
上述方法顯然比較復雜。因此,我們可以通過將自己的日志數(shù)據(jù)構建成一套標準的格式,如:JavaScript Object Notation(JSON),來簡化解析日志的過程。JSON允許您擁有多層次的數(shù)據(jù)。在必要的時候,您可以在單個日志的事件中獲取更多的語義信息。
同時,此法也使得對于特定日志格式的解析更加直接。通過對數(shù)據(jù)采取結構化,就算您的日志里有各種不同的字段,其格式也會變得更加標準。籍此,您也可以在集中化的位置上創(chuàng)建各種搜索,例如:檢索包含有500條及以上,“HTTP_CODE”字段的日志信息??梢哉f,使用結構化的日志方式既能讓您的微服務日志實現(xiàn)標準化,又不失靈活性。
5.為每個請求添加上下文
通常情況下,如果系統(tǒng)能夠提供足夠的信息,那么我們就能夠更好地了解針對某個問題的上下文請求,更快地發(fā)現(xiàn)該問題的根本原因。不過,給各種日志添加上下文,也會在代碼層面上產(chǎn)生一些重復性的工作,因為在您所需要的許多日志事件中,已經(jīng)包含了諸如日期和時間等通用數(shù)據(jù)信息。因此在我們的代碼中,應當只記錄那些重要的消息、并涉及到一些特定的領域,以使得日志看起來簡單明了。
您可能會想到各種五花八門的數(shù)據(jù)需要被記錄,但是讓我們通過如下的列表,來告訴您哪些才是真正需要記錄的具體特定領域吧。
- 日期和時間。當然,如果能夠保證讀取日志的人都在同一時區(qū)的話,您大可不必一律采用UTC(世界標準時間)的格式。
- 堆棧錯誤。您可以將異常對象作為參數(shù)傳遞給自己的日志庫。
- 服務的名稱或代碼,這樣您就可以根據(jù)微服務來區(qū)分不同的日志。
- 發(fā)生錯誤的函數(shù)、類或文件名,這樣您就省去了跟蹤問題出處的時間。
- 與外部服務交互的各種名稱,例如:您可以獲悉是哪個進程在調(diào)用數(shù)據(jù)庫時出現(xiàn)了問題。
- 服務器和客戶端請求的IP地址。這些信息將有助于發(fā)現(xiàn)那些不健康的服務器、或識別出DDoS類攻擊。
- 應用程序的用戶代理,以便您能判斷是哪些瀏覽器或用戶碰到了問題。
- 通過HTTP代碼來獲取錯誤的更多語義。這些代碼將有助于創(chuàng)建各類警報。
可見,為每個請求添加上下文,能夠節(jié)省您對系統(tǒng)進行排障的時間。
6.將日志存儲到本地
將日志存儲到本地,似乎聽起來和我們前面說的“發(fā)送日志到集中的位置”有些矛盾,其實則不然。最初我是將各種日志,直接通過HTTP請求的方式發(fā)送到別處的。但是我屢次發(fā)現(xiàn)這些流量傳輸占用掉了我大量的出站帶寬,以至于影響到了其他更為重要的微服務調(diào)用。
因此,我們需要對日志的外發(fā)和本地存儲有所取舍。最終,我之所以選擇了本地存儲,是因為這樣有助于從應用程序中分離日志、并減少上下文的切換。針對數(shù)據(jù)庫,您可以采取將應用程序與其日志區(qū)分不同存儲卷的方式。
例如:亞馬遜的AWS就一個選項,用戶可以使用一種稱為Elastic File System(EFS)的服務,去掛載某個卷。其功能類似于網(wǎng)絡附屬存儲(network-attached storage,NAS)。那么,您可以按需輾轉到另一臺服務器上,掛載相同容量的卷,然后將各種日志轉發(fā)到那個集中的位置上。
簡單說來,我們可以使用Docker容器,來實現(xiàn)將所有應用程序的日志都發(fā)送到相同的位置。然后匯總、過濾和轉發(fā)這些日志的存儲庫,到其他進程或服務那里。
7.記錄重要且有意義的數(shù)據(jù),有備無患
如果您是剛開始接觸微服務的日志問題,那么上述最佳實踐可能會對你比較“無感”。但是,只要您足夠細心,在持續(xù)使用了微服務一段時間之后,您就可以通過對現(xiàn)有日志信息和方式的評估,逐漸摸索出哪些才是您可以用來發(fā)現(xiàn)和解決奇怪問題的有用信息。
同時,在記錄和積累了足夠多的日志數(shù)據(jù)之后,您還可以伺機采用自動化的警報方式,以節(jié)約您通過讀取大量日志來定位問題的時間。當然,自動化警報也能夠幫助您以一種積極主動方式,限制各種錯誤向所有用戶處蔓延。
總之,集中化日志信息,是微服務錯誤分析的必備手段。而為日志添加足夠多的上下文信息,則能夠更好地分辨出那些是有用的日志,那些是無用的信息。
原文標題:Microservices Logging Best Practices,作者:Christian Melendez & David McAllister
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】