1. 程式人生 > >[不得不知道系列]微服務面試你不得不知道的基礎知識

[不得不知道系列]微服務面試你不得不知道的基礎知識

1. [Java記憶體管理面試指南一](https://zthinker.com/archives/java-memory-interview-1) 2. [Java基礎面試指南一](https://zthinker.com/archives/java-basic-interview-1) 3. [Java基礎面試指南二](https://zthinker.com/archives/java-basic-interview-2) 4. [Java基礎面試指南三](https://zthinker.com/archives/java-basic-interview-3) 5. [Java基礎面試指南四](https://zthinker.com/archives/java-basic-interview-4) 6. [Java執行緒面試指南一](https://zthinker.com/archives/java-thread-interview-1) 7. [Java執行緒面試指南二](https://zthinker.com/archives/java-thread-interview-2) 8. [Redis面試指南一](https://zthinker.com/archives/redis-interview-1) 9. [Kafka面試指南一](https://zthinker.com/archives/kafka-interview-1) 10. [Spring面試指南一](https://zthinker.com/archives/spring-interview-1) 11. [SpringBoot面試指南一](https://zthinker.com/archives/springboot-interview-1) 12. [微服務面試指南一](https://zthinker.com/archives/microservice-interview-1) #### [1. 什麼是微服務,為什麼有人要考慮實現它. ](#collapse-beginner-1317) 微服務是一種架構樣式,其結構和應用程式是圍繞業務功能組織的鬆散耦合,可獨立維護,可測試和可部署的服務的集合.   如果您以業務為中心,並且想要在沒有技術限制的情況下有效地解決用例或問題,想要無限擴充套件獨立的服務,易於維護和管理以及可獨立測試的高可用性無狀態服務,那麼我們將繼續實施微服務架構. #### [2. 什麼時候應該考慮微服務型別的架構?](#collapse-beginner-1318) **有兩種情況. ** * 如果您已經擁有一個整體應用程式,並且該應用程式的增長到一定程度,在擴充套件方面存在問題,或者我們無法跨不同專案/平臺重新利用元件/模組/服務,則需要這樣做. 同時實現新功能是痛苦的,而且更容易出錯,並且很難進一步擴充套件. * 對於尚未開始實施的新應用程式,我們可以考慮一個有效實施的業務案例,該業務案例將來可以輕鬆維護,測試和擴充套件,並且可以同時用於其他專案/產品/平臺. . #### [3. 您將如何測試基於微服務的架構?](#collapse-beginner-1324) 應該進行單元測試和整合測試,以測試微服務的所有功能. 還應該進行基於元件的測試. 人們應該通過合同測試來斷言客戶的期望沒有打破. 但是,微服務的端到端測試應該僅測試關鍵流程,因為這些流程很耗時. 測試可以從兩個方面進行,消費者驅動的合同測試和消費者方的合同測試. 您還可以利用命令查詢職責隔離來查詢多個數據庫並獲得持久資料的組合檢視. #### [4. 什麼是服務發現?它有什麼幫助?](#collapse-beginner-1331) 在將docker映像動態部署在任何計算機或IP +埠組合上的雲環境中,相關服務在執行時很難更新. 僅出於此目的而建立服務發現. 服務發現是在微服務架構下執行的服務之一,它註冊在服務網格下執行的所有服務的條目. 所有操作都可以通過REST API獲得. 因此,每當服務啟動並執行時,各個服務便會向服務發現服務進行註冊,並且服務發現服務會保持心跳,以確保這些服務處於活動狀態. 這也用於監視服務的目的. 服務發現還有助於在以公平方式部署的服務之間分配請求. #### [5,什麼是客戶端和伺服器端服務發現?](#collapse-beginner-1332) 在這種體系結構模式中,客戶端不是連線到負載平衡器,而是直接連線到服務登錄檔並嘗試從中獲取資料或服務. 一旦獲得所有資料,它就會自行進行負載平衡,並直接與需要與之通訊的服務聯絡. 在存在多個代理層並且由於多層通訊而發生延遲的情況下,這可能會有好處. 在伺服器端發現中,代理層或API閘道器稍後會嘗試連線到服務登錄檔,然後再呼叫適當的服務. 客戶端在此處連線到該代理層或API閘道器層. #### [6. 說明如何擴充套件基於微服務的系統?](#collapse-beginner-1334) 假設大多數提供商都使用微服務架構, * 可以通過啟動更多容器來增加服務例項的數量來擴充套件系統. * 也可以將其應用於微服務層的快取,因為微服務將是事實的唯一來源,因此快取的失效可以非常容易地實現,因此可以輕鬆管理. * 也可以在API閘道器層引入快取,在其中可以定義快取規則,例如何時使快取無效. * 當需求較少時,也可以關閉一些容器. 也就是說,按比例縮小. #### [7. 定義微服務架構?](#collapse-beginner-3580) 微服務架構是一種開發由許多小型自治服務組成的可伸縮,分散式和高度自動化系統的樣式. 它不是一項技術,而是SOA衍生出的一種新趨勢. 沒有單一定義可以完全描述術語“微服務”. 一些著名的作者試圖通過以下方式對其進行定義: 1. 微服務是可以協同工作的小型自治服務. 2. 帶有邊界上下文的鬆散耦合的面向服務的體系結構. 3. 微服務架構是在架構級別應用單責任原則的自然結果. ![微服務架構](https://www.images.mdan.top/1563516283327-Image-4_1589847729213.jpg) #### [8. 微服務和SOA之間的區別](#collapse-beginner-3581) **_微服務是SOA的延續. _** SOA由於其分散式體系結構方法而開始獲得發展,並在2006年左右出現,以解決大型單片應用程式的問題. 這些架構(SOA和微服務)都具有一個共同點,即它們都是分散式架構,並且都具有很高的可伸縮性. 在這兩種服務中,服務元件都是通過遠端訪問協議(RMI,REST,SOAP,AMQP,JMS等)進行遠端訪問的. 兩者都是模組化的,通過設計可以鬆散地耦合在一起,並具有很高的可擴充套件性. 在輕量級容器,Docker,編排框架(Kubernetes,Mesos)出現之後,微服務在2000年底開始引起關注. 微服務在概念上與SOA有很大的不同- 1. SOA使用企業服務匯流排進行通訊,而微服務使用REST或其他不太複雜的訊息傳遞系統(AMQP等). 同樣,微服務遵循“智慧端點和啞點”,這意味著當微服務需要另一個作為依賴時,它應直接使用它,而無需任何路由邏輯/元件來處理管道. 2. 在微服務中,服務部署和管理應該是完全自動化的,而SOA服務通常是在部署整體中實現的. 3. 通常,微服務比SOA趨向要小得多. 這裡我們不在這裡討論程式碼庫,因為很少有語言比其他語言更冗長. 我們正在談論服務本身的範圍(問題域). 微服務通常以更好的方式做一件事. 4. 微服務應擁有自己的資料,而SOA可以共享一個公共資料庫. 因此,一個微服務不應允許另一個微服務直接更改/讀取其資料. 5. 經典SOA更加受平臺驅動,而在微服務方面,我們具有很多技術獨立性. 每個微服務都可以根據其自身的功能要求擁有自己的技術堆疊. 因此,微服務在各個維度上提供了更多選擇. 6. 微服務對外部環境的假設儘可能少. 微服務應管理自己的功能域和資料模型. #### [9. 什麼是有界上下文?](#collapse-beginner-3582) 有界上下文是域驅動設計中的中心模式. 在有界上下文中,與域相關的所有內容在內部上下文中都是可見的,但對其他有界上下文是不透明的. DDD通過將大型模型劃分為不同的有界上下文並明確說明它們之間的相互關係來處理它們. _整體概念模型問題 _ 整個組織的單一概念模型很難處理. 這種統一模型的唯一好處是,在整個企業範圍內整合都很容易,但是缺點很多,例如: 1. 首先,很難建立一個適用於整個組織的模型. 2. 其他人(團隊)很難理解它. 3. 更改這種共享模型以適應新的業務需求非常困難. 這種變化的影響將在團隊之間廣泛傳播. 4. 任何大型企業都需要一個非常大或抽象的模型. 5. 單個詞的含義在組織的不同部門中可能有所不同,因此可能很難提出一個統一的模型. 即使建立了這樣的模型,也會在團隊中引起很多混亂. #### [10. 微服務架構的特徵](#collapse-beginner-3583) 1. **高凝聚力** -小,專注於做好一件事. 小並不意味著更少的程式碼行,因為很少有程式語言比其他語言更冗長,但這意味著單個微服務所能滿足的最小功能範圍. 2. **鬆散耦合** -自主-能夠獨立部署不同服務的能力以及可靠性,這是因為即使另一個服務出現故障,該服務也可以執行. 3. **限界上下文** -一個微服務供應域中的界上下文. 通過使用該有界上下文的介面,它與域的其餘部分進行通訊. 4. 圍繞業務能力而非技術進行組織. 5. 持續交付和基礎設施自動化. 6. 向後相容的版本控制. 生產環境中甚至可以存在相同微服務的多個版本. 7. **容錯** -如果一項服務失敗,它將不會影響系統的其餘部分. 例如,如果為電子商務提供評論和評論的微服務失敗,則網站的其餘部分應執行良好. 8. 分散式資料管理,每個服務擁有其資料庫,而不是單個共享資料庫. 每個微服務都可以自由選擇適合其業務用例的資料庫型別(例如,RDBMS用於訂單管理,NoSql用於電子商務網站的目錄管理) 9. **最終一致性** -事件驅動的非同步更新. 10. **安全性** -每個微服務都應具有保護其自身資源免受未經授權訪問的能力. 這是通過使用無狀態安全性機制(例如帶有OAuth2的JSON Web令牌(JWT,發音為jot))實現的. #### [11. 使用微服務架構有什麼好處?](#collapse-beginner-3584) 與在應用程式中使用整體式體系結構相比,採用微服務體系結構可帶來許多好處,包括: * **自主部署** 在單個微服務上工作的分散團隊大多彼此獨立,因此更改服務不需要與其他團隊協調. 這可以導致明顯更快的釋放週期. 在現實的單片應用程式中,很難實現相同的目標,因為微小的變化可能需要整個系統的迴歸. * **理念轉變** 系統架構的微服務風格強調自由文化,單一責任,團隊自治,更快的釋出迭代和技術多樣化. * **技術多元化** 與單片應用程式不同,微服務沒有繫結到一個技術堆疊(Java,.Net,Go,Erlang,Python等). 每個團隊都可以自由選擇最適合其要求的技術堆疊. 例如,我們可以自由地為微服務選擇Java,為其他服務選擇c ++,為另一個服務選擇Go. * **DevOps文化** 該術語來自“開發”和“運營”的縮寫. 這種文化強調產品管理,軟體開發和運營團隊之間的有效溝通與協作. 如果正確實施DevOps文化,可以縮短開發週期,從而加快產品上市時間. #### [12 什麼是多語種永續性?這個想法也可以在整體應用中使用嗎?](#collapse-beginner-3585) 多語言永續性是關於在單個分散式系統中使用不同的資料庫來滿足不同的業務需求. 我們在市場上已經有不同的資料庫產品,每種產品都可以滿足特定的業務需求,例如:  * **關係資料庫管理系統** 關係資料庫用於滿足交易需求(儲存財務資料,報告要求等)  * **MongoDB** 面向文件的資料庫用於滿足面向文件的需求(例如,產品目錄). 文件是無架構的,因此架構中的更改可以輕鬆容納到應用程式中. * **Cassandra / Amazon DynamoDB** 基於鍵值對的資料庫(使用者活動跟蹤,分析等). DynamoDB可以儲存文件以及鍵值對. * **Redis** 在記憶體分散式資料庫(使用者會話跟蹤)中,其主要用作多個微服務之間的分散式快取. * **Neo4j** 圖表資料庫(社交關係,建議等)  _Polyglot Persistence的 _好處是多方面的,可以在整體以及微服務架構中獲得. 任何體面大小的產品都會有各種各樣的需求,僅憑一種資料庫就無法滿足. 例如,如果對特定的微服務沒有事務需求,那麼使用鍵值對或面向文件的NoSql比使用事務性RDBMS資料庫更好.   _參考:_[https](https://martinfowler.com/bliki/PolyglotPersistence.html) _:_ [//martinfowler.com/bliki/PolyglotPersistence.html](https://martinfowler.com/bliki/PolyglotPersistence.html) #### [13 什麼是應用程式的十二要素?](#collapse-beginner-3586) 十二要素應用程式是一種用於編寫作為服務執行的Web應用程式的最新方法(和/或宣言). ![12因素應用](https://www.images.mdan.top/12top_1590020008133.png) * **程式庫** 一個程式碼庫,多個部署. 這意味著我們僅應為不同版本的微服務使用一個程式碼庫. 分支可以,但不同的儲存庫則不行. * **依存關係** 明確宣告並隔離依賴項. 宣告建議不要依賴主機上的軟體或庫. 每個依賴項都應放入pom.xml或build.gradle檔案中.   * **Config** 將配置儲存在環境中. 不要在原始碼儲存庫中提交特定於環境的配置(最重要的是:密碼). Spring Cloud Config為分散式系統中的外部化配置提供伺服器和客戶端支援. 使用Spring Cloud Config Server,您可以集中管理所有環境中應用程式的外部屬性.   * **支援服務** 將支援服務視為附加資源. 無論您是管理外部服務還是其他團隊,微服務都應平等對待外部服務. 例如,即使從屬微服務是由您自己的團隊開發的,也不要在您的應用程式程式碼中硬編碼從屬服務的絕對URL. 例如,不要在RestTemplate中對其他服務的URL進行硬編碼,而使用Ribbon(帶有或不帶有Eureka)來定義URL:  * **Release & Run** 嚴格分開構建和執行階段. 換句話說,您應該能夠構建或編譯程式碼,然後將其與特定的配置資訊結合起來以建立特定的發行版,然後有意地執行該發行版. 在執行時更改程式碼應該是不可能的,例如,直接在tomcat中更改類檔案. 每個版本的發行版都應該始終有一個唯一的ID,主要是時間戳記. 釋出資訊應該是不變的,任何更改都應導致新的釋出.   * **Processes** 將應用程式作為一個或多個無狀態程序執行. 這意味著我們的微服務本質上應該是無狀態的,並且不應依賴於記憶體或檔案系統中存在的任何狀態. 實際上,狀態不屬於程式碼. 因此,沒有粘性會話,沒有記憶體中的快取,沒有本地檔案系統的儲存等. 應該使用分散式快取(如memcache,ehcache或Redis)代替 * **埠繫結** 通過埠繫結匯出服務. 這是關於使您的應用程式獨立執行,而不是依賴您要在其中部署的應用程式伺服器的執行例項. Spring Boot提供了一種機制,可以建立一個包含所有依賴項和嵌入式servlet容器(jetty或tomcat)的可自我執行的uber jar.   * **併發** 通過過程模型進行橫向擴充套件. 在十二要素應用程式中,流程是一等公民. 這並不排除各個程序通過執行時VM內的執行緒或在諸如EventMachine,Twisted或Node.js之類的工具中找到的非同步/事件模型來處理其自身的內部多路複用. 但是單個VM只能增長得如此之大(垂直規模),因此應用程式還必須能夠跨越多個物理機上執行的多個程序. 十二因子應用程式程序絕不應寫入PID檔案,而應依賴於作業系統程序管理器,例如systemd-雲平臺上的分散式程序管理器.   * **Disposability** 十二要素應用程式的過程是一次性的,這意味著它們可以立即啟動或停止. 這有利於快速彈性擴充套件,程式碼或配置更改的快速部署以及生產部署的穩定性. 流程應努力減少啟動時間. 理想情況下,從啟動命令執行到啟動並準備好接收請求或作業的過程需要花費幾秒鐘的時間. 較短的啟動時間為釋出過程和擴充套件提供了更大的靈活性;並且它有助於增強魯棒性,因為在需要時,流程管理器可以更輕鬆地將流程移至新的物理機.   * **開發/線上一致** 保持開發,暫存和生產儘可能相似. 您的開發環境應該幾乎與生產環境相同(例如,避免某些“在我的機器上工作”的問題). 但是,這並不意味著您的作業系統必須是在生產環境中執行的作業系統. Docker可用於為您的微服務建立邏輯隔離.   * **日誌** 將日誌視為事件流,僅將所有日誌傳送到stdout. 但是,大多數Java開發人員不同意這個建議.   * **管理流程** 一次性執行管理/管理任務. 例如,應該完全使用單獨的過程來執行資料庫遷移. #### [14. 微服務面臨哪些挑戰?](#collapse-beginner-3587) 1. 由於生產系統中大量流程的激增,DevOps是必須的. 如何啟動和停止服務團隊? 2. 分散式計算的複雜性,例如“網路延遲,容錯,訊息序列化,不可靠的網路,非同步o / p處理,應用程式層中不同的負載,分散式事務等”. 3. 如何以最小的努力在大型服務群中進行配置更改? 4. 如何部署單個微服務的多個版本並適當地路由呼叫? 5. 當微服務開始意外崩潰時,如何斷開其與生態系統的連線? 6. 如何隔離發生故障的微服務並避免整個生態系統中的級聯故障? 7. 考慮到服務在任何時間點都可能上升或下降,如何以彈性方式發現服務? 8. 如何彙總服務中的日誌/指標?如何識別跨微服務範圍的單個客戶端請求的不同步驟? #### [15為什麼微服務比單體應用更好?](#collapse-beginner-3588) 微服務體系結構旨在開發可安全擴充套件的大型分散式系統. 微服務架構相對於整體而言有很多好處,例如: 1. 單體應用是作為一個整體構建的,它通常由3個元件組成–資料庫(通常是RDBMS),伺服器端可執行檔案(部署在tomcat,websphere等中的war檔案)和客戶端介面(JSP等). 2. 每當我們要新增/更新功能時,開發人員都需要更改這三個元件中的至少一個並將新版本部署到生產中. 整個系統緊密耦合,在選擇技術堆疊方面有侷限性,凝聚力低.   3. 當我們需要縮放整體時,可以通過一次又一次地複製大war / ear檔案,在多臺機器上部署相同版本的整體. 一切都包含在一個可執行檔案中. 4. 另一方面,微服務架構由小型的自治服務組成,這些服務由業務功能劃分,業務功能主要通過非同步方式在網路上相互通訊.   ![典型的整體應用](https://www.images.mdan.top/1563517219165-Image-5_1589847806236.jpg) 如上面的示例所示,典型的整體eShop應用程式通常是部署在單個JVM程序(tomcat / jboss / websphere等)中的大型war檔案. 整體中的不同元件使用程序內通訊(例如直接方法呼叫)相互通訊. 一個或多個數據庫在整體應用程式的不同元件之間共享. #### [16. 如何將大型應用程式轉換為微服務架構?](#collapse-beginner-3589) 微服務應該是自主的,並應根據業務功能進行劃分. 每個軟體元件都應具有單一的明確定義的職責(又稱“單一職責原則”),並且應使用“受限上下文”的原則(由“域驅動設計”定義)來建立具有高度凝聚力的軟體元件.   例如,一個電子商務站點可以根據其業務功能分為以下微服務: * **產品目錄** 負責產品資訊,搜尋產品,過濾產品和產品方面. * **庫存** 負責管理產品庫存(庫存/數量和方面).   * **產品評論和反饋** 收集使用者對產品的反饋. * **訂單** 負責建立和管理訂單. * **付款方式** 線上和離線處理付款(貨到付款). * **出貨量** 根據訂單管理和跟蹤貨運. * **使用者帳號** 管理使用者及其偏好. * **推薦建議** 根據使用者的偏好或過去的購買來推薦新產品. * **通知事項** 有關訂單,付款和裝運的電子郵件和SMS通知. 客戶端應用程式(瀏覽器,移動應用程式)將通過API閘道器與這些服務進行互動,並將相關資訊呈現給使用者. #### [17. 如果啟動期間無法連線到Config伺服器,如何在啟動時停止基於Spring Boot的微服務?](#collapse-beginner-3590) 如果要在引導過程中無法找到配置伺服器時停止該服務,則需要在微服務的bootstrap.yml中配置以下屬性:  ``` spring: cloud: config: fail-fast: true ``` 當引導過程中無法訪問config-server時,使用此配置將使微服務啟動失敗併發生異常. 我們可以啟用重試機制,其中微服務將在丟擲異常之前重試6次. 我們只需要在類路徑中新增spring-retry和spring-boot-starter-aop即可啟用此功能.   build.gradle:-  ``` dependencies { compile('org.springframework.boot:spring-boot-starter-aop') compile('org.springframework.retry:spring-retry') ... } ``` #### [18 單個微服務應該有多大?](#collapse-beginner-3592) 良好的經驗法則(儘管非特定性)應儘可能小,但應儘可能大,以代表他們擁有的領域概念(由馬丁·福勒(Martin Fowler)說) 規模不應成為微服務中的決定因素,而應使用有限上下文原則和單一責任原則將業務能力隔離到單個微服務邊界中. 微服務通常很小,但並非所有的小服務都是微服務. 如果任何服務未遵循“繫結上下文原則”,“單一職責原則”等,則它不是微服務,無論其大小如何. 因此,規模並不是服務成為微服務的唯一資格標準. 實際上,微服務的大小在很大程度上取決於您選擇的語言(Java,Scala,PHP),因為很少有語言比其他語言更冗長. #### [19 微服務如何相互通訊?](#collapse-beginner-3593) 微服務通常使用諸如HTTP上的REST之類的簡單協議進行整合. 其他通訊協議也可以用於整合,例如AMQP,JMS,Kafka等. 通訊協議可以大致分為兩類:同步通訊和非同步通訊. * **同步通訊** RestTemplate,WebClient,FeignClient可用於兩個微服務之間的同步通訊. 理想情況下,我們應該最小化微服務之間的同步呼叫數量,因為網路很脆弱並且會引入延遲. 功能區-客戶端負載平衡器可用於在RestTemplate頂部更好地利用資源. Hystrix斷路器可用於優雅地處理部分故障,而不會對整個生態系統造成連鎖影響. 應該不惜一切代價避免分散式提交,相反,我們將選擇使用非同步通訊實現最終的一致性. * **非同步通訊** 在這種型別的通訊中,客戶端不等待響應,而是僅將訊息傳送到訊息代理. AMQP(如RabbitMQ)或Kafka可用於跨微服務的非同步通訊,以實現最終的一致性. #### [20 微服務中首選的通訊方式是什麼:同步還是非同步?](#collapse-beginner-3594) 1. 您必須使用一些可靠的佇列機制(RabbitMQ,AMQP等)在處理HTTP POST / PUT(任何修改資料的)請求時使用非同步通訊.   2. 可以在API閘道器級別將同步通訊用於聚合模式. 但是,此聚合除聚合外不應包含任何業務邏輯. 不得在閘道器上轉換資料值,否則,它將無法達到“受限上下文”的目的. 在非同步通訊中,事件應釋出到佇列中. 事件包含有關域的資料,它不應該告訴對此資料做什麼(操作).   3. 如果微服務到微服務的通訊仍然需要GET操作進行同步通訊,那麼請認真考慮為有限的上下文重新劃分微服務,並在積壓/技術債務中建立一些任務. #### [21 在微服務環境下,業務流程和編排有什麼區別?](#collapse-beginner-3595) 在業務流程中,我們依靠中央系統以某種方式控制和呼叫其他微服務來完成給定的任務. 中央系統維護整個工作流程的每個步驟和順序的狀態. 在編排中,每個微服務都像狀態機一樣工作,並根據其他部分的輸入做出反應. 每個服務都知道如何對來自其他系統的不同事件做出反應. 在這種情況下,沒有中央命令. 業務流程是緊密耦合的方法,並且是微服務體系結構中的反模式. 鑑於此,應儘可能採用編排的鬆散耦合方法. **_例_** 假設我們要開發一種微服務,該服務將在虛擬的電子商店中傳送產品推薦電子郵件. 為了傳送建議,我們需要訪問位於不同微服務中的使用者的訂單歷史記錄.   在編排方法中,此新的建議微服務將同步呼叫訂購服務並獲取相關資料,然後根據其過去的購買量來計算建議. 為一百萬使用者執行此操作將變得很麻煩,並將兩個微服務緊密結合在一起.   在編排方法中,我們將使用基於事件的非同步通訊,每當使用者進行購買時,訂單服務都會發布事件. 推薦服務將監聽此事件並開始建立使用者推薦. 這是一種鬆散耦合的方法,具有高度的可擴充套件性. 在這種情況下,事件並不能說明操作,而只能說明資料. #### [22. 微服務釋出到生產中的頻率如何?](#collapse-beginner-3596) 這個問題沒有正確的答案,可能每十分鐘,每小時或每週釋出一次. 這完全取決於您在軟體開發生命週期的不同級別上的自動化程度-構建自動化,測試自動化,部署自動化和監視. 當然還有業務需求-在一次釋出中,您關心的低風險變化有多小. 在一個理想的世界中,每個微服務的邊界都明確定義(有界上下文),並且給定的服務不會影響其他微服務,您可以輕鬆地一天完成多次部署而不會造成很大的複雜性. **部署/釋出頻率示例** 1. 據記錄,亞馬遜在2011年5月平均每11.6秒進行一次生產更改. 2. Github以其積極的工程實踐而聞名,平均每天將程式碼部署到生產中60次. 3. Facebook每天釋出兩次. 4. 許多Google服務每週都會發布多個版本,而Google中的幾乎所有內容都是在主線上開發的. 5. Etsy每天部署超過50次. #### [23 什麼是雲原生應用程式?](#collapse-beginner-3597) 雲原生應用程式(NCA)是一種應用程式開發樣式,鼓勵在連續交付和分散式軟體開發領域輕鬆採用最佳實踐. 這些應用程式是專門為雲端計算體系結構(AWS,Azure,CloudFoundary等)設計的. DevOps,持續交付,微服務和容器是開發雲原生應用程式的關鍵概念. Spring Boot,Spring Cloud,Docker,Jenkins,Git是一些工具,可以幫助您輕鬆編寫Cloud-Native Application. * **微服務** 這是一種將分散式系統開發為小服務集合的體系結構方法. 每個服務負責特定的業務功能,在其自己的流程中執行,並通過HTTP REST API或訊息傳遞(AMQP)進行通訊. * **開發運維** 它是軟體開發人員與IT運營部門之間的合作,其目標是根據客戶的需求不斷提供高質量的軟體. * **持續交付** 所有這些都涉及不斷不斷地自動交付低風險的小批量生產變更. 這樣可以更快地收集反饋. * **容器** 容器(例如Docker)為每個微服務提供邏輯隔離,從而永遠消除了“在我的機器上執行”的問題. 與虛擬機器相比,它更快,更高效. #### [24 您將如何使用Java開發微服務?](#collapse-beginner-3598) Spring Boot和Spring Cloud是開始使用Java語言構建微服務的一個很好的選擇. Spring Cloud中有很多模組可以為微服務的不同設計模式提供樣板程式碼,因此Spring Cloud確實可以加快開發過程. 此外,Spring Boot提供了開箱即用的支援,可將servlet容器(tomcat / jetty / undertow)嵌入可執行jar(超級jar)中,以便可以直接從命令列執行這些jar,從而無需部署war檔案放入Servlet容器.   您還可以使用Docker容器將整個可執行程式包運送並部署到雲環境中. Docker還可以通過在開發階段為執行時環境提供邏輯隔離來幫助消除“在我的機器上工作”的問題. 這樣,您就可以跨本地和雲環境獲得可移植性. #### [25 什麼是Spring Boot?](#collapse-beginner-3599) Spring Boot使得建立獨立的,基於生產級別的基於Spring的應用程式變得容易,您可以通過對Spring平臺和第三方庫的獨到見解來“執行”這些應用程式,以便您大驚小怪.   Spring Boot的主要功能  1. 建立獨立的Spring應用程式(12要素應用程式樣式)  2. 直接嵌入Tomcat,Jetty或Undertow(無需部署WAR檔案)  3. 提供可靠的入門POM,以簡化您的Maven或Gradle配置  4. 儘可能自動配置Spring  5. 提供可用於生產的功能,例如指標,執行狀況檢查和外部化配置  6. 完全沒有程式碼生成,也不需要XML配置  您可以使用託管在https://start.spring.io/的線上工具為專案選擇所需的依賴項來建立Spring Boot入門專案.   任何Spring Boot應用程式的最小最小依賴關係是:  ``` dependencies { compile("org.springframework.boot:spring-boot-starter-web:2.0.4.RELEASE") } import org.springframework.boot.*; import org.springframework.boot.autoconfigure.*; import org.springframework.stereotype.*; import org.springframework.web.bind.annotation.*; @Controller @EnableAutoConfiguration public class HelloWorldController { @RequestMapping("/") @ResponseBody String home() { return "Hello World!"; } public static void main(String[] args) throws Exception { SpringApplication.run(SampleController.class, args); } } ``` 您可以直接執行此類,而無需將其部署到servlet容器中.   _有用的參考 _ * Spring Boot Project * Spring Boot Starter * 使用Spring Boot構建應用程式 #### [26. 什麼是API閘道器?](#collapse-beginner-3600) API閘道器是一類特殊的微服務,可滿足單個客戶端應用程式(例如android應用程式,Web應用程式,Angular JS應用程式,iPhone應用程式等)的需求,併為其提供後端資源(微服務)的單個入口,向他們提供跨領域的關注,例如安全性,監視/指標和彈性.   客戶端應用程式可以與每個請求同時訪問數十個或數百個微服務,彙總響應並將其轉換為滿足客戶端應用程式的需求. Api Gateway可以使用客戶端負載平衡器庫(Ribbon)以迴圈方式在例項之間分配負載. 如果需要,它也可以進行協議轉換,即HTTP到AMQP. 它也可以處理受保護資源的安全性. API閘道器的功能 1. Spring Cloud DiscoveryClient整合 2. 請求速率限制(在Spring Boot 2.x中可用) 3. 路徑改寫 4. Hystrix斷路器整合,具有彈性 #### [27 在部署期間如何實現零停機時間?](#collapse-beginner-3601) 顧名思義,零停機時間部署不會在生產環境中造成停機. 這是將更改部署到生產的一種聰明方法,在任何給定時間點,至少有一項服務將對客戶可用. * **藍綠色部署** 實現此目標的一種方法是藍色/綠色部署. 在這種方法中,一次部署了一個微服務的兩個版本. 但是隻有一個版本正在接受真正的請求. 一旦將新版本測試到所需的滿意度,就可以從舊版本切換到新版本. 您可以執行冒煙測試套件,以驗證該功能在新部署的版本中是否正常執行. 根據冒煙測試的結果,可以釋出較新的版本,成為實時版本. * **客戶端程式碼中需要進行更改以處理零停機時間** 假設您有兩個同時執行的服務例項,並且兩個例項都在Eureka登錄檔中註冊. 此外,兩個例項都使用兩個不同的主機名進行部署:  ``` /src/main/resources/application.yml spring.application.name: ticketBooks-service --- spring.profiles: blue eureka.instance.hostname: ticketBooks-service -blue.example.com --- spring.profiles: green ``` 現在需要對books-service進行api呼叫的客戶端應用程式可能如下所示:  ``` @RestController @SpringBootApplication @EnableDiscoveryClient public class ClientApp { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } @RequestMapping("/hit-some-api") public Object hitSomeApi() { return restTemplate().getForObject("https://ticketBooks-service/some-uri", Object.class); } } ``` 現在,當ticketBooks-service-green.example.com停止升級時,它會正常關閉並從Eureka登錄檔中刪除其條目. 但是,直到再次獲取登錄檔(每30秒發生一次),這些更改才會反映在ClientApp中. 因此,長達30秒,ClientApp的@LoadBalanced RestTemplate可能會將請求傳送到ticketBooks-service-green.example.com,即使它失敗了.   為了解決這個問題,我們可以在Ribbon客戶端負載均衡器中使用Spring Retry支援. 要啟用Spring Retry,我們需要執行以下步驟:  _新增spring-retry到build.gradle依賴項 _ ``` compile("org.springframework.boot:spring-boot-starter-aop") compile("org.springframework.retry:spring-retry") ``` 現在,使用@EnableRetry批註在ClientApp中啟用spring-retry機制,如下所示:  ``` @EnableRetry @RestController @SpringBootApplication @EnableDiscoveryClient public class ClientApp { ... } ``` 完成此操作後,Ribbon將自動將其自身配置為使用重試邏輯,Ribbon將重試對ticketBooks-service-green.example.com com的任何失敗請求(以迴圈方式). 您可以使用以下屬性來自定義此行為:  ``` /src/main/resources/application.yml ribbon: MaxAutoRetries: 5 MaxAutoRetriesNextServer: 5 OkToRetryOnAllOperations: true OkToRetryOnAllErrors: true ``` #### [28. 資料庫發生更改時,如何實現零停機時間部署(藍色/綠色)?](#collapse-beginner-3602) 當升級期間資料庫發生更改時,部署方案將變得複雜. 有兩種不同的方案:1.資料庫更改是向後相容的(例如,新增新的表列)2.資料庫更改與應用程式的舊版本不相容(例如,重新命名現有的表列)  1. **向後相容更改**:此方案易於實現,並且可以使用Flyway完全自動化. 我們可以新增指令碼以建立新列,並且指令碼將在部署時執行. 現在,在藍/綠部署期間,該應用程式的兩個版本(例如v1和v2)將連線到同一資料庫. 我們需要確保新新增的列允許空值(順便說一下,這是向後相容更改的一部分). 如果一切順利,那麼我們可以關閉舊版本v1,否則可以關閉應用程式v2.   2. **不相容的資料庫更改**:這是一個棘手的情況,在回滾的情況下可能需要手動干預. 假設我們要在資料庫中將first_name列重新命名為fname. 除了直接重新命名,我們還可以建立一個新列fname,並將first_name的所有現有值複製到fname列中,並保持first_name列在資料庫中的狀態. 我們可以將對fname的非null檢查推遲到部署後的成功. 如果部署成功,我們需要在關閉v1之後手動將v1寫入first_name的資料遷移到新列(fname). 如果v2部署失敗,則需要執行其他操作.   在實際的生產應用程式中,複雜性可能更大,此類討論超出了本書的範圍. #### [29 如何在微服務架構中維護ACID?](#collapse-beginner-3603) ACID是資料庫事務管理器確保的四個主要屬性(原子性,一致性,隔離性和永續性)的首字母縮寫.   * **原子性** 在涉及兩個或多個實體的事務中,所有記錄都已提交,也沒有提交.   * **一致性** 資料庫事務必須僅遵循包括約束/觸發等的特定規則,以允許的方式更改受影響的資料.   * **隔離** 任何進行中的事務(尚未提交)必須與其他任何事務保持隔離.   * **高可用** 提交的記錄由資料庫儲存,這樣即使發生故障或資料庫重新啟動,資料也可以以正確的狀態使用.   在涉及多個數據庫的分散式系統中,我們有兩種選擇來實現ACID遵從性:  1. 實現ACID遵從性的一種方法是使用兩階段提交(也稱為2PC),以確保所有涉及的服務必須提交事務完成或所有事務回滾. 2. 使用最終的一致性,其中不同的微服務擁有的多個數據庫最終會通過使用訊息傳遞協議的非同步訊息傳遞而變得一致. 最終一致性是弱一致性的一種特定形式.   理想的情況下,由於微服務架構的脆弱性和複雜性,不建議使用2期提交. 通過最終的一致性,我們可以在分散式系統中達到某種程度的ACID合規性,這應該是正確的方法. #### [30. 什麼是Spring Cloud?](#collapse-beginner-3604) Spring團隊整合了一些經過考驗的開源專案,這些專案從Pivotal,Netflix等公司整合到一個稱為Spring Cloud的Spring專案中. Spring Cloud提供了用於快速構建分散式系統的一些常見設計模式的庫和工具,包括: | 模式型別 | 模式名稱 | Spring Cloud Library | |------|---------------|---------------------------------------------| | 配置模式 | 分散式/版本化配置管理 | Spring Cloud Config伺服器 | | \- | 核心微服務模式 | Spring Boot | | \- | 非同步/分散式訊息傳遞 | Spring Cloud Stream (AMQP and Kafka) | | \- | 服務間通訊 | RestTemplate和Spring Cloud Feign | | 路由模式 | 服務註冊與發現 | Spring Cloud Netflix Eureka和領事 | | 路由模式 | 服務路由/ API閘道器模式 | Spring Cloud Netflix Zuul | | 彈性模式 | 客戶端負載均衡 | Spring Cloud Netflix功能區 | | \- | 斷路器和後備模式 | Spring Cloud Netflix Hystrix | | \- | Bulkhead pattern | Spring Cloud / Spring Cloud Netflix Hystrix | | Logging Patterns | Log Correlation | Spring Cloud Sleuth | | \- | 微服務跟蹤 | Spring Cloud Sleuth / Zipkin | | 安全模式 | 授權與認證 | Spring Cloud Security OAuth2 | | \- | 憑證管理 | Spring Cloud Security OAuth2 / JWT | | \- | 分散式會話 | Spring Cloud OAuth2和Redis | Spring Cloud使得為Cloud開發,部署和操作JVM應用程式變得非常