做者簡介:Chris Richardson,世界著名的軟件架構師,經典著做《POJOS IN ACTION》的做者,cloudfoundry.com 的創始人html
微服務目前正受到大量的關注,成爲文章、博客、會議討論的熱點。與此同時,也有人質疑微服務並不是新事物,只是SOA(Service Oriented Architecure)的二度封裝。不管是追捧仍是質疑,微服務架構擁有巨大的優點,尤爲是讓敏捷開發和複雜的企業應用支付成爲可能。nginx
本系列包含7篇文章,介紹了微服務架構的各個因素,瞭解微服務模型的優劣,以此來指導微服務是否符合您的項目,如何應用等。程序員
Chris Richardson 微服務系列翻譯全7篇連接:web
原文連接:Introduction to Microservices
數據庫
假設咱們要開發一個全新的與 Uber 競爭的打車軟件。在需求整理後,須要建立一個新項目,這個應用可應該有以下六邊形的架構模塊:編程
應用的核心是業務邏輯:它定義了服務、領域對象和事件模塊。各類適配器圍繞核心與外部交互,適配器包括了數據庫訪問組件、生產與消費信息的消息組件、以及API或web UI組件。小程序
儘管按模塊化進行設計,整個應用仍須要總體打包、部署。實際格式與選擇的編程語言和框架相關,例如:Java 應用會打成 War 包部署到 Tomcat 或 Jetty 等服務器;還有一部分會打成 Jar 包;Rails 和 Node.js 應用直接以目錄結構的形式部署。後端
這種單一應用能夠經過 IDE 工具來方便的構建,也易於部署與測試,擴展應用時只須要添加負載均衡。在項目早起,這樣作是頗有效的。緩存
很不幸,這種簡單的方法存在着侷限性:服務器
1)一個成功的應用會隨着時間而變的的愈來愈大。在每一個敏捷 Sprint 期間,開發團隊會實現更多的功能,添加新的代碼。幾年以後,當初簡單的小應用會複雜到任何一個開發者都沒法徹底理解,修復 bug 和開發新功能也所以耗時頗多。而且這是一個惡性循環,代碼越難理解,正確的修改就越難。最後開發團隊則會飽受折磨,苦苦掙扎與敏捷開發和交付中。
2)應用程序越大,啓動時間就越長。例如在最近的調查中,很多開發者指出啓動時長達12分鐘。若是開發過程當中頻繁的重啓應用,那麼就會浪費大量的時間,效率天然就低下。
3)龐大複雜的單體應用另外一問題就是難以持續交付。如今SaaS應用的宗旨是若是有改動,可以天天在生產環境部署屢次。然而要讓複雜的單體應用達到這個水平卻很困難。若是更新應用的某個部分,必須從新部署整個應用,啓動一次的時間就很漫長,並且不能徹底預期修改的影響,不得不進行大量的人工測試。結果就是,持續部署變的不可能。
4)單體應用在多個模塊對資源需求有衝突時很難擴展。例如:模塊1實現了 CPU密集型的圖像處理邏輯,最適合部署到 Amazon EC2 Compute Optimized instances;而模塊2須要內存數據庫,更適合部署到 EC2 Memory-optimized instances,這兩個模塊一塊兒部署時,不得不在硬件方面進行妥協。
5)單體應用的另外一問題就是可靠性。全部模塊運行在同一進程中,任何模塊的一個bug(例如:內存泄露)均可能拖垮整個應用。
6)單體應用很難擁抱新的框架和編程語言。例如:你有200萬行代碼性 XYZ 框架,若是須要使用 ABC 框架重寫,將會耗費大量的時間和人力。這就在嘗試新技術時候存在巨大的阻礙。
最後總結一下,從一個業務清晰,幾個程序員就能理解的小程序,逐步成長爲一個臃腫、沒法理解的龐然大物。使用過期、效率低下的技術來實現(畢竟技術在進步),招聘都變的困難。整個應用擴展性、可靠性差,敏捷開發和持續交付幾乎成爲不可能。
面對這些,該何去何從?
不少公司,例如Amazon、eBay、Netflix,都已經經過擁抱微服務來解決以上問題了,他們再也不是構建一個可怕的單體應用,而是經過微服務架構將應用拆分爲更小的、相互鏈接的服務。
一個微服務通常完成某個特定的功能,例如:訂單管理、客戶管理等。每一個微服務都是一個小應用,有自身的邏輯以及適配器來構成六邊形架構。有的微服務會暴露 API 供其餘微服務或客戶使用,有的微服務會實現 Web UI。運行時,每一個實例一般是一個虛擬雲主機或 Docker 容器。下面是對上述老架構的拆分:
應用的每一個功能都由自身微服務實現。整個應用被拆分爲一系列更小的 Web應用(例如:乘客管理、司機管理)。拆分後更方便爲特定用戶、設備或案例而單獨部署。
每一個後端服務暴露 REST API,也會調用其餘服務提供的 API。例如:司機管理服務會使用 通知服務 來告訴司機的行程;UI服務調用其餘服務來呈現頁面。服務之間也可能使用異步的消息通訊。
部分 REST API 也會提供給司機和乘客的移動 APP 使用,這些應用不能直接訪問後端服務器,而是經過 API網關 來協調訪問。API網關的職責有:負載均衡、緩存、訪問控制、API計費、監控等。
上圖是 Scale Cube 的 3D 模型,來自《The Art of Scalability》一書,應用通常以3個維度進行擴展:
下圖展現了行程管理服務採用 Docker鏡像部署到 AWS EC2上:
行程管理服務由多個實例組成,每一個實例就是一個 Docker 容器。爲了達到高可用,容器會在多個虛擬雲主機上。實例前是 Nginx 負載均衡,將請求分發到所有實例,也處理緩存、訪問控制、API測量和監控等。
微服務架構也影響應用和數據庫之間的關係。每一個服務都有自身的數據庫,而不與其餘服務共享同一個數據庫。這樣一來,數據模型會比較奇怪,也會出現部分數據冗餘。然而,要想從微服務中受益,這樣作仍是頗有必要的,由於微服務提倡的就是鬆耦合。下圖展現了微服務架構下應用的數據架構:
此外,每一個服務還能夠選用符合本身特性需求的數據庫,例如:司機須要查找附近的乘客,那司機管理服務就須要使用能高效支持地理位置查詢的數據庫。
表面上看,微服務和 SOA 很是相似,這兩種架構都有一系列服務。然而,微服務能夠當作沒有 web service規範和 EBS套件 約束的 SOA。微服務更青睞採用 REST 這樣簡單、輕量級的協議,而不是老舊的 web service。微服務也會去避免使用笨重的 EBS 套件而喜歡使用實現 EBS 部分功能的輕量級工具。微服務也避免 SOA 諸如canonical schema 的定義。
微服務架構有不少好處:
1)經過將巨大的單體應用拆分爲多個服務,解決了單體複雜度問題。拆分後總體功能沒有改變,但應用變成了多個方便管理的小應用。每一個服務經過 RPC 或 消息驅動的 API定義清晰的服務邊界。拆分後的服務能更快的部署,更容易理解、開發和維護。
2)拆分後的服務可由更專一的開發團隊來維護。程序員可在 API 約定下自由的選擇合適的技術。更重要的是,每一個服務拆分的很小,使用現有技術重寫老的服務也不是很困難的事。
3)微服務架構使得獨立部署成爲可能。開發者不須要協調其餘服務部署對本服務的影響(單體應用,該一部分可能對其餘部分產生影響,某個更改可能涉及多個模塊的協調),這種改變能夠加快部署,快速迭代而不用等整個應用部署。微服務使可持續交付成爲可能。
4)微服務使得每一個服務獨立擴展。能夠針對某些有容量和可用性要求的微服務進行擴展,部署多個服務而不是多個單體應用去得到性能提高。能夠針對服務需求使用合適的硬件資源,例如:在EC2 Compute Optimized instances 部署 CPU密集型的圖片處理服務,在 EC2 memory-optimized instances 上部署有內存數據庫需求的服務。
正如Fred Brooks 30年前所說:『沒有銀彈』,微服務也有其不足和挑戰:
1)劣勢之一就是它的名字,微服務過度強調了服務的大小,實際上有開發者號召你們寫10-100行代碼的微服務。然而微服務更想表達的是一種工具和途徑,並非最終目的(爲微服務而微服務)。微服務是爲了便利敏捷開發和部署而去有效的拆分應用。
2)由單體應用拆分爲分佈式應用帶來的複雜。開發者須要基於消息或 RPC 的方式進行進程間的通訊,還須要寫額外的代碼去處理請求超時或不可用致使的局部故障。
3)分區的數據庫架構。一個事務中更新多個業務記錄是常見的,單體應用實現事務比較簡單,畢竟是共用同一個數據庫。而微服務架構中,就須要更新多個服務的多個數據庫,通常不使用分佈式事務,不只僅是由於CAP 理論,還由於一些流行的 NoSQL 和 MQ 並不支持這一需求。最終還得使用最終一致性方案,而這對開發者提出了更高的挑戰。
4)測試微服務的應用也更加複雜。例如,採用了 Spring Boot 這種框架的單體應用,測試它的 REST API比較容易。而在微服務中,須要啓動或 mock 其依賴的服務才能完成。
5)跨服務的改動。例如:假設你完成一個需求,須要修改A、B、C服務,而A 依賴 B,B 依賴 C。單體應用中能夠簡單的修改對應的模塊,而後一塊兒部署。而微服務架構下,你須要當心翼翼的計劃和協調每一個服務的改動和發佈:先更新C,再更新B,最後更新A。
6)部署微服務應用也更加複雜。單體應用都是相同的,拷貝部署到負載均衡後面就好了。而微服務應用由大量的服務組成,例如:NetFlix 有超過 600 個服務。就有不少部分須要去配置、部署、擴展和監控。此外還須要實現服務發現機制,用來讓服務找到它須要通訊的服務的地址。最終,成功部署一個微服務應用須要開發者有足夠的部署方法並實現高水平的自動化。自動化的方法之一就是使用Cloud Foundry 這樣的 PaaS 服務,讓開發者無需糾結於購買和配置 IT 資源。另外一種方法是開發本身的 PaaS平臺,一般起步方式是使用Mesos 或Kubernetes 這樣的集羣管理方案,配合 Docker 的容器技術使用。
構建複雜的應用自己就是困難的事情,單體架構在針對簡單、輕量級的應用時是好的。但運用在複雜的應用上會變得痛苦不堪。儘管微服務架構有諸多的缺點和挑戰,但對於複雜的、演進的應用來說是一個更好的選擇。
後續文章中將介紹微服務的幾個方面,討論一些諸如服務發現、服務部署和重構單體應用到微服務的話題。