聊聊微服务架构
?
?
1. 微服務(wù)架構(gòu)概念解析
2. 構(gòu)建微服務(wù)架構(gòu):使用 API Gateway
3.?深入微服務(wù)架構(gòu)的進(jìn)程間通信
4.?服務(wù)發(fā)現(xiàn)的可行方案以及實(shí)踐案例
5.?微服務(wù)的事件驅(qū)動(dòng)數(shù)據(jù)管理
6.?選擇微服務(wù)部署策略
7. 將單體應(yīng)用改造為微服務(wù)
首先讓我們了解為何要將微服務(wù)納入考量。
構(gòu)建單體應(yīng)用
假設(shè)我們要開發(fā)一款全新的與 Uber 和 Hailo 競(jìng)爭(zhēng)的打車軟件。在前期的會(huì)議和需求整理后,你要么需要手動(dòng)創(chuàng)建一個(gè)新項(xiàng)目,要么可以使用 Rails、Spring Boot、Play 或者 Maven 來生成。這個(gè)新應(yīng)用可能采用了六邊形架構(gòu)模塊,如下圖所示:
應(yīng)用的核心是商業(yè)邏輯,它由定義服務(wù)、域?qū)ο蠛褪录髂K來完成。各種適配器圍繞核心與外部交互。適配器包括數(shù)據(jù)庫(kù)訪問組件、生成和 consume 信息的消息組件,以及提供 API 或者 UI 訪問支持的 web 模塊。
盡管擁有邏輯縝密的模塊化設(shè)計(jì),整個(gè)應(yīng)用仍然以整體打包和部署,實(shí)際格式依賴于應(yīng)用的語言和框架。譬如,許多 Java 應(yīng)用被打包為 WAR 文件,部署在 Tomcat 或者 Jetty 這樣的應(yīng)用服務(wù)器。有些 Java 應(yīng)用本身就是包涵 JARs 的軟件包。與此類似,Rails 和 Node.js 應(yīng)用也通過目錄層級(jí)打包。
采用此種風(fēng)格的應(yīng)用非常普遍。由于 IDE 和其他工具擅長(zhǎng)構(gòu)建單一應(yīng)用,這類應(yīng)用也易于部署。這類應(yīng)用也非常容易測(cè)試。你可以非常輕松地進(jìn)行端到端測(cè)試,使用 Seleniu 測(cè)試 UI 。整體應(yīng)用也便于部署,只需將軟件包復(fù)制到服務(wù)器。你也可以通過運(yùn)行多個(gè)包和負(fù)載均衡實(shí)現(xiàn)擴(kuò)展。在項(xiàng)目早期這么做非常有效。
踏入單體架構(gòu)的地獄
很不幸,這一簡(jiǎn)單的方法有著巨大的局限。成功的應(yīng)用最終會(huì)隨著時(shí)間變得巨大。在每個(gè) sprint 階段,開發(fā)團(tuán)隊(duì)都會(huì)新加許多行代碼。幾年后,原本小而簡(jiǎn)單的應(yīng)用會(huì)變得臃腫。舉個(gè)極端的例子,我最近與一位開發(fā)者交流,他正在開發(fā)一款小工具,來分析他們應(yīng)用(包括幾百萬行代碼)中的幾千個(gè) JARs 的依賴。我相信每年都會(huì)有大量開發(fā)者不遺余力地對(duì)付這種麻煩。
一旦你的應(yīng)用變得龐大、復(fù)雜,你的開發(fā)團(tuán)隊(duì)將飽受折磨,苦苦掙扎于敏捷開發(fā)和交付。一大原因就是應(yīng)用已經(jīng)格外復(fù)雜,龐大到任何一個(gè)開發(fā)者都無法完全理解。最后,修復(fù) bug 和實(shí)施新功能也就極其困難且耗時(shí)頗多。更可怕的是,這是一個(gè)向下的螺旋發(fā)展。代碼庫(kù)越難理解,正確的修改就越難。最后你會(huì)深陷龐大的、無法估量的泥淖之中。
而這種應(yīng)用的尺寸也會(huì)拖慢開發(fā)進(jìn)度。應(yīng)用越大,啟動(dòng)時(shí)間越長(zhǎng)。譬如在最近的調(diào)查中,不少開發(fā)者指出啟動(dòng)時(shí)間長(zhǎng)達(dá) 12 分鐘。我也聽說有的應(yīng)用啟動(dòng)時(shí)間居然得 40 分鐘。如果開發(fā)者不得不頻繁重啟應(yīng)用服務(wù)器,那大量時(shí)間就被浪費(fèi),生產(chǎn)效率也飽受其害。
龐大且復(fù)雜的單體應(yīng)用的另一大問題就是難以進(jìn)行持續(xù)部署。現(xiàn)在, SaaS 應(yīng)用的發(fā)展水平足以在單日內(nèi)多次將修改推送到生產(chǎn)環(huán)境。然而要讓復(fù)雜的單個(gè)應(yīng)用達(dá)到此水平卻極為棘手。想更新應(yīng)用的單個(gè)部分,必須重新部署整個(gè)應(yīng)用,漫長(zhǎng)的啟動(dòng)時(shí)間更是雪上加霜。另外,由于不能完全預(yù)見修改的影響,你不得不提前進(jìn)行大量人工測(cè)試。結(jié)果就是,持續(xù)部署變得不可能。
如果單體應(yīng)用的不同模塊在資源需求方面有沖突的話,那應(yīng)用的擴(kuò)展也很難。比如,模塊之一需要執(zhí)行 CPU-intensive 圖像處理邏輯,最好部署到 AWS 的 EC2 Compute Optimized instances;而另一模塊需要內(nèi)存數(shù)據(jù)庫(kù),最好適配 EC2 Memory-optimized instances。由于這兩個(gè)模塊需要共同部署,你不得不在在硬件選擇方面做妥協(xié)。
單體應(yīng)用的另一問題就是可靠性。由于所有模塊都運(yùn)行在同一進(jìn)程中,任何模塊中的一個(gè) bug,比如內(nèi)存泄漏都可能弄垮整個(gè)進(jìn)程;此外,由于應(yīng)用中的所有實(shí)例都是唯一,這個(gè) bug 將影響整個(gè)應(yīng)用的可用性。
最后,單體應(yīng)用會(huì)讓采用新框架和語言極其困難。舉例來說,你有兩百萬行使用 XYZ 框架的代碼,如果要使用 ABC 框架重寫代碼,無論時(shí)間還是成本都將非常高昂,即便新框架更好。這也就成為使用新技術(shù)的阻礙。
總結(jié):這個(gè)一開始曾經(jīng)成功關(guān)鍵業(yè)務(wù)應(yīng)用,最終卻變成一個(gè)臃腫的、無法理解的龐然大物。它使用老舊、陳腐、低效的技術(shù),幾乎吸引不到出色的開發(fā)者。這個(gè)應(yīng)用非常難于擴(kuò)展,也不穩(wěn)定可靠。最終,敏捷開發(fā)和交付幾乎成為不可能。
你該何去何從?
微服務(wù)——直擊痛點(diǎn)
諸如亞馬遜、eBay、Netflix 等公司已經(jīng)通過采用微服務(wù)架構(gòu)范式解決了上文(第一部分)提到的問題。不同于構(gòu)建單一、龐大的應(yīng)用,微服務(wù)架構(gòu)將應(yīng)用拆分為一套小且互相關(guān)聯(lián)的服務(wù)。
一個(gè)微服務(wù)一般完成某個(gè)特定的功能,比如訂單管理、客戶管理等。每個(gè)微服務(wù)都是一個(gè)微型應(yīng)用,有著自己六邊形架構(gòu),包括商業(yè)邏輯和各種接口。有的微服務(wù)通過暴露 API 被別的微服務(wù)或者應(yīng)用客戶端所用;有的微服務(wù)則通過網(wǎng)頁(yè) UI 實(shí)現(xiàn)。在運(yùn)行時(shí),每個(gè)實(shí)例通常是一個(gè)云虛擬機(jī)或者 Docker 容器。
對(duì)于前文所述的系統(tǒng),一種可能的系統(tǒng)分解圖如下:
應(yīng)用的每個(gè)功能區(qū)都由其自身微服務(wù)實(shí)施。此外,整個(gè)網(wǎng)頁(yè)應(yīng)用被拆分為一套簡(jiǎn)單的網(wǎng)頁(yè)應(yīng)用(比如我們的打車軟件拆分為乘客應(yīng)用和司機(jī)應(yīng)用),從而能夠輕松地針對(duì)特定用戶、設(shè)備或者用戶案例進(jìn)行單獨(dú)部署。
每個(gè)后端服務(wù)包括一個(gè) REST API 和由其它服務(wù)提供的服務(wù)消耗 API。例如,司機(jī)管理服務(wù)使用“通知”服務(wù)器來告知司機(jī)即將的行程。UI 服務(wù)喚醒其它服務(wù),從而呈現(xiàn)網(wǎng)頁(yè)。這些服務(wù)也可能用到基于信息的異步通信。內(nèi)部服務(wù)通信會(huì)在本系列文章中詳述。
有的 REST API 也對(duì)司機(jī)和乘客的移動(dòng)應(yīng)用開放。這些應(yīng)用并不能直接訪問后端服務(wù)器,相反,通信由名為 API Gateway 的中間人調(diào)解。AIP Gateway 負(fù)責(zé)負(fù)載均衡、緩存、訪問控制、API 計(jì)費(fèi)、監(jiān)控等,通過 NGINX 高效實(shí)施。本系列的后續(xù)文章將會(huì)講解 API Gateway。
上圖是 Scale Cube 的 3D 模型,來自《The Art of Scalability》 一書。微服務(wù)架構(gòu)范式對(duì)應(yīng) Y 軸,X 軸由負(fù)載均衡器后端運(yùn)行的多個(gè)應(yīng)用副本組成,Z 軸(數(shù)據(jù)分割)將需求路由到相關(guān)服務(wù)。
應(yīng)用通常同時(shí)使用這三種不同類型的擴(kuò)展。Y 軸擴(kuò)展將應(yīng)用分解為如圖一(https://www.nginx.com/wp-content/uploads/2015/05/Graph-031-e1431992337817.png)所示的微服務(wù)。在運(yùn)行時(shí)維度,X 軸擴(kuò)展在輸出和可用性的負(fù)載均衡后運(yùn)行多個(gè)實(shí)例。部分應(yīng)用會(huì)使用 Z 軸擴(kuò)展來對(duì)服務(wù)進(jìn)行數(shù)據(jù)分割。下圖展示了行程管理服務(wù)(Trip Management)是如何使用 Docker 部署到 AWS EC2 上的。
在運(yùn)行時(shí),行程管理服務(wù)包括多個(gè)服務(wù)實(shí)例,每個(gè)服務(wù)實(shí)例都是一個(gè) Docker 容器。為了實(shí)現(xiàn)高可用性,這些容器運(yùn)行在多個(gè)云虛擬機(jī)上。在應(yīng)用實(shí)例前面是 NGINX 這樣的負(fù)載均衡,將請(qǐng)求分發(fā)給全部實(shí)例。負(fù)載均衡也可以處理緩存、訪問控制、 API 測(cè)量和監(jiān)控等。
微服務(wù)架構(gòu)范式對(duì)應(yīng)用和數(shù)據(jù)庫(kù)的關(guān)系影響巨大。每個(gè)服務(wù)都有自身的數(shù)據(jù)庫(kù)計(jì)劃,而不與其它服務(wù)共享同一個(gè)數(shù)據(jù)庫(kù)。一方面,這個(gè)方法類似企業(yè)級(jí)數(shù)據(jù)模型。同時(shí),它也導(dǎo)致部分?jǐn)?shù)據(jù)的重復(fù)。然而,要想從微服務(wù)中獲益,為每個(gè)服務(wù)提供單個(gè)的數(shù)據(jù)庫(kù)計(jì)劃就非常必要,這能保證松散耦合。下面的圖表展示了示例應(yīng)用的數(shù)據(jù)庫(kù)架構(gòu)。
每個(gè)服務(wù)都有其自己的數(shù)據(jù)庫(kù)。此外,單個(gè)服務(wù)可以使用符合自己需要的特定類型的數(shù)據(jù)庫(kù),即多語言一致性架構(gòu)。例如,為了發(fā)現(xiàn)附近乘客,駕駛員管理服務(wù)必須使用高效支持地理位置請(qǐng)求的數(shù)據(jù)庫(kù)。
表面上看,微服務(wù)架構(gòu)范式與 SOA 非常類似,這兩種架構(gòu)都包括一套服務(wù)。然而,微服務(wù)架構(gòu)范式被看作不包含某些功能的 SOA 。這些功能包括網(wǎng)絡(luò)服務(wù)說明( WS-* )和 Enterprise Service Bus (ESB) 的商品化和請(qǐng)求包。基于微服務(wù)的應(yīng)用更青睞 REST 這樣簡(jiǎn)單的、輕量級(jí)的協(xié)議,而不是 WS-* 。他們也極力避免在微服務(wù)中使用 ESBs 及類似功能。微服務(wù)架構(gòu)范式也拒絕 SOA 的其它部分,比如 canonical schema 的概念。
微服務(wù)架構(gòu)的好處
微服務(wù)架構(gòu)模式有很多好處。首先,通過分解巨大單體應(yīng)用為多個(gè)服務(wù)方法解決了復(fù)雜性問題。在功能不變的情況下,應(yīng)用被分解為多個(gè)可管理的分支或服務(wù)。每個(gè)服務(wù)都有一個(gè)用 RPC- 或者消息驅(qū)動(dòng) API 定義清楚的邊界。微服務(wù)架構(gòu)模式給采用單體式編碼方式很難實(shí)現(xiàn)的功能提供了模塊化的解決方案,由此,單個(gè)服務(wù)很容易開發(fā)、理解和維護(hù)。
第二,這種架構(gòu)使得每個(gè)服務(wù)都可以有專門開發(fā)團(tuán)隊(duì)來開發(fā)。開發(fā)者可以自由選擇開發(fā)技術(shù),提供 API 服務(wù)。當(dāng)然,許多公司試圖避免混亂,只提供某些技術(shù)選擇。然后,這種自由意味著開發(fā)者不需要被迫使用某項(xiàng)目開始時(shí)采用的過時(shí)技術(shù),他們可以選擇現(xiàn)在的技術(shù)。甚至于,因?yàn)榉?wù)都是相對(duì)簡(jiǎn)單,即使用現(xiàn)在技術(shù)重寫以前代碼也不是很困難的事情。
第三,微服務(wù)架構(gòu)模式使得每個(gè)微服務(wù)獨(dú)立部署,開發(fā)者不再需要協(xié)調(diào)其它服務(wù)部署對(duì)本服務(wù)的影響。這種改變可以加快部署速度,譬如 UI 團(tuán)隊(duì)可以采用 AB 測(cè)試并快速部署變化。微服務(wù)架構(gòu)模式使得持續(xù)化部署成為可能。
最后,微服務(wù)架構(gòu)模式使得每個(gè)服務(wù)獨(dú)立擴(kuò)展。你可以根據(jù)每個(gè)服務(wù)的規(guī)模來部署滿足需求的實(shí)利。甚至于,你可以使用更適合于服務(wù)資源需求的硬件。比如,你可以在 EC2 Compute Optimized instances 上部署 CPU 敏感的服務(wù),而在 EC2 memory-optimized instances 上部署內(nèi)存數(shù)據(jù)庫(kù)。
微服務(wù)架構(gòu)的不足
Fred Brooks 在 30 年前寫道 “there are no silver bullets”,像任何其它科技一樣,微服務(wù)架構(gòu)也有不足。其中一個(gè)跟他的名字類似,“微服務(wù)”強(qiáng)調(diào)了服務(wù)大小,實(shí)際上,有一些開發(fā)者鼓吹建立稍微大一些的,10-100 LOC服務(wù)組。盡管小服務(wù)更樂于被采用,但是不要忘了微服務(wù)只是結(jié)果,而不是最終目的。微服務(wù)的目的是有效的拆分應(yīng)用,實(shí)現(xiàn)敏捷開發(fā)和部署。
另外一個(gè)不足之處在于,微服務(wù)應(yīng)用是分布式系統(tǒng),由此會(huì)帶來固有的復(fù)雜性。開發(fā)者需要在 RPC 或者消息傳遞之間選擇并完成進(jìn)程間通訊機(jī)制。此外,他們必須寫代碼來處理消息傳遞中速度過慢或者不可用等局部失效問題。當(dāng)然這并不是什么難事,但相對(duì)于單體式應(yīng)用中通過語言層級(jí)的方法或者進(jìn)程調(diào)用,微服務(wù)下這種技術(shù)顯得更復(fù)雜一些。
另外一個(gè)關(guān)于微服務(wù)的挑戰(zhàn)來自于分區(qū)的數(shù)據(jù)庫(kù)架構(gòu)。同時(shí)更新多個(gè)業(yè)務(wù)主體的事務(wù)很普遍。這種事務(wù)對(duì)于單體式應(yīng)用來說很容易,因?yàn)橹挥幸粋€(gè)數(shù)據(jù)庫(kù)。在微服務(wù)架構(gòu)應(yīng)用中,需要更新不同服務(wù)所使用的不同的數(shù)據(jù)庫(kù)。使用分布式事務(wù)并不一定是好的選擇,不僅僅是因?yàn)?CAP 理論,還因?yàn)楫?dāng)前高擴(kuò)展性的 NoSQL 數(shù)據(jù)庫(kù)和消息傳遞中間件并不支持這一需求。最終你不得不使用一個(gè)最終一致性的方法,從而對(duì)開發(fā)者提出了更高的要求和挑戰(zhàn)。
測(cè)試一個(gè)基于微服務(wù)架構(gòu)的應(yīng)用也是很復(fù)雜的任務(wù)。比如,對(duì)于采用流行的 Spring Boot 架構(gòu)的單體式 web 應(yīng)用,測(cè)試它的 REST API,是很容易的事情。反過來,同樣的服務(wù)測(cè)試需要啟動(dòng)與它有關(guān)的所有服務(wù)(至少需要這些服務(wù)的 stubs)。再重申一次,不能低估了采用微服務(wù)架構(gòu)帶來的復(fù)雜性。
另外一個(gè)挑戰(zhàn)在于,微服務(wù)架構(gòu)模式應(yīng)用的改變將會(huì)波及多個(gè)服務(wù)。比如,假設(shè)你在完成一個(gè)案例,需要修改服務(wù)A、B、C,而 A 依賴 B,B 依賴 C。在單體應(yīng)用中,你只需要改變相關(guān)模塊,整合變化,部署就好了。對(duì)比之下,微服務(wù)架構(gòu)模式就需要考慮相關(guān)改變對(duì)不同服務(wù)的影響。比如,你需要更新服務(wù) C,然后是 B,最后才是 A。幸運(yùn)的是,許多改變一般只影響一個(gè)服務(wù),而需要協(xié)調(diào)多服務(wù)的改變很少。
部署一個(gè)微服務(wù)應(yīng)用也很復(fù)雜,一個(gè)單體應(yīng)用只需要在復(fù)雜均衡器后面部署各自的服務(wù)器就好了。每個(gè)應(yīng)用實(shí)例是需要配置諸如數(shù)據(jù)庫(kù)和消息中間件等基礎(chǔ)服務(wù)。相比之下,一個(gè)微服務(wù)應(yīng)用一般由大批服務(wù)構(gòu)成。根據(jù) Adrian Cockcroft 的分享,Hailo 由 160 個(gè)不同服務(wù)構(gòu)成,而 NetFlix 則超過 600 個(gè)服務(wù)。每個(gè)服務(wù)都有多個(gè)實(shí)例,這就形成大量需要配置、部署、擴(kuò)展和監(jiān)控的部分。除此之外,你還需要完成一個(gè)服務(wù)發(fā)現(xiàn)機(jī)制(后續(xù)文章中發(fā)表),以用來發(fā)現(xiàn)與它通訊服務(wù)的地址(包括服務(wù)器地址和端口)。傳統(tǒng)的解決問題辦法并不能解決這么復(fù)雜的問題。最終,成功部署一個(gè)微服務(wù)應(yīng)用需要開發(fā)者有足夠的控制部署方法,并高度自動(dòng)化。
自動(dòng)化的方法之一是使用譬如 Cloud Foundry 這樣的 PaaS 服務(wù)。PaaS 能讓開發(fā)者輕松部署和管理微服務(wù),讓他們無需為獲取并配置 IT 資源勞神。同時(shí),配置 PaaS 的系統(tǒng)和網(wǎng)絡(luò)專家可以采用最佳實(shí)踐和策略來簡(jiǎn)化這些問題。另外一個(gè)自動(dòng)部署微服務(wù)應(yīng)用的方法是開發(fā)自己的基礎(chǔ) PaaS 系統(tǒng)。通常的起步方式是 Mesos 或 Kubernetes 這樣的集群管理方案,配合 Docker 使用。作為一種基于軟件的應(yīng)用交付方法,NGINX 能夠方便地在微服務(wù)層面提供緩沖、權(quán)限控制、API 統(tǒng)計(jì)、以及監(jiān)控。我們會(huì)在后續(xù)的文章中分析它如何解決這些問題。
總結(jié)
構(gòu)建復(fù)雜的應(yīng)用的確非常困難。單體式的架構(gòu)更適合輕量級(jí)的簡(jiǎn)單應(yīng)用。如果你用它來開發(fā)復(fù)雜應(yīng)用,那真的會(huì)很糟糕。微服務(wù)架構(gòu)模式可以用來構(gòu)建復(fù)雜應(yīng)用,當(dāng)然,這種架構(gòu)模型也有自己的缺點(diǎn)和挑戰(zhàn)。
在后續(xù)的博客中,我會(huì)深入探索微服務(wù)架構(gòu)模式,并討論多個(gè)話題,包括服務(wù)發(fā)現(xiàn)、服務(wù)部署選擇、以及將單體應(yīng)用拆分為多個(gè)服務(wù)的策略。
?
轉(zhuǎn)載于:https://www.cnblogs.com/ZJOE80/p/5788351.html
總結(jié)
- 上一篇: Linux中source是什么指令?
- 下一篇: NDTTS-II变压器综合试验系统