在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

Cortex Data Lake收集,轉換和集成企業的安全數據,以啟用Palo Alto Networks解決方案。 該產品可幫助組織以更高的速度使用和理解數據-讓系統管理員專注於最重要的警報。 它結合了跨企業所有數據的高級人工智能和機器學習,並提供了對複雜攻擊的更有意義的響應。

Cortex Data Lake提取服務要求每秒接收數百萬個請求,同時確認每個請求,以確保在低延遲下不會丟失數據。 Cortex Data Lake客戶端通常是長期存在的,並且可以連續發送數據。 有了這些要求,gRPC迅速成為構建Cortex Data Lake Ingestion Service的首選技術。 當我們開始這個項目時,Envoy是唯一支持gRPC的高性能代理,而Istio是Envoy的首選控制平面。

Envoy

Envoy是專為雲原生應用程序設計的高性能開源邊緣和服務代理。 它通常以分佈式方式部署為在同一應用程序容器中具有應用程序容器的邊車。 Envoy處理高級路由,監視,跟蹤,日誌記錄和其他跨領域問題。 Envoy具有程序控制平面,可對其進行動態配置。

Istio

Istio是一個開放源代碼的服務網格和API網關,提供連接,保護,控制和觀察服務的功能。 Istio依靠Envoy進行數據平面設計,並實現Envoy的控制平面API。 它包括所有應用程序網絡和操作最佳實踐,例如超時,重試,斷路,高級負載平衡,故障注入和mTLS。 Istio為Cortex Data Lake API網關以及用於數據服務的服務網格提供了支持。 以下是Cortex Data Lake Infrastructure安裝程序的高級框架。

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

> Cortex Data Lake Infrastructure Setup

在API網關層,Istio同時支持mTLS和JWT身份驗證策略。 我們根據用例使用兩種身份驗證機制。 根據客戶的不同,公開支持mTLS和JWT的服務存在一些挑戰。 這些細節將在單獨的帖子中介紹。 總體而言,Istio對我們來說運行良好,但是在Istio的早期版本中,Istio遙測技術遇到了瓶頸,使大量流過載。 我們關閉了Istio遙測,現在正在使用Envoy本地遙測。

gRPC

gRPC由Google創建,是其內部RPC技術Stubby的開源演變。 gRPC使用HTTP / 2作為其傳輸協議。 HTTP / 2可以通過同一連接多路複用許多並行請求,並允許全雙工雙向通信。

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

> Image Source: Introduction to Http2

gRPC使用通道抽象來促進底層HTTP / 2連接的併發使用並提供流控制功能。 在一個通道內,可以發出多個RPC,每個RPC都映射到基礎HTTP / 2流。

gRPC使用協議緩衝區作為接口定義語言,也用於基礎消息交換格式。 使用protoc編譯器為不同的語言生成gRPC客戶端和服務器接口的源代碼。

gRPC客戶端和服務器存根實現了StreamObserver接口,用於發送和接收消息。 對於傳出消息,gRPC庫將StreamObserver提供給應用程序。 對於傳入消息,該應用程序實現StreamObserver並將其傳遞到gRPC庫以進行接收。 StreamObserver接口非常簡單,僅使用以下三種方法:

· onNext:從流中接收值

· onError:從流中接收終止錯誤

· onCompleted:接收成功完成流的通知

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

一元VS雙向

可以使用不同類型的服務方法來編寫gRPC應用程序,並且我們評估了一元和雙向。 下面列出了每種方法的優缺點,並以粗體顯示了首選特徵。

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

使用雙向流,消息吞吐量更高,等待時間更低,從而滿足我們的設計要求。 具有長壽命的流和每個流具有多個消息會將一些責任從gRPC協議轉移到應用程序。 所需的功能必須在我們的客戶端和服務器應用程序中實現。 增加的複雜度值得雙向流提供更高的吞吐量。

消息確認和錯誤處理

Cortex Data Lake要求確認每個請求。 我們的gRPC客戶端應用程序在其出站流上發送離散請求有效負載,並在入站流上接收這些請求的ACK。 這允許客戶端使用計時器和重試來補償網絡問題。 每個請求都包含一個唯一的ID。 每個ACK都包含一個相應請求的ID以及對該請求結果的描述。 當客戶端從服務器接收到ACK時,它將檢查消息,檢查錯誤並確定可以重試的消息和必須丟棄的消息。 客戶端還對重試實現指數補償,以允許服務器在過載時恢復。

流量控制

流控制是一種防止發送方壓倒數據接收方的機制。 接收器可能在重負載下很忙,可能沒有資源來處理其他負載。 在這種情況下,接收器應進行流量控制。 gRPC依賴於基礎的HTTP / 2流控制功能。

在我們的接收管道中,我們使gRPC客戶端通過Istio API Gateway與gRPC服務器通信,如下圖所示 Stream buffers in the pipeline > Stream buffers in the pipeline

管道中涉及許多流緩衝區。 緩衝區越大,它可以在擁塞的上游使用更多的內存,並且溝通背壓所需的時間也越長。

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

> Stream Buffers

要在gRPC客戶端中為每個流實現反壓反饋循環,我們使用CallStreamObserver.html#setOnReadyHandler。 每當流的isReady()狀態從false變為true時,此通知就會調用我們的應用程序客戶端代碼。

gRPC服務器優化

在我們的gRPC Server的最初實現中,我們有大隊列和許多線程。 在高負載下,我們觀察到級聯故障和吞吐量受限,延遲時間更長。

我們在每個步驟都添加了詳細的指標,以確定我們在哪裡花費時間並進行了線程轉儲。 我們確定線程正在爭用,並且服務器沒有迅速施加背壓。 我們甚至遇到了一個JDK錯誤,其中java.security.Provider.getService()同步成為高負載時的可伸縮性瓶頸。 這要求我們升級到JDK13。我們將gRPC服務器中的線程池的大小減少到內核數的兩倍,並且消除了大多數線程爭用。

由於流水線與多個緩衝區/隊列是異步的,因此我們僅使更多的工作入隊,而無法處理。 我們做了很多受控負載測試,使gRPC Server CPU保持繁忙。 我們分析了代碼並對其進行了調整,然後對嵌入在服務器應用程序中的Kafka生產者進行了調整。 我們確定請求處理線程p99可以實現的處理時間為70–80 ms,Kafka寫入為125–200 ms。

通過限制輸入隊列,服務器將不會在gRPC裝滿並施加反壓時從gRPC進行讀取。 我們使用以下公式來計算gRPC Server請求隊列長度:

maxLatency =(事務時間/線程數)* queueLength

要麼

queueLength = maxLatency /(transactionTime /線程數)

我們將maxLatency保持與transactionTime相同,以產生最大的背壓,並以與線程數相同的隊列長度來解決。 通過這種方法,工作負載主要受CPU限制,並且可以隨著負載的變化自動擴展。

負載均衡

gRPC使TCP會話儘可能長時間地保持打開狀態,以最大程度地提高吞吐量並最大程度地減少開銷,但是長期存在的會話使負載平衡變得複雜。 在自動擴展的Kubernetes環境中,這是一個更大的問題,在該環境中,隨著負載的增加,添加了新的Pod,但是客戶端將保持連接到相同的gRPC服務器Pod,從而導致負載分配不均。

gRPC的設計者已經考慮了這個問題,並增加了對gRPC服務器上的連接過期策略的支持。 此到期策略將強制客戶端斷開連接,然後重新連接到另一臺服務器。 可以通過在經過一定時間後使連接過期來執行連接過期。 Java gRPC庫使用maxConnectionAge()和maxConnectionAgeGrace()服務器構建器選項來實現此目的。 這些函數分別用於限制和強制終止gRPC通道。 當gRPC通道到期時,服務器將發送HTTP / 2 GOAWAY,指示客戶端可能不會啟動新請求,但可能會完成現有請求。 在最大連接期限寬限期結束時,gRPC服務器將發送第二個HTTP / 2 GOAWAY並關閉通道。

我們使用固定大小的流發送批量請求,並且必須考慮以下折衷:

· 較大的流大小允許更高的吞吐量,但使用更多的內存

· 較小的流大小會減少內存使用量,但會導致客戶端和服務器在等待確認消息時更頻繁地阻塞。

流大小在負載平衡中起著非常重要的作用。 對於較大的流,它們在不同的Ingestion Server Pod上的分佈不均勻,並且會導致整個Ingestion Server Pod的CPU利用率範圍很廣,從而影響Kubernetes水平Pod的自動縮放。 下表顯示了不同流大小的測試摘要結果。

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

GKE

我們正在使用GKE,並且需要對我們的應用程序進行其他調整。

節點內核調整

在高負載下,由於低的conntrack和threadMax限制,節點變得無響應。 我們將CONNTRACK_MAX增加到200萬,將CONNTRACK_HASHSIZE增加到50萬,將THREAD_MAX增加到400萬。

IO節流

我們使用常規磁盤進入IO限制,導致Docker守護程序和Kubernetes變得不穩定。 我們將工作負載轉移到具有SSD的節點池中,以避免節流。

節點內存耗盡

我們的某些工作負載最初並未進行調整,也沒有設置適當的限制,從而導致節點不穩定和內存耗盡,以及頻繁的docker和kubelet重新啟動。 我們分析了我們的工作負載並調整了資源請求和限制,以免耗盡節點資源。

結果

經過所有這些更改和調整,這是一個測試的結果,在該測試中,我們運行了800k rps的負載,並且系統快速自動縮放以吸收負載。

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

> Auto scale from 0–800k rps

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

> Initial pods take in the large load. New pods start and quickly accept load and join their peers.

在Cortex Data Lake中使用gRPC,Envoy和Istio進行大規模數據攝取

> CPU Utilization

管道非常有效。 Istio ILB可以輕鬆地在平均cpu利用率為65%的情況下處理每個內核10,000個請求,而Ingestion Frontend可以在平均cpu利用率為65%的情況下處理每個內核1000個請求。

這是gRPC客戶端,API網關和Ingestion小組成員的馬拉松工作,即

· 尚丹·庫瑪(Chandan Kumar)

· 普里揚卡·波伊(Priyanka Bhoj)

· 薩加爾·洛克

· 克里斯·貢薩爾維斯

· Kishore波拉

· 阿努塔·穆克吉(Anuta Mukherjee)

· 魯普雷納·查布拉(Rupleena Chhabra)

有問題嗎? 訪問Twitter或電子郵件:

[email protected]:@Ani_chaturvedi

(本文翻譯自Animesh Chaturvedi的文章《Large scale Data Ingestion using gRPC, Envoy and Istio in Cortex Data Lake》,參考:https://medium.com/engineering-at-palo-alto-networks/large-scale-data-ingestion-using-grpc-envoy-and-istio-in-cortex-data-lake-ec82ea87fa3b)


分享到:


相關文章: