作者簡介:Chris Richardson师郑,世界著名的軟件架構(gòu)師林束,經(jīng)典著作《POJOS IN ACTION》的作者,cloudfoundry.com 的創(chuàng)始人
微服務(wù)目前正受到大量的關(guān)注,成為文章洁闰、博客帖努、會(huì)議討論的熱點(diǎn)梢薪。與此同時(shí)予借,也有人質(zhì)疑微服務(wù)并非新事物,只是SOA(Service Oriented Architecure)的二度封裝昌跌。無論是追捧還是質(zhì)疑仰禀,微服務(wù)架構(gòu)擁有巨大的優(yōu)勢,尤其是讓敏捷開發(fā)和復(fù)雜的企業(yè)應(yīng)用支付成為可能蚕愤。
本系列包含7篇文章答恶,介紹了微服務(wù)架構(gòu)的各個(gè)因素,了解微服務(wù)模型的優(yōu)劣审胸,以此來指導(dǎo)微服務(wù)是否符合您的項(xiàng)目亥宿,如何應(yīng)用等。
Chris Richardson 微服務(wù)系列翻譯全7篇鏈接:
- 微服務(wù)介紹(本文)
- 構(gòu)建微服務(wù)之使用API網(wǎng)關(guān)
- 構(gòu)建微服務(wù)之微服務(wù)架構(gòu)的進(jìn)程通訊
- 微服務(wù)架構(gòu)中的服務(wù)發(fā)現(xiàn)
- 微服務(wù)之事件驅(qū)動(dòng)的數(shù)據(jù)管理
- 微服務(wù)部署
- 重構(gòu)單體應(yīng)用為微服務(wù)
原文鏈接:Introduction to Microservices
構(gòu)建單體應(yīng)用
假設(shè)我們要開發(fā)一個(gè)全新的與 Uber 競爭的打車軟件砂沛。在需求整理后烫扼,需要?jiǎng)?chuàng)建一個(gè)新項(xiàng)目,這個(gè)應(yīng)用可應(yīng)該有如下六邊形的架構(gòu)模塊:
應(yīng)用的核心是業(yè)務(wù)邏輯:它定義了服務(wù)碍庵、領(lǐng)域?qū)ο蠛褪录K映企。各種適配器圍繞核心與外部交互,適配器包括了數(shù)據(jù)庫訪問組件静浴、生產(chǎn)與消費(fèi)信息的消息組件堰氓、以及API或web UI組件。
盡管按模塊化進(jìn)行設(shè)計(jì)苹享,整個(gè)應(yīng)用仍需要整體打包双絮、部署。實(shí)際格式與選擇的編程語言和框架相關(guān)得问,例如:Java 應(yīng)用會(huì)打成 War 包部署到 Tomcat 或 Jetty 等服務(wù)器囤攀;還有一部分會(huì)打成 Jar 包;Rails 和 Node.js 應(yīng)用直接以目錄結(jié)構(gòu)的形式部署宫纬。
這種單一應(yīng)用可以通過 IDE 工具來方便的構(gòu)建焚挠,也易于部署與測試,擴(kuò)展應(yīng)用時(shí)只需要添加負(fù)載均衡漓骚。在項(xiàng)目早起蝌衔,這樣做是很有效的榛泛。
邁向單體的地獄
很不幸,這種簡單的方法存在著局限性:
1)一個(gè)成功的應(yīng)用會(huì)隨著時(shí)間而變的的越來越大噩斟。在每個(gè)敏捷 Sprint 期間曹锨,開發(fā)團(tuán)隊(duì)會(huì)實(shí)現(xiàn)更多的功能,添加新的代碼剃允。幾年之后艘希,當(dāng)初簡單的小應(yīng)用會(huì)復(fù)雜到任何一個(gè)開發(fā)者都無法完全理解,修復(fù) bug 和開發(fā)新功能也因此耗時(shí)頗多硅急。并且這是一個(gè)惡性循環(huán),代碼越難理解佳遂,正確的修改就越難营袜。最后開發(fā)團(tuán)隊(duì)則會(huì)飽受折磨,苦苦掙扎與敏捷開發(fā)和交付中丑罪。
2)應(yīng)用程序越大荚板,啟動(dòng)時(shí)間就越長。例如在最近的調(diào)查中吩屹,不少開發(fā)者指出啟動(dòng)時(shí)長達(dá)12分鐘跪另。如果開發(fā)過程中頻繁的重啟應(yīng)用,那么就會(huì)浪費(fèi)大量的時(shí)間煤搜,效率自然就低下免绿。
3)龐大復(fù)雜的單體應(yīng)用另一問題就是難以持續(xù)交付。現(xiàn)在SaaS應(yīng)用的宗旨是如果有改動(dòng)擦盾,能夠每天在生產(chǎn)環(huán)境部署多次嘲驾。然而要讓復(fù)雜的單體應(yīng)用達(dá)到這個(gè)水平卻很困難。如果更新應(yīng)用的某個(gè)部分迹卢,必須重新部署整個(gè)應(yīng)用辽故,啟動(dòng)一次的時(shí)間就很漫長,而且不能完全預(yù)期修改的影響腐碱,不得不進(jìn)行大量的人工測試誊垢。結(jié)果就是,持續(xù)部署變的不可能症见。
4)單體應(yīng)用在多個(gè)模塊對(duì)資源需求有沖突時(shí)很難擴(kuò)展喂走。例如:模塊1實(shí)現(xiàn)了 CPU密集型的圖像處理邏輯,最適合部署到 Amazon EC2 Compute Optimized instances筒饰;而模塊2需要內(nèi)存數(shù)據(jù)庫缴啡,更適合部署到 EC2 Memory-optimized instances,這兩個(gè)模塊一起部署時(shí)瓷们,不得不在硬件方面進(jìn)行妥協(xié)业栅。
5)單體應(yīng)用的另一問題就是可靠性秒咐。所有模塊運(yùn)行在同一進(jìn)程中,任何模塊的一個(gè)bug(例如:內(nèi)存泄露)都可能拖垮整個(gè)應(yīng)用碘裕。
6)單體應(yīng)用很難擁抱新的框架和編程語言携取。例如:你有200萬行代碼性 XYZ 框架,如果需要使用 ABC 框架重寫帮孔,將會(huì)耗費(fèi)大量的時(shí)間和人力雷滋。這就在嘗試新技術(shù)時(shí)候存在巨大的阻礙。
最后總結(jié)一下文兢,從一個(gè)業(yè)務(wù)清晰晤斩,幾個(gè)程序員就能理解的小程序,逐步成長為一個(gè)臃腫姆坚、無法理解的龐然大物澳泵。使用過時(shí)、效率低下的技術(shù)來實(shí)現(xiàn)(畢竟技術(shù)在進(jìn)步)兼呵,招聘都變的困難兔辅。整個(gè)應(yīng)用擴(kuò)展性、可靠性差击喂,敏捷開發(fā)和持續(xù)交付幾乎成為不可能维苔。
面對(duì)這些,該何去何從懂昂?
微服務(wù)-處理這些復(fù)雜問題
很多公司介时,例如Amazon、eBay忍法、Netflix潮尝,都已經(jīng)通過擁抱微服務(wù)來解決以上問題了,他們不再是構(gòu)建一個(gè)可怕的單體應(yīng)用饿序,而是通過微服務(wù)架構(gòu)將應(yīng)用拆分為更小的勉失、相互連接的服務(wù)。
一個(gè)微服務(wù)一般完成某個(gè)特定的功能原探,例如:訂單管理乱凿、客戶管理等。每個(gè)微服務(wù)都是一個(gè)小應(yīng)用咽弦,有自身的邏輯以及適配器來構(gòu)成六邊形架構(gòu)徒蟆。有的微服務(wù)會(huì)暴露 API 供其他微服務(wù)或客戶使用,有的微服務(wù)會(huì)實(shí)現(xiàn) Web UI型型。運(yùn)行時(shí)段审,每個(gè)實(shí)例通常是一個(gè)虛擬云主機(jī)或 Docker 容器。下面是對(duì)上述老架構(gòu)的拆分:
應(yīng)用的每個(gè)功能都由自身微服務(wù)實(shí)現(xiàn)闹蒜。整個(gè)應(yīng)用被拆分為一系列更小的 Web應(yīng)用(例如:乘客管理寺枉、司機(jī)管理)抑淫。拆分后更方便為特定用戶、設(shè)備或案例而單獨(dú)部署姥闪。
每個(gè)后端服務(wù)暴露 REST API始苇,也會(huì)調(diào)用其他服務(wù)提供的 API。例如:司機(jī)管理服務(wù)會(huì)使用 通知服務(wù) 來告訴司機(jī)的行程筐喳;UI服務(wù)調(diào)用其他服務(wù)來呈現(xiàn)頁面催式。服務(wù)之間也可能使用異步的消息通信。
部分 REST API 也會(huì)提供給司機(jī)和乘客的移動(dòng) APP 使用避归,這些應(yīng)用不能直接訪問后端服務(wù)器荣月,而是通過 API網(wǎng)關(guān) 來協(xié)調(diào)訪問。API網(wǎng)關(guān)的職責(zé)有:負(fù)載均衡梳毙、緩存喉童、訪問控制、API計(jì)費(fèi)顿天、監(jiān)控等。
上圖是 Scale Cube的 3D 模型蔑担,來自《The Art of Scalability》一書牌废,應(yīng)用一般以3個(gè)維度進(jìn)行擴(kuò)展:
- X軸 :水平擴(kuò)展,通過克隆的方式擴(kuò)展啤握。一般是負(fù)載均衡后運(yùn)行多個(gè)應(yīng)用副本鸟缕,達(dá)到某個(gè)服務(wù)的高吞吐和高可用性。
- Y軸 :功能拆分排抬,哦通過拆分不同的事務(wù)進(jìn)行擴(kuò)展懂从。微服務(wù)對(duì)應(yīng)著 Y 軸,將單體應(yīng)用拆分為微服務(wù)蹲蒲。
- Z軸 :數(shù)據(jù)分區(qū)番甩,通過分隔相同的事務(wù)進(jìn)行擴(kuò)展,例如:數(shù)據(jù)庫分庫分表届搁。
下圖展示了行程管理服務(wù)采用 Docker鏡像部署到 AWS EC2上:
行程管理服務(wù)由多個(gè)實(shí)例組成缘薛,每個(gè)實(shí)例就是一個(gè) Docker 容器。為了達(dá)到高可用卡睦,容器會(huì)在多個(gè)虛擬云主機(jī)上宴胧。實(shí)例前是 Nginx 負(fù)載均衡,將請(qǐng)求分發(fā)到全部實(shí)例表锻,也處理緩存恕齐、訪問控制、API測量和監(jiān)控等瞬逊。
微服務(wù)架構(gòu)也影響應(yīng)用和數(shù)據(jù)庫之間的關(guān)系显歧。每個(gè)服務(wù)都有自身的數(shù)據(jù)庫仪或,而不與其他服務(wù)共享同一個(gè)數(shù)據(jù)庫。這樣一來追迟,數(shù)據(jù)模型會(huì)比較奇怪溶其,也會(huì)出現(xiàn)部分?jǐn)?shù)據(jù)冗余。然而敦间,要想從微服務(wù)中受益瓶逃,這樣做還是很有必要的,因?yàn)槲⒎?wù)提倡的就是松耦合廓块。下圖展示了微服務(wù)架構(gòu)下應(yīng)用的數(shù)據(jù)架構(gòu):
此外厢绝,每個(gè)服務(wù)還可以選用符合自己特性需求的數(shù)據(jù)庫,例如:司機(jī)需要查找附近的乘客带猴,那司機(jī)管理服務(wù)就需要使用能高效支持地理位置查詢的數(shù)據(jù)庫昔汉。
表面上看,微服務(wù)和 SOA 非常類似拴清,這兩種架構(gòu)都有一系列服務(wù)靶病。然而,微服務(wù)可以看成沒有 web service規(guī)范和 EBS套件 約束的 SOA口予。微服務(wù)更青睞采用 REST 這樣簡單娄周、輕量級(jí)的協(xié)議,而不是老舊的 web service沪停。微服務(wù)也會(huì)去避免使用笨重的 EBS 套件而喜歡使用實(shí)現(xiàn) EBS 部分功能的輕量級(jí)工具煤辨。微服務(wù)也避免 SOA 諸如canonical schema 的定義。
微服務(wù)的優(yōu)勢
微服務(wù)架構(gòu)有很多好處:
1)通過將巨大的單體應(yīng)用拆分為多個(gè)服務(wù)木张,解決了單體復(fù)雜度問題众辨。拆分后整體功能沒有改變,但應(yīng)用變成了多個(gè)方便管理的小應(yīng)用舷礼。每個(gè)服務(wù)通過 RPC 或 消息驅(qū)動(dòng)的 API定義清晰的服務(wù)邊界鹃彻。拆分后的服務(wù)能更快的部署,更容易理解妻献、開發(fā)和維護(hù)浮声。
2)拆分后的服務(wù)可由更專注的開發(fā)團(tuán)隊(duì)來維護(hù)。程序員可在 API 約定下自由的選擇合適的技術(shù)旋奢。更重要的是泳挥,每個(gè)服務(wù)拆分的很小,使用現(xiàn)有技術(shù)重寫老的服務(wù)也不是很困難的事至朗。
3)微服務(wù)架構(gòu)使得獨(dú)立部署成為可能屉符。開發(fā)者不需要協(xié)調(diào)其他服務(wù)部署對(duì)本服務(wù)的影響(單體應(yīng)用,該一部分可能對(duì)其他部分產(chǎn)生影響,某個(gè)更改可能涉及多個(gè)模塊的協(xié)調(diào))矗钟,這種改變可以加快部署唆香,快速迭代而不用等整個(gè)應(yīng)用部署。微服務(wù)使可持續(xù)交付成為可能吨艇。
4)微服務(wù)使得每個(gè)服務(wù)獨(dú)立擴(kuò)展躬它。可以針對(duì)某些有容量和可用性要求的微服務(wù)進(jìn)行擴(kuò)展东涡,部署多個(gè)服務(wù)而不是多個(gè)單體應(yīng)用去獲得性能提升冯吓。可以針對(duì)服務(wù)需求使用合適的硬件資源疮跑,例如:在EC2 Compute Optimized instances 部署 CPU密集型的圖片處理服務(wù)组贺,在 EC2 memory-optimized instances 上部署有內(nèi)存數(shù)據(jù)庫需求的服務(wù)。
微服務(wù)的不足
正如Fred Brooks 30年前所說:『沒有銀彈』祖娘,微服務(wù)也有其不足和挑戰(zhàn):
1)劣勢之一就是它的名字失尖,微服務(wù)過分強(qiáng)調(diào)了服務(wù)的大小,實(shí)際上有開發(fā)者號(hào)召大家寫10-100行代碼的微服務(wù)渐苏。然而微服務(wù)更想表達(dá)的是一種工具和途徑掀潮,并不是最終目的(為微服務(wù)而微服務(wù))。微服務(wù)是為了便利敏捷開發(fā)和部署而去有效的拆分應(yīng)用琼富。
2)由單體應(yīng)用拆分為分布式應(yīng)用帶來的復(fù)雜胧辽。開發(fā)者需要基于消息或 RPC 的方式進(jìn)行進(jìn)程間的通信,還需要寫額外的代碼去處理請(qǐng)求超時(shí)或不可用導(dǎo)致的局部故障公黑。
3)分區(qū)的數(shù)據(jù)庫架構(gòu)。一個(gè)事務(wù)中更新多個(gè)業(yè)務(wù)記錄是常見的摄咆,單體應(yīng)用實(shí)現(xiàn)事務(wù)比較簡單凡蚜,畢竟是共用同一個(gè)數(shù)據(jù)庫。而微服務(wù)架構(gòu)中吭从,就需要更新多個(gè)服務(wù)的多個(gè)數(shù)據(jù)庫朝蜘,一般不使用分布式事務(wù),不僅僅是因?yàn)镃AP 理論涩金,還因?yàn)橐恍┝餍械?NoSQL 和 MQ 并不支持這一需求谱醇。最終還得使用最終一致性方案,而這對(duì)開發(fā)者提出了更高的挑戰(zhàn)步做。
4)測試微服務(wù)的應(yīng)用也更加復(fù)雜副渴。例如,采用了 Spring Boot 這種框架的單體應(yīng)用全度,測試它的 REST API比較容易煮剧。而在微服務(wù)中,需要啟動(dòng)或 mock 其依賴的服務(wù)才能完成。
5)跨服務(wù)的改動(dòng)勉盅。例如:假設(shè)你完成一個(gè)需求佑颇,需要修改A、B草娜、C服務(wù)挑胸,而A 依賴 B,B 依賴 C宰闰。單體應(yīng)用中可以簡單的修改對(duì)應(yīng)的模塊茬贵,然后一起部署。而微服務(wù)架構(gòu)下议蟆,你需要小心翼翼的計(jì)劃和協(xié)調(diào)每個(gè)服務(wù)的改動(dòng)和發(fā)布:先更新C闷沥,再更新B,最后更新A咐容。
6)部署微服務(wù)應(yīng)用也更加復(fù)雜舆逃。單體應(yīng)用都是相同的,拷貝部署到負(fù)載均衡后面就行了戳粒。而微服務(wù)應(yīng)用由大量的服務(wù)組成路狮,例如:NetFlix 有超過 600 個(gè)服務(wù)。就有很多部分需要去配置蔚约、部署奄妨、擴(kuò)展和監(jiān)控。此外還需要實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)機(jī)制苹祟,用來讓服務(wù)找到它需要通信的服務(wù)的地址砸抛。最終,成功部署一個(gè)微服務(wù)應(yīng)用需要開發(fā)者有足夠的部署方法并實(shí)現(xiàn)高水平的自動(dòng)化树枫。自動(dòng)化的方法之一就是使用Cloud Foundry 這樣的 PaaS 服務(wù)直焙,讓開發(fā)者無需糾結(jié)于購買和配置 IT 資源。另一種方法是開發(fā)自己的 PaaS平臺(tái)砂轻,通常起步方式是使用Mesos 或Kubernetes 這樣的集群管理方案奔誓,配合 Docker 的容器技術(shù)使用。
總結(jié)
構(gòu)建復(fù)雜的應(yīng)用本身就是困難的事情搔涝,單體架構(gòu)在針對(duì)簡單厨喂、輕量級(jí)的應(yīng)用時(shí)是好的。但運(yùn)用在復(fù)雜的應(yīng)用上會(huì)變得痛苦不堪庄呈。盡管微服務(wù)架構(gòu)有諸多的缺點(diǎn)和挑戰(zhàn)蜕煌,但對(duì)于復(fù)雜的、演進(jìn)的應(yīng)用來講是一個(gè)更好的選擇诬留。
后續(xù)文章中將介紹微服務(wù)的幾個(gè)方面幌绍,討論一些諸如服務(wù)發(fā)現(xiàn)颁褂、服務(wù)部署和重構(gòu)單體應(yīng)用到微服務(wù)的話題。