服務發現技術是如何演進出來的?


  昨天寫了一篇<微服務的時間和成本去哪兒了>,有人在底下留言:

  我的回答是:

  "微服務可以不用服務發現和負載均衡嗎?它是微服務一個核心組件。怎么能說沒有關系?"

  我覺得有必要來思考和總結一下服務發現技術是如何演進的。於是周末一通閱讀和消化,希望能掰開揉碎在這里講一下服務發現技術的演進歷史。

催生的背景

  為了提升研發效能,賦能業務規模化創新。不管是一線互聯網企業還是傳統互聯網企業,將單塊架構解耦成微服務架構,已經成為企業目前數字化轉型的一個大趨勢。

  

  微服務架構下的服務少則幾個,幾十個,多則上百個,每個服務一般都以集群HA的方式進行部署。

  這個時候就出現了兩個問題:

  • 一個是服務發現,也就是服務的消費方Consumer如何找到服務的提供方Provider。
  • 另外一個是負載均衡,服務消費方如何以負載策略去訪問服務當中的服務提供方的實例。

  

 通用解決思路~代理(proxy)

  在服務發現演進過程中,先后出現了三代服務發現解決方案。這三代的核心都是代理,只不過代理在架構中出現的位置是不同的。通過在消費方和提供方中間增加一層代理,由代理來處理服務發現和負載均衡等功能,消費方通過代理間接去訪問服務實例。

  

三代服務發現方案

第一代:傳統集中式代理  

  

  • 該方案比較簡單,在消費和提供方中間部署一層代理服務。
  • 常用的集中制代理有硬件負載均衡器,比如F5/A10;或者軟件的負載均衡器,比如Nginx,HAPROXY。也可以是軟硬結合,比如前面是F5,后面是Nginx,這種方法兼顧了配置的靈活性,因為Ngix比F5更容易配置。
  • 這種配置需要引入DNS服務域名進行配合,每個服務都要申請注冊域名,並且每個域名都要在代理上配置域名和服務IP的映射關系
  • DNS和代理的配置一般由運維人員手工完成。

  

  • 國內外的公司采用這種方式的有ebay,攜程,拍拍貸。
  • 缺點是手工配置,效率不高也缺乏靈活性,對開發人員不友好。

第二代:客戶端嵌入式代理

  隨着微服務和雲技術的興起,企業對服務發現的效率和靈活性提出了更高的要求,於是出現了第二代方案。

  • 該方案將服務發現和負載均衡以客戶庫Library的形式嵌入到應用或服務程序中。
  • 該方案需要獨立的服務注冊中心配合,服務啟動的時候將服務自動注冊到中心,並且定期的報心跳進行保活。客戶端通過服務注冊中心發現服務的ip列表,通過某種負載均衡策略選擇某個服務進行調用,這種對開發人員比較友好,可以做到開發自助,不需要太多的運維介入。

  這種做法也是很多互聯網公司的一個主流,相應的開源也很多。比如:

  • eureka就是一個注冊中心,配套ribbon客戶端代理。
  • dubbo和近期開源的nacos
  • consul+ribbon

  

   缺點:

  • 客戶端依賴語言棧,不同的語言需要開發不同的客戶端,在微服務下可能出現的多語言問題,顯然開發成本太高。
  • 另外嵌入式代理也給客戶端增加了復雜性

第三代:主機獨立進程方案。

  隨着容器和雲原生技術的興起,業界開始探索第三代的解決方案。

  

  主機獨立進程方案是上面兩種方案的折中,代理既不集中部署,也不嵌入在客戶的應用程序當中,而是作為獨立的進程部署在每個主機上,這個主機可以是物理的或者虛擬的。一個主機上的多個消費者可以共享這個代理,實現服務發現和負載均衡。

  第三代結構和第二代是類似的,也需要引入服務注冊中心進行配合,三代之間只不過代理的位置發生了變化

  這個方案目前有個更時髦的稱謂叫ServiceMesh。

  

   開源產品:Envoy,Linkerd,Istio對應到服務注冊中心,當然K8S也內置支持服務發現機制,也是屬於第三代的主機獨立進程方案。

K8S服務發現機制

  考慮到K8S在業界比較火,而且內部服務發現機制比較復雜,這里獨立出來就進行剖析。

  

  如上圖所示,在K8S中一個服務是由一組Pod構成的服務集群。

  • Pod是K8S當中最基本的調度單位,它相當於K8S集群當中虛擬機的概念。
  • 每個Pod都有一個PodIP,並且相互之間是通過PodIP相互訪問,但是服務的PodIP在K8S當中是不固定的,可能會變(包括預期和非預期)。
  • 為了屏蔽這種變化,K8S引入了服務Service這個概念,一方面實現服務發現和負載均衡,另一方面屏蔽PodIP可能的變更。
  • 在服務發布的時候,K8S會為每個服務分配一個虛擬的ClusterIP

  

  在K8S的worker節點上,有kubelet和kube-proxy,其中后者是實現服務發現的關鍵,上面是簡化的服務發現流程。

服務注冊階段:

  1. 其中kubelet負責啟動Pod服務實例--->
  2. 啟動完成后kubelet會把Pod的IP列表注冊到Master節點上-->
  3. 最后通過服務Service的發布,K8S會為服務分配相應的ClusterIP,相關信息也會記錄在Master上。

服務發現階段:

  • kube-proxy會發現clusterIP和podIP列表之間的映射關系,並且修改本地iptables的轉發規則,進行負載均衡和轉發到對應的PodIP
  • 當有消費者Pod要訪問某個目標服務實例Pod的時候,通過ClusterIP發起調用,這個ClusterIP會被本地的Iptables機制截獲,然后進行負載均衡,轉發到指定的Pod實例。
  • 實際消費這Pod也是通過服務名進行訪問ClusterIP,因為ClusterIP本身也會變,為了屏蔽變化,K8S還引入了kubeDNS這個概念,它通過master可以發現服務名和ClusterIP之間的映射關系。這樣消費者Pod通過kubeDNS間接的發現服務的ClusterIP。

 比較總結和選型

  

  三種方案各有利弊,沒有絕對的好壞。他們都有大規模的成功落地的案例。架構師需要在理解這些方案優劣的基礎上,根據企業的實際上下文,綜合考量,做出技術選型。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM