微服務架構基本原理學習筆記(三)

上一篇:微服務架構基本原理學習筆記(二)

五、微服務之間的通信

微服務通信模式

  微服務本身並沒有規定通信規則,換句話說,一個微服務並沒有規定可以被哪些應用程序訪問,或者被哪些其它的微服務調用。應用程序與微服務間的直接通信,或者微服務與微服務間的直接調用,往往會因爲其中錯綜複雜的關係而導致級聯故障,任何一個環節的錯誤都會導致與其關聯的其它部分無法正常工作。而且,如果執行某個操作需要調用多個不同的微服務才能完成,也會導致整個系統性能下降。我們應該儘量較少微服務之間的通信。

  下圖展示了一個較好的微服務之間的通信架構圖:

  微服務之間可以將數據以消息的方式發佈到事件總線上,這樣其它的微服務就可以以消息訂閱的方式來完成微服務之間的數據通信,後面我們會討論這樣做的好處。另外,我們也可以在前端應用程序和微服務之間建立一個API網關,用來隔離它們之間的直接通信。對於前端應用程序而言,後端的微服務是透明的,所有來自前端應用程序的調用都可以通過API網關路由到對應的微服務。這樣的設計可以帶來幾個好處:首先我們可以在API網關級別實現用戶身份認證;其次是將前端應用程序與後端微服務之間進行解耦,從而使我們可以更加靈活地對微服務進行修改,同時保證面向公衆的API的一致性。假如有第三方的開發團隊基於我們的公共API來開發客戶端程序,那麼保證API的一致性就變得尤其重要,因爲我們無法控制第三方開發團隊的升級計劃。在API網關中,我們甚至可以針對不同的客戶端來聚合或轉換數據格式,以滿足前端的需要。

  在示例eShopOnContainers的微服務架構中,我們可以看到,它有一個用來接收前端請求的API網關,並且移動應用和兩個網站都通過API網關來訪問後端的微服務。此外,我們從架構圖中也可以看到,微服務之間並不會直接訪問,而是通過事件總線以消息訂閱的方式來實現異步數據通信。

同步通信

  這裏所說的同步通信與我們在編程語言中(例如Node.js中的同步與異步)所遇到的同步是兩個不同的概念。在前端應用程序通過API網關調用後端服務的過程中,有時我們需要等待服務器馬上返回結果,而不是將該請求發送到消息隊列,然後服務器在處理完之後再返回結果。例如eShopOnContainers中有一個需要顯示前10個最受歡迎的商品的功能,它是通過API網關向Catalog微服務發送一個請求,然後Catalog微服務從數據庫中獲取對應的數據並返回給前端應用程序。就整個過程而言,這是一種同步通信機制,因爲前端應用程序在發送請求之後一直處於等待狀態,直到後端服務返回結果,才進行下一步的動作(在網頁上顯示數據,或者給出錯誤提示)。

  有許多方式可以用來實現通信,但HTTP仍是迄今爲止最爲流行的方式,它作爲行業標準,幾乎所有的編程語言都支持,這意味着我們可以非常方便地在網頁或移動應用中來調用我們的API和微服務。另外,HTTP還具備一些其它的特性,例如響應頭文件和狀態標識、緩存功能、代理機制等等。在用HTTP請求數據時,通常使用JSON或XML數據格式,但推薦使用JSON,其優勢之一是絕大多數編程語言都原生支持JSON格式,而且如果你使用JavaScript作爲編程語言,JSON本身就是其數據類型的一部分。所以如果你正在開發網頁應用程序,那麼JSON數據格式是最完美的選擇。

  另外一種經常與微服務架構相關的模式是將API封裝爲RESTful資源,這是另一種用來組織和有效表達服務器資源的實踐方式。我在《RESTful服務最佳實踐》一文中對此有非常詳細的介紹。

異步通信

  有時我們在調用後端服務時不希望一直等待服務器返回結果,服務器會在適當的時候處理我們的請求。例如eShopOnContainers中提交訂單的過程:

  當客戶通過前端應用程序提交訂單時,後端系統需要完成一系列的操作,包括從第三方支付系統檢查客戶是否已成功完成支付,從供應商處檢查商品庫存狀態並啓動發貨流程等。這個過程可能會持續幾天的時間,所以對前端用戶而言,他只需要知道訂單已經成功提交,而並不需要一直等待整個過程處理完畢,他可以在稍後查詢訂單的處理進度。我們甚至可以在這個過程中添加訂單狀態更新通知功能,當訂單的狀態更新時,通過電子郵件或者短信告知用戶訂單的狀態,並在成功發貨後通知用戶。

  常用的微服務異步通信模式是將消息發送到事件總線(即消息隊列),微服務間並不直接進行通信,而是創建一條消息併發送給消息代理,其它的微服務訂閱這些消息並在適當的時候處理消息的內容。這種模式帶來許多好處,首先,它將微服務彼此完全解耦,微服務間通過消息代理完成通信。當某一個微服務暫時不可用時,仍然不影響其它微服務的正常運行,它可以繼續向消息代理髮送消息,當不可用的微服務再次上線後,便可以從消息隊列中繼續處理消息內容。其次,這種架構也有利於支持更高級的縮放,如果消息隊列中的消息數量不斷增加,我們可以對微服務進行擴展,以幫助快速處理積壓的消息。如果你使用雲託管平臺,通常可以自動支持這一操作。如果使用容器,則可以通過爲運行容器的虛擬機集羣配置一些自動擴展的功能來實現這一操作。

  消息的類型有很多,但最常用的有兩種,即命令和事件。

  命令表示要執行某種特定的操作,例如發送電子郵件,它不一定需要同步完成,該命令只需要將電子郵件的地址和內容說明清楚,剩下的事情就交給電子郵件微服務來完成。如果我們將大量的命令消息發佈到消息隊列中,電子郵間微服務可能不會馬上處理這些消息,但最終它們都會被一一處理完。

  另一種消息類型是事件,它表示發生了某件事。這有點像語法中的過去式,當事件發佈時,系統中任何對此事件“感興趣”並訂閱了該事件的微服務都可以響應並執行它們各自定義的操作。在面向對象編程中,這一模式被稱爲“發佈-訂閱”模式,例如C#中的事件處理機制就是採用的這種模式。在eShopOnContainers中,提交訂單的過程就存在OrderPlaced事件,該事件會執行多個不同的操作,如支付、發送電子郵件、檢查商品庫存等。這裏每個需要響應該事件的微服務都從發佈到事件總線上的消息觸發對應的操作。

彈性通信模式

  我們無法保證系統中所有的微服務都一直正常運行,甚至我們無法保證網絡通信沒有故障,所以,我們需要提前預料到可能出現的各種問題。這裏有幾種技術和模式可以用來幫助我們提高系統的穩定性和通信彈性。

  1. 自動重試功能。有時會因爲網絡通信故障或者微服務本身不可用而導致某個操作在一開始的時候失敗,如果系統能夠在稍後自動重試會是一個不錯的設計。例如通過一個HTTP請求對數據庫進行查詢,第一次嘗試失敗了,然後過幾秒鐘再試一次,如果仍然失敗則等待一段時間後再試一次。許多現代的編程框架已經內置了對這種功能的支持,可以使我們非常容易地實現這一特性,例如.NET中的Polly。
  2. 斷路器。自動重試功能固然好用,但是如果由於某種原因導致重試的次數過多,或者一直處於重試狀態,則可能會導致系統性能下降,或者由於過於頻繁的請求而讓下游服務拒絕響應。斷路器可以用來很好地解決這一問題。斷路器位於客戶端和服務器之間,一開始它允許所有的請求通過,此時我們稱斷路器處於關閉狀態。一旦檢測到任何錯誤,例如服務器返回特定的錯誤代碼或者根本沒有響應,那麼斷路器就會打開,這意味着客戶端的所有請求都會立刻失敗而不會發送給服務器。我們可以在斷路器上配置超時時間,超時時間過後,斷路器再次關閉,所有客戶端的請求會被正常發送給服務器。如果服務器仍然沒有響應,斷路器會再次打開並保持一段時間,所有來自客戶端的請求都被會拒絕。這是一種實現起來非常簡單但是功能卻很強大的技術。同樣,許多編程框架也都內置了該功能,你完全不必自己來實現。

  3. 緩存。靈活地運用緩存可以提高系統的彈性。如果我們緩存從服務器或者下游服務中接收的數據,那麼如果短時間內服務不可用,我們仍然可以使用緩存中的數據。當然,前提是我們已經考慮過舊數據給系統帶來的影響。

   消息代理在微服務架構中如此受歡迎的原因之一是它具有對彈性的內在支持,我們可以向消息代理髮布消息,下游服務當前是否在線都沒有關係,當服務再次啓動時,可以繼續處理積壓的消息。另外,消息代理通常還具備重試發送消息的能力,如果消息處理程序因爲某種原因無法正常處理消息,消息可以返回給消息代理以便稍後重新發送。當然,重試的次數也不是無限的,如果消息在被進行一定數量的重試後仍然無法被消息處理程序正常處理,消息代理會認爲這是一條“死”消息而將它放入“死”消息隊列中。

  另外需要注意的一點是我們無法保證消息總是按順序被接收的,這是由異步通信的本質所決定的。所以對消息處理程序而言,即便收到的消息是無序的,也能按照正確的邏輯進行處理。還有一種情況是消息處理程序可能會接收到重複的消息,這往往是因爲消息代理重複發送消息而導致的,我們需要確保消息處理是冪等的。對於一條消息而言,消息處理程序處理一次和處理兩次的結果相同,則認爲消息處理是冪等的。在eShopOnContainers中,提交訂單時的扣款和發貨過程就屬於這種情況,我們不希望這個過程中客戶被扣款兩次,而且也不希望對同一訂單重複發貨,所以,我們必須確保在代碼中進行了嚴格的檢查來避免出現這樣的情況。

微服務發現

  爲了讓微服務能夠相互通信,每個微服務都需要有一個地址,如何才能知道所有微服務的地址呢?假設我們有三臺虛機,每臺虛機上都運行着各種微服務,甚至同一個微服務的多個不同實例分別運行在不同的虛機中,我們不可能給每一個在虛機上運行的微服務都分配一個固定的IP地址,那麼如果解決這個問題呢?

  一種方法是使用註冊中心,它記錄了所有當前運行的微服務的地址。每個微服務在啓動時都向註冊中心報告並註冊自己的信息,這樣其它微服務在需要的時候就可以通過註冊中心找到該微服務。如果你使用雲託管平臺,通常它都支持這部分功能,我們不需要自己創建註冊中心。而且,在雲託管平臺上,我們部署的每個微服務通常都會自動分配一個DNS名稱,同時它還支持負載均衡,這意味着我們可以通過DNS名稱來找到微服務,而不用關心微服務是在哪臺虛擬機上。

  如果使用容器,則可以考慮使用KubernetesKubernetes內置了DNS,我們不需要知道每個容器的IP地址,只需要知道微服務的名稱即可。Kubernetes負責將請求路由到對應容器並在必要時進行負載均衡。

六、微服務安全

  微服務應用程中通常都要存儲和處理大量數據,這些數據常常都包含了各種敏感信息。例如,在eShopOnContainers中,Catalog微服務用來處理商品信息,這些信息應該對所有客戶開放,因此這部分數據不是敏感數據。但是在Ordering微服務中,我們需要保存哪些客戶訂購了哪些商品,同時還包含客戶的送貨地址和付款信息,這些數據都是非常敏感的,如果一旦泄露,將會產生非常嚴重的後果。因此,對於那些處理敏感數據的微服務,我們必須採取有效的保護措施。

對數據進行加密

  數據的加密包括幾個方面,首先是數據傳輸過程中的加密,以防止數據被中間方監聽。推薦使用業界標準的加密算法,而不要嘗試自己發明新的加密算法。對於HTTP通信,可以通過配置傳輸層安全或者TLS(Transport Layer Security)來實現加密,使所有的請求都通過HTTPS進行訪問。實現HTTPS訪問需要配置SSL證書,這是一個比較複雜的過程,你需要爲每一個服務申請一個證書,該證書由第三方受信任的機構頒發,證書有一定的有效期,過期之後需要更新證書。使用雲託管平臺可以簡化這個過程,它默認就支持HTTPS訪問機制。

  數據的加密還包括對靜態數據的加密,所謂靜態數據,就是指存儲在硬盤上的數據。任何保存在硬盤上的數據都應該被加密。許多雲提供商都提供了標準的靜態數據加密服務,所以我們無需自己花時間去配置和管理加密密鑰。需要注意的一點是,不應該僅僅對正在使用的靜態數據進行加密,任何備份的數據也應該被加密。

身份認證

  僅僅對數據進行加密是遠遠不夠的,我們還需要確保所有的HTTPS請求是安全的,換句話說,我們需要知道請求者是誰,他們是否獲得授權以訪問我們的服務。最常見的實現身份認證的方式是在每一個HTTP請求中包含一個Header,其中帶有用來識別用戶身份的用戶名和密碼,這種方式被稱爲基本身份認證方式(Basic authentication),例如用來實現用戶登錄的功能就可以使用此方法。但是這種認證方式會暴露用戶的密碼,而且微服務代碼中如果對用戶的密碼處理不當,也會帶來一定的安全隱患。因此這種認證方式並不推薦。

  還有一種方式是爲微服務的每個客戶端提供自己的密鑰,然後客戶端在HTTP請求頭中包含API密鑰。但是這種方式帶來了密鑰管理上的問題,一旦密鑰管理程序受到攻擊或者密鑰被泄露,後果也是非常嚴重的。

  另外一種方式是使用客戶端證書,通過使用公鑰加密,證書爲我們提供了一種非常安全的身份認證方式。不過,證書的安裝和管理也會帶來一些的問題。最好的方式是按照業界標準在微服務中實現身份認證,例如OAuth 2.0OpenID。這通常是通過授權服務器(Authorization Server)來實現的。在eShopOnContainers中,這一部分的功能包含在Identity微服務中。首先,客戶端通過發送某種憑據向授權服務器進行身份認證,如果認證通過,授權服務器返回一個有限時間的訪問令牌(token)。然後,客戶端將該令牌放在HTTP請求頭中訪問微服務,由於令牌使用了公鑰加密進行簽名,所以授權服務器可以驗證令牌的真實性和有效性。因爲OAuth 2.0和OpenID都是行業標準,有很多現成的第三方組件和服務可以直接使用,所以你不需要自己來實現,例如示例程序eShopOnContainers中使用了名爲IdentityServer4的開源產品。

授權

  身份認證用來告訴我們訪問者是誰,而授權的作用是知道可以幹什麼。例如,當用戶登錄到eShopOnContainers時,他有權查看自己的歷史訂單,但無權查看其他用戶的歷史訂單。許多Web API框架都內置了授權機制,用於檢查用戶的角色和權限,例如eShopOnContainers中使用的ASP.NET Core框架。

  對於微服務提供的每一個API,我們都應該認證考慮哪些用戶可以被訪問,哪些用戶不能訪問。在微服務中,有一種特殊的情況我們需要特別注意。假設用戶Mark通過了身份認證併成功訪問了Ordering微服務的某個功能,而該功能又會調用另一個微服務,例如Payment微服務。Ordering微服務知道當前訪問的用戶是Mark,並知道Mark可以執行哪些操作,但是當Ordering微服務調用Payment微服務時,由於Payment微服務信任Ordering微服務,它假定所有來自Ordering微服務的請求都是安全的,所以可能會存在某種安全隱患,使得用戶Mark能以某種方式欺騙Payment微服務而使用其他用戶的信用卡來支付自己的訂單。解決方法就是當Ordering微服務訪問Payment微服務時也需要同時傳入用戶Mark的訪問令牌,用來告訴Payment微服務最終的用戶身份,如果Payment微服務識別出請求者不是Mark用戶,則請求被拒絕,這樣可以有效地避免Payment微服務的調用被欺騙的問題。

網絡安全

  我們可以使用防火牆、IP白名單和虛擬網絡等網絡功能來共同保護我們的微服務。下圖中,我們可以看到其中有三個相互通信的微服務,如果我們將其放到虛擬網絡中,那麼我們就有能力拒絕任何來自虛擬網絡外部的訪問請求,而只允許微服務之間彼此進行通信。這種方式可以很好地保護後端服務的網絡安全,這些微服務可能只需要在它們之間進行通信,而不需要從外部直接訪問。但是,如果確實存在需要從外部直接訪問微服務的情況呢?例如,一個單頁面應用程序(SPA),它可能需要直接訪問某個微服務,這是否意味着我們需要放開虛擬網絡對外部請求的限制而允許訪問某些微服務呢?有關這一點我們在前面“微服務通信模式”一節中已經討論過了,一個好的實踐方式是使用API網關將外部請求與虛擬網絡中的微服務隔離開,這樣我們就可以非常有選擇性地確定哪些API可以從外部訪問,哪些API不能從外部訪問。而且,單一的訪問入口也有利於對API網關配置防火牆,以防範DDOS攻擊和SQL注入等。

  通常,在微服務應用中,有一個面向公衆的網站,例如eShopOnContainers網站,但同時可能還有一些其它的應用只面向一小部分用戶,例如針對系統管理員訪問的系統後臺管理程序,或者專門針對市場部進行營銷活動的頁面等。對於這部分應用,我們希望只有特定的用戶才能訪問,而不是對公衆開放。我們可以通過IP白名單的方式只允許來自特定IP地址的請求(例如系統管理員或市場部用戶的IP地址),而拒絕來自其它IP地址的請求。

  微服務的安全涉及到多方面的技術,而不僅僅是其中的一兩個,爲了保證後臺服務的安全,我們應該避免僅僅依賴單個的保護機制,而應該儘可能地使用多層安全保護,這就是所謂的縱深防禦機制。

縱深防禦機制

  前面我們談了有關微服務安全的許多方面,包括對數據進行加密、對用戶進行身份認證、授權用戶只訪問允許的資源、通過使用虛擬網絡和IP白名單拒絕來自未經授權的網絡請求等。縱深防禦指的是我們不應該只依賴於其中一種技術來保護我們的應用程序和服務,這是因爲一旦某一個防禦被突破,那麼攻擊者就可以免費獲取到所有數據。我們需要結合多種不同的安全措施來保證我們數據的安全性,從而儘可能地降低數據泄露的可能性。處理的數據越敏感,所需要的防護也就越多。除了上面提到的一些安全防護機制外,還有一些額外的防禦措施。

  黑客們會使用各種非常複雜的工具和技術來入侵和破壞我們的服務和應用,對於開發人員而言,瞭解這些攻擊技術可以有效地採取一些防護措施來阻止攻擊。我們可以安排信息安全專家對應用程序進行滲透測試,這可以知道我們的應用程序是否能夠防禦最先進的黑客技術,同時專家也可以提供一些有關如何提供應用程序安全性的建議。另外,創建自動化測試來驗證安全性設置是否正常工作並有效,而不要僅僅假設我們已經進行了正確的網絡和安全設置。可以有針對性地進行一些安全測試,例如用未經授權的用戶訪問API,還可以檢測攻擊行爲何時進行,例如嘗試多次重複登錄和HTTP請求、對於敏感文件的網絡釣魚訪問、SQL注入攻擊等。所有這些攻擊都可以實時檢測到,我們可以進行系統報警配置,當攻擊行爲發生時,系統可以主動做出響應,例如阻止攻擊者的IP地址請求,或者暫時關閉系統的部分功能以防止攻擊等。最後,我們應該對系統中所有正在執行的操作都記錄日誌,這樣我們纔可以準確地知道誰在什麼時間做了什麼,當系統受到攻擊或者數據發生泄露時,纔能有機會了解事情是如何發生的,以及哪些數據被泄露。

七、發佈微服務

自動化部署

  在單體應用程序中,部署過程往往比較簡單,而且通過手動就可以輕易地完成,我們只需要將所有步驟和注意事項在文檔中描述清楚,然後按部就班地逐一執行就可以了。但是這種操作方式對微服務而言並不適用,因爲微服務需要部署的東西往往非常多,相互之間的依賴關係也比較複雜,而且部署過程相對也較爲頻繁,所以我們強烈推薦通過自動化的方式來完成微服務的部署。

  在微服務的部署中,這一過程被稱之爲CICD(Continuous Integration/Continuous Delivery),即所謂的持續集成和部署。那麼如何構建一個可以持續集成和部署的自動化過程呢?持續集成從我們將代碼簽入到Github使開始,首先集成服務器會執行一系列的單元測試,以保證我們簽入代碼的質量是相對可靠的;然後通過CI管道(Pipeline)按照預先定義好的步驟部署微服務,可以將微服務部署到本地虛擬機或者雲端;一旦微服務部署成功,就需要進行服務級別的集成測試;如果測試通過,接下來就可以將微服務部署到QA環境中進行整個系統級別的測試,如運行自動化的端到端的測試;在正式將微服務投入到生產環境之前,通常還需要一些額外的準備工作,如進行一些必要的手動測試、執行風險評估掃描、相關簽署工作等;最後,我們將準備好的release發佈到生產環境。一個完整的流程看起來像這樣:

部署環境

  通常,我們希望微服務能夠被部署到不同的環境中。開發人員希望將微服務部署到本地虛擬機,以便在開發過程中能夠在本地調試代碼。同時我們還需要有一個測試環境,能夠在其中對微服務進行端到端的測試,並且QA小組也希望能夠在測試環境中進行一些必要的手動測試。有時,我們可能還需要專門用於滲透測試和性能測試的環境。除此之外,我們還需要生產環境,這是我們的微服務最終運行的環境,也是我們交付給客戶能夠真正使用的環境,不言而喻,生產環境是最重要的。在某些情況下,我們可能會有多個生產環境,比如爲不同的客戶準備不同的生產環境,在不同的地理區域中準備不同的生產環境等。因此,參數化我們的自動化部署腳本非常有必要,這可以使我們的部署過程儘可能簡單。我們可以使用JSON或者YAML爲不同的環境定義不同的參數,當然,也可以使用各種工具如Docker Compose或者Kubernetes來獲得更加成熟的解決方案。

構建註冊表(Artifact Registry)

  將構建工件(Artifact)存儲在某種註冊表中可以使我們非常方便地部署微服務的任意版本,從而使得我們可以輕鬆地將微服務回滾到之前的某個特定版本。示例應用程序eShopOnContainers選擇將每個微服務構建爲Docker容器鏡像,這樣做有很多好處,其中之一是版本命名的標準化,並且可以存儲在容器註冊表中,當我們使用Docker來進行部署時,操作會變得很容易。例如名稱“eshoponcontainers/orderingservice:1.3.1”代表eshop應用程序中ordering微服務的1.3.1版本。由於eShopOnContainers應用程序使用容器作爲交付機制,因此它非常適合使用Kubernetes。如果我們使用Kubernetes集羣,那麼可以通過YAML配置文件來定義應用程序中所有的微服務。Kubernetes是基於狀態策略來運行的,配置文件定義了哪些微服務需要運行以及如何進行設置,Kubernetes將配置文件中的內容與集羣上的配置文件進行比較,如果不一致,則相應地添加或刪除容器,直到運行的內容與所要求的內容相匹配。所以,對於微服務版本的升級,或者其它任何屬性的改變(例如環境變量或者副本數量等),只需要更改配置文件即可。有關Kubernetes的詳細介紹可以參考官網網站的說明。

獨立升級

  在前面的章節中,我們討論過微服務之間松耦合的重要性,我們不希望單個微服務的升級同時依賴於其它的微服務。我們的自動化流程可以一次性部署所有的微服務,但是一次只能更新(或升級)一個微服務。如何對單個微服務進行升級是一個值得思考的問題。你可能會想,不就是停止服務,更新,然後再重新啓動嗎?如此簡單的步驟還需要大費周折嗎?當然,如果你不想服務被中斷,這個方法當然行之有效。不過,在生產環境中,某些微服務是不允許被中斷的,我們應該通過技術手段儘可能地在微服務的升級過程中減少或者避免停機時間。

  一種有效的方法是同時運行新舊兩個版本的微服務,然後通過負載均衡將流量從舊版本移動到新版本。這樣升級過程中不會有停機時間,客戶幾乎不會感覺到升級過程中的任何停頓。

  另一種方法是同時運行多個微服務的副本,然後逐個升級替換。例如有三個V1版本的微服務實現負載均衡,我們可以每次添加一個V2版本的新實例並同時刪除一個V1版本的實例,直到所有的V1被替換成V2,並最終完成對整個微服務的升級過程,但前提是兩個不同版本的微服務之間能夠兼容。值得一提的是,Kubernetes集成了許多高級的升級策略,你可以查看官方文檔並使用這些策略。

  另外還需要考慮的一個問題是,當升級出現問題時,我們可以無縫地回滾到之前的版本。Kubernetes同樣可以非常輕鬆地幫我們解決這一問題,回滾操作只需要更新配置文件使其指向之前版本的標籤即可。

監控微服務

  微服務的一大挑戰是我們需要監控的東西非常多。一個微服務可能同時在多個不同的服務器上以多個不同的進程運行,所以通過手動的方式連接到這些虛擬機集羣中的每個工作節點來檢查和查看工作日誌幾乎變得不可能,而我們需要的是通過一個系統來自動監控和管理這些日誌,管理員可以在一個集中的地方操作和查看這些日誌。通常,這個系統會有一個稱之爲儀表盤(Dashboard)的界面,能夠讓我們實時瞭解系統的整體運行狀況,並在出現問題時報告具體原因。通常,它分爲這幾個部分:

  • 主機指標。包括CPU和內存使用情況。通過這些指標我們可以檢測是否需要對主機容量進行擴充以滿足更多的需求。許多雲提供商都會提供這一類的監測數據,同時還包括警報功能,當主機運行狀況超過閾值時會自動發出通知(短信、郵件或其它通知方式)。
  • 應用程序級別的監測數據(Web API)。包括HTTP請求數量,以及失敗的請求數量和錯誤代碼等。例如,如果日誌中有很多401 Unauthorized的響應代碼,那麼很可能我們的服務受到了黑客攻擊,或者存在錯誤的配置項;如果日誌中有很多500的錯誤代碼,那麼表明我們的代碼中存在某種錯誤。如果使用消息代理,則需要跟蹤並查看消息隊列中是否存在大量的死消息,以表明我們的程序是否在處理消息時遇到了問題。另外,一個好的實踐是讓每一個微服務都支持端點檢查,這是一個特定的Web API,允許定期被調用來檢查微服務運行是否正常,當它被調用時,只需要回覆是否OK即可,用以表明服務是否啓動並工作正常,同時它還可以返回一些額外的信息,例如該微服務所依賴的下游服務是否正常工作等。
  • 易於訪問的日誌文件。每個微服務都應該記錄日誌,我們需要將這些日誌集中到一個地方,以方面查看和管理。使用容器的好處是可以通過一種標準化的方式來捕獲日誌,並將日誌集中到一個統一的地方。有許多第三方的開源產品可以幫助我們實現這個功能,例如可以將日誌發送到Elasticsearch,然後使用Kibana查看日誌,或者在Microsoft Azure中使用Application Insights。許多雲託管平臺也提供了很多易於啓用的監控和日誌功能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章