構(gòu)建Serverless風(fēng)格的微服務(wù)架構(gòu)案例
一、一次微服務(wù)架構(gòu)的奇遇
2016年12月初,當(dāng)時(shí)我正在以一名 DevOps 咨詢師的身份參與某客戶的 DevOps 轉(zhuǎn)型項(xiàng)目。這個(gè)項(xiàng)目是提升該部門在 AWS (Amazon Web Services)云計(jì)算平臺(tái)上的 DevOps 能力。
自助服務(wù)的應(yīng)用系統(tǒng)基于 Ruby on Rails 框架開發(fā),前端部分采用 AngularJS 1.0,但是沒有采用前后端分離的設(shè)計(jì),頁面代碼仍然是通過 ERB 組合而成。移動(dòng)端則采用 Cordova 開發(fā)。為了降低開發(fā)難度和工作量, 移動(dòng)端的應(yīng)用內(nèi)容實(shí)際上是把 AngularJS 所生成的 Web 頁面通過響應(yīng)式樣式的方式嵌入到移動(dòng)端。但因?yàn)榻?jīng)常超時(shí),所以這款 APP 體驗(yàn)并不好。
整套 Rails 應(yīng)用部署在 AWS 上,并且通過網(wǎng)關(guān)和內(nèi)部業(yè)務(wù)系統(tǒng)隔離。BOSS 系統(tǒng)采用 SOAP 對(duì)外暴露服務(wù),并由另外一個(gè)部門負(fù)責(zé)。因此,云上的應(yīng)用所做的業(yè)務(wù)是給用戶展現(xiàn)一個(gè)使用友好的界面,并通過數(shù)據(jù)的轉(zhuǎn)化和內(nèi)部 BOSS 系統(tǒng)進(jìn)行交互。系統(tǒng)架構(gòu)如下圖所示:
應(yīng)用的交互流程如下
- 瀏覽器或者移動(dòng)端通過域名(由 AWS Route 53托管)轉(zhuǎn)向 CDN(采用 AWS Cloudfront)。
- CDN 根據(jù)請(qǐng)求的內(nèi)容類別進(jìn)行區(qū)分,靜態(tài)文件(圖片,JS,CSS 樣式等),會(huì)轉(zhuǎn)向 AWS S3 存儲(chǔ)。動(dòng)態(tài)請(qǐng)求會(huì)直接發(fā)給負(fù)載均衡器 (AWS Elastic Load Balancer)。
- 負(fù)載均衡器會(huì)根據(jù)各 EC2 計(jì)算實(shí)例的負(fù)載狀態(tài)將請(qǐng)求轉(zhuǎn)發(fā)到不同的實(shí)例上的 Ruby On Rails 應(yīng)用上。每一個(gè)應(yīng)用都是一個(gè)典型的 MVC Web 應(yīng)用。
- EC2 上的應(yīng)用會(huì)將一部分?jǐn)?shù)據(jù)存儲(chǔ)在關(guān)系型數(shù)據(jù)服務(wù)(AWS RDS,Relational Database Service)上,一部分存儲(chǔ)在本地文件里。經(jīng)過應(yīng)用的處理,轉(zhuǎn)換成 SOAP 請(qǐng)求通過 網(wǎng)關(guān)發(fā)送給 BOSS 系統(tǒng)處理。BOSS 系統(tǒng)處理完成后會(huì)返回對(duì)應(yīng)的消息。
根據(jù)業(yè)務(wù)的需要,一部分?jǐn)?shù)據(jù)會(huì)采用 AWS ElastiCache 的 Redis 服務(wù)作為緩存以優(yōu)化業(yè)務(wù)響應(yīng)速度。
二、團(tuán)隊(duì)痛點(diǎn)
這個(gè)應(yīng)用經(jīng)歷了多年的開發(fā),前后已經(jīng)更換過很多技術(shù)人員。但是沒有人對(duì)這個(gè)應(yīng)用代碼庫有完整的的認(rèn)識(shí)。因此,我們對(duì)整個(gè)團(tuán)隊(duì)和產(chǎn)品進(jìn)行了一次痛點(diǎn)總結(jié):
1. 組織結(jié)構(gòu)方面
運(yùn)維團(tuán)隊(duì)成為瓶頸,60 個(gè)人左右的開發(fā)團(tuán)隊(duì)只有 4 名 Ops 支持。運(yùn)維團(tuán)隊(duì)除了日常的事務(wù)以外,還要給開發(fā)團(tuán)隊(duì)提供各種支持。很多資源的使用權(quán)限被限制在這個(gè)團(tuán)隊(duì)里,就導(dǎo)致各種問題的解決進(jìn)度進(jìn)一步拖延。
隨著業(yè)務(wù)的增長,需要基礎(chǔ)設(shè)施代碼庫提供各種各樣的能力。然而 Ops 團(tuán)隊(duì)的任何更改都會(huì)導(dǎo)致所有的開發(fā)團(tuán)隊(duì)停下手頭的進(jìn)度去修復(fù)更新所帶來的各種問題。
2. 應(yīng)用架構(gòu)方面
應(yīng)用架構(gòu)并沒有達(dá)到前后端分離的效果,仍然需要同一個(gè)工程師編寫前后端代碼。這樣的技術(shù)棧對(duì)于對(duì)于開發(fā)人員的要求很高,然而市場(chǎng)上缺乏合適的 RoR 工程師,導(dǎo)致維護(hù)成本進(jìn)一步上升。經(jīng)過了三個(gè)月,仍然很難招聘到合適的工程師。
多個(gè)團(tuán)隊(duì)在一個(gè)代碼庫上工作,新舊功能之間存在各種依賴點(diǎn)。加上 Ruby 的語言特性,使得代碼中存在很多隱含的依賴點(diǎn)和類/方法覆蓋,導(dǎo)致了開發(fā)進(jìn)度緩慢。我們一共有 4 個(gè)團(tuán)隊(duì)在一個(gè)代碼庫上工作,3個(gè)團(tuán)隊(duì)在開發(fā)新的功能。1 個(gè)團(tuán)隊(duì)需要修復(fù) Bug 和清理技術(shù)債,這一切都要同時(shí)進(jìn)行。
3. 技術(shù)債方面
代碼庫中有大量的重復(fù) Cucumber 自動(dòng)化測(cè)試,但是缺乏正確的并行測(cè)試策略,導(dǎo)致自動(dòng)化測(cè)試會(huì)隨機(jī)失敗,持續(xù)集成服務(wù)器 (Jenkins)的 slave 節(jié)點(diǎn)本地難以創(chuàng)建,導(dǎo)致失敗原因更加難以查找。如果走運(yùn)的話,從提交代碼到新的版本發(fā)布至少需要 45 分鐘。如果不走運(yùn)的話,兩三天都無法完成一次成功的構(gòu)建,真是依靠人品構(gòu)建。
基礎(chǔ)設(shè)施即代碼(Infrastructure as Code)建立在一個(gè)混合的遺留的 Ruby 代碼庫上。這個(gè)代碼庫用來封裝一些類似于 Packer 和 AWS CLI 這樣的命令行工具,包含一些 CloudFormation 的轉(zhuǎn)化能力。由于缺乏長期的規(guī)劃和編碼規(guī)范,加之人員變動(dòng)十分頻繁,使得代碼庫難以維護(hù)。
此外,基礎(chǔ)設(shè)施代碼庫作為一個(gè) gem 和應(yīng)用程序代碼庫耦合在一起,運(yùn)維團(tuán)隊(duì)有唯一的維護(hù)權(quán)限。因此很多基礎(chǔ)設(shè)施上的問題開發(fā)團(tuán)隊(duì)無法解決,也不愿解決。
我參與過很多 Ruby 技術(shù)棧遺留系統(tǒng)的維護(hù)。在經(jīng)歷了這些 Ruby 項(xiàng)目之后,我發(fā)現(xiàn) Ruby 是一個(gè)開發(fā)起來很爽但是維護(hù)起來很痛苦的技術(shù)棧。大部分的維護(hù)更改是由于 Ruby 的版本 和 Gem 的版本更新導(dǎo)致的。此外,由于 Ruby 比較靈活,人們都有自己的想法和使用習(xí)慣,因此代碼庫很難維護(hù)。
雖然團(tuán)隊(duì)已經(jīng)有比較好的持續(xù)交付流程,但是 Ops 能力缺乏和應(yīng)用架構(gòu)帶來的局限阻礙了整個(gè)產(chǎn)品的前進(jìn)。因此,當(dāng)務(wù)之急是能夠通過 DevOps 提升團(tuán)隊(duì)的 Ops 能力,緩解 Ops 資源不足,削弱 DevOps 矛盾。
DevOps 組織轉(zhuǎn)型中一般有兩種方法:一種方法是提升 Dev 的 Ops 能力,另一種方法是降低 Ops 工作門檻。在時(shí)間資源很緊張的情況下,通過技術(shù)的改進(jìn),降低 Ops 的門檻是短期內(nèi)收益***的方法。
三、微服務(wù)觸發(fā)點(diǎn):并購帶來的業(yè)務(wù)功能合并
在我加入項(xiàng)目之后,客戶收購了另外一家業(yè)務(wù)相關(guān)的企業(yè)。因此原有的系統(tǒng)要同時(shí)承載兩個(gè)業(yè)務(wù)。恰巧有個(gè)訂單查詢的業(yè)務(wù)需要讓當(dāng)前的團(tuán)隊(duì)完成這樣一個(gè)需求:通過現(xiàn)有的訂單查詢功能同時(shí)查詢兩個(gè)系統(tǒng)的業(yè)務(wù)訂單。
這個(gè)需求看起來很簡單,只需要在現(xiàn)有系統(tǒng)中增加一個(gè)數(shù)據(jù)源,然后把輸入的訂單號(hào)進(jìn)行轉(zhuǎn)化就可以。但由于存在上述的痛點(diǎn),完成這樣一個(gè)簡單的功能的代價(jià)是十分高昂的。幾乎 70% 的工作量都和功能開發(fā)本身沒有關(guān)系。
在開發(fā)的項(xiàng)目上進(jìn)行 DevOps 轉(zhuǎn)型就像在行進(jìn)的汽車上換車輪,一不留心就會(huì)讓所有團(tuán)隊(duì)停止工作。因此我建議通過設(shè)立并行的新團(tuán)隊(duì)來同時(shí)完成新功能的開發(fā)和 DevOps 轉(zhuǎn)型的試點(diǎn)。
這是一個(gè)功能拆分和新功能拆分需求,剛好訂單查詢是原系統(tǒng)中一個(gè)比較獨(dú)立和成熟的功能。為了避免影響原有各功能開發(fā)的進(jìn)度。我們決定采用微服務(wù)架構(gòu)來完成這個(gè)功能。
四、構(gòu)建微服務(wù)的架構(gòu)的策略
我們并不想重蹈之前應(yīng)用架構(gòu)的覆轍,我們要做到前后端分離。使得比較小的開發(fā)團(tuán)隊(duì)可以并行開發(fā),只要協(xié)商好了接口之間的契約(Contract),未來開發(fā)完成之后會(huì)很好集成。
這讓我想起了 Chris Richardson 提出了三種微服務(wù)架構(gòu)策略,分別是:停止挖坑,前后端分離和提取微服務(wù)。
停止挖坑的意思是說:如果發(fā)現(xiàn)自己掉坑里,馬上停止。
原先的單體應(yīng)用對(duì)我們來說就是一個(gè)焦油坑,因此我們要停止在原來的代碼庫上繼續(xù)工作。并且為新應(yīng)用單***建一個(gè)代碼庫。所以,我們拆分策略模式如下所示:
在我們的架構(gòu)里,實(shí)現(xiàn)新的需求就要變動(dòng)老的應(yīng)用。我們的想法是:
- 構(gòu)建出新的業(yè)務(wù)頁面,生成微服務(wù)契約。
- 根據(jù) API 契約構(gòu)建出新的微服務(wù)。
- 部署 Web 前端到 S3 上,采用 S3 的 Static Web Hosting (靜態(tài) Web 服務(wù)) 發(fā)布。
- 部署后端微服務(wù)上線,并采用臨時(shí)的域名和 CDN 加載點(diǎn)進(jìn)行測(cè)試。
- 通過更新 CDN 把原應(yīng)用的流量導(dǎo)向新的微服務(wù)。
- 刪除舊的服務(wù)代碼。
我們?cè)疽谠械膽?yīng)用上增加一個(gè) API 用來訪問以前應(yīng)用的邏輯。但想想這實(shí)際上也是一種挖坑。在評(píng)估了業(yè)務(wù)的復(fù)雜性之后。我們發(fā)現(xiàn)這個(gè)功能如果全新開發(fā)只需要 2人2周(一個(gè)人月)的時(shí)間,這僅僅占我們預(yù)估工作量的20%不到。因此我們放棄了對(duì)遺留代碼動(dòng)工的念頭。最終通過微服務(wù)直接訪問后臺(tái)系統(tǒng),而不需要通過原有的應(yīng)用。
在我們拆微服務(wù)的部分十分簡單。對(duì)于后端來說說只需要修改 CDN 覆蓋原先的訪問源(Origin)以及保存在 route.rb 里的原功能訪問點(diǎn),就可以完成微服務(wù)的集成。
1. 構(gòu)建出新的業(yè)務(wù)頁面,生成微服務(wù)契約
結(jié)合上面的應(yīng)用痛點(diǎn)和思路,在構(gòu)建微服務(wù)的技術(shù)選型時(shí)我們確定了以下方向:
- 前端框架要具備很好的 Responsive 擴(kuò)展。
- 采用 Swagger 來描述 API 需要具備的行為。
- 過消費(fèi)者驅(qū)動(dòng)進(jìn)行契約測(cè)試驅(qū)動(dòng)微服務(wù)后端開發(fā)。
- 前端代碼庫和后端代碼庫分開。
- 前端代碼框架要對(duì)持續(xù)交付友好。
因此我們選擇了 React 作為前端技術(shù)棧并且用 yarn 管理依賴和任務(wù)。另外一個(gè)原因是我們能夠通過 React-native 為未來構(gòu)建新的應(yīng)用做好準(zhǔn)備。此外,我們引入了 AWS SDK 的 nodejs 版本。用編寫一些常見的諸如構(gòu)建、部署、配置等 AWS 相關(guān)的操作。并且通過 swagger 描述后端 API 的行為。這樣,后端只需要滿足這個(gè) API 規(guī)范,就很容易做前后端集成。
2. 部署前端部分到S3上
由于 AWS S3 服務(wù)自帶 Static Web Hosting (靜態(tài)頁面服務(wù)) 功能,這就大大減少了我們構(gòu)建基礎(chǔ)環(huán)境所花費(fèi)的時(shí)間。如果你還想著用 Nginx 和 Apache 作為靜態(tài)內(nèi)容的 Web 服務(wù)器,那么你還不夠 CloudNative。
雖然AWS S3 服務(wù)曾經(jīng)發(fā)生過故障,但 SLA 也比我們自己構(gòu)建的 EC2 實(shí)例處理靜態(tài)內(nèi)容要強(qiáng)得多。此外還有以下優(yōu)點(diǎn):
- 擁有獨(dú)立的 URL,很容易做很多 301 和 302 的重定向和改寫操作。
- 和 CDN(CloudFront)集成很好。
- 很容易和持續(xù)集成工具集成。
- ***的優(yōu)點(diǎn):比 EC2 便宜。
3. 根據(jù) API 契約構(gòu)建出新的微服務(wù)
在構(gòu)建微服務(wù)的最初,我們當(dāng)時(shí)有兩個(gè)選擇:
采用 Sinatra (一個(gè)用來構(gòu)建 API 的 Ruby gem) 構(gòu)建一個(gè)微服務(wù) ,這樣可以復(fù)用原先 Rails 代碼庫的很多組件。換句話說,只需要 copy 一些代碼,放到一個(gè)單獨(dú)的代碼庫里,就可以完成功能。但也同樣會(huì)面臨之前 Ruby 技術(shù)棧帶來的種種問題。
采用 Spring Boot 構(gòu)建一個(gè)微服務(wù),Java 作為成熟工程語言目前還是***的選擇,社區(qū)和實(shí)踐都非常成熟??梢詮?fù)用后臺(tái)很多用來做 SOAP 處理的 JAR 包。另一方面是解決了 Ruby 技術(shù)棧帶來的問題。
然而,這兩個(gè)方案的都有一個(gè)共同的問題:需要通過 ruby 語言編寫的基礎(chǔ)設(shè)施工具構(gòu)建一套運(yùn)行微服務(wù)的基礎(chǔ)設(shè)施。而這個(gè)基礎(chǔ)設(shè)施的搭建,前前后后估計(jì)得需要至少 1個(gè)月,這還是在運(yùn)維團(tuán)隊(duì)有人幫助的情況下的樂觀估計(jì)。
所以,要找到一種降低環(huán)境構(gòu)建和運(yùn)維團(tuán)隊(duì)阻塞的方式避開傳統(tǒng)的 EC2 搭建應(yīng)用的方式。
這,只有 Lambda 可以做到!
基于上面的種種考量,我們選擇了 Amazon API Gateway + Lambda 的組合。而 Amazon API Gateway + Lambda 還有額外好處:
- 支持用 Swagger 規(guī)范配置 API Gateway。也就是說,你只要導(dǎo)入前端的 Swagger 規(guī)范,就可以生成 API Gateway。
- 可以用數(shù)據(jù)構(gòu)建 Mock API,這樣就可以很大程度上實(shí)現(xiàn)消費(fèi)者驅(qū)動(dòng)契約開發(fā)。
- 通過 Amazon API Gateway 的 Stage 功能,我們無需構(gòu)建 QA 環(huán)境,UAT 環(huán)境和 Staging 環(huán)境。只需要指定不同的 Stage,就可以完成對(duì)應(yīng)的切換。
- Lambda 的發(fā)布生效時(shí)間很短,反饋很快。原先用 CloudFormation 構(gòu)建的 API 基礎(chǔ)設(shè)施需要至少 15 分鐘,而 Lambda 的生效只需要短短幾秒鐘。
- Lambda 的編寫很方便,可以采用在線的方式。雖然在線 IDE 并不很好用,但是真的也寫不了幾行代碼。
- Lambda 自動(dòng)根據(jù)請(qǐng)求自擴(kuò)展,無需考慮負(fù)載均衡。
雖然有這么多優(yōu)點(diǎn),但不能忽略了關(guān)鍵性的問題:AWS Lambda 不一定適合你的應(yīng)用場(chǎng)景!
很多對(duì)同步和強(qiáng)一致性的業(yè)務(wù)需求是無法滿足的。所以,AWS Lambda 更適合能夠異步處理的業(yè)務(wù)場(chǎng)景。此外,AWS Lambda 對(duì)消耗存儲(chǔ)空間和 CPU 很多的場(chǎng)景支持不是很好,例如 AI 和 大數(shù)據(jù)。(PS: AWS 已經(jīng)有專門的 AI 和大數(shù)據(jù)服務(wù)了,所以不需要和自己過不去)
對(duì)于我們的應(yīng)用場(chǎng)景而言,上文中的 Ruby On Rails 應(yīng)用中的主要功能(至少60% 以上)實(shí)際上只是一個(gè)數(shù)據(jù)轉(zhuǎn)換適配器:把前端輸入的數(shù)據(jù)進(jìn)行加工,轉(zhuǎn)換成對(duì)應(yīng)的 SOAP 調(diào)用。因此,對(duì)于這樣一個(gè)簡單的場(chǎng)景而言,Amazon API Gateway + Lambda 完全滿足需求!
4. 部署后端微服務(wù)
選擇了Amazon API Gateway + Lambda 后,后端的微服務(wù)部署看起來很簡單:
- 更新 Lambda 函數(shù)。
- 更新 API 規(guī)范,并要求 API 綁定對(duì)應(yīng) Lambda 函數(shù)處理請(qǐng)求。
但是,這卻不是很容易的一件事。我們將在下一篇文章《Serverless 風(fēng)格微服務(wù)的持續(xù)交付》中對(duì)這方面踩過的坑詳細(xì)介紹。
5. 把原應(yīng)用的請(qǐng)求導(dǎo)向新的微服務(wù)
這時(shí)候在 CDN 上給新的微服務(wù)配置 API Gateway 作為一個(gè)新的源(Origin),覆蓋原先寫在 route.rb 和 nginx.conf 里的 API 訪問規(guī)則就可以了。CDN 會(huì)攔截訪問請(qǐng)求,使得請(qǐng)求在 nginx 處理之前就會(huì)把對(duì)應(yīng)的請(qǐng)求轉(zhuǎn)發(fā)到 API Gateway。
當(dāng)然,如果你想做灰度發(fā)布的話,就不能按上面這種方式搞了。CloudFront 和 ELB 負(fù)載均衡 并不具備帶權(quán)轉(zhuǎn)發(fā)功能。因此你需要通過 nginx 配置,按訪問權(quán)重把 API Gateway 作為一個(gè) upstream 里的一個(gè) Server 就可以。
6. 刪除舊的服務(wù)代碼
不要留著無用的遺留代碼!
不要留著無用的遺留代碼!
不要留著無用的遺留代碼!
重要且最容易被忽略的事情要說三遍。斬草要除根,雖然我們可以保持代碼不動(dòng)。但是清理不再使用的遺留代碼和自動(dòng)化測(cè)試可以為其它團(tuán)隊(duì)減少很多不必要的工作量。
7. 最終的架構(gòu)
經(jīng)過6個(gè)人兩個(gè)月的開發(fā)(原計(jì)劃8個(gè)人3個(gè)月),我們的 Serverless 微服務(wù)最終落地了。當(dāng)然這中間有 60% 的時(shí)間是在探索全新的技術(shù)棧。如果熟練的話,估計(jì) 4 個(gè)人一個(gè)月就可以完成工作。
***的架構(gòu)如下圖所示:
在上圖中,請(qǐng)求仍然是先通過域名到 CDN (CloudFront),然后:
- CDN 根據(jù)請(qǐng)求點(diǎn)的不同,把頁面請(qǐng)求轉(zhuǎn)發(fā)至 S3 ,把 API 請(qǐng)求轉(zhuǎn)發(fā)到 API Gateway。
- 前端的內(nèi)容通過藍(lán)綠部署被放到了不同的 S3 Bucket 里面,只需要改變 CDN 設(shè)置就可以完成對(duì)應(yīng)內(nèi)容的部署。雖然對(duì)于部署來說藍(lán)綠 Bucket 乍看有一點(diǎn)多余,但這是為了能夠在生產(chǎn)環(huán)境下做集成在線測(cè)試準(zhǔn)備的。這樣可以使環(huán)境不一致盡可能少。
- API Gateway 有自己作用的 VPC,很好的實(shí)現(xiàn)了網(wǎng)絡(luò)級(jí)別的隔離。
- 通過 API Gateway 轉(zhuǎn)發(fā)的 API 請(qǐng)求分成了三類,每一類都可以根據(jù)請(qǐng)求狀況自擴(kuò)展。
- 身份驗(yàn)證類:***次訪問會(huì)請(qǐng)求 ElastCache(Redis),如果 Token 失效或者不存在,則重新走一遍用戶驗(yàn)證流程。
- 數(shù)據(jù)請(qǐng)求類:數(shù)據(jù)請(qǐng)求類會(huì)通過 Lambda 訪問由其他團(tuán)隊(duì)開發(fā)的 Java 微服務(wù),這類微服務(wù)是后臺(tái)系統(tǒng)唯一的訪問點(diǎn)。
- 操作審計(jì)類:請(qǐng)求會(huì)記錄到 DynamoDB (一種時(shí)間序列數(shù)據(jù)庫)中,用來跟蹤異步請(qǐng)求的各種日志。
- API Gateway 自己有一些緩存,可以加速 API 的訪問。
- 消息返回后,再有三類不同的請(qǐng)求的結(jié)果統(tǒng)一通過 API Gateway 返回給客戶端。
五、Serverless 風(fēng)格微服務(wù)架構(gòu)的優(yōu)點(diǎn)
由于沒有 EC2 設(shè)施初始化的時(shí)間,我們減少了至少一個(gè)月的工作量,分別是:
- 初始化網(wǎng)絡(luò)配置的時(shí)間。
- 構(gòu)建 EC2 配置的時(shí)間。
- 構(gòu)建反向代理和前端靜態(tài)內(nèi)容服務(wù)器的時(shí)間。
- 構(gòu)建后端 API 應(yīng)用基礎(chǔ)設(shè)施的時(shí)間。
- 構(gòu)建負(fù)載均衡的時(shí)間。
- 把上述內(nèi)容用 Ruby 進(jìn)行基礎(chǔ)設(shè)施即代碼化的時(shí)間。
如果要把 API Gateway 算作是基礎(chǔ)設(shè)施初始化的時(shí)間來看。***次初始化 API Gateway 用了一天,以后 API Gateway 結(jié)合持續(xù)交付流程每次修改僅僅需要幾分鐘,Serverless 風(fēng)格的微服務(wù)大大降低了基礎(chǔ)設(shè)施配置和運(yùn)維門檻。
此外,對(duì)于團(tuán)隊(duì)來說,Amazon API Gateway + Lambda 的微服務(wù)還帶來其它好處:
- 開發(fā)效率高,原先至少 45 分鐘的開發(fā)反饋周期縮短為 5 分鐘以內(nèi)。
- 無關(guān)的代碼量少,需要維護(hù)的代碼量少。除了專注業(yè)務(wù)本身。上游和 API Gateway 的集成以及下游和后端服務(wù)的集成代碼量很少。
- 應(yīng)用維護(hù)成本低。代碼僅僅幾十行,且都為函數(shù)式,很容易測(cè)試。避免了代碼庫內(nèi)部復(fù)雜性的增加。
此外,我們做了 Java 和 NodeJs 比較。在開發(fā)同樣的功能下,NodeJS 的開發(fā)效率更高,原因是 Java 要把請(qǐng)求的 json 轉(zhuǎn)化為對(duì)象,也要把返回的 json 轉(zhuǎn)化為對(duì)象,而不像 nodejs 直接處理 json。此外, Java 需要引入一些其它 JAR 包作為依賴。在 AWS 場(chǎng)景下開發(fā)同樣一個(gè)函數(shù)式微服務(wù),nodejs 有 4 倍于 java 的開發(fā)效率提升。
六、***
Serverless 風(fēng)格的微服務(wù)雖然大大減少了開發(fā)工作量以及基礎(chǔ)設(shè)施的開發(fā)維護(hù)工作量。但也帶來了新的挑戰(zhàn):
- 大量函數(shù)的管理。
- SIT,UAT 環(huán)境的管理。
- 持續(xù)交付流水線的配置。
- 面對(duì)基礎(chǔ)設(shè)施集成帶來的測(cè)試。
這讓我們重新思考了 Serverless 架構(gòu)的微服務(wù)如何更好的進(jìn)行持續(xù)交付。
【本文是51CTO專欄作者“ThoughtWorks”的原創(chuàng)稿件,微信公眾號(hào):思特沃克,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】