「和耳朵」聊聊微服務與分散式系統

和耳朵發表於2020-12-16

我是和耳朵,好久沒有寫文了,今天和大家聊聊分散式

前段時間一直沒有寫文是因為忙於面試~,沒錯?離職了換了一家公司工作,新公司的系統都是分散式的,入職一個月且寫了點東西上線之後我才敢於寫寫這個分散式主題,不然怕自己沒有生產經驗誤人子弟了。

今天呢,主要是想和大家聊一聊分散式系統的相關概念及其常見分散式元件和設計思想(不涉及電腦科學中分散式系統的技術理論之類的東西),之前為了準備這次的面試我是把市面上的很多分散式元件都看了一遍,我們公司所用的分散式元件基本也沒出我瞭解的那個知識圈(公司用了Apollo我沒提前瞭解,大E了),如果對分散式相關技術棧不太瞭解,也可以當我這篇徵文做你的掃盲貼,不過別忘了點贊?

單體應用與叢集

單體應用、叢集和微服務,這個標題一出你們可能就知道我想說啥了,emm,就是架構的演進過程,很多人可能都看過相關知識,不過我為了文章的完整性還是打算簡單講一講。

首先是單體應用,在一個業務的起步階段,往往是使用者量不大且訪問請求少的階段,這個時候我們一般只需要部署一個Web應用和一臺資料庫就能滿足我們的業務需求,且隨著SpringBoot的流行,Web伺服器可以內建在應用裡面,能夠更加方便快捷的部署應用。

同時因為專案規模小,業務流程簡單,維護和迭代起來也很方便,所以在當前這個階段單體應用是非常適合的。

但是隨著業務增長,單體應用不可避免的會出現瓶頸,我舉個例子:

假如我們現在的單體Tomcat應用只能支撐QPS200,隨著使用者量的增大併發隨之增大,慢慢超出了單臺應用能承受的極限,假如現在達到了QPS300,那麼多出來的100請求就只能等著前面的請求處理完了之後才能請求進去,這樣帶來的後果就是響應時間變長,影響使用者體驗。

或者我們應用中的業務比較複雜,單次請求響應時間比較長,這樣的話大量請求擠壓也會導致使用者的體驗很差,他們能明顯的感覺到點選某個按鈕之後隔了1~2s才有結果返回。

這個時候我們就可以引入叢集架構了,我們可以將單體應用同時部署兩份,並通過Nginx進行反向代理和負載均衡進行流量分流,這樣每個單體應用承受的QPS就是150了,就在可以接受的範圍內,而且維護叢集應用和維護單機應用區別不大,只是在涉及到鎖的時候可能要藉助分散式鎖來做。

至此,每當訪問量增大系統到達瓶頸時我們就可以通過加機器這種方式進行橫向擴容,不斷的擴大應用的負載能力,但是如果這種方式完美無缺,我們也就不需要微服務的架構了~~~

從單體應用過渡到叢集架構,解決的其實是效能的問題,單臺機器已經無法滿足人民日益增長的訪問需求,所以出現了叢集架構。

那麼從叢集過渡到微服務架構的更多原因肯定就不在效能了,這裡我說說我自己的看法與感悟:

  1. 首先既然專案已經是叢集了證明業務量也不會非常小,這也就代表了程式碼一定有一些規模了,這時候要面臨的第一個問題就是所有開發人員都會在這一個專案裡面修改程式碼,極大情況下是衝突不斷。
  2. 其次這麼多程式碼聚合在一塊,當你進行一處功能修改的時候,如果需要進行全量回歸測試的話那簡直太要命了。
  3. 再者說,所有業務塊都在一個系統這會導致資源無法最大化利用,比如一個電商系統肯定是商品搜尋/推薦系統為最常用的系統,理所當然在資源方面他們應該佔有更多的機器資源,但是業務不進行拆分想進行橫向擴充套件只能將所有業務一起擴充套件。
  4. 最後是有可能會引起雪崩效應,舉個例子你的系統中假如有一塊非常不重要的業務(比如簽到)程式碼寫的有問題在生產環境中引發了OOM,那麼它必然會連累到整個系統中的所有業務都變成不可用,因為不同業務之間並沒有物理隔離。

通過這幾條可以知道過渡到微服務更多的考慮的已經不是效能瓶頸,而是人,是業務,也是應用系統最重要的高可用。

微服務與分散式

微服務是一種面向服務的軟體架構模式,自2014年Martin FowlerJames Lewis寫了一篇微服務架構的文章之後(微服務這個概念在此之前就有),微服務就被大量的討論以及實踐到生產專案中:Netflix、Amazon這些商業公司都有微服務的成功案例,商業公司最會考慮的一件事就是成本,他們不會因為Martin Fowler是軟體工程的名人(巨佬)就對他提出的某個概念迅速披掛上馬,一定是經過了很多權衡之後,才對他們的專案使用微服務的架構模式。

上一節中我已經簡要說了說叢集架構的缺點,微服務則是解決了那些缺點才變得如此受歡迎,微服務的相關定義,這裡我引用一段Martin Fowler原文的配圖和翻譯來說明:

簡而言之,微服務架構風格,就像是把一個單獨的應用程式開發為一套小服務,每個小服務執行在自己的程式中,並使用輕量級機制通訊,通常是 HTTP API。

這些服務圍繞業務能力來構建,並通過完全自動化部署機制來獨立部署。這些服務使用不同的程式語言書寫,以及不同資料儲存技術,並保持最低限度的集中式管理。

如果非要我用自己的語言來理解一下就是:將一個大型系統分為一個個的小型服務系統,共同支撐大型系統,每個小服務系統都可以獨立開發/測試/迭代/部署/擴容。

將大系統拆分為小服務之後既擁有了小服務的相關優點(利於團隊協作/測試/迭代),又能在面對大流量時進行叢集擴容,可以說是集兩者優點於一身,可能這就是所謂的”天下大勢,合久必分,分久必合。”

我新入職的這家公司也是在今年初全面轉入微服務架構,我們部門中所有的業務都已經拆成了微服務在跑,微服務拆分這事算是見仁見智把,要根據具體業務具體分析,我們的拆分過程中感覺比較好的一點是:有一些在未來一兩年內將要停止運營的業務也單獨拆出來放在一個服務裡跑。

其實微服務的概念不難理解,但真正動手起來做的話遇到的則一般不是微服務的問題而是分散式問題,有很多人經常把這兩個概念搞混淆,認為他倆說的是一個東西,其實是兩個東西,我們做出來的東西往往是涵蓋了這兩個概念。

微服務是指的一種面向服務的軟體架構方式,而分散式則是一種為了某個共同目標而協調多臺計算機節點進行工作的軟體系統。

在上一節的講解中,有一句話一直出現:隨著業務量/訪問量增大,這個日益增長的訪問量/業務量/資料量是我們使用微服務和分散式系統的主要原因:

  1. 業務的增加我們通過業務拆分來解決其帶來的問題,這可以算是微服務的範疇。
  2. 不同的服務部署在不同的機器上,但是對於使用者來說卻和訪問一個系統沒什麼區別,依靠網路將多個計算機節點組成一個統一的整體,這可以算是分散式系統的範疇。
  3. 由於資料量的不斷增加我們可以通過增加機器節點來分攤資料量,這算是分散式系統中分散式儲存的範疇。比如我們的Redis資料一臺機器已經存不下了,就要考慮使用RedisCluster將資料分散到多臺機器上面,其他例如Kafaka、ES都是分散式架構的中介軟體都可以進行分散式儲存。
  4. 如果應用中某些計算量比較大的任務使用一臺機器執行會耗時過長,這時我們可以拆分任務給多臺節點同時執行,這算是分散式系統中分散式計算的範疇。最近我在接手專案的時候就遇到了類似的問題,原任務單機執行時間過久,讓我改為所有線上節點同時執行,共同分攤任務,並且要能動態根據線上節點數量進行任務拆分。

通過上面四點的說明,我想大家對微服務和分散式應該有個簡單的區分了把,再次總結一下:

微服務是指的一種面向服務的軟體架構方式,而分散式則是一種為了某個共同目標而協調多臺計算機節點進行工作的軟體系統。

那為什麼微服務和分散式系統老放在一塊討論,導致很多人對他倆的定義模糊不清呢,因為往往我們要實現一個微服務架構的應用時,我們就在實現一個分散式系統。

如果你不明白我這句話,請好好想想使用微服務架構組成的應用是不是也同時符合分散式的定義。

Tips: 分散式計算/儲存也是一門電腦科學中的研究方向,所以它們其實還是可以挺深奧的一堆東西。

分散式與CAP

看了上一節大家應該已經明白了微服務和分散式的關係了吧,我這篇文章的重點其實是分散式,因為微服務只是一個面向服務的軟體架構概念,讓我理解起來它的主要作用就是提出了服務拆分、獨立開發部署這些概念,emm~概念,但是一個分散式系統卻有很多各種各樣的實際問題需要解決,所以我的重點是在分散式。

先來說說分散式的CAP原則,但凡對分散式有點了解的,都不能不知道這個CAP,先來看看它的定義:

CAP原則又稱CAP定理,指的是在一個分散式系統中,一致性(Consistency)、可用性(Availability)、分割槽容錯性(Partition tolerance)。

CAP 原則指的是,這三個要素最多隻能同時實現兩點,不可能三者兼顧。

分割槽容錯性: 是指在分散式系統中部署在不同地點的機器可能出現網路連線失敗的情況,這就像我的推薦服務會請求商品服務裡面的資料,但有可能發生了網路波動導致我推薦服務發起的請求網路連線超時。

可用性: 是指使用者的請求必須返回結果,要做到這個程度就需要我們在不同機房部署應用避免出現某些地方機房遭遇了事故導致服務當機的情況。

一致性: 是指資料被修改後,之後讀到的資料一定是最新的資料。

上面的定義已經說了,CAP只能最多同時實現兩點,因為我們是分散式系統,所以多臺服務節點是無法避免的,也就是分割槽容錯性我們必須要保證,所以我們只能保證實現CP或者AP。

為什麼不能同時實現CAP呢?原因很簡單,因為可用性這個要求需要每個節點的資料都要有幾個冗餘的副本,用來保證有一個節點掛掉之後副本能頂上去。然而副本節點和主機節點之間因為有網路通訊所以往往這個資料的傳輸是有延遲的,這也就不能保證主機的資料被修改後副本能立即收到修改,而是經過一頓延遲後才能收到主機修改的資料。

為了方便大家理解,我再舉一個例子來說明一下,比如說分散式中介軟體Redis

它在單機的情況下可以保證CP,因為只有一臺Redis節點所以資料被修改後之後的請求所訪問到的資料都是最新的。

它在叢集的情況下可以保證AP,AP是強調可用性,叢集架構下如果主節點掛掉之後,副本節點還可以接著響應請求。


既然CAP無法同時保證,那我們就要退而求其次,這裡將會引出一個新的理論:BASE

BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)的簡寫。

BASE是對CAP中一致性和可用性權衡的結果,契合性思想是即使無法做到強一致性,但每個應用都可以根據自身的業務特點,採用適當的方式來使得系統達到最終一致性。

基本可用: 是指某些情況下允許部分可用性的丟失,比如我們的雙十一大促,可能會由於下單量激增導致你下不了單,這就屬於下單服務不可用了,但是並不會持久太久,而是短暫的。

軟狀態: 是指允許副本同步過程中出現延遲而導致副本不一致的情況。

最終一致性: 是指系統的所有系統資料副本可以經過一段延遲後最終達到資料的一致性,不需要保證實時的資料一致。

我們既想要可用性也想要一致性,然而二者無法兼得,所以BASE理論就提出了這樣一種兼顧的思想,代價是強可用和強一致的損失。

現實中的很多系統中都是BASE理論這種思想,達到系統的一個基本可用和最終一致。

分散式開發與元件

這節我們來聊聊我們分散式系統的常見的各種元件以及相關特性,大家接觸過分散式開發的話就會發現分散式開發中有一大籮筐的名詞等著你:註冊中心、配置中心、閘道器、熔斷、遠端呼叫等等。

初來乍到,不要被這些名詞嚇住,別人能會的你也能,這一節我會自頂向下的講解一下分散式開發的基本組成,你可以先忘記這些名詞,慢慢看我的講解,看完這一章後我相信對這些都不會再迷茫。

前面我已經說過,分散式系統是多個節點組成一個整體,那不同節點的IP肯定不同,想要感覺像是一個整體,就得有一個部件在所有節點的最前面承擔一個請求分發的作用,這個東西就叫:閘道器

一般的閘道器有兩層,第一層是伺服器的Nginx+LVS這種,第二層是分散式應用的閘道器,我這裡說的是分散式應用的閘道器。

這個閘道器的作用有點像Nginx,可以幫你做反向代理幫你做負載均衡,但是比它更強大,分散式應用的所有請求第一站就是應用的閘道器層,在這裡可以校驗請求是否合法,阻擋網路攻擊,也可以進行動態的請求分發。

請求被閘道器轉發到對應的服務之後,就由對應的服務來處理了,這個時候問題又來了,我們同一個服務可能部署了三四臺節點,這個時候我該往哪個伺服器轉發呢?

我們要想轉發首先要知道各個節點的IP和埠號,這個資訊我們不能寫死,寫死的話不利於動態加機器,所以這個時候我們需要用到一箇中間價:註冊中心

我們所有的服務都會註冊到註冊中心上面去,當然這個註冊中心也要是一個叢集,這樣可以保證高可用。

舉個例子:我有一個商品服務給它起了個名字叫做goods-service,我給他起了三臺伺服器,這三臺伺服器都會註冊到註冊中心上去,然後我們就可以在註冊中心上看到有一個叫goods-service的東西下面又三臺節點,每臺節點的IP埠號都會在註冊中心上面儲存。

這時候我們閘道器來轉發的時候是通過goods-service這個名稱去註冊中心拿到三臺節點的地址,然後根據不同的策略最終決定我們是要將請求發到哪一臺節點。

請求傳送到服某某服務的這個過程,我們可以稱作為服務通訊,這個通訊方式一般有兩種:HTTP和RPC,這個其實我覺得沒啥好說的,主要就是通訊的協議不一樣,協議的不同也造成了效率的不同。

上面說了三個比較重要的元件,還有兩個比較重要的聽我娓娓道來。

第一個是配置中心,這個其實是屬於用不用都行的東西,但是用起來還是更方便的,它的主要作用是將分散式應用的配置都放在一個地方管理,我們需要更改的時候就可以讓所有引用這些配置的應用感知到並在執行的過程中動態載入到這些被修改的配置。

比如我們有六個微服務應用,我們可以統一的把配置都放在配置中心中介軟體上,這個資料一般是放在配置中心所連的資料庫裡,所以等於把我們所有專案的配置抽出來都放在資料庫了,一旦線上執行有什麼需要動態修改的配置,我們都可以直接在中介軟體上修改然後所有應用都會收到修改的通知,就會對修改的配置進行重新載入。

它對於某些公共的配置也很方便,比如六個微服務用的是一個Redis叢集,我們只需要配置一份就夠了,而且叢集配置有變化我們也只需要修改一次,六個微服務應用都能感知到。

第二個是熔斷器,所謂熔斷器,就是為了保護應用而設計的中介軟體,比如淘寶雙十一下單伺服器頂不住的時候就會給你提示一個哎呀,伺服器太火爆了,請稍後再試呢” 這種提示,這個東西就是為了保護淘寶服務不被沖垮而使用的一種限流措施,這種措施叫做服務降級。

使用熔斷器還有一些場景,比如下單經歷了商品服務和下單服務和庫存服務,走到最後一步時庫存服務崩掉了,這個時候下單服務這裡會報錯,進而引起羊群效應,所有和崩掉的節點有通訊的節點都會發生錯誤,這個時候就需要熔斷器出場了,發現那個服務不會響應之後會給一個提示,防止羊群效應的產生。

這兩個概念表現方式很像,但是不要被表象迷惑,他倆很主要的一個區別是引起的內因不一樣,大家有機會寫一次相關的程式碼就能明白了。

以上介紹的這些都是分散式開發中比較基礎的中介軟體,還有其他可選的中介軟體鏈路追蹤我會在下一節提一下,在這就不多說了。

SpringCloud與Alibaba

上一節大概講了五個分散式相關的元件,一般也就這五種:微服務閘道器、註冊中心、配置中心、服務通訊元件、熔斷元件。

這一節要給大家說說相關的實現,給大家認認臉熟,因為我們搞Java應用開發的一般都是用Spring全家桶的,在微服務開發這塊Spring推出了它的SpringCloud全家桶用來做微服務分散式開發。

經過這幾年的發展其實大致可以分為兩套開發套件:SpringCloud開發套件和SpringCloudAlibaba開發套件,這個只是我個人的分法,還有一些其他家的我也會提一下。

我們先來看看SpringCloud這一套,這一套相關的元件一開始基本都是Netflix公司開發的,這是一個做流媒體應用的,可以理解為國外的愛奇藝。

這張導圖右邊的是三個註冊中心中介軟體,Eureka就是Netflix公司開發的,Zookeeper這個功能比較強不是簡簡單單隻做註冊中心,它還可以做註冊中心和分散式鎖,Consul則是一個Go語言開發的註冊中心中介軟體(也可以用作配置中心),這幾個裡面Eureka是這兩年用的比較多的,更早之前國內可能Zookeeper用的更多。

左邊第一個SpringCloudGateway則是閘道器中介軟體,由Spring開發,之前Netflix還有一個Zuul,也是用來做閘道器中介軟體的。

Feign/OpenFeign/Rabbon這三個我放在一塊說,Feign和OpenFeign其實是一個東西,OpenFeign是在Feign停更之後在其基礎上開發的,都是用來做服務間通訊的,他們使用HTTP做通訊協議,其實就是Spring中的RestTemplate,而Rabbon是一個做服務轉發策略的中介軟體,前文我們提到閘道器進行服務轉發時可以根據一定的策略比如:輪詢、隨機、權重這些策略,這塊其實就是Rabbon在起效,我們用Eureka的時候現在都是自帶Rabbon不需要額外去引入相關JAR包了,畢竟都是Netflix一家的東西。

SpringCloudConfig是Spring開發的配置中心中介軟體,功能比起其他的後起之秀比如攜程的Apollo,阿里的Nacos稍弱,所以不推薦用。

Hystrix也是Netflix公司開發的中介軟體,它的作用就是熔斷器,是一款非常經典的熔斷器中介軟體,這些中介軟體裡面它是相對來說最複雜的。

Sleuth是一款鏈路追蹤中介軟體,可以記錄你的請求會經過哪些鏈路,Zipkin則可以以視覺化的形式將其表現出來。

上面這一套東西在我現在的公司裡面除了配置中心用的Apollo之外其他都用到了,算是比較流行的套件了。


不同於上面的基本都是由Netflix開發的套件,下面我要介紹的套件是SpringCloudAlibaba套件,因為是由Alibaba開發的所以一般都這樣稱呼。

上面這幅圖相比上一張就要簡單的多了。

Nacos是一個多功能中介軟體,同時可以做註冊中心和配置中心,這個元件我自己也用過感覺還是蠻好用的,而且自帶一套比較美觀的視覺化介面。

Duubo這個可能大家比較熟悉,原來是由阿里開發後來捐給Apache,現在是Apache的頂級專案之一,它是一個服務通訊的元件,使用RPC通訊方式。

Sentinel阿里開發的熔斷器,名字翻譯過來就是哨兵可以說是很貼切了,並且擁有鏈路追蹤的功能,還配有配套的視覺化介面,可以說是一個人幹了Hystrix+Sleuth+Zipkin的活。


像阿里這套中介軟體我是比較推薦的,因為第一套Netflix公司基本都已經宣佈停止更新了,比如Feign不更新之後Spring又接手進行二次開發搞了一個OpenFeign。

這裡在提一下Apollo,攜程開發的配置中心中介軟體,現在也有很多公司在用,我們公司也在用個人用起來感覺還是可以的,很方便上手也簡單。

其實別看這裡羅列了這麼多的中介軟體,每中學一種,剩下的看看文件也就上手了,大同小異吧,開源界的東西就是喜歡弄的簡單易上手,這對大家來說也是減少學習成本。

框架學的越多用的越多,你越會發現其實大部分都是大同小異,越能明白學好Java基礎的作用,越能知道設計模式、演算法才是一個軟體工程師必備的技能。

下個月我應該會把這些中介軟體也逐一寫文章寫個入門夠用的程度吧,大家一起加油?。

我是和耳朵,歡迎關注我的公眾號,加入後端相關交流群:

相關文章