歡迎光臨
每天分享高質量文章

華爾街見聞Istio生產實踐

 

隨著見聞業務不斷增加,所涉及語⾔也越來越多。由於微服務化的引入,就需要為不同語言開發各自的服務發現、監控、鏈路追蹤等組件,更新運維成本較高。同時應用的灰度部署也是見聞在著⼒解決的問題。Istio通過下沉基礎設置,很好的解決了組件跨語言兼容問題, 同時帶來了智慧路由、服務熔斷、錯誤註入等重要的特性。整個搭建過程中也遇到了很多坑和經驗,希望和大家分享。
見聞開發團隊以Golang為主,同時存在Python,Java服務,這就需要SRE提供更容易接入的微服務基礎組件,常見的方案就是為每種語言提供適配的微服務基礎組件,但痛點是基礎組件更新維護的成本較高。
為瞭解決痛點,我們將目光放到服務網格,它能利用基礎設施下沉來解決多語言基礎庫依賴的問題,不同的語言不需要再引入各種不同的服務發現、監控等依賴庫,只需簡單的配置並運行在給定的環境下,就能享有服務發現、流量監控、鏈路追蹤等功能,同時網絡作為最重要的通信組件,可以基於它實現很多複雜的功能,譬如智慧路由、服務熔斷降級等。
我們調研了一些服務網格方案,包括Istio、Linkerd。
對比下來,Istio擁有更多活躍的開源貢獻者,迭代速度快,以及Istio架構可行性討論,我們選擇Istio作為實踐方案。
服務網格架構圖:
這張圖介紹了華爾街見聞典型的服務網格架構,左半圖介紹了用戶請求是如何處理,右半圖介紹運維繫統是如何監控服務。

 

架構可行性

 

通過架構圖,我們拆分出以下關鍵組件,經過評估,Istio高度模塊化、可拓展,各個組件的可用性、拓展性都有相應的策略達到保障,我們認為Istio是具有可實施性的。
Istio Ingress高性能,可拓展
性能:Istio Ingress用來處理用戶入流量,使用Envoy實現,轉發性能高。
可用性:保證實體數量並使用服務探活接口保證服務可用性。
拓展性:掛載在負載均衡後,通過增加實體實現可拓展。
Istio Proxy隨應用部署,輕微性能損耗,可隨應用數量拓展
Istio Proxy以Sidecar形式隨應用一起部署,增加2次流量轉發,存在性能損耗。
性能:4核8G服務器,上面運行Proxy服務和API服務,API服務只傳回ok字樣。(此測試只測試極限QPS)
單獨測試API服務的QPS在59k+,平均延時在1.68ms,CPU占用4核。通過代理訪問的QPS6.8k+,平均延時14.97ms,代理CPU占用2核,API服務CPU占用2核。
CPU消耗以及轉發消耗降低了QPS,增加了延時,通過增加機器核數並增加服務部署數量解決該問題,經過測試環境測試,延時可以接受。
可用性:基於Envoy,我們認為Envoy的可用性高於應用。依賴Pilot Discovery進行服務路由,可用性受Pilot Discovery影響。
拓展性:Sidecar形式,隨應用數拓展。
Istio Policy服務可拓展,但同步呼叫存在風險
Istio Policy需要在服務呼叫前訪問,是同步請求,會增加服務呼叫延時,通過拓展服務數量增加處理能力。屬於可選服務,華爾街見聞生產環境未使用該組件。
性能:未測試。
可用性:若開啟Policy,必須保證Policy高可用,否則正常服務將不可用。
拓展性:增加實體數量進行拓展。
Istio Telemetry監控收集服務
性能:從監控上觀察Report 5000qps,使用25核,響應時間p99在72ms。異步呼叫不影響應用的響應時間。
可用性:Telemetry不影響服務可用性。
拓展性:增加實體數量進行拓展。
Pilot Discovery
性能:服務發現組件(1.0.5版本)經過監控觀察,300個Service,1000個Pod,服務變更次數1天100次,平均CPU消耗在0.04核左右,記憶體占用在1G以內。
可用性:在服務更新時需要保證可用,否則新創建的Pod無法獲取最新路由規則,對於已運行Pod由於Proxy存在路由快取不受Pilot Discovery關閉的影響。
拓展性:增加實體數量可以增加處理量。

 

服務監控

 

Istio通過mixer來搜集上報的遙測資料,並自帶Prometheus、Grafana等監控組件,可方便的對服務狀態進行監控。見聞目前監控在用Istio自帶的,利用Prometheus拉取集群指標,經由Grafana看板展示,可直觀展示出各種全域性指標及應用服務指標,包括全域性QPS、全域性呼叫成功率、各服務延時分佈情況、QPS及狀態碼分佈等, 基本滿足監控所需。
儲存暫未做持久化操作,採用Prometheus的預設的記憶體儲存,資料的儲存策略可通過設定Prometheus的啟動引數–storage.tsdb.retention來設定,見聞生產時間設定為了6h。
Prometheus服務由於資料儲存原因會消耗大量記憶體,所以在部署時建議將Prometheus部署在專有的大記憶體node節點上,這樣如果記憶體使用過大導致該node節點報錯也不會對別的服務造成影響。Istio mixer擔負著全網的遙測資料搜集任務,容易成為性能瓶頸,建議和Prometheus一樣將其部署在專有節點上, 避免出現問題時對應用服務造成影響。
以下是Mesh彙總面板的Demo:
Service Mesh彙總監控頁面

鏈路追蹤

 

Envoy原生支持分佈式鏈路追蹤, 如Jaeger、Zipkin等,見聞生產選擇了Istio自帶的Jaeger作為自身鏈路追蹤系統。預設Jaeger服務為all_in_one形式,包含jaeger-collect、jaeger-query、jaeger-agent等組件,資料儲存在記憶體中。
見聞測試集群採用了此種部署形式。見聞生產環境基於性能與資料持久性考慮,基於Cassandra儲存搭建了單獨的jaeger-collect、jaeger-query服務。Jaeger兼容Zipkin,可以通過設定Istio ConfigMap中的zipkinAddress引數值為jaeger-collector對應地址,來設置Proxy的trace上報地址。同時通過設置istio-pilot環境變數PILOT_TRACE_SAMPLING來設置tracing的採樣率,見聞生產採用了1%的採樣率。
Tracing不像Istio監控系統一樣對業務代碼完全無侵入性。Envoy在收發請求時若發現該請求沒有相關trace essay-headers,就會為該請求自動創建。tracing的實現需要對業務代碼稍作變動,這個變動主要用來傳遞trace相關的essay-header,以便將一次呼叫產生的各個span串聯起來。
見聞底層採用 grpc 微服務框架,在Gateway層面將trace essay-header 加入到入口grpc呼叫的context中,從而將trace essay-headers 逐級傳遞下去。
Istio探活

 

Istio通過向Pod註入Sidecar接管流量的形式實現服務治理,那麼就會有Sidecar與業務容器狀態不同步的可能,從而造成各種的呼叫問題,如下兩方面:
  • Sidecar就緒時間晚於業務容器:業務容器此時若發起呼叫,由於Sidecar還未就緒, 就會出現類似no healthy upstream之類錯誤。若此時該Pod接收請求,就又會出現類似upstream connect error錯誤。

  • Sidecar就緒時間早於業務容器:例如某業務容器初始化時間過長導致Kubernetes誤以為該容器已就緒,Sidecar開始進行處理請求,此時就會出現類似upstream connect error錯誤。

探活涉及Sidecar、業務容器兩部分,只有兩部分同時就緒,此Pod才可以正式對外提供服務,分為下麵兩方面:
  • Sidecar探活:v1.0.3及以上版本針對Pilot-agent新增了一個探活接口healthz/ready,涉及statusPort、applicationPorts、adminPort等三個端口。其基本邏輯為在statusPort上啟動健康監測服務,監聽applicationPorts設定的端口是否至少有一個成功監聽,之後通過呼叫本地adminPort端口獲取xDS同步狀態。若滿足至少一個applicationPort成功監聽,且CDS、LDS都進行過同步,則該Sidecar才被標記為Ready。

  • 業務容器探活:見聞通過基本庫,在所有Golang grpc後端服務中註冊了一個用於健康檢查的handler, 該handler可由開發人員根據自身業務自定義,最後根據handler傳回值來判斷業務容器狀態(如下圖)。

Istio應用更新

 

為了實現灰度部署,見聞基於Kubernetes Dashboard進行了二次開發,增加了對Istio相關資源的支持,利用Gateway、VirtualService、DestinationRule等crd實現了應用程式的灰度部署,實際細節如下:
  1. 更新流量控制將流量指向已有版本,利用VirtualService將流量全部指向v1版本(見下動圖)。

  2. 部署新版本的Deployment,查找舊的Deployment配置,通過篩選app標簽符合應用名的Deployment,運維人員基於該Deployment創建v2版本的Deployment,並向destinationRule中增加v2版本。

  3. 更新流量控制將流量指向新版,本利用VirtualService將ServiceA的服務流量全部指向v2版本。

  4. 下線老版本的Deployment並刪除對應DestinationRule。

利用Istio Dashboard來實現上述流程:
為了方便開發人員服務部署,開發了精簡版後臺,並對可修改部分進行了限定。最終,SRE提供兩個後臺,對Istio Dashboard進行精細控制:

 

 

實踐中的寶貴經驗

 

在Istio實踐過程中,有哪些需要註意的問題。
API server的強依賴,單點故障
Istio對Kubernetes的API有很強的依賴,諸如流量控制(Kubernetes資源)、集群監控(Prometheus通過Kubernetes服務發現查找Pod)、服務權限控制(Mixer Policy)。所以需要保障API server的高可用,我們曾遇到Policy組件瘋狂請求Kubernetes API server使API server無法服務,從而導致服務發現等服務無法更新配置。
  • 為避免這種請求,建議使用者瞭解與API server直接通信組件的原理,並儘量減少直接通信的組件數量,增加必要的Rate limit。

  • 儘量將與API server通信的服務置於可以隨時關閉的環境,這是考慮如果部署在同一Kubernetes集群,如果API server掛掉,無法關閉這些有問題的服務,導致死鎖(又想恢復API server,又要依靠API server關閉服務)。

服務配置的自動化
服務配置是Istio部署後的重頭戲,避免使用手動方式更改配置,使用代碼更新配置,將常用的幾個配置更新操作做到運維後臺,相信手動一定會犯錯。
關於Pilot Discovery
Pilot Discovery 1.0.0版本有很大的性能問題,1.0.4有很大的性能提升,但引入了一個新bug,所以請使用1.0.5及以上的版本,我們觀察到CPU消耗至少是1.0.0版本的1/10,大大降低了Proxy同步配置的延時。
關於Mixer Policy 1.0.0
這個組件曾導致API server負載過高(很高的list pods請求),所以我們暫時束之高閣,慎用。
性能調優
在使用Proxy、Telemetry時,預設它們會打印訪問日誌,我們選擇在生產上關閉該日誌。時刻觀察Istio社區的最新版本,查看新版本各個組件的性能優化以及bug修複情況,將Istio當做高度模塊化的系統,單獨升級某些組件。上面就提到我們在Istio1.0的基礎上使用了1.0.5版本的Policy、Telemetry、Pilot Discovery等組件。
服務平滑更新和關閉
Istio依靠Proxy來幫助APP進行路由,考慮幾種情況會出現意外的狀態:
  • APP啟動先於Proxy,並開始呼叫其它服務,這時Proxy尚未初始化完畢,APP呼叫失敗。

  • Service B關閉時,呼叫者Service A的Proxy尚未同步更新Service B關閉的狀態,向Service B發送請求,呼叫失敗。第一種情況要求APP有重試機制,能適當重試請求,避免啟動時的Proxy初始化與APP初始化的時差,Istio提供了retry次數配置,可以考慮使用。第二種情況,一種是服務更新時,我們使用新建新服務,再切流量;一種是服務異常退出,這種情況是在客戶端重試機制。希望使用Istio的開發人員有更好的解決方案。

 

Q&A;

 

Q:學Service Mesh什麼用?
A:Service Mesh是最近比較火的一個概念,和微服務、Kubernetes有密切關係。出於以後業務發展需要,可以學習下, 增加知識儲備。見聞上Istio的主要目的在文章已說明,主要是基礎服務的下沉,解決了語言兼容性問題, 還有一個就是灰度發佈。
Q:鏈路追蹤的採集方式是怎樣的,比如Nodejs,C++等多語言如何支持的?
A:Envoy本身支持鏈路追蹤,也就是將Envoy會在請求head中增加鏈路追蹤相關的資料頭,比如x-b3-traceid,x-b3-spanid等等。業務要做的就是將這些head沿著呼叫鏈路傳遞下去即可。所以多語言的話需要在自己的業務側實現該邏輯。所以Istio的鏈路追蹤對業務代碼還是有很小的侵入性的(這個分享中有說明)。
Q:Istio與Spring Cloud兩者的優缺點與今後的發展趨勢會是怎麼樣?
A:見聞技術棧是Golang,所以沒太認真對比過兩者。從社區活躍度上將,Istio > Spring Cloud,穩定性方面,Spring Cloud是更有優勢,更適合Java沉澱較深的企業。但個人感覺對於更多企業來講,跨越了語言兼容性的Istio未來發展很值得期待。
Q:Docker鏡像部署可以做到代碼保護嗎,比如像Nodejs這種非二進制執行程式的專案?
A:代碼保護可以通過將鏡像上傳至指定雲服務商上的鏡像倉庫中,見聞是將自己的業務鏡像提交儲存在了騰訊雲。如果鏡像泄露,那麼非二進制執行程式的代碼還是有泄露風險的。
Q:選型時為什麼沒考慮Linkerd?
A:選型之初也調研了Linkerd, 對比下來,Istio擁有更多活躍的開源貢獻者,迭代速度快,以及Istio架構相較於見聞有較大可行性,所以選擇了Istio作為實踐方案。
Q:Istio在做運維部署時沒有UI工具,你們如何實現運維人員更加便捷地使用?
A:見聞基於Kubernetes官方的Dashboard, 對內容進行了擴充,增加了對Gateway,VirtualService等Istio crd資源的支持, 同時增加了灰度部署等和見聞運維業務相關的功能,所以一定程度上解決了運維部署的問題。
Q:流量從Sidecar代理勢必會對請求響應時間有影響,這個有沒有更詳細案例的說明性能上的損耗情況?
A:Sidecar的轉發其實帶來了性能一定的性能損耗。4核8G服務器,上面運行Proxy服務和API服務,API服務只傳回ok字樣。(此測試只測試極限QPS)單獨測試API服務的QPS在59k+,平均延時在1.68ms,CPU占用4核。通過代理訪問的QPS6.8k+,平均延時14.97ms,代理CPU占用2核,API服務CPU占用2核。CPU消耗以及轉發消耗降低了QPS,增加了延時,通過增加機器核數並增加服務部署數量緩解該問題,經過測試環境測試,延時可以接受。
Q:Sidecar在生產中資源占用為多少?是否會對集群資源占用很多?
A:以單個Pod為例,見聞業務單個Pod中Sidecar所占資源約占整個Pod所耗資源的1/10。
Q:Jeager你們是進行了代碼埋點嗎?更為底層代碼級別的追蹤,有用其他方案嗎?
A:Envoy本身對tracing有良好的支持,所以業務端所做的改動只需將其所產生的追蹤資料延續下去即可。上Istio之前,見聞在相關微服務中通過在基礎庫中增加鏈路追蹤邏輯(Zipkin)實現了鏈路追蹤,不過只做了Golang版,多語言兼容開發運維難度較大。

已同步到看一看
赞(0)

分享創造快樂