摘要:在實際的產品部署中,一個namespace中往往會部署大量相關的微服務,這些微服務在邏輯上屬於同一個業務系統,但並不是namespace中的任意兩個微服務之間都存在訪問關係,因此按照namespace進行隔離還是會導致Envoy中存在大量該Sidecar不需要的Listener和Cluster配置。根據Envoy的這個github issue Per listener and per cluster memory overhead is too high #4196 和 Istio 文檔可以得知,Envoy佔用的內存和其配置的Listener和Cluster個數是成線性關係的,Listener和Cluster越多,Envoy佔用的內存越大,因此一個自然的想法就是通過減少Pilot爲Envoy創建的Listener和Cluster數量來降低Envoy的內存開銷。

Envoy的內存佔用

在Istio服務網格中,每個Envoy佔用的內存也許並不算多,但所有sidecar增加的內存累積起來則是一個不小的數字。在進行商用部署時,我們需要考慮如何優化並減少服務網格帶來的額外內存消耗。

下面是在我環境中的一個實測數據:

Envoy配置中的Listener和Cluster數量

  • Listener數量 175
  • Cluster數量 325
  • endpoint數量 466

內存佔用情況

$ sudo docker stats 2e8fb
CONTAINER           CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
2e8fb               0.75%               105.9 MiB / 256 MiB   41.39%              0 B / 0 B           0 B / 0 B           165

從上面的數據可以看到,在一個有325個cluster和175個Listener的服務網格中,一個Envoy的實際內存佔用量達到了100M左右;網格中一共有466個實例,則所有Envoy佔用的內存達到了466*100M=46.6G,這些增加的內存消耗是一個不容小視的數據。

減少TCMalloc預留系統內存

根據 Istio官方文檔 ,Envoy佔用的內存數量和其配置狀態相關,和請求處理速率無關。在一個較大的namespace中,Envoy大約佔用50M內存。然而對於多大爲“較大”,Istio官方文檔並未給出一個明確的數據。

通過Envoy的管理端口查看上面環境中一個Envoy內存分配的詳細情況:

$ sudo docker exec 2e8fb curl http://127.0.0.1:15000/memory
{
 "allocated": "50315720",                //Envoy實際佔用內存
 "heap_size": "102637568",               //TCMalloc預留的系統內存
 "pageheap_unmapped": "4603904",
 "pageheap_free": "9183232",
 "total_thread_cache": "27784296"
}

各個指標的詳細說明參見 Envoy文檔 。從上面的數據可以看到Envoy真正使用的內存爲50M左右,和官方文檔一致。但由於Envoy採用了 TCMalloc 作爲內存管理器,導致其佔用內存大於Envoy實際使用內存。

TCMalloc的內存分配效率比glibc的malloc更高,但會預留系統內存,導致程序佔用內存大於其實際所需內存。從前面的Envoy admin 接口的輸出可以看到TCMalloc預留的內存爲100M左右,遠遠大於了Envoy實際所需的內存數量。

根據Envoy的實際內存佔用情況,將container的最大內存限制調整爲60M後再運行,Envoy可以正常啓動。再次用docker stat命令查看,其消耗的內存也在60M以內。

通過優化配置降低Envoy內存佔用

即是將內存降低到50M,在一些對資源要求比較嚴格的環境,例如邊緣計算的場景中,網格中這些Envoy內存累加在一起也是不能接受的,因此需要想辦法進一步降低Envoy的資源使用。

根據Envoy的這個github issue Per listener and per cluster memory overhead is too high #4196Istio 文檔可以得知,Envoy佔用的內存和其配置的Listener和Cluster個數是成線性關係的,Listener和Cluster越多,Envoy佔用的內存越大,因此一個自然的想法就是通過減少Pilot爲Envoy創建的Listener和Cluster數量來降低Envoy的內存開銷。

按nampese對配置進行隔離

在Istio 1.3中,Pilot在創建Lister和Cluster時已經按照namespace對Service進行了隔離,Pilot缺省只會爲Envoy創建同一個namespace中的Service相關的Listener和Cluster。這在一定程度上減少了Envoy中的Listener和Cluster數量,但按照namespace進行隔離還是太過於粗獷。

在實際的產品部署中,一個namespace中往往會部署大量相關的微服務,這些微服務在邏輯上屬於同一個業務系統,但並不是namespace中的任意兩個微服務之間都存在訪問關係,因此按照namespace進行隔離還是會導致Envoy中存在大量該Sidecar不需要的Listener和Cluster配置。

按服務訪問關係進行細粒度隔離

在一個微服務運用中,一個服務訪問的其他服務一般不會超過10個,而一個namespace中可能部署多達上百個微服務,導致Envoy中存在大量冗餘配置,導致不必要的內存消耗。最合理的做法是隻爲一個Sidecar配置該Sidecar所代理服務需要訪問的外部服務相關的配置。

Istio提供了 Siedecar CRD,用於對Pilot向Sidecar下發的缺省配置進行更細粒度的調整。下面以Bookinfo示例程序說明如何調整一個Sidecar的配置。

在Bookinfo示例程序中,幾個微服務之間的調用關係如下:

從圖中可以看到,reviews服務只需要訪問ratings服務,因此在reviews的Sidecar中只需要ratings服務相關的outbound配置。

但是通過查詢reviews pod中proxy的配置,可以看到Pilot下發的缺省配置信息中包含了reviews, productpage,details這些它並不需要的outbound cluster信息,這些outbound cluster會導致額外的內存消耗。

master $ kubectl exec reviews-v3-54c6c64795-2tzjc -c istio-proxy curl 127.0.0.1:15000/clusters|grep 9080|grep added_via_api::true|grep outbound

outbound|9080||reviews.default.svc.cluster.local::added_via_api::true
outbound|9080||details.default.svc.cluster.local::added_via_api::true
outbound|9080||ratings.default.svc.cluster.local::added_via_api::true
outbound|9080||productpage.default.svc.cluster.local::added_via_api::true

下面通過Sidecar來對reviews服務的Sidecar進行配置,只爲ratings服務創建相關的outbound cluster。

創建一個sidecar.yaml文件,對reviews服務進行配置。

apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
  name: reviews
  namespace: default
spec:
  workloadSelector:
    labels:
      app: reviews
  egress:
  - hosts:
    - "./ratings.default.svc.cluster.local"

在Istio中運用該Sidecar配置。

master $ kubectl apply -f sidecar.yaml
sidecar.networking.istio.io/reviews created

再查看Reviews Pod中的Envoy配置,配置中的outbound cluster只包含ratings服務,去掉了其他無關的服務相關的配置。

master $ kubectl exec reviews-v1-75b979578c-x7g46 -c istio-proxy curl 127.0.0.1:15000/clusters|grep 9080|grep added_via_api::true|grep outbound

outbound|9080||ratings.default.svc.cluster.local::added_via_api::true

–未完待續

參考文檔

「嗯,這篇文章對我有用,鼓勵一下...」

相關文章