《極簡微服務》

1 概述

1.1 寫做的目的

《極簡微服務》的原始動機是爲了總結本身所學,但後來發現不少同窗在學習微服務後仍然一頭霧水,處於一種知道可是還沒有深入的階段。我但願可以經過《極簡微服務》這篇文章,用盡可能少的語言將各部分的知識串聯起來,幫助剛入門的同窗們從新梳理一遍,但願可以讓你們對微服務造成一個更清晰的認識。由於是「極簡」,因此本文不會涉及到任何代碼的具體實現。java

我想要爲你們帶來的思路是:linux

  • 微服務是什麼?
  • 微服務包含了哪些東西?
  • 組件之間是如何相互做用,並構建成爲一個總體?
  • 微服務會對咱們的開發帶來何種影響?

首先要說明的是,我入門微服務走的是Spring Cloud相關技術棧,因此我可能很難作到徹底的脫離這個技術棧去總結。我對於微服務的瞭解可能也是膚淺的,某些方面上的理解可能也會存在一些誤差,我更多的把這看做是一種記錄和交流,由於我也不過是經過閱讀書籍和一些博文後作了一些梳理,因此但願讀者朋友們可以有批判地閱讀個人文字。數據庫

當你們閱讀個人文字,而後再提起微服務的時候,若是能說出更多本身想法,那這恐怕就是對我莫大的鼓勵了。windows

由於叫作 「極簡」,因此其實我已經儘可能想要控制好篇幅不要太長了,可是很無奈到最後仍是超過了本身所認爲的最理想篇幅,由於我以爲有些東西是不得不去了解的,望讀者朋友可以見諒。安全

1.2 咱們的目標

其實就是微服務的目標啦。服務器

終極目標網絡

經過將大的項目拆分紅不一樣子服務,不一樣子服務相互協做,創造出一個分佈式的、穩定的、高可用的、可控制的系統。

管理對象架構

服務。爲了實現終極目標管理好各個服務,讓他們之間的溝通無障礙。

所以,接下來我將針對咱們的服務與服務之間的關係來描述微服務。負載均衡

2 什麼是微服務

2.1 微服務

微服務是一種架構風格 ,就是將業務系統拆分爲不一樣的服務,而後每一個服務是獨立的。不一樣的服務經過輕量級的協議通訊(如HTTP)。部署的時候,一個服務可能會有多個實例。服務與服務的合做,構成了一個完整的系統。框架

經過微服務咱們能夠達到一些理想的效果。

  • 組件化
  • 可伸縮
  • 面向錯誤設計
  • 職責分明
  • 技術多樣性

    ...

2.2 什麼是好服務

  • 高內聚:相關的東西都扔一起,不然出BUG不知道哪裏找問題。
  • 鬆耦合:不強依賴其餘服務,減小每次改動所影響的範圍。
  • 獨立性:能夠開發、測試、部署,不受其餘因素影響。
  • 好看:指的是接口好看,好用。

3 微服務的組件

3.1 配置中心

3.1.1 配置的發展

有一種說法是,開發人員是被迫寫配置的。由於開發者得讓本身的軟件去適應不一樣的變化。

650,450

一開始是寫配置文件,可是太零散,因而將配置都寫在一個大的集合裏面,好比數據庫或者一個文件。

可是存在幾個問題:

  • 不容易拓展:就一我的文件或者數據庫,通常就只能讀取和修改。想要別的功能,SORRY。
  • 邊界模糊:誰來管理這個大的集合體?權限怎麼分配?怎麼保證你的修改不影響到別人?
  • 單點故障:數據庫掛了,文件丟了,讀取這個集合的配置的應用也均可能受到影響。固然能夠經過一些手段解決,但大都比較麻煩。

因此,後面提出了 配置中心 ,但願可以解決上述的問題。

3.1.2 需求

對於程序而言,它但願:

  • 配置與程序部署徹底分離
  • 調用可別太麻煩了
  • 配置有變化請立刻通知我
  • 配置中心千萬別掛掉

對於配置中心而言,它但願:

  • 隱私,加密,配置得是足夠安全的
  • 權限,每一個人只能讀取本身的配置

3.1.3 配置中心工做流程

800,600

3.1.4 問題

既然配置中心存了全部服務的配置,當服務們要加載配置就至少要和配置中心通訊一次。若是說服務要硬編碼配置中心的地址,假如配置中心換個地址,那麼就必須手動修改全部服務的這個配置。當服務數量達到幾十個的時候,這簡直是個噩耗。

因此硬編碼地址顯然不是一個好的方案。

微服務架構裏面,配置中心也是一個服務。發散的思考一下:不一樣服務之間的通訊是怎樣的?總不可能都是硬編碼吧?

3.2 服務發現

3.2.1 問題

回顧上一個章節的問題,服務之間應該如何通訊。簡單來講就是:服務太多了,不知道怎麼才能找到對方。

3.2.2 方案

其實很簡單,咱們找一個第三者,讓第三者告訴咱們就行了。就像是出去旅行同樣,不認識路的話,你查百度地圖就行了,讓地圖告訴你具體的位置。

800,550

因此咱們要抽象出一箇中間服務,專門用來作這個事情,告訴你其餘服務的位置,這個過程就叫作服務發現。而其餘服務告訴這個中間服務本身的位置的過程,就叫作服務註冊(相似於把本身的位置告訴百度地圖,讓他記錄你的位置)。

3.2.3 需求

服務註冊/發現中心:

  • 我很懶,其餘服務大家要本身上門註冊本身的位置啊。

其餘服務(客戶端):

  • 方便我查其餘服務的地址;
  • 我無論,反正你不能掛掉,否則我好不着北;

3.2.4 流程

不一樣的服務註冊、發現中心實現,流程可能存在差別。我在這裏只拿Eureka來看一下(目前我也只瞭解這個 = = )。

600,800

說明:

  • 啓用多個Eureka ,多個Eureka 實例信息共享,防止一個服務中心掛掉致使所有服務不可用。
  • 啓用客戶端的時候,客戶端本身告訴Eureka 本身是誰,地址是多少。
  • 客戶端(消費者)按期從服務中心Eureka處拉取最新的服務地址,這個服務地址就像是一本地圖小手冊,上面記錄了全部服務的地址。這個客戶端只須要定時更新這個小手冊,保證它是最新的就行了。

3.2.5 問題

服務註冊於發現機制,解決了不一樣服務之間的位置問題。可是僅僅是這樣是否足夠呢?

來聽一聽客戶端的疑問:

我就想去吃鴨脖,你這個地圖小手冊,鴨脖店的地址怎麼有兩個啊?那我到底要去哪個店家呢?

3.3 負載均衡

3.3.1 問題

選擇鴨脖子店的問題,嚴肅一點來講,就是當擁有多個服務實例的時候,選擇哪一個實例去調用的問題。

這個過程實際上就叫作負載均衡。

3.3.2 負載均衡

負載均衡能夠分兩種類型:服務端的負載均衡和客戶端的負載均衡。他們之間存在什麼樣的差別呢?

服務端負載均衡

600,300

顧名思義,就是把負載均衡(選擇哪一個鴨脖子店的選擇權)在服務端完成。在這種方案下,其實對於客戶端來講,就不存在選擇的問題了。當客戶端說 「要吃鴨脖」 的時候,服務端查看本身的地址列表,發現有兩個鴨脖店,那麼服務端會挑一個店的地址告訴客戶端。

怎麼挑選呢?一般能夠根據目標服務實例的網絡情況,負載的請求數量,甚至是隨機分配等,通常都是事先制定好一套規則。

客戶端負載均衡

600,300

相對於服務端的負載均衡,客戶端負載均衡就是把所謂的選擇權交給客戶端。也就是說,有多少個可用的服務實例的地址,服務端就返回多少個地址。客戶端要調用哪個服務實例,徹底由本身去選擇。

一樣,客戶端怎麼去選擇,通常也都是預先設定好規則的。

3.3.3 問題

如今,服務與服務之間的通訊,服務註冊與發現解決了 「在哪裏」 的問題;負載均衡解決了 「若是有多個位置應該去哪裏」 的問題。服務註冊/發現 和 負載均衡是屬於相互合做的關係,共同解決了 「去哪裏」 的問題。

可是咱們要如何保證客戶端真的順利到達目的地呢?

嚴肅點說就是:要如何保證客戶端對目標服務的調用是正常的?

3.4 彈性

3.4.1 問題

接過上一小節的問題,你以爲咱們應該如何保障咱們服務之間的調用是正常的呢?

爲了回答這個問題,咱們先拋出一個概念,叫作 「彈性」。

何謂彈性呢?彈性對於不一樣的對象來講略有不一樣。

對於客戶端來講:

彈性就是是否有響應。任何一個請求都應該有響應,且響應時間不該太長。

對於被調用的服務端來講:

彈性就是自我保護。爲了保護正常的運做,我可能會拒絕一些請求,以保障服務沒有由於過多的請求而崩潰。

咱們在這裏打個比方。服務之間的調用是正常 就像是 去店裏買蛋糕,這就是一個 「是否能順利抵達目標地點並買到蛋糕」 的問題。

在這裏咱們首先要明確,確定不能保證每一個人都可以順利抵達商店,由於目標商店隨時均可能會 「關門不幹」;其次,就算抵達了店裏,也不必定可以買到蛋糕,由於可能賣完了,或者機器出故障了。

因此咱們要換個思路,若是店家關門了,我就提早告訴它關門了,你最好別去了;或者你已經到了店家但發現蛋糕都賣完了,因而你改爲買餅乾,或者是你乾脆直接去別的店裏買。

3.4.2 方案

維持彈性的方案有很多,其實以前也有碰到過,讓咱們來總結一下。

以前咱們學習到的有:

  • 服務發現與註冊機制:移除註冊但已死掉的服務實例,這就保障了客戶端不會調用到已經崩潰的服務啦。
  • 負載均衡:選擇好的服務來調用。調用狀態正佳的服務纔會有快速的響應。

再來看看其餘的方案吧:

  • 斷路器 :就像是保險絲同樣,若是請求過多了服務器承受不住,或者服務器長期有問題。就斷開鏈接。不讓後續的請求過來了。
  • 後備模式:若是不當心碰到了服務沒反應或者網絡故障,拿出一個B方案臨時處理。
  • 艙壁模式 :就是隔離性。將某個服務(或者某些服務)進行隔離,就算調用它出錯了,也不影響其餘的服務調用。把影響控制在必定範圍內。

因爲服務發現與註冊機制、負載均衡在上面的章節已經有介紹了,故在此就再也不贅述。下面會圍繞其餘的方案來進行分析。

3.4.3 流程

斷路器的流程

微服務中最多見的就是斷路器了,下面來看看斷路器的流程(不一樣的斷路器實現可能會有所差別):

970,650

如上圖所示,有四個對象,分別是用戶、客戶端、斷路器、目標服務。

由用戶向客戶端發起請求,客戶端調用目標服務來完成用戶的指望。斷路器在這其中承擔了客戶端與目標服務之間的 「中間人」 的角色。

通訊能夠劃分爲三個階段:

  • 第一階段:客戶端對目標服務的調用 全放行。此時斷路器認爲目標服務沒有問題,因此所有放行。可是當達到一些特定指標(好比必定次數之後的故障比率)之後,斷定目標服務已經出現問題,則斷路器切換到第二階段。
  • 第二階段:客戶端對目標服務的調用在一段時間內 全拒絕。通常來講,第二階段過了一段時間之後纔會觸發第三階段的檢測。
  • 第三階段:客戶端經過特殊機制 檢測目標服務是否已經恢復正常。若是目標服務已恢復正常狀態,則切換到第一階段,不然切換到第二階段。

後備模式的流程

其實很簡單,用僞碼來表示就是:

boolean success = callService();
if (success) {
    doSomething();
} else {
    excutePlanB();
}

其實後備模式是能夠和斷路器結合起來使用的,當在斷路器流程中,判斷目標服務出現問題後的第二階段,客戶端的調用能夠所有走Plan B。

艙壁模式的流程

其實就是隔離,隔離的方式有不少種,好比線程的隔離,模塊的隔離,地域隔離等。這裏咱們拿線程隔離的舉個例子:

600,300

上圖中,本來客戶端對全部服務的調用都使用同一個線程池。

當某個目標服務A出現故障的時候,堆積在這個服務的調用越積越多,一直到線程池中的線程全被佔用了,此時客戶端新來一個須要對服務B的調用,卻沒有線程池能夠用了,只能排隊等待。

解決方案很簡單,事先將不一樣的服務劃分到不一樣的線程池中去,這樣就不會出現一個服務佔用資源,致使其餘服務不可用的狀況了。

3.4.4 問題

如今咱們不只解決了 「去哪裏」 的問題,還解決了 「是否能抵達並買到東西」 的問題。

讓咱們好好想一想,咱們如今解決的都是服務與服務之間的通訊問題。若是是外部服務(咱們微服務體系外的客戶端)要與咱們的服務通訊,如何解決呢?

3.5 網關

3.5.1 問題

接回上一小節的問題。

問題描述

內部服務與服務之間,是經過一本字典來查找對方的位置,可是若是是一個「外國人」(外部服務),一方面我不能把字典給他由於字典是機密,其次,就算給了他他也看不懂畢竟文字不通。

分析

所謂內部服務,通常對外都是不可見的。咱們經過服務之間的合做給外部提供一個總體,因此對外而言咱們應該是一個總體。基於安全性考慮咱們也不能講內部服務暴露給外部服務使用。

解決方案

選舉出一個中間人,專門用來和外部服務通訊。由這個中間人來判斷對方是否是合法的請求,而後作相應轉發工做。

這個中間人又像是一個守門人,只接納有「令牌」的人,並「通風報信」。

550,400

3.5.2 流程

970,700

其實沒有太多想要說的。咱們看一下網關所處的位置,恰好就是處於對外來請求的「守門人」的位置。咱們只須要明白網關的做用便可。

很明顯,網關的做用有:

  • 驗證和受權:你從哪裏來?看一下隨身令牌?
  • 路由(動態/靜態):你要到哪裏去?來,往這兒走!
  • 負載均衡:有兩個蛋糕店,你去這個好了。
  • 流量控制:人滿了,不能讓你進來啦,抱歉!
  • 數據蒐集、日誌:等我記錄一下,你從哪裏來,去哪兒,買了啥。
  • 其餘公共需求:略略略。

3.5.3 問題

想必到這裏,你已經基本瞭解服務註冊與發現、配置中心、負載均衡、斷路器、網關之間是如何共同工做的了。

如今惟一的問題是,相對於以前的單體架構系統來講,服務的數量變多了,服務之間的通訊也變多了。系統反而一會兒變得複雜了。若是服務與服務之間的調用出了問題,我應該怎麼排查問題呢?

3.6 日誌

3.6.1 問題

接回上一小節問題。

問題描述

相對於單體架構系統而言,微服務架構犧牲了原有的簡單,換取了系統的靈活性。因此微服務看起來反而變得更復雜了。一個請求,可能要通過網關、服務與服務之間來回的調用,因此作的日誌也都十分零散,怎麼監控系統、排查問題,變成了使人頭疼的問題。

3.6.2 解決方案

來自風箏的啓發

300,300

不管風箏怎麼飛,只要我手裏握着一條線,我就能知道風箏在哪裏。咱們能夠借鑑這個思路,爲咱們的請求創造出一根看不見的 「線」 。

TraceID

700,450

如上圖所示,當請求進來的時候,我只須要爲這個請求添加上一個標識(traceID),無論後續這個請求被如何轉發,只要帶有這個traceID,那他們確定是同一請求。

這個traceID不只僅要可以被轉發,作日誌的時候,也要將traceID一併記錄下來,這樣無論日誌分散在哪一個服務,我均可以知道他們是否是同一個請求產生的。

經過traceID咱們能夠實現請求的鏈路跟蹤問題。

日誌蒐集

咱們知道,不一樣的服務多是部署在不一樣的服務器上的,因此纔會顯得零散。若是咱們要查日誌,確定不可以來回登陸到不一樣服務器上去查。因此,咱們須要將全部的服務的日誌統一搜集起來,統一管理。這叫作日誌聚合。

3.6.3 流程

600,500

經過將全部服務的日誌統一搜集起來,統一存儲,統一分析。再經過TraceID作鏈路的跟蹤,咱們就能夠搭建出一個日誌管理和分析平臺。

如此,在微服務架構下,監控和查找問題,變得一目瞭然。

總結

如今來回顧一下,微服務的組件,都還記得有哪些嗎?

來看一下他們是如何相互協做的吧!

1000,750

4 測試

4.1 測試分類

4.1.1 測試類型

(這只是從一種維度上去劃分,劃分的維度能夠有不少)

  • 面向業務的測試。如驗收測試、可用性測試等。
  • 面向技術的測試。如單元測試、集成測試、性能測試、安全測試等;

4.1.2 單元測試

是函數級別的。一般咱們在這裏捕獲到大部分的錯誤。

4.1.3 服務測試

服務級別的集成測試。測試某個服務的功能。

4.1.4 端到端測試

系統測試,多個服務的測試。一般須要在頁面上用鼠標點點點。

4.2 測試的手段

對於單元測試而言,有時候一個函數依賴於另一個函數,也就是說,另一個的正確與否,會直接影響到我這個測試的結果。因此有時候咱們須要製造必定的隔離空間。

對於服務測試來講,也存在這樣的問題。

如此來講,測試的隔離性咱們須要重視。

爲了創造這種隔離性,咱們能夠用Mock、或者打樁技術。

4.2.1 打樁

所謂打樁,最簡單的理解就是你能夠認爲是「寫死」,a函數,須要依賴b函數的返回值。那麼咱們能夠將b函數的返回值「寫死」。這就保證了b的返回確定不會出錯了。

看似簡單,可是你不能直接修改函數b,由於很容易出錯,如果你忘了改回來,就把你「寫死」的代碼一併提交了。

4.2.2 Mock

Mock和打樁很相似,區別在於,打樁是不關心你函數b(即你這個測試要依賴的那個函數)執行了多少次的。而Mock不只僅能夠模擬調用函數b不少次,還會不少其餘的問題,好比,調用是否成功等。

咱們一般藉助一些測試框架來打樁和Mock,好比Java最經常使用的JUnit。

4.3 測試金字塔

900,650

如上圖所示,不一樣的測試,會帶來不一樣的效果。

  • 測試範圍越大,會讓咱們對本身的系統更有信心。範圍越大的測試,測試時間越長,致使反饋時間比較越長;
  • 底層的單元測試測試很快,可是單元測試是函數級的,單元測試的數量大。由於單元測試範圍小,因此問題定位會比較精準,普通的錯誤咱們甚至能夠定位到「行」;
  • 金字塔的比例是能夠變化的。咱們應該針對現有的系統去改造。爲這三者找到一個合適的測試比例。但每一次改造都會產生額外的成本,成本隨着項目規模愈來愈大。

4.4 自動化

隨着服務愈來愈大,測試愈來愈多,人工的測試變得愈來愈困難。微服務離不開自動化測試。因此咱們須要藉助CI/CD來讓咱們的測試變得自動化。

5 持續集成

持續集成對於微服務來講真的很重要。微服務組件解決的是技術上的問題,而持續集成所解決的是流程和效率上的問題。

持續集成可以加快微服務架構下的開發、測試、部署,可以幫助咱們更快的發現和解決問題。

初聞持續集成,讓人摸不着頭腦,怎麼會有如此晦澀的詞語呢!

可是且慢,先來看看哪些典型的場景:

  • 咱們寫完代碼後,提交到SVN/GIT,而後本身打包,登FTP將打包好的代碼上傳到測試服務器,而後對服務器 shutdown/startup。
  • 一我的修改了不少東西,可是不當心改錯了某個東西,可是他提交了,這時候沒人知道出錯了。
  • 幾我的一塊兒開發同一個服務,由於週期較長,其中有一我的長時間不提交代碼,一個月後,他要提交的時候發現,全是代碼衝突都不知道怎麼merge了。

這些場景都使人頭疼,他們的共同特徵是:要麼都是重複的工做,要麼是常常出現的問題,對項目工期、團隊協做產生了較大的影響。

咱們須要解決這些問題,用的手段就是持續集成。接下來咱們就來解釋什麼叫持續集成。

5.1 CI 持續集成

所謂持續集成(Continuous Integration)。

先來看一下什麼叫作集成。什麼是集成呢?集成就是將代碼提交到主幹,經過一系列自動化的工具來構建(你能夠簡單理解爲打包)和測試,驗證是否有錯誤,是否會對其餘人的代碼產生影響。

因此持續集成,就是不斷的進行集成,即常常提交代碼以集成。持續集成的目的就是儘早集成,早點發現錯誤,早點解決問題。

咱們談到CI的時候,每每涉及到幾個方面:

  • 自動化工具:人工手段的集成是及其低效率的,因此咱們須要藉助自動化工具來協助;
  • 版本管理:擁有一套良好的版本管理機制,咱們纔可以更好的進行持續集成。
  • 多提交:。因此開發者得有這樣的意識,多提交代碼,多集成。
  • 多寫測試:有測試才能發現問題。

這其實也就是技術和流程問題。

一個好的持續集成環境是怎樣的?

代碼提交後自動(或者按期手動)觸發持續集成:自動跑單元測試,自動構建代碼,自動上傳部署。不須要過多的人工參與。中間每一步出現問題的時候,都會立刻經過一些手段進行反饋,防止出現更多的錯誤。

5.2 CD 持續部署

咱們談論CI的時候,不少時候也包含了持續部署(Continuous Delivery)的含義在裏面。

何謂持續部署?

是CI的下一步。CI經過自動化的流程,確保軟件語法和單元測試上是沒有問題的。可是還不夠,因此下一步須要將軟件的新版本交給質量團隊或者用戶。讓他們去繼續測試、評審。若評審經過則說明代碼就能夠進入生產階段了。

5.3 常見的CI/CD工具

  • Jenkins
  • Travis CI

6 容器

容器也是微服務架構不得不去思考的一個問題。它解決的是部署的問題。

6.1 部署的問題

部署有哪些問題呢?

  • 不一樣服務器之間環境存在差別且這些差別難於發現。環境的差別性可能會致使許多讓人意想不到的問題。
  • 要新增或者刪除一臺服務器成本較高。包含時間成本和金錢成本。要能達到部署標準的服務器,須要裝各類軟件和配置很多環境變量,很難保證新配置的環境徹底沒有問題。並且不一樣服務的部署,所須要的環境也是不一樣的。
  • 難於管理。服務器數量幾十臺的時候,你們基本上處於戰戰兢兢提醒吊膽的狀態,由於根本管不過來。

6.2 虛擬機

能不能減小服務器的數量,在一臺服務器部署多個服務,而且能作到能夠支持多種服務的部署?

要支持不一樣服務,確定要支持不一樣的環境,好比windows,好比linux。

其實能夠的,用虛擬機嘛。

虛擬機的大概思路是:

將整個環境先搭建好,而後打包成爲虛擬機鏡像,每次須要增長一個新環境的時候,直接實例化作好的鏡像便可

900,550

一方面,虛擬機技術解決了環境的問題,部署比之前快了很多;

另外一方面,構建鏡像耗費時間長(一旦環境須要改變的時候,或者須要多個不一樣環境的時候),鏡像文件大;而且,虛擬機的管理也須要佔用額外的資源和空間;

虛擬機技術的特色是:

  • 擁有一個Hypervisor,用來管理全部的虛擬機;
  • 實例化的鏡像中,是一個獨立的空間,擁有獨立的操做系統,內核,應用;
標準的虛擬機中存在一個Hypervisor,它會幫助咱們管理運行在Hypervisor之上的其餘虛擬機,包括資源的分配,外部的請求路由管理,內存的映射等;虛擬機越多,Hypervisor佔用的資源越多;

6.3 Linux 容器

即Linux container,簡稱LXC。

LXC的原理是,建立一個隔離的進程空間,在這個空間中運行其餘的進程。而且由物理機的內核來完成資源的分配工做。

以下圖所示:

400,600

與傳統虛擬機不同的地方是:

  • 不須要Hypervisor
  • 隔離的空間內沒有內核
  • 啓動快,只須要幾秒
  • 更輕量,對資源利用更充分

6.4 Docker

如今你們都知道Docker了

LXC是操做系統級別的虛擬化方案,畢竟是Linux下的容器。是否存在應用級別的容器技術呢?

那就是Docker了。

Docker的發展

2013年,Docker橫空出世的時候,在底層上也藉助了LXC來管理容器,而後本身在上層作其餘的管理工做。可是過了幾年,Docker 0.9的時候有了新歡libcontainer,LXC就變成了一個「備胎」,此時Docker能夠選擇再也不依賴Linux部件了。再Docker 1.8的時候,LXC被認定爲「前妻」。

再到後來,libcontainer上位。Docker致力於去實現容器化的標準,你只須要實現libcontainer提供的標準接口,那麼你就可以運行Docker,這爲Docker的全面跨平臺提供了可能。

Docker的特色

分層

一個鏡像能夠分爲任意多層,好比:

  • 操做系統層(第一層)
  • 依賴庫(第二層)
  • 軟件包和配置文件(第三層)
  • 運行的應用程序(第四層)

若是幾個鏡像擁有相同的層。好比,鏡像A和鏡像B用的是相同的操做系統,那麼下載A時已經下載好了這個操做系統,下載B的時候,就不須要從新下載了,只須要下載第一層之上的數據便可。

增量更新/版本管理

對於一個公共鏡像A來講,有許多鏡像可能都是根據它來製做的,而鏡像A製做好了便不能夠改變。但對於其餘鏡像來講,有時候一些環境變量不免須要改變,這時應該怎麼辦呢?

Docker中約定:

  • 上層的優先級大於下級
  • 層都是隻讀的

這樣,只須要在最上層添加一個讀寫層,將須要改變的配置都集中到這個層來進行改寫。在寫的時候同時拷貝出一個只讀屬性的文件備份,應用實際讀取的時候讀取的是這個只讀屬性的拷貝。

400,250

如上圖所示,底層中環境變量A是1,可是在讀寫層,咱們將A設置爲3,那麼應用程序讀取的時候,讀取到的是A=3。而讀寫層不只僅能夠修改配置,還能夠將移除某些組件。每新加一層發佈出去的時候,就至關於發佈了一個更新。這樣的一個好處就是,對於以前發佈出去的鏡像,咱們擁有了 增量更新版本管理 的能力。

Docker的構成

Docker採用了C/S架構。分爲Client和Server,而後還借鑑了Git的思想,能夠搭建本身的中央鏡像倉庫。大致的架構以下圖所示(圖片來自於網絡):

700,500

須要解釋一下幾個名詞:

  • Image:鏡像。一個可執行的包。它包括了一個程序要正常運行,所依賴的包括應用程序自己在內的軟件,環境變量,配置文件,依賴包等環境;
  • Container:容器,一個鏡像的運行實例;
  • Docker-Daemon:一個運行在後臺的守護進程,能夠看作是Server;
  • Registry:鏡像註冊中心,這裏存在着各類鏡像,用戶能夠上傳或者下載上面的鏡像。分爲public和private,咱們還能夠搭建本身的Registry;

咱們所說的Docker,一般是指Docker Engine,它包括了:

  • Docker-Daemon
  • REST API
  • CLI

其中,REST API和CLI都是用來跟server交互的。

6.5 與CI合做

咱們原先所謂的部署,對於Java來講,都是將代碼打包成jar或者war,也就是說,jar和war就是咱們CI的構建物。

採用了容器技術之後,CI每次集成的結果是一個容器鏡像,那麼咱們就只須要在服務器將這個鏡像實例化就能夠了,從而不須要關心環境的差別問題。

7 總結

微服務經過將系統拆分爲不一樣的服務,經過服務與服務之間的相互協做,構成一個總體。

在微服務架構下,咱們關心服務與服務之間如何通訊。因此咱們會單獨構建一個服務中心,專用用於幫助服務與服務之間更好的溝通;再經過斷路器的方式,爲咱們的服務提供保障,讓服務間的調用具有彈性;此外,咱們還會獨立出一個服務,專門管理服務的配置;考慮到咱們須要支持外部的訪問,因此咱們獨立出一個網關,用來承擔「看門人」的角色。上述的種種爲系統帶來了巨大的複雜性,爲此,咱們還單首創造創一套日誌聚合和鏈路跟蹤機制,用於監控微服務的狀態。

除了這些,咱們還須要經過持續集成和容器技術來幫助咱們達成更高效的開發、測試、部署效率,讓服務具有更好的伸縮性,要增長新的服務實例的時候,只須要再實例化一次鏡像便可。

彷彿一切都變得美好了,這就是微服務。

8 參考書目

《Spring微服務實戰》

《微服務設計》

(這是個人原創文章,若要轉載,但願你們可以註明出處,謝謝你們~)

相關文章
相關標籤/搜索