微服務的戰爭:按什麼維度拆分服務

微服務,這三個字正在席捲着目前的互聯網軟件行業,尤爲在近幾年雲原生迸發後,彷佛人人都對微服務有了更普遍的使用和理解,張口就是各類各樣的問號,有着強大的好奇心。web

無獨有偶,我有一個朋友鯉魚在內部微服務的早期(每一個業務組起步)就常常遇到下述的對話:數據庫

  1. 張三:爲何要拆如今的代碼?微信

  2. 鯉魚:由於 !@)&&#@!)&#!&)@!&!的緣由。網絡

  3. 張三:那即將要作的 「微服務」 是按照什麼維度去拆分的服務?架構

  4. 鯉魚:常見的通常根據 !@#*@!#&!(@&!@)#@ 的方式來拆分。編輯器

  5. 張三:照你這麼說好像也不大對,我看每一個業務組拆分的維度彷佛都不大同樣?函數

  6. 鯉魚:嗯,每一個業務組還有本身的看法,不會徹底相同。微服務

  7. 張三:。。。因此微服務的拆分維度究竟是什麼?工具

爲何想拆

爲何張三會有這個疑問呢,其實是由於研發內部但願從原先的大單體,大倉庫向微服務體系拆分轉換,其原先大單體倉庫結構,類 Monorepo:性能

但類 Monorepo 又有很多的問題,像是:

  1. 單個 Repo 體積過大:致使 Git 沒法直接拉取。當你設置完再拉取時,在網速慢時還能去泡杯咖啡,而且在開發機性能不佳的狀況下,IDE 會比較卡,代碼運行起來也慢。

  2. 單個 Repo 存在公共函數/SDK:在代碼倉庫中,必然存在公共依賴。所以在解決代碼衝突時,若遺留了衝突符,且在動態語言中,不涉及便運行正常。但其實在上線後卻又影響到其餘業務,可真是糟糕透頂,分分鐘被迫抱着事故。

  3. 單個 Repo 模塊職責/邊界不清:在實際的軟件開發中,涉及數十個業務組同時在一個大 Repo 下進行開發,沒有強控邊界的狀況下,每每會逐漸模糊,即便在設計時管得住本身,你也不必定能 100% 防止別人模糊你的邊界。

  4. 單個 Repo 包含了全部的源碼:出現公司源代碼泄露時,會致使整個 Repo 外泄,至關的刺激和具備教育意義。由於雖然開放和協同了,不屬於大家組的業務代碼你也有權限查看了。

固然,Monorepo 是否又徹底不可行呢?實際上國外 Google,Facebook,Twitter 等公司都有在使用 Monorepo,並取得了必定的收益。

其實作 Monorepo 是須要相應的大量工具支撐,若單純只是一個 Repo 塞多個模塊,基本都作很差,甚至引火燒身。還不如早早拆開,至少能確保各業務線服務的相對獨立性。

拆成什麼樣

張三在明白了拆的緣由後,就出現了第二個問題,那就是 「微服務」 要按照什麼樣的維度去拆分服務?

張三公司內部對於這塊的知識處於模糊不清的階段,所以須要進行深刻了解,便於後續的團隊共識和方法論創建,理所固然,十萬個爲何也就出現了。

大單體變獨立服務

最多見的拆分的方式是按照業務模塊進行服務的拆解,像是前文所提到的業務模塊,在設計上邊界很是清晰,這種狀況直接拆成各個服務就能夠了:

而在拆分後,又會遇到一個新的問題,也就是張三問第三個問題 「每一個業務組拆分的維度彷佛都不大同樣?」。

由於在實際的執行過程當中,嚴謹一些會由 SM 與 RD 一同開會探討/規範第一版的服務劃分,而在持續的快速的迭代中,每每新服務的拆分都是由一線 RD 親自操刀。

即便是架構師親自操刀,在相對複雜的業務模型下,不一樣架構師劃分出來的也有可能不徹底一致,所以不管是哪一種狀況,你都會發現每一個業務組拆分的維度多多少少都不同了,畢竟人與人的思想都是不同的,一千我的有一個千個哈姆雷特,所以張三的疑惑是正常的。

就像下圖,核心是定義一隻魚,在不一樣人的眼中能演化出各類奇奇怪怪的魚:

大數據庫變獨立數據庫

在之前早期的大單體快速迭代中,每每是一個大數據庫包含全部的業務數據庫(甚至數據庫帳號都不分),這種時候就會帶來各類問題。

像是某一天,你所負責的業務模塊數據庫莫名其妙出現了一些奇奇怪怪的值,你可能就要抓破腦殼去各類代碼和 binlog 查了。更甚還有被網絡攻擊後,數據庫配置被獲取,直接跳板一拖直接整個脫褲,那但是糟糕透頂了。

所以在常見的應用設計中,應用程序在鏈接數據庫時會指定鏈接特定的域名(例如:eddycjy-user),方便將來遷移。而且每一個業務服務分別給予獨立的數據庫只讀權限,進行軟隔離。

而在業務量上來後,也會對業務數據庫進行硬隔離,分配特定的 RDS 實例,就不會互相影響了。

環境隔離,獨立

在服務拆分後,大多會採起獨立部署的方式,將二者之間的環境隔離開來,互不干擾,互不影響:

像在雲原生中,常見於在 Kubernetes 將一個業務服務做爲一個 Service 部署發佈,再根據實際的資源和調度狀況進行 Pod 的擴縮容就能夠了,資源也不會有直接干擾,且外部/內部調用都是有統一的入口管理。

拆分的陣痛

業務接口聚合

在服務拆分的過程當中,老是會有陣痛出現。

例如在服務須要獲取 「項目」 和 「房源」 信息時,究竟是由誰來聚合這兩個服務的信息。是否是應該由 BFF 來聚合:

或是應該新寫一個膠水服務,用於聚合「項目」 和 「房源」 信息,保證其聚合性,減輕 BFF 的負擔:

又或是在量級愈來愈多的狀況下,是否是要懷疑一下,這兩個服務拆分是否是有問題,「項目」 和 「房源」 在當前業務模型下是否應是一家:

顯然在鯉魚的經歷中,這三種類型他都見過,不一樣的人總會在不一樣的思想和業務模型下選擇了不一樣的解決方案,還真的沒有絕對準確的準則。

分久必合,合久必分

隨着對服務化的進程推動,常見的會遇到兩種狀況:

  • 剛接觸服務化時:服務一個沒有,偶爾會有一個新的小業務,竟然能拆出好好幾個微型服務,並揚言要把剩餘業務直接抄底重構了,都拆掉,怎麼勸都勸不回頭。

  • 隨着業務的不斷髮展:快速迭代,服務愈來愈多,工期壓縮,多個 RD 交叉背好幾個業務服務,有點力不從心,發現拆的好像有點問題,從最新的狀況來看,某某幾個服務彷佛應該合在一塊兒。

  • 業務階段性穩定:。。。這,之前這塊好像有點問題,也太難拓展了,不該該這麼拆,誰調了我,個人上下游是誰。

大多數的狀況都是第二和第三者,但在實際操做中也不見得會合並服務,大多數 RD 會選擇吞進內心,由於服務變遷所帶來的工期延長和影響面沒法直接預估(且存在歷史代碼,人員可能已經離職多年)。即便是服務拓撲也只能查看到必定時間內的服務調用,不會看到所有,所以上下游均沒法 100% 肯定。所以綜合來看,弊大於利。

在解決方案上,更多的是在下次新服務規劃時控制劃分變量(由於已經有更成熟的經驗了)。

實在不行了,纔有可能會新起聚合服務將本來的多個服務聚合,又或是採起版本號等方式進行新老分流。甚至下定決心,螞蟻搬家,起新服務一個個板塊重構,一個個挪,持續灰度,「完全」 解決歷史包袱,完成轉化。

拆分準則

張三又發話了,你說的我都懂,內部微服務都發展好幾年了,做爲已經有豐富研發經驗的人,能不能釋出一套微服務拆分的準則呢,不然每個人都要經歷一遍,怎麼辦,有沒有什麼基本準則能夠遵照呢,你看如今 DDD 那麼火,能不能 DDD 一下,讓核心一致呢?

機智的鯉魚掐指一算,張三確定想的是讓全部業務組的拆分,都能依據拆分的核心準則走,實現你中有我,我中有你,看哪哪都有影子,核心不跑偏就行,創建一套完美的方法核心論:

這種建議右拐 Google 「微服務如何拆分」,網上有超級多的指導資料,建議先培養在團隊內的共識。畢竟在每次拆服務時讓每個人都對照着那一長串的 「微服務拆分準則」 是一件很不科學的事情,更多的工程師會依據自身的經驗進行當前其認爲的最合理拆解。

而準則,你認爲的核心 A,在他人眼裏並不必定是正確,他可能認爲是 B,所以在事業部,業務團隊中達成共識並把拆分思想融合進每位 RD 思想中,長期的共同分析如今的拆分狀況,且讓你們基本認同纔是最重要的。

同時讓全公司都依據一個準則來作,在服務拆分這種沒法利用工具流程強控制的狀況,自己就是一個僞命題,更多的會是人與人之間的妥協,基本上會變成一個少有人看的 「指導」 文檔。

總結

在微服務中,服務的拆分老是能讓人如此細細品味,本文並非具體的講某幾個知識點,更多的是闡述在服務化發展的歷程中的 「衝突點」 又或是 「矛盾點」,不一樣的人總有不同的理解,但願可以給你們帶來一些思考。

且在閱讀微服務相關指南時,更建議看企業實踐後拆分的經驗分享,不然單純看 「指南」 沒有過多的意義,要看具體的公司/團隊狀況和業務模型。

推薦閱讀

Monorepo:

  • Why Google Stores Billions of Lines of Code in a Single Repository

  • Monorepos: Please don’t!

  • Why might a project/company use a monorepo?

Microservices:

  • Nginx Refactoring a Monolith into Microservices


本文分享自微信公衆號 - 腦子進煎魚了(eddycjy)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索