一、搭建一個微服務框架所需要哪些技術(spring-cloud)
搭建一個微服務框架所需要哪些技術:
1、Eureka用於服務的註冊於發現
2、Feign支援服務的呼叫以及均衡負載
3、Hystrix處理服務的熔斷防止故障擴散
4、Spring Cloud Config服務叢集配置中心
5、Spring Cloud zuul提供負載均衡、反向代理、許可權認證的一個API gateway
二、要搞定微服務架構,先搞定RPC框架
一、需求緣起
服務化的一個好處就是,不限定服務的提供方使用什麼技術選型,能夠實現大公司跨團隊的技術解耦,如下圖:
服務A是歐洲團隊提供服務,歐洲團隊的技術背景是Java,可以用Java實現服務;
服務B是美洲團隊提供服務,可以用C++實現服務;
服務C是中國團隊提供服務,可以用Go實現服務;
服務的上游呼叫方,按照介面、協議即可完成對遠端服務的呼叫。
但實際上,99.9%的公司的團隊規模有限,技術團隊人數也有限,基本是使用同一套技術體系來呼叫和提供服務的:
這樣的話,如果沒有統一的服務框架,RPC框架,各個團隊的服務提供方就需要各自實現一套序列化、反序列化、網路框架、連線池、收發執行緒、超時處理、狀態機等“業務之外”的重複技術勞動,造成整體的低效。所以,統一RPC框架把上述“業務之外”的技術勞動統一處理,是服務化首要解決的問題。
在達成【“使用統一的RPC框架”是正確的道路】這個一致的前提下,本文期望用簡單通俗的言語簡述一下一個通用RPC框架的技術點與實現。
二、RPC背景與過程
什麼是RPC(Remote Procedure Call Protocol),遠端過程呼叫?
先來看下什麼是本地函式呼叫,當我們寫下:
int result = Add(1, 2);
這段程式碼的時候,我們知道,我們傳入了1,2兩個入引數,呼叫了原生程式碼段中的一個Add函式,得到了result出參。此時,傳入資料,傳出資料,程式碼段在同一個程式空間裡,這是本地函式呼叫。
那有沒有辦法,我們能夠呼叫一個跨程式(所以叫“遠端”,典型的,這個程式部署在另一臺伺服器上)的函式呢?
最容易想到的,兩個程式約定一個協議格式,使用Socket通訊,來傳輸【入參】【呼叫哪個函式】【出參】。
假設請求報文協議是一個11位元組的位元組流:
(1)前3個位元組填入函式名
(2)中間4個位元組填入第一個引數
(3)末尾4個位元組填入第二個引數
同時可以設計響應報文協議是一個4位元組的位元組流:
即處理結果。
呼叫方的程式碼可能變為:
request = MakePacket(“add”, 1, 2);
SendRequest_ToService_B(request);
response = RecieveRespnse_FromService_B();
int result = unMakePacket(respnse);
簡單解釋一下:
(1)講傳入引數變為位元組流
(2)將位元組流發給服務B
(3)從服務B接受返回位元組流
(4)將返回位元組流變為傳出引數
服務方的程式碼可能變為:
request = RecieveRequest();
args/function = unMakePacket(request);
result = Add(1, 2);
response = MakePacket(result);
SendResponse(response);
這個過程也很好理解:
(1)服務端收到位元組流
(2)將位元組流轉為函式名與引數
(3)本地呼叫函式得到結果
(4)將結果轉變為位元組流
(5)將位元組流傳送給呼叫方
這個過程用一張圖描述如上,呼叫方與服務方的處理步驟都是非常清晰的。這個過程存在最大的問題是什麼呢?
回答:呼叫方太麻煩了,每次都要關注很多底層細節
(1)入參到位元組流的轉化,即序列化應用層協議細節
(2)socket傳送,即網路傳輸協議細節
(3)socket接受
(4)位元組流到出參的轉化,即反序列化應用層協議細節
能不能呼叫層不關注這個細節呢?
回答:可以,RPC框架就是解決這個問題的,它能夠讓呼叫方“像呼叫本地函式一樣呼叫遠端的函式(服務)”。
在此我向大家推薦一個架構學習交流群。交流學習群號:575745314 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化、分散式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
三、RPC框架職責
通過上面的討論,RPC框架要向呼叫方遮蔽各種複雜性,要向服務提供方也遮蔽各類複雜性:
(1)呼叫方感覺就像呼叫本地函式一樣
(2)服務提供方感覺就像實現一個本地函式一樣來實現服務
所以整個RPC框架又分為client部分與server部分,負責把整個非(1)(2)的各類複雜性遮蔽,這些複雜性就是RPC框架的職責。
再細化一些,client端又包含:序列化、反序列化、連線池管理、負載均衡、故障轉移、佇列管理,超時管理、非同步管理等等等等職責。
server端包含:服務端元件、服務端收發包佇列、io執行緒、工作執行緒、序列化反序列化、上下文管理器、超時管理、非同步回撥等等等等職責。
however,因為篇幅有限,這些細節不做深入展開
三、微服務架構設計
微服務
軟體架構是一個包含各種組織的系統組織,這些元件包括 Web伺服器, 應用伺服器, 資料庫,儲存, 通訊層), 它們彼此或和環境存在關係。系統架構的目標是解決利益相關者的關注點。
Conway’s law: Organizations which design systems[…] are constrained to produce designs which are copies of the communication structures of these organizations.
(設計系統的組織,其產生的設計和架構等價於組織間的溝通結構。)
Monolithic架構
Monolithic比較適合小專案,優點是:
開發簡單直接,集中式管理, 基本不會重複開發
功能都在本地,沒有分散式的管理開銷和呼叫開銷。它的缺點也非常明顯,特別對於網際網路公司來說(不一一列舉了):
開發效率低:所有的開發在一個專案改程式碼,遞交程式碼相互等待,程式碼衝突不斷
程式碼維護難:程式碼功能耦合在一起,新人不知道何從下手
部署不靈活:構建時間長,任何小修改必須重新構建整個專案,這個過程往往很長
穩定性不高:一個微不足道的小問題,可以導致整個應用掛掉
擴充套件性不夠:無法滿足高併發情況下的業務需求
微服務架構
微服務是指開發一個單個小型的但有業務功能的服務,每個服務都有自己的處理和輕量通訊機制,可以部署在單個或多個伺服器上。微服務也指一種種鬆耦合的、有一定的有界上下文的面向服務架構。也就是說,如果每個服務都要同時修改,那麼它們就不是微服務,因為它們緊耦合在一起;如果你需要掌握一個服務太多的上下文場景使用條件,那麼它就是一個有上下文邊界的服務,這個定義來自DDD領域驅動設計。
相對於單體架構和SOA,它的主要特點是元件化、鬆耦合、自治、去中心化,體現在以下幾個方面:
-
一組小的服務
服務粒度要小,而每個服務是針對一個單一職責的業務能力的封裝,專注做好一件事情。 -
獨立部署執行和擴充套件
每個服務能夠獨立被部署並執行在一個程式內。這種執行和部署方式能夠賦予系統靈活的程式碼組織方式和釋出節奏,使得快速交付和應對變化成為可能。 -
獨立開發和演化
技術選型靈活,不受遺留系統技術約束。合適的業務問題選擇合適的技術可以獨立演化。服務與服務之間採取與語言無關的API進行整合。相對單體架構,微服務架構是更面向業務創新的一種架構模式。 -
獨立團隊和自治
團隊對服務的整個生命週期負責,工作在獨立的上下文中,自己決策自己治理,而不需要統一的指揮中心。團隊和團隊之間通過鬆散的社群部落進行銜接。
我們可以看到整個微服務的思想就如我們現在面對資訊爆炸、知識爆炸是一樣的:通過解耦我們所做的事情,分而治之以減少不必要的損耗,使得整個複雜的系統和組織能夠快速的應對變化。
我們為什麼採用微服務呢?
“讓我們的系統儘可能快地響應變化” – Rebecca Parson
讓我們的系統儘可能快地去響應變化。其實幾十年來我們一直在嘗試解決這個問題。如果一定要在前面加個限制的話,那就是低成本的快速響應變化。上世紀90年代Kent Beck提出要擁抱變化,在同期出現了諸多輕量級開發方法(諸如 XP、Scrum);2001年敏捷宣言誕生,之後又出現了精益、看板等新的管理方式。如果說,這些是為了儘快的響應變化,在軟體開發流程和實踐方面提出的解決方案,那麼微服務架構就是在軟體技術和架構層面提出的應對之道。
Autonomous
A Microservice is a unit of functionality; it provides an API for a set of capabilities oriented around a business domain or common utility
Isolated
A Microservice is a unit of deployment; it can be modified, tested and deployed as a unit without impacting other areas of a solution
Elastic
A Microservice is stateless; it can be horizontally scaled up and down as needed
Resilient
A Microservice is designed for failure; it is fault tolerant and highly available
Responsive
A Microservice responds to requests in a reasonable amount of time
Intelligent
The intelligence in a system is found in the Microservice endpoints not ‘on the wire’
Message Oriented
Microservices rely on HTTP or a lightweight message bus to establish a boundary between components; this ensures loose coupling, isolation, location transparency, and provides the means to delegate errors as messages
Programmable
Microservices provide API’s for access by developers and administrators
Composable
Applications are composed from multiple Microservices
Automated
The lifecycle of a Microservice is managed through automation that includes development, build, test, staging, production and distribution
服務之間如何通訊
一般同步呼叫比較簡單,一致性強,但是容易出呼叫問題,效能體驗上也會差些,特別是呼叫層次多的時候。RESTful和RPC的比較也是一個很有意 思的話題。一般REST基於HTTP,更容易實現,更容易被接受,服務端實現技術也更靈活些,各個語言都能支援,同時能跨客戶端,對客戶端沒有特殊的要 求,只要封裝了HTTP的SDK就能呼叫,所以相對使用的廣一些。RPC也有自己的優點,傳輸協議更高效,安全更可控,特別在一個公司內部,如果有統一個 的開發規範和統一的服務框架時,他的開發效率優勢更明顯些。就看各自的技術積累實際條件,自己的選擇了。而非同步訊息的方式在分散式系統中有特別廣泛的應用,他既能減低呼叫服務之間的耦合,又能成為呼叫之間的緩衝,確保訊息積壓不會沖垮被呼叫方,同時能 保證呼叫方的服務體驗,繼續幹自己該乾的活,不至於被後臺效能拖慢。不過需要付出的代價是一致性的減弱,需要接受資料最終一致性;還有就是後臺服務一般要 實現冪等性,因為訊息傳送出於效能的考慮一般會有重複(保證訊息的被收到且僅收到一次對效能是很大的考驗);最後就是必須引入一個獨立的broker,如 果公司內部沒有技術積累,對broker分散式管理也是一個很大的挑戰。
微服務優點
- 每個微服務都很小,這樣能聚焦一個指定的業務功能或業務需求。
- 微服務能夠被小團隊單獨開發,這個小團隊是2到5人的開發人員組成。
- 微服務是鬆耦合的,是有功能意義的服務,無論是在開發階段或部署階段都是獨立的。
- 微服務能使用不同的語言開發。
- 微服務允許容易且靈活的方式整合自動部署,通過持續整合工具,如Jenkins, bamboo 。
- 一個團隊的新成員能夠更快投入生產。
- 微服務易於被一個開發人員理解,修改和維護,這樣小團隊能夠更關注自己的工作成果。無需通過合作才能體現價值。
- 微服務允許你利用融合最新技術。
- 微服務只是業務邏輯的程式碼,不會和HTML,CSS 或其他介面元件混合。
- 微服務能夠即時被要求擴充套件。
- 微服務能部署中低端配置的伺服器上。
- 易於和第三方整合。
- 每個微服務都有自己的儲存能力,可以有自己的資料庫。也可以有統一資料庫。
微服務架構的缺點
- 微服務架構可能帶來過多的操作。
- 需要DevOps技巧 (http://en.wikipedia.org/wiki/DevOps).
- 可能雙倍的努力。
- 分散式系統可能複雜難以管理。
- 因為分佈部署跟蹤問題難。
- 當服務數量增加,管理複雜性增加。
需要考慮的問題
- 單個微服務程式碼量小,易修改和維護。但是,系統複雜度的總量是不變的,每個服務程式碼少了,但服務的個數肯定就多了。就跟拼圖遊戲一樣,切的越碎,越難拼出整幅圖。一個系統被拆分成零碎的微服務,最後要整合為一個完整的系統,其複雜度肯定比大塊的功能整合要高很多。
- 單個微服務資料獨立,可獨立部署和執行。雖然微服務本身是可以獨立部署和執行的,但仍然避免不了業務上的你來我往,這就涉及到要對外通訊,當微服務的數量達到一定量級的時候,如何提供一個高效的叢集通訊機制成為一個問題。
- 單個微服務擁有自己的程式,程式本身就可以動態的啟停,為無縫升級的打好了基礎,但誰來啟動和停止程式,什麼時機,選擇在哪臺裝置上做這件事情才是無縫升級的關鍵。這個能力並不是微服務本身提供的,而是需要背後強大的版本管理和部署能力。
- 多個相同的微服務可以做負載均衡,提高效能和可靠性。正是因為相同微服務可以有多個不同例項,讓服務按需動態伸縮成為可能,在高峰期可以啟動更多的相同的微服務例項為更多使用者服務,以此提高響應速度。同時這種機制也提供了高可靠性,在某個微服務故障後,其他相同的微服務可以接替其工作,對外表現為某個裝置故障後業務不中斷。同樣的道理,微服務本身是不會去關心繫統負載的,那麼什麼時候應該啟動更多的微服務,多個微服務的流量應該如何排程和分發,這背後也有一套複雜的負載監控和均衡的系統在起作用。
- 微服務可以獨立部署和對外提供服務,微服務的業務上線和下線是動態的,當一個新的微服務上線時,使用者是如何訪問到這種新的服務?這就需要有一個統一的入口,新的服務可以動態的註冊到這個入口上,使用者每次訪問時可以從這個入口拿到系統所有服務的訪問地址。這個統一的系統入口並不是微服務本身的一部分,所以這種能力需要系統單獨提供。
- 還有一些企業級關注的系統問題,比如,安全策略如何集中管理?系統故障如何快速審計和跟蹤到具體服務?整個系統狀態如何監控?服務之間的依賴關係如何管理?等等這些問題都不是單個微服務考慮的範疇,而需要有一個系統性的考慮和設計,讓每個微服務都能夠按照系統性的要求和約束提供對應的安全性,可靠性,可維護性的能力。
API為什麼很重要
•服務價值的精華體現
•可靠、可用、可讀
•只有一次機會
實現一個API閘道器作為所有客戶端的唯一入口。API閘道器有兩種方式來處理請求。有些請求被簡單地代理/路由到合適的服務上,其他的請求被轉給到一組服務。
相比於提供普適的API,API閘道器根據不同的客戶端開放不同的API。比如,Netflix API閘道器執行著客戶端特定的介面卡程式碼,會向客戶端提供最適合其需求的API。
API閘道器也可以實現安全性,比如驗證客戶端是否被授權進行某請求。
在此我向大家推薦一個架構學習交流群。交流學習群號:575745314 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化、分散式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
設計要素
•Version
•RequstID
•Auth&Signature
•RateLimit
•Docs
•ErrorCode&Message
微服務治理
•按需伸縮
–部署與監控運維成本
•獨立部署
–機器數量與部署成本
•業務獨立
–服務依賴、治理,版本管理、事務處理
•技術多樣性
–環境部署成本、約定成本
•執行狀態治理
–監控、限流、SLA、LB、日誌分析
•服務註冊與發現
•部署
–快速、複製、擴容
–單機開發
•呼叫
–安全、容錯、服務降級、呼叫延時
服務容錯
當企業微服務化以後,服務之間會有錯綜複雜的依賴關係,例如,一個前端請求一般會依賴於多個後端服務,技術上稱為1 -> N扇出. 在實際生產環境中,服務往往不是百分百可靠,服務可能會出錯或者產生延遲,如果一個應用不能對其依賴的故障進行容錯和隔離,那麼該應用本身就處在被拖垮的風險中。在一個高流量的網站中,某個單一後端一旦發生延遲,可能在數秒內導致所有應用資源(執行緒,佇列等)被耗盡,造成所謂的雪崩效應(Cascading Failure),嚴重時可致整個網站癱瘓。
服務依賴
服務框架
- 服務註冊、發現、負載均衡和健康檢查,假定採用程式內LB方案,那麼服務自注冊一般統一做在伺服器端框架中,健康檢查邏輯由具體業務服務定製,框架層提供呼叫健康檢查邏輯的機制,服務發現和負載均衡則整合在服務客戶端框架中。
- 監控日誌,框架一方面要記錄重要的框架層日誌、metrics和呼叫鏈資料,還要將日誌、metrics等介面暴露出來,讓業務層能根據需要記錄業務日誌資料。在執行環境中,所有日誌資料一般集中落地到企業後臺日誌系統,做進一步分析和處理。
- REST/RPC和序列化,框架層要支援將業務邏輯以HTTP/REST或者RPC方式暴露出來,HTTP/REST是當前主流API暴露方式,在效能要求高的場合則可採用Binary/RPC方式。針對當前多樣化的裝置型別(瀏覽器、普通PC、無線裝置等),框架層要支援可定製的序列化機制,例如,對瀏覽器,框架支援輸出Ajax友好的JSON訊息格式,而對無線裝置上的Native App,框架支援輸出效能高的Binary訊息格式。
- 配置,除了支援普通配置檔案方式的配置,框架層還可整合動態執行時配置,能夠在執行時針對不同環境動態調整服務的引數和配置。
- 限流和容錯,框架整合限流容錯元件,能夠在執行時自動限流和容錯,保護服務,如果進一步和動態配置相結合,還可以實現動態限流和熔斷。
- 管理介面,框架整合管理介面,一方面可以線上檢視框架和服務內部狀態,同時還可以動態調整內部狀態,對除錯、監控和管理能提供快速反饋。Spring Boot微框架的Actuator模組就是一個強大的管理介面。
- 統一錯誤處理,對於框架層和服務的內部異常,如果框架層能夠統一處理並記錄日誌,對服務監控和快速問題定位有很大幫助。
- 安全,安全和訪問控制邏輯可以在框架層統一進行封裝,可做成外掛形式,具體業務服務根據需要載入相關安全外掛。
- 文件自動生成,文件的書寫和同步一直是一個痛點,框架層如果能支援文件的自動生成和同步,會給使用API的開發和測試人員帶來極大便利。Swagger是一種流行Restful API的文件方案。
微服務系統底座
一個完整的微服務系統,它的底座最少要包含以下功能:
-
日誌和審計,主要是日誌的彙總,分類和查詢
-
監控和告警,主要是監控每個服務的狀態,必要時產生告警
-
訊息匯流排,輕量級的MQ或HTTP
-
註冊發現
-
負載均衡
-
部署和升級
-
事件排程機制
-
資源管理,如:底層的虛擬機器,物理機和網路管理
以下功能不是最小集的一部分,但也屬於底座功能:
-
認證和鑑權
-
微服務統一程式碼框架,支援多種程式語言
-
統一服務構建和打包
-
統一服務測試
-
微服務CI/CD流水線
-
服務依賴關係管理
-
統一問題跟蹤除錯框架,俗稱呼叫鏈
-
灰度釋出
-
藍綠部署
容器(Docker)與微服務
•容器夠小
–解決微服務對機器數量的訴求
•容器獨立
–解決多語言問題
•開發環境與生產環境相同
–單機開發、提升效率
•容器效率高
–省錢
•程式碼/image一體化
–可複用管理系統
•容器的橫向與縱向擴容
–可複製
–可動態調節CPU與記憶體
容器(Docker)與微服務
•Image管理
•系統安全管理
•授權管理
•系統成熟度
•社群成熟度
開發方式影響
隨著持續交付概念推廣以及Docker容器普及,微服務將這兩種理念和技術結合起來,形成新的微服務+API + 平臺的開發模式,提出了容器化微服務的持續交付概念。
下圖傳統Monolithic的DevOps開發隊伍方式:
這種整體型架構要求產品隊伍橫跨產品管理 Dev開發 QA DBA 以及系統運營管理,而微服務架構引入以後,如下圖:
微服務促進了DevOps方式的重組,將一個大臃腫的整體產品開發隊伍切分為根據不同微服務的劃分的產品隊伍,以及一個大的整體的平臺隊伍負責運營管理,兩者之間通過API互動,做到了鬆耦合隔絕。
- 首先需要考慮構建DevOps能力,這是保證微服務架構在持續交付和應對複雜運維問題的動力之源;
- 其次保持服務持續演進,使之能夠快速、低成本地被拆分和合並,以快速響應業務的變化;
- 同時要保持團隊和架構對齊。微服務貌似是技術層面的變革,但它對團隊結構和組織文化有很強的要求和影響。識別和構建匹配架構的團隊是解決問題的另一大支柱。
- 最後,打造持續改進的自組織文化是實施微服務的關鍵基石。只有持續改進,持續學習和反饋,持續打造這樣一個文化氛圍和團隊,微服務架構才能持續發展下去,保持新鮮的生命力,從而實現我們的初衷。
微服務的實施是有一定的先決條件:基礎的運維能力(如監控、快速配置、快速部署)需提前構建,否則就會陷入如我們般被動的局面。推薦採用基礎設施及程式碼的實踐,通過程式碼來描述計算和網路基礎設施的方法,使得圖案度i可以快速安全的搭建和處理由新的配置代替的伺服器,伺服器之間可以擁有更高的一致性,降低了在“我的環境工作,而你的環境不工作”的可能,也是為後續的釋出策略和運維提供更好的支撐。
由於Docker引入,不同的微服務可以使用不同的技術架構,比如Node.js Java Ruby Python等等,這些單個的服務都可以獨立完成交付生命週期,如下:
微服務案例
Netflix的微服務架構如下,著重全球分發 高可擴充套件性和可用性:
Twitter的微服務架構,注重高效的可擴充套件的資料中心:
四、輕量級微服務架構及最佳部署
一、微服務將變得輕量級
架構需要由人去設計,這些人被稱為架構師。或許很多人並未授予架構師的頭銜,但自己卻從事著架構的工作。我們認為,架構這項工作永遠都需要由人去完成,可能短期內都無法由機器來取代。如果我們不理解什麼是架構,或者對架構師的職責感到疑惑,那麼很難讓架構這項工作有效地落地。我們將在本節重新認識架構,並重新定義架構師的職責。此外,架構演進是一個曲折的過程,但我們卻不難看出架構的發展規律,甚至還能推測出架構將來的發展趨勢。我們相信,微服務一定不是架構的終點,它或許只是架構從重量級轉型為輕量級的橋樑,我們正是設計並建造這座橋樑的工程師。
現在我們從架構與架構師的角度開始出發,開啟輕量級微服務的架構探險之旅。
1. 架構與架構師
可能絕大多數的程式設計師都想成為一名優秀的架構師,每天都能從事技術架構的相關工作,編點框架程式碼,畫點架構圖,寫點PPT,帥氣地站在講臺上給程式設計師們進行技術培訓。大家普遍認為,架構師的程式碼比別人寫得少,但是工資卻比別人拿得多,架構師是技術團隊中技術最牛的人,別人搞不定的技術問題,在架構師眼中都是小菜一碟。
這樣的人真的是架構師嗎?
我們認為,他們不是架構師,而是技術專家。其實架構師與技術專家有著本質的區別,從他們所關注的技術方向來看,架構師更偏向技術廣度,而技術專家更偏向技術深度,如圖1-1所示。
圖1-1 架構師與技術專家的區別
換句話說,架構師需要有較強的綜合能力,他們需要接觸的技術領域較廣,但他們所掌握的技術專業能力卻沒有技術專家那麼深。如果我們想成為一名架構師,那麼就不應該把所有的精力都投入在某個技術領域上,而是要學會分散自己所關注的層面,做到在眾多技術領域上都要有一定的深度。
架構師除了需要具備在技術上所需的“硬技能”,還需要不斷完善自己的“軟技能”,比如溝通、組織、學習等技能。有時候軟技能可能比硬技能更加重要,甚至軟技能還會影響自己的職業發展。如果沒有較好的軟技能,架構師將無法將自己所設計的架構順利地移交到程式設計師們手中,並指導他們將其真正落地。架構師正是通過他們所具備的綜合能力來帶領技術團隊,解決不斷出現的技術挑戰。
架構師的職責是什麼?
我們的回答是:制定規範 + 指導落地。
架構師根據業務需求所制定的合理且可落地的技術規範,我們將這樣的規範稱為架構。
將架構工作做好猶如我們用兩條腿走路一樣,左腿邁出去表示“制定規範”,右腿跟上來表示“指導落地”,如圖1-2所示。
圖1-2 架構師的職責
如果左腿邁出去,右腿沒跟上來,那不是架構師,可能是需要拄拐的人。然而,我們身邊卻有一些這樣的不合格的架構師,他們只懂得制定規範,卻忽略了指導落地。如果架構無法落地,那麼就無法稱為架構了。
此外,還有一些架構師認為,架構只是技術層面上的問題,自己設計的架構應該用到市面上最為流行的新技術,比如別人公司在用微服務,那麼自己公司也要用起來。如果將架構工作脫離於業務需求,我們認為這不是做架構,而是玩技術。脫離業務來設計架構是對架構的不尊重。微服務是一種應用系統架構,需要架構師圍繞業務進行設計。
但是,我們絕不要為了微服務而去微服務。
從事微服務架構工作的架構師,相比傳統架構的架構師而言,所要求的技能更加全面。他們不僅僅是系統架構師,也是業務分析師,他們的責任重大且挑戰艱鉅。
從大的方向來看,微服務架構師需要具備以下基本職責。
(1)分析業務需求並切分微服務邊界。
(2)定義架構規範與文件標準。
(3)確保微服務架構順利落地。
(4)改善微服務架構並提高開發效率。
職責與挑戰往往是無法分離的,微服務架構師必須面對並克服這些挑戰。
(1)架構需要適應不斷變化的業務需求。
(2)架構具備穩定性、擴充套件性、安全性、容錯性等。
(3)使技術團隊深刻理解微服務思想。
(4)展現微服務架構的價值。
我們認為,傳統架構師轉型為微服務架構首先需要做到的是深刻理解業務,而不是表面上瞭解需求。業務和需求其實是兩碼事,業務的背後反映了客戶的剛需,而需求往往是產品經理根據業務剛需所指定的解決方案。作為微服務架構師,我們需要透過需求的表象去理解業務的本質。其次需要做到的是不斷優化架構,讓架構變得更加簡單,更加輕量級。我們要將昨天最好的表現,當成今天最低的要求,只有在技術上不斷要求自己,才能讓架構變得更好。
2. 架構演進過程
話說天下大勢,分久必合,合久必分,對於架構演進過程而言,也符合這個規律。
最早的應用程式實際上是沒有任何架構的,因為那時業務比較簡單,沒有架構也許是合理的,如圖1-3所示。
圖1-3 沒有架構
但隨著業務不斷複雜起來,我們意識到架構可以做到水平分層,比如表現層、邏輯層、資料層等,我們可在不同的層上實現每一層所關注的內容,我們稱其為“關注點分離”。但此時的架構更像是一塊“鐵板”,每一層的無法進行分離,因此我們也將這樣的架構稱為“單塊架構”,如圖1-4所示。
從此架構發生了更為複雜的變化,層次結構越來越深,而且不再侷限於水平方向上的分層,實際上越來越多的應用程式圍繞著不同的業務需求來實現,此時出現了“垂直分層架構”,每個垂直應用中實際上都是一個獨立的子系統,它們共同組成了整個應用系統。然而,這些子系統一般可以部署在不同的伺服器上,這些伺服器可以分佈在不同的地域中,我們也稱其為“分散式架構”,如圖1-5所示。
圖1-4 水平分層架構(單塊架構)
圖1-5 垂直分層架構(分散式架構)
業務並沒有停止發展的腳步,架構的演變也是如此。分散式應用之間的呼叫越來越多,整個系統的複雜度急劇上升,人們希望找到一種途徑來降低分散式應用之間的耦合。此時出現了面向服務架構(SOA),人們希望SOA能成為解決分散式應用系統複雜性的“銀彈”,然而事實卻事與願違。應用的複雜性不僅沒有得到解決,反而還讓架構變得更加複雜,同時也形成了大量的SOA商業產品,這些現象讓人們更加恐懼SOA,將它視為複雜和昂貴的代名詞,如圖1-6所示。
隨著網際網路行業不斷髮展,使用者對產品的體驗要求越來越高,前端的價值逐漸被凸顯出來,此時出現了“前後端分離”的趨勢,前端工程師專心在介面展現與資料渲染上,後端工程師關注在業務邏輯與資料結構上,前後端只需通過REST API進行互動,工作分工更加明確,開發效率更加高效,如圖1-7所示。
圖1-6 面向服務架構(SOA)
圖1-7 前後端分離架構
似乎很長時間都未出現任何技術能與當年的SOA相提並論,除了微服務架構。微服務的概念在2014年首次被提出以來,近幾年一直是應用架構領域的核心話題。但人們往往還是容易想到當年的SOA,認為微服務與SOA有著相同的目的,只是實現細節不太一樣罷了,如圖1-8所示。
圖1-8 微服務架構
微服務與SOA到底有何區別?
我們認為,微服務是SOA的一種落地方案。
SOA是一種面向服務的架構思想,微服務也同樣推崇這種思想。微服務是將一個大型的單塊架構,拆分為多個細粒度服務的架構。微服務更加考驗我們的是,深入理解業務併合理地對服務邊界進行切分。微服務的概念相比SOA更容易落地的原因不是概念上的創新,而是技術上的突破,尤其是容器與自動化運維技術的普及與應用。
我們始終相信,微服務並不是架構發展的終點,也許是新架構時代的起點。
3. 微服務架構發展趨勢
微服務架構所涉及的範圍相當廣泛,我們不妨從多個角度來推測微服務架構的發展趨勢。
從微服務開發角度來看,我們認為微服務的開發框架將變得更加多樣化。
開發人員可使用更加適合的開發框架來完成微服務業務實現,而不再拘泥於某一種程式語言,只需確保對外提供統一的API介面方式即可。甚至可將查詢與修改操作相分離,查詢操作可以用一種更加輕量級的程式語言來實現,而修改操作會涉及事務,一般需要藉助開發框架的事務特性來保證。
我們堅信,微服務必將堅持走輕量級技術路線。
究竟什麼是輕量級?
我們認為,輕量級必須包含三個特徵:易用、快速、穩定。
我們希望微服務架構中所涉及的技術都能夠快速上手,執行時不佔用過多的系統資源且效能突出,而且能夠長期穩定地執行。
從微服務部署角度來看,我們認為微服務的部署過程將變得更加自動化。
部署微服務不再通過手工的方式去完成,因為這樣既低效又容易出錯,我們更加傾向於使用軟體工具將其自動完成。要實現自動化部署這個目標,我們往往無法一步到位,最合理的方式是“先讓它跑起來,再讓它跑得快”。也就是說,早期的自動化部署方案也許不夠完備,或多或少會存在一些人工參與的情況,其實這些都再正常不過了,但我們需要不斷優化,努力通過自動化技術來取代重複性的人工操作。
最後想說的是,自動化雖好,但不要為了自動化而去自動化,或許有些環節通過手工處理才是最有效的方式。
二、微服務架構前期準備
搭建微服務架構絕不是一件輕鬆的事情,我們不僅要對微服務概念有著深刻的理解,還要研究大量的技術工具,並掌握它們的優缺點,最終需要結合技術團隊對技術的瞭解程度,選擇最為合適的技術選型。這些純技術的技術工具只是微服務的基礎設施,我們還需要在此基礎設施上圍繞真實的業務場景,對微服務邊界進行合理地切分。我們將在本節介紹微服務的冰山模型,大家將從這座冰山中看到微服務架構的全貌,隨後我們將深入冰山之下的世界,去探索微服務基礎設施的八大中心,最後我們還會介紹一些關於切分微服務邊界的原則和技巧。
我們現在就從微服務冰山模型開始吧,這座冰山似乎比我們想象中的要大很多。
1. 認識微服務架構冰山模型
有些人認為,使用了Spring Boot開發框架就是擁有了微服務,其實這樣的認識是不正確的。Spring Boot只是一款微服務的開發框架,而且僅能用於Java應用程式中,毫無疑問,它只是微服務的冰山一角。此外,我們建議大家結合自身的業務場景,選擇更為合適的程式語言以及開發框架來實現微服務,而不要拘泥於一種程式語言。
還有一些人認為,用上了Docker就進入了微服務時代,其實這樣的認識也是不正確的。Docker只是一種封裝微服務應用程式的容器化技術,它改變了應用程式的交付方式,也加速了微服務架構的落地速度。可以肯定地說,如果沒有Docker容器技術,或許今天我們無法聽到微服務的概念。
如果將微服務架構中所涉及的技術棧比喻為一座冰山的話,那麼冰山之上最顯而易見的部分就是微服務的開發框架與容器技術了,Spring Boot與Docker都屬於冰山之上的技術。
冰山之下到底有哪些技術呢?
我們認為冰山之下的技術是整個微服務架構的基石,它們構成了整個微服務架構的基礎設施。比如我們在上冊中學習的ZooKeeper服務登錄檔、Node.js服務閘道器、Jenkins持續部署系統等,它們都屬於冰山之下的部分。
我們可通過一幅圖來描繪微服務架構這座冰山,如圖1-9所示。
圖1-9 微服務架構冰山模型
由於服務登錄檔集中管理了微服務相關的服務配置,因此我們也將它稱為“註冊中心”;由於服務閘道器是前端應用程式的唯一入口,因此我們也將其稱為“呼叫中心”;同樣,我們也將持續部署系統稱為“部署中心”。這些中心都彙集在微服務冰山模型之下,除此之外,還有其他功能的中心,這些中心共同構成了微服務的基礎設施。
2. 冰山下的微服務基礎設施
冰山下的微服務基礎設施,實際包括了八大中心。
(1)註冊中心:用於註冊微服務相關配置資訊的中心,我們選用ZooKeeper實現。
(2)呼叫中心:用於提供給前端呼叫的統一入口,我們選用Node.js實現。
(3)部署中心:用於編譯並打包微服務原始碼並將其部署到Docker引擎中,我們選用Jenkins實現。
(4)日誌中心:用於收集並管理微服務應用程式中產生的日誌,第2章中將詳細介紹。
(5)監控中心:用於監控微服務的實時執行狀況,第3章中將詳細介紹。
(6)追蹤中心:用於最終微服務的呼叫軌跡,第3章中將詳細介紹。
(7)訊息中心:用於解耦微服務之間的呼叫關係,第5章中將詳細介紹。
(8)配置中心:用於管理微服務應用程式所需的配置引數,第7章中將詳細介紹。
也許大家看到以上八大中心後會產生一些疑惑:很多人說微服務是去中心化的,為何我們還要提供這些中心呢?
我們認為,中心分為兩類:一類是含有業務意義的中心;另一類是不含業務意義的中心(只是技術層面的中心)。
在微服務架構中我們應該去除的是含有業務意義的中心,而不是去除技術層面上的廣義中心。比如,我們所設計的呼叫中心內部是不可能帶有任何業務流程的,它只是一個純技術層面的框架。對於其他中心也是如此,絕對不含有任何的業務,否則我們就應該將其去除。
3. 根據業務切分微服務邊界
凡是學習過微服務的人都知道,我們需要根據業務來切分微服務邊界。道理可能大家都懂,但或許仍然不知道應該怎麼去做。例如,切分微服務邊界有哪些關鍵性步驟,以及包含哪些重要性原則?
經過大量的微服務實踐,我們總結了以下五個步驟,可幫助大家有效地切分微服務邊界。
- 第一步:梳理業務流程。
在切分微服務之前,我們要做的第一件事情就是梳理業務流程。不妨找業務專家諮詢,通過與他們溝通從而瞭解真實的業務流程,並將其繪製成流程圖。對於過於複雜的業務流程,我們也可單獨繪製流程圖,並增加相關的流程說明。當然也能提供相應的狀態圖,用於說明業務流程中所涉及狀態的變化過程。
花再多時間去分析業務流程都不過分,現在所花的每一分鐘都是相當值得的。
- 第二步:抽取公共服務。
在業務流程中與業務不太相關的部分,我們可考慮將其剝離出來,並形成公共服務。例如,郵件傳送、檔案上傳、其他第三方介面等。每種公共服務都對應一個微服務,每個微服務都有相關API,每個API都有自己的輸入與輸出。這些API一定要形成文件,以便其他服務呼叫。
一般情況下,抽取的公共服務都不太會變化,我們一定要想辦法將不變的東西從可變的世界中抽取出來。
- 第三步:定義業務服務。
當公共服務抽取完畢後,業務流程中剩下來的部分就是業務服務了。建議剛開始實施微服務時,不要將業務服務的邊界切得太細,可以考慮先“大切幾塊”,但需要確保每個服務之間儘量不要有依賴關係。換句話說,每個服務都是獨立的,雖然此時服務的塊頭可能比較大。
我們先確保這些大塊頭服務可以執行在微服務基礎設施上,再不斷將它們進行細化,拆解為更小的服務。
- 第四步:設計資料模型。
深入到每個業務服務中,我們首先要做的是定義它底層所涉及的資料模型,也稱為“領域模型”。此時會涉及資料庫表結構設計,以及資料模型與關係設計。在資料層面上的設計是至關重要的,如果該部分設計得不到位,將增加後期實現微服務的成本。
資料模型的設計同樣也需要進行文件化,這些文件將指導後端工程師順利地完成微服務實現。
- 第五步:定義服務介面。
底層的資料模型設計完畢後,我們將視角轉換到頂層的服務介面上。服務介面實際上就是一組API,這些API需做到職責單一,而且需要通過名稱就能識別出它的業務含義。建議確保每個API的命名是全域性唯一的,也建議每個API都有各自的版本號,版本號可以用自增長的方式來體現。
服務介面也需要進行文件化,這些文件一般由後端工程師編寫,並提供給前端與測試工程師閱讀。
在此我向大家推薦一個架構學習交流群。交流學習群號:575745314 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化、分散式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
三、輕量級微服務架構圖
作為一名微服務架構師,我們不僅需要深入理解業務,並能準確地劃分服務邊界,而且還需要深入理解微服務,並能合理地選擇技術選型。我們認為,微服務架構實際上分為兩大部分,其中一部分對應部署階段,另一部分對應執行階段。這兩部分包含了大量的技術工具,我們需要結合多方面因素來考慮,選擇最為合適的技術選型來搭建微服務架構,並確保它能保持輕量級。
本節將著眼於微服務的部署與執行兩大階段,通過圖文方式來描述輕量級微服務架構。
1. 輕量級微服務部署架構
當開發人員完成了微服務的細節實現後,首先要做的是確保自己所寫程式碼的可用性,他們往往會藉助單元測試工具來保證這一環節不出問題。當他們將原始碼提交併推送到程式碼倉庫後,此時部署中心將從程式碼倉庫中獲取原始碼,並執行編譯與打包操作。
不僅如此,部署中心還需從配置中心獲取對應執行環境的配置引數,並生成相應的配置檔案,並將這些配置檔案與應用程式一同複製到Docker映象中,最後還需將此映象上傳到映象倉庫,以便後續可從映象倉庫中下載指定的映象,從而執行相應的Docker容器。
此外,部署中心還可掃描原始碼並自動生成API文件站點,以便其他技術人員可隨時從文件站點中檢視最新部署服務所包含的API文件。當然,我們還可以對所需完成的微服務僅提供簡單的程式碼實現,這樣就能將微服務文件的輸出時間儘可能提前,以便其他技術人員能夠更早地瞭解到微服務的相關API資訊,隨後再去完成更加細節的程式碼實現,這是我們推薦的工作方法。
當Docker映象上傳到映象倉庫後,部署中心可在不同的執行環境下根據特定的映象來啟動相應的Docker容器。為了便於描述,我們將該容器稱為“服務容器”,它包含了承載微服務的應用程式及其配置檔案。
當服務容器啟動後,會自動將其配置資訊寫入註冊中心,與此同時,部署中心也會連線到註冊中心,並設定服務的版本號,以便於在後續呼叫服務時可根據版本號來識別當前可用的服務。
我們可將以上過程繪製為一幅架構圖,如圖1-10所示。
圖1-10 輕量級微服務部署架構
可見,在微服務部署階段中,部署中心是其中的主角,它支配其他元件,使服務可以成功部署,我們需要確保它的穩定性。
2. 輕量級微服務執行架構
當使用者通過瀏覽器或移動端訪問應用系統時,請求首先將進入服務閘道器,因為它是所有請求呼叫的中心,我們也將其稱為“呼叫中心”。它雖然是不帶任何業務的中心,但我們需要確保它所做的事情足夠少,讓它不會成為整個應用系統的呼叫瓶頸。
隨後呼叫中心將連線註冊中心,並通過服務名稱從註冊中心中獲取服務所在的IP地址與埠號(即服務地址),該過程稱為“服務發現”,進而呼叫中心可根據服務地址以反向代理的方式來呼叫具體的服務容器,該過程稱為“服務呼叫”。
在服務容器中可能會觸發一些事件,這些事件將以訊息的方式寫入訊息中心,以便其他服務可監聽訊息中心並從中獲取相應的訊息。該方案可解決服務之間的耦合問題,同時能將同步呼叫轉為非同步呼叫,提高整個應用系統的吞吐率。
在服務容器執行時會產生大量的日誌,我們可將這些日誌統一寫入日誌中心,並能在日誌中心所提供的控制檯上查詢具體的日誌資訊。此外,日誌中心也能幫助我們快速地定位並分析系統出現的異常狀況。
為了觀察服務容器是否執行正常,我們可藉助監控中心所輸出的圖形化資料來判斷。監控中心將不斷地收集服務容器中的執行狀態,包括CPU、記憶體、硬碟、網路,以及應用程式的JVM記憶體使用情況。
由於微服務很難切得乾淨,服務之間難免會出現少量的呼叫關係,我們可將每次呼叫所產生的相關資訊寫入追蹤中心,並通過追蹤中心提供的圖形化介面來檢視服務之間的呼叫軌跡以及所產生的呼叫延時,從而可分析出服務呼叫所產生的效能瓶頸。
我們可將以上過程繪製為一幅架構圖,如圖1-11所示。
圖1-11 輕量級微服務執行架構
可見,在微服務執行階段中,呼叫中心是其中的主角,註冊中心作為它的資料來源,服務容器作為它的呼叫目標,它需要具備良好的高效能與高可用等特性。
3. 輕量級微服務全域性架構
我們用一張圖將輕量級微服務的部署架構與執行架構進行整合,它就是輕量級微服務架構的全貌,如圖1-12所示。
圖1-12 輕量級微服務全域性架構
圖1-12所示的架構圖中包括12個元件,其中的程式碼倉庫、部署中心、註冊中心、映象倉庫、呼叫中心、服務容器這6個元件已在上冊中進行描述,剩下的配置中心、文件站點、訊息中心、日誌中心、監控中心、追蹤中心這6個元件將在下冊後續章節中深入探索。
四、總結
本章從巨集觀上描述了輕量級微服務架構,為後續探險歷程提供了明確的藍圖。首先我們從架構與架構師開始講起,簡單回顧了架構演進的過程與微服務的發展趨勢,我們認為,微服務的出現是必然的,而且它將朝著輕量級方向發展。隨後我們探討了在搭建微服務架構之前需要準備的工作,也認識了微服務架構的“冰山模型”,本書將重點集中在冰山之下的微服務基礎設施中,此外還介紹了切分微服務邊界的方法和技巧,我們認為,合理地切分微服務邊界是微服務架構師的職責之一。最後我們從部署與執行兩個角度來觀察微服務架構,並以一幅架構全景圖來結束本章,隨後的章節將圍繞這張架構圖的相關部分進行展開,我們會選擇最為合適的技術選型來搭建這款輕量級微服務架構。