古典、SOA、傳統、K8S、ServiceMesh

古典、SOA、傳統、K8S、ServiceMesh

十幾年前就有一些公司開始踐行服務拆分以及SOA,六年前有了微服務的概念,因而你們開始思考SOA和微服務的關係和區別。最近三年Spring Cloud的大火把微服務的實踐推到了高潮,而近兩年K8S在容器編排的地位肯定以後你們又開始實踐起以K8S爲核心的雲原生思想和微服務的結合如何去落地,2018年又多出一個ServiceMesh服務網格的概念,你們又在思考如何引入落地ServiceMesh,ServiceMesh和K8S以及Spring Cloud的關係如何等等。html

確實有點亂了,這一波又一波的熱潮,幾乎每兩年都會來一波有關微服務架構理念和平臺,許多公司還沒完成微服務的改造就又提出了服務+容器道路,又有一些公司打算從微服務直接升級成ServiceMesh。本文嘗試總結一下我見過的或實踐過的一些微服務落地方式,而且提出一些本身的觀點,但願拋磚引玉,你們能夠暢談一下本身公司的微服務落地方式。程序員

一、微服務v0.1——古典玩法


(圖中灰色部分表明元數據存儲區域,也就是Service和Endpoint關係所保存的地方,以後全部的圖都是這樣)spring

其實在2006年在使用.NET Remoting作服務拆分的時候(其實當時咱們沒有意識到這叫服務拆分,這是打算把一些邏輯使用獨立的進程來承載,以Windows服務形式安裝在不一樣服務器上分散壓力),咱們使用了F5來作服務的負載均衡。沒有所謂的服務發現,針對每個服務,咱們直接在程序配置文件中寫死F5的IP地址和端口,使用Excel來記錄全部服務在F5的端口地址以及服務實際部署的IP:端口,而後在F5進行配置。F5在這裏作了負載均衡、簡單的路由策略(相同的客戶端老是優先路由到相同的後端)以及簡單的白名單策略等等。數據庫

二、微服務v0.2——改進版古典玩法


以後嘗試過這種改進版的古典玩法。相比v0.1的區別是,再也不使用硬件F5了,而是使用幾組軟件反向代理服務器,好比Nginx來作服務負載均衡(若是是TCP的負載均衡的話能夠選擇HaProxy),Nginx的配置會比F5更方便並且還不花錢。因爲生產環境Nginx多是多組,客戶端不在配置文件中寫死Nginx地址而是把地址放到了配置中心去,而Nginx的配置由源碼倉庫統一管理,運維經過文件同步方式或其它方式從源碼倉庫拉取配置文件下發到不一樣的Nginx集羣作後端服務的配置(Nginx的配置也不必定須要是一個大文件放全部的配置,能夠每一組服務作一個配置文件更清晰)。後端

雖然個人標題說這是古典玩法,可是能夠說不少公司若是沒有上RPC,沒有上Spring Cloud,也沒有上K8S的話極可能就是這樣的玩法。不管是v0.2仍是v0.1,本質上服務是固定在虛擬機或實體機部署的,若是須要擴容,須要遷移,那麼確定須要修改反向代理或負載均衡器的配置。少數狀況下,若是調整了反向代理或負載均衡器的IP地址,那麼還可能會須要修改客戶端的配置。緩存

三、微服務v0.5——SOA ESB玩法


SOA的一個特色是使用了服務總線,服務總線承擔了服務的發現、路由、協議轉換、安全控制、限流等等。2012年我參與了一個大型MMO遊戲《激戰2》項目的技術整合工做,這個遊戲整個服務端就是這種架構。它有一個叫作Portal的服務總線,全部遊戲的十幾個子服務都會把本身註冊到服務總線,無論是什麼服務須要調用什麼接口,都是在調用服務總線,由服務總線來進行服務的尋址路由和協議轉換,服務總線也會作服務的精細化限流,每個用戶都有本身的服務請求隊列。這種架構的好處是簡單,服務總線承擔了全部工做,可是服務總線的壓力很大,承擔了全部的服務轉發工做。同時須要考慮服務總線自己如何進行擴容,若是服務總線是有狀態的,顯然要進行擴容不是這麼簡單。對於遊戲服務器來講,擴容可能不是一個強需求,由於遊戲服務自然會按照大區進行分流,一個大區的最大人數上限是固定的。安全

貌似互聯網公司這樣玩的很少,傳統企業或是遊戲服務端是比較適合服務總線這種架構的,若是服務和服務之間的協議不統一的話,要在客戶端作協議轉換的工做比較痛苦,若是能夠由統一的中間層接入全部協議統一進行轉換的話,客戶端會比較輕量,可是這種架構的很大問題在於服務總線的擴容和可靠性。服務器

四、微服務v1.0——傳統服務框架玩法


上圖是大多數RPC框架的架構圖。大多數早期的微服務實踐都是RPC的方式,最近幾年Spring Cloud盛行後其實Spring Cloud的玩法也差很少,只是Spring Cloud推崇的是JSON over HTTP的RESTful接口,而大多數RPC框架是二進制序列化over TCP的玩法(也有JSON over HTTP的RPC)。markdown

其實RPC框架我我的喜歡JSON over HTTP,雖然咱們知道HTTP和JSON序列化性能確定不如一些精簡的二進制序列化+TCP,可是優勢是良好的可讀性、測試方便、客戶端開發方便,並且我不認爲15000的QPS和20000的QPS對於通常應用有什麼區別。架構

總的來講,咱們會有一個集羣化的分佈式配置中心來充當服務註冊的存儲,好比ZK、Consul、Eureka或etcd。咱們的服務框架會有客戶端和服務端部分,客戶端部分會提供服務的發現、軟負載、路由、安全、策略控制等功能(可能也會經過插件形式包含Metrics、Logging、Tracing、Resilience等功能),服務端部分對於RPC框架會作服務的調用也會輔助作一些安全、策略控制,對於RESTful的話就服務端通常除了監控沒有額外的功能。

好比使用Spring Cloud來玩,那麼:

  • Service Discovery:Eureka、Open Feign
  • Load Balancing:Ribbon、Spring Cloud LoadBalancer
  • Metrics:Micrometer、Spring Boot Actuator
  • Resilience:Hystrix、Resilience4j
  • Tracing:Sleuth、Zipkin

在以前《朱曄和你聊Spring系列S1E8:湊活着用的Spring Cloud(含一個實際業務貫穿全部組件的完整例子)》一文中,我有一個完整的例子介紹過Spring Cloud的這套玩法,能夠說的確Spring Cloud給了咱們構建一套微服務體系最基本的東西,咱們只須要進行一些簡單的擴展和補充,好比灰度功能,好比更好的配置服務,就徹底能夠用於生產。
這種模式和以前0.x的很大區別是,服務的註冊有一個獨立的組件,註冊中心完成,經過配合客戶端類庫的服務發現,至少服務的擴容很輕鬆,擴容後也不須要手動維護負載均衡器的配置,至關於服務端從死到活的一個重大轉變。並且在1.0的時代,咱們更多看到了服務治理的部分,開始意識到成百上千的服務,若是沒有Metrics、Logging、Tracing、Resilience等功能來輔助的話,微服務就是一個災難。

Spring Cloud已經出了G版了,表示Netflix那套已經進入了維護模式,許多程序員表示表示扶我起來還能學。我認爲Spring Cloud這個方向實際上是挺對的,先有開源的東西來填補空白,慢慢再用本身的東西來替換,可是開發比較苦,特別是一些公司基於Spring Cloud辛苦二次開發的框架圍繞了Netflix那套東西來作的會比較痛苦。總的來講,雖然Spring Cloud給人的感受很亂,變化很大,大到E到G版的升級不亞於在換框架,並且組件質量層次不齊,可是它確實是一無全部的創業公司可以起步微服務的很少的選擇之一。若是沒有現成的框架(不是說RPC框架,RPC框架雖是微服務功能的80%重點,但倒是代碼量20%的部分,工做量最大的是治理和整合那套),基於Spring Cloud起步微服務,至少你能夠當天起步,1個月完成適合本身公司的二次開發改造。

五、微服務v2.0——容器+K8S容器調度玩法


K8S或者說容器調度平臺的引入是比較革命性的,容器使得咱們的微服務對環境的依賴能夠打包整合進行隨意分發,這是微服務節點能夠任意調度的基礎,調度平臺經過服務的分類和抽象,使得微服務自己的部署和維護實現自動化,以及實現更上一層樓的自動伸縮。在1.x時代,服務能夠進行擴縮容,可是一切都須要人工介入,在2.x時代,服務自己在哪裏存在甚至有多少實例存在並不重要,重要的只是咱們有多少資源,但願服務的SLA是怎麼樣的,其他留給調度平臺來調度。

若是說1.0時代你們糾結過Dubbo仍是Spring Cloud,2.0時代我相信也有一些公司上過Mesos的「賊船」,咱們不是先知很難預測什麼框架什麼技術會在最後存活下來,可是這倒是也給技術帶來了很多痛苦,相信仍是有很多公司在幹Mesos轉K8S的事情。

若是引入了K8S,那麼服務發現能夠由K8S來作,不必定須要Eureka。咱們能夠爲Pod建立Service,經過Cluster虛擬IP的方式(如上圖所示,經過IP tables)路由到Pod IP來作服務的路由(除了Cluster IP方式也有的人對於內部鏈接會採用Ingress方式去作,路由方面會更強大,不過這是否是又相似v0.2了呢?)。固然,咱們還能夠更進一步引入內部DNS,使用內部域名解析成Cluster IP,客戶端在調用服務的時候直接使用域名(域名能夠經過配置服務來配置,也能夠直接讀取環境變量)便可。若是這麼幹的話其實就沒有Eureka啥事了,有的公司沒有選擇這種純K8S服務路由的方式仍是使用了註冊中心,若是這樣的話其實服務註冊到註冊中心的就是Pod IP,仍是由微服務客戶端作服務發現的工做。我更喜歡這種方式,我以爲K8S的服務發現仍是弱了一點,並且IP tables的方式讓人沒有安全感(IPVS應該是更好的選擇),與其說是服務發現,我更願意讓K8S只作容器調度的工做以及Pod發現的工做。

雖然K8S能夠作一部分服務發現的工做,咱們仍是須要在客戶端中去實現更多的一些彈力方面的功能,所以我認爲2.0時代只是說是微服務框架結合容器、容器調度,而不能是脫離微服務框架自己徹底依靠K8S實現微服務。2.0和1.0的本質區別或者說加強仍是很明顯,那就是咱們能夠全局來統籌解決咱們的微服務部署和可靠性問題,在沒有容器和容器調度這層抽象以前,有的公司經過實現自動化虛擬機分配拉起,加上自動化初始腳原本實現自動的微服務調度擴容,有相似的意思,可是很是花時間並且速度慢。K8S真正讓OPS成爲了DEV而不是執行者,讓OPS站在整體架構的層面經過DEV(咱不能說開發DSL文件不算開發吧)資源和資源之間的關係來統籌整個集羣。在只有十幾個微服務若干臺服務器的小公司可能沒法發揮2.0容器雲的威力,可是服務器和服務一多,純手工的命令式配置容易出錯且難以管理,K8S真的釋放了幾十個運維人力。

六、微服務v3.0——ServiceMesh服務網格玩法


在以前提到過幾個問題:

  • SOA的模式雖然簡單,可是集中的Proxy在高併發下性能和擴容會是問題
  • 傳統的RPC方式,客戶端很重,作了不少工做,甚至協議轉換都在客戶端作,並且若是涉及到跨語言,那麼RPC框架須要好幾套客戶端和服務端
  • K8S雖然是一個重要的變革,可是在服務調度方面仍是太弱了,它的專項在於資源調度

因而ServiceMesh服務網格的概念騰空而出,巧妙解決了這幾個問題:

  • 採用邊車模式的Proxy隨服務自己部署,一服務一邊車與服務共生死(固然,有的公司會使用相似ServiceBus的Global Proxy做爲Sidecar Proxy的後備,防止服務活着Sidecar死了的狀況)能夠解決性能問題
  • Sidecar裏面作了路由、彈力等工做,客戶端裏能夠啥都不幹,如上圖所示,上圖是Istio的架構,Istio的理念是把ServiceMesh分紅了數據面和控制面,數據面主要是負責數據傳輸,由智能代理負責(典型的組件是Envoy),控制面由三大組件構成,Pilot負責流量管理和配置(路由策略、受權策略)下發,Mixer負責策略和數據上報(遙測),Citadel用於密鑰和證書管理
  • 因爲咱們雙邊都走Sidecar Proxy,咱們對於流量的進出均可以作很細粒度的控制,這個控制力度是以前任何一種模式都沒法比擬的,這種架構的方式就像把服務放到了網格之中,服務鏈接外部的通信都由網格進行,服務自己輕量且只須要關注業務邏輯,網格功能強大而靈活
  • 對於Proxy的流量劫持可使用IP table進行攔截,對於服務自己無感知,並且Sidecar能夠自動注入Pod,和K8S進行自動整合,無需特殊配置,作到透明部署透明使用
  • Pilot是平臺無關的,採用適配器形式能夠和多個平臺作整合,若是和K8S整合的話,它會和API Server進行通信,訂閱服務、端點的信息,而後把信息轉變成Istio本身的格式做爲路由的元數據
  • Mixer指望的是抽象底層的基礎設施,無論是Logging仍是Metrics、Tracing,在以前RPC時代的作法是客戶端和服務端都會直接上報信息到InfluxDb、Tracing Server等,這讓客戶端變得很臃腫,Istio的理念是這部分對接後端的工做應該由統一的組件進行,不但使得Proxy能夠更輕並且能夠經過Plugin機制對接各類後端基礎設施

說了這麼多ServiceMesh的優點,咱們來看一下這種模式的性能問題。想一下各類模式下客戶端要請求服務端整個HTTP請求(跳)次數:

  • 古典模式:2跳,代理轉發一次
  • SOA模式:2跳,總線轉發一次
  • 傳統模式:1跳,客戶端直連服務端
  • K8S Service模式:1跳(路由表會有必定損耗)
  • ServiceMesh模式:3跳(其中2跳是localhost迴環)

總的來講,3跳並非ServiceMesh的瓶頸所在,而更多的可能性是Istio的倔強的架構理念。Istio認爲策略和遙測不該該耦合在Sidecar Proxy應該放到Mixer,那麼至關於在調用服務的時候還須要額外增長Mixer的同步請求(來得到策略方面的放行)。Istio也在一直優化這方面,好比爲Mixer的策略在Proxy作本地緩存,爲遙測數據作批量上報等等。雖然通過層層優化,可是Istio目前的TPS不足2000,仍是和通常的RPC能達到的20000+有着十倍的差距,說不定未來Istio會有架構上的妥協,把Mixer變爲非直接依賴,策略方面仍是採用相似Pilot統一管理配置下發的方式,遙測方面仍是由Sidecar直接上報數據到Mixer。

我我的認爲,ServiceMesh是一個很是正確的道路,並且ServiceMesh和K8S結合會更好,理由在於:

  • K8S讓資源調度變得自由,但微服務調度不是其所長也不該該由它深刻實現
  • 以Istio爲表明的ServiceMesh作了K8S少的,可是微服務又必須的那塊工做
  • Istio的設計方面和K8S極其類似,低耦合,抽象的很好,二者結合的也很好,我很是喜歡和贊同Agent+統一的資源管理配置下發的方式(K8S的Agent就是KubeProxy和Kubelet,Istio的Agent就是Sidecar Proxy),這是鬆耦合和高性能的平衡
  • 在複雜的異構環境下,多協議的內部通信,跨平臺跨語言的內部通信很常見,若是採用傳統方式,框架太胖過重,把這部分工做從內部剝離出來好處多多

可是,能夠看到目前ServiceMesh還不算很是成熟,Istio在不斷優化中,Linkerd 2.x也想再和Istio拼一下,到底誰會勝出還難以知曉,通過以前Dubbo vs Spring Cloud的折騰,Mesos vs K8S的折騰,VM vs Docker的折騰,是否還能經得起折騰Istio vs Linkerd 2呢?我建議仍是再看一看,再等一等。

七、暢想Everything Mesh模式?


以前看到過ShardingSphere受到ServiceMesh的理念影響提出了DB Mesh的架構。其實DB Proxy的中間件已經存在不少年了(集中化的Proxy相似服務總線的方式),DB Mesh把Proxy也變爲輕量的Sidecar方式,DB的訪問也都走本地代理。那麼這裏我也在想,是否是有可能全部東西都有本地的代理呢?

做爲應用服務自己而言,只須要和本地代理作通信調用外部服務、緩存、數據庫、消息隊列,不須要關心服務和資源所在何地,以及背後的實際服務的組件形態。固然,這只是一個暢想了,對於有狀態的資源,Mesh的難度很大,對於相似DB這樣的資源由於調用層次並不複雜,也不太會存在異構場景,Mesh的意義不大,綜合起來看Everything Mesh的投入產出比相比Service Mesh仍是小不少。

八、Spring Cloud、K8S和ServiceMesh的關係

若是搞Java微服務的話,Spring Boot是離不開的,可是是否要用Spring Cloud呢?個人觀點是,在目前階段若是沒有什麼更好的選擇,仍是應該先用。Spring Cloud和K8S首先並非矛盾的東西,K8S是偏運維的,主要作資源整合和管理,若是完全沒有服務治理框架純靠K8S的話會很累,並且功能不完整。開發和架構能夠在Spring Cloud方面深耕,運維能夠在容器和K8S方面發力,兩套體系能夠協做造成目前來講比較好的微服務基石。至於K8S的推行,這必定是一個正確的方向,並且和軟件架構方面的改進工做一點不矛盾,畢竟K8S是脫離於具體語言和平臺的。

至於Service Mesh,它作的事情和Spring Cloud是有不少重複的,在未來Istio若是發展的更好的狀況下,應該能夠替代Spring Cloud,開發人員只須要用Spring Boot開發微服務便可,客戶端方面也能夠很瘦,不須要過多關心服務如何通信和路由,服務的安全、通信、治理、控制都由Service Mesh進行(可是,是否有了Sidecar,客戶端真的徹底不須要SDK了呢?我認爲可能仍是須要的,對於Tracing,若是沒有客戶端部分顯然是不完整的,雖然Sidecar是localhost可是仍是跨進程了)。

Spring Cloud目前雖然針對K8S和Istio作了一些整合,可是並沒看到一套針對ServiceMesh的最佳實踐出來,是否未來Spring Cloud會在微服務這方面作退化給ServiceMesh讓步還不得而知。總的來講,長期我看好Spring Boot + K8S + Istio的組合,短時間我認爲仍是Spring Boot + K8S + Spring Cloud這麼用着。

九、總結

本文總結了各類微服務落地的形態,因爲技術多樣,各類理念層出不窮,形成了微服務的落地方式真的很難找到兩家相同的公司,本文中咱們介紹了:

  • 客戶端寫死地址+F5代理的方式
  • 客戶端把地址配置在配置服務+Nginx代理的方式
  • SOA+集中式ESB的方式
  • 傳統的具備註冊中心的服務框架SDK形式
  • 服務框架+K8S方式
  • K8S Service Iptables路由方式
  • ServiceMesh代理3跳轉發方式

固然,可能還會有更多的方式:

  • 內部DNS方式(直接DNS輪詢)
  • K8S內部服務走Ingress方式(內部服務也走Ingress,相似全部服務Nginx代理的方式)
  • ServiceMesh代理2跳轉發方式(能夠根據須要跳過遠端的Sidecar來提升性能等等)
  • 瘦服務框架SDK+ServiceMesh方式(也就是仍是有一個小的SDK來對接ServiceMesh的Sidecar,而不是讓應用程序本身發揮Http Client,這個方式的好處在於更靈活,這個SDK能夠在這一層再作一次路由,甚至在Sidecar出問題的時候直接把流量切換出去,切換爲直連遠端或統一的Global Proxy)

也可能不少公司在混用各類方式,具備N套服務註冊中心,正在作容器化遷移,想一想就頭痛,微服務的理念層出不窮伴隨着巨頭之間的技術戰役,苦的仍是架構和開發,固然,運維可能也苦,2019新年快樂,Enjoy微服務!

做者: lovecindywang
相關文章
相關標籤/搜索