微服務(wù)拆分之道
解耦何物粉洼,何時解耦
當(dāng)單體系統(tǒng)龐大到無法應(yīng)付時按价,大多企業(yè)都會被迫把它們拆分成微服務(wù)餐茵。這是一次值得的旅行炬转,但卻非坦途辆苔。我們學(xué)到了一些如何把這件事情做好的東西。我們需要從簡單的服務(wù)入手扼劈,然后把對業(yè)務(wù)重要的經(jīng)常變化的垂直功能的服務(wù)挑出來驻啤。這些服務(wù)首先應(yīng)該是大的,而且最好不依賴單體系統(tǒng)的其他部分荐吵。我們應(yīng)該確保遷移的每一步都代表一個對整個架構(gòu)的原子性改善骑冗。
遷移單體系統(tǒng)到一個微服務(wù)生態(tài)系統(tǒng)將會是一場史詩搬的旅行。開啟這段旅行的人們都希望能夠擴大運維的規(guī)模先煎,加快變更的步伐以及避免變更的高昂代價贼涩。他們希望他們團(tuán)隊的數(shù)量獲得增長,同時可以彼此獨立并行的交付價值薯蝎;他們希望快速試驗核心業(yè)務(wù)功能磁携,更快地交付價值;他們也希望避免因?qū)σ延袉误w系統(tǒng)的改變產(chǎn)生高成本良风。
把一個單體系統(tǒng)拆分進(jìn)微服務(wù)生態(tài)系統(tǒng)谊迄,解耦什么功能,何時及如何增量遷移是架構(gòu)挑戰(zhàn)的一部分烟央。在這篇文章中统诺,我將分享一些技巧以指導(dǎo)交付團(tuán)隊——開發(fā)人員、架構(gòu)師及技術(shù)經(jīng)理——在這次旅途中如何拆分服務(wù)疑俭。
為了闡明這些技巧粮呢,我要借用一個多層的在線零售系統(tǒng)。該系統(tǒng)把用戶接口,業(yè)務(wù)邏輯和數(shù)據(jù)層緊密結(jié)合在一起啄寡。我選擇這個例子的原因是因為它的架構(gòu)具有許多運行業(yè)務(wù)的單體應(yīng)用的特征豪硅,而且它采用的技術(shù)棧也是很先進(jìn)的,非常適合分解挺物,而不是完全重寫和替換懒浮。
目的地——微服務(wù)生態(tài)系統(tǒng)
在踏上旅途之前,擁有一個對微服務(wù)生態(tài)系統(tǒng)的一致的理解對我們來說是關(guān)鍵的识藤。微服務(wù)生態(tài)系統(tǒng)就是一個服務(wù)平臺砚著,其上的每個服務(wù)封裝了一個業(yè)務(wù)功能。業(yè)務(wù)功能代表在一個具體的域里面為了實現(xiàn)業(yè)務(wù)目標(biāo)和職責(zé)而做的事情痴昧。每個微服務(wù)暴露一個API稽穆,開發(fā)者可以發(fā)現(xiàn)并以自服務(wù)方式使用它。微服務(wù)擁有獨立的生命周期赶撰。開發(fā)者可以獨立的構(gòu)建舌镶、測試和發(fā)布每個微服務(wù)。微服務(wù)生態(tài)系統(tǒng)實施的組織結(jié)構(gòu)中豪娜,團(tuán)隊是自治的且長期存在的餐胀,每個團(tuán)隊負(fù)責(zé)一個或多個服務(wù)。與人們普遍的認(rèn)知不同侵歇,與微服務(wù)這個詞中的‘微’字面意思不同骂澄,每個服務(wù)的大小并不重要,它會因組織運維成熟度不同而變化惕虑。正如Martin Fowler所說:“微服務(wù)是一個標(biāo)簽而不是一種描述”坟冲。
旅行指南
在開始深入了解本指南之前,認(rèn)識到拆分已有系統(tǒng)到微服務(wù)總體成本會很高而且可能需要多次迭代很重要溃蔫。開發(fā)者和架構(gòu)師必須仔細(xì)評估是不是有必要分拆單體系統(tǒng)健提,微服務(wù)本身是不是其真正的歸宿。講完這些伟叛,讓我們來看看本指南私痹。
從簡單,能合理解耦的功能開始熱身
開始微服務(wù)之旅需要一個最低級別的運維就緒统刮。它需要按需訪問部署環(huán)境紊遵,創(chuàng)建新類型的CI管道,獨立編譯侥蒙,測試和部署可執(zhí)行的服務(wù)暗膜。同時它還需要為分布式系統(tǒng)提供安全,調(diào)試以及監(jiān)控的能力鞭衩。無論是構(gòu)建全新(greenfield)服務(wù)還是分解已有系統(tǒng)都需要成熟的運維就緒環(huán)境学搜。關(guān)于運維就緒的更多信息娃善,可以閱讀Martin的關(guān)于微服務(wù)前置條件的文章。不過瑞佩,好消息是從Martin的那篇文章之后微服務(wù)架構(gòu)運維技術(shù)得到快速的演進(jìn)聚磺。其中包括誕生了Service Mesh——一個具體的運行快速、可靠及安全的微服務(wù)網(wǎng)格的基礎(chǔ)架構(gòu)層炬丸,提供更高層面的部署架構(gòu)抽象的容器編排系統(tǒng)瘫寝,像GoCD這樣的以容器的方式編譯,測試和部署微服務(wù)的CD系統(tǒng)御雕。
我的建議是開發(fā)和運維團(tuán)隊構(gòu)建底層基礎(chǔ)架構(gòu)矢沿,為第一個和第二個被分解出來或新構(gòu)建的服務(wù)構(gòu)建CI管道和API管理系統(tǒng)滥搭。我們從單體系統(tǒng)中能合理分解出來的功能開始酸纲。因為,他們不需要改變許多正在使用單體系統(tǒng)的面向客戶的應(yīng)用瑟匆,可能也不需要數(shù)據(jù)存儲闽坡。在這個時候交付團(tuán)隊需要優(yōu)化他們交付方法,為團(tuán)隊成員提供技能培訓(xùn)愁溜,建立最小化的基礎(chǔ)架構(gòu)來交付安全的可獨立部署的暴露自服務(wù)API的服務(wù)疾嗅。比如,對于在線零售系統(tǒng)冕象,第一個服務(wù)可能是這個單體系統(tǒng)調(diào)用驗證用戶的“終端用戶驗證”服務(wù)代承。第二個可能是“用戶Profile”服務(wù), 它是一個面板服務(wù)渐扮,為新的客戶應(yīng)用提供一個更好地消費者視圖论悴。
首先,我建議解耦簡單的邊界服務(wù)墓律。其次我們采用不同的方法來分解深度嵌入在單體系統(tǒng)中的功能膀估。之所以建議一開始分解邊界服務(wù)是因為在這段旅行之初,交互團(tuán)隊最大的風(fēng)險在于不能對微服務(wù)進(jìn)行合適的運維耻讽。所以可以使用邊界服務(wù)來實踐他們所需的“運維前提”察纯。一旦他們解決了運維先決條件相關(guān)的問題,他們就能夠應(yīng)對拆分單體系統(tǒng)的關(guān)鍵問題针肥。
最小化對單體系統(tǒng)的向后依賴
作為一個最基本的原則饼记,交付團(tuán)隊?wèi)?yīng)該最小化新形成的微服務(wù)對原單體系統(tǒng)的依賴。微服務(wù)主要的一個優(yōu)勢在于具有一個快速且獨立的發(fā)布周期慰枕。與原單體系統(tǒng)的數(shù)據(jù)具则、邏輯或者API的依賴會把服務(wù)與單體系統(tǒng)耦合在一起,妨礙微服務(wù)優(yōu)勢的發(fā)揮捺僻。通常我們從單體系統(tǒng)分解出服務(wù)的原因是與其綁定的功能變更的高成本和低效率乡洼。所以崇裁,我們希望通過消除對這個單體系統(tǒng)的依賴逐步解耦這些核心功能。假如團(tuán)隊遵守這個原則構(gòu)建功能服務(wù)束昵,他們會發(fā)現(xiàn)依賴都是反向的從單體系統(tǒng)到服務(wù)拔稳。這是所期望的依賴方向,因為這不會影響新的服務(wù)的變更速度锹雏。
考慮在線零售系統(tǒng)巴比,“購買”和“促銷”都是核心功能〗缸瘢“購買”的功能結(jié)賬的時候會使用“促銷”功能根據(jù)用戶購買的產(chǎn)品為他們提供有效的最佳優(yōu)惠轻绞。假如我們需要決定先解耦這兩個功能的哪一個,我建議先解耦“促銷”佣耐,再解耦“購買”政勃。因為按照這個順序我們就能夠減少對這個單體系統(tǒng)的依賴。按照這個順序兼砖,“購買”起初還會維持在老的單體系統(tǒng)內(nèi)奸远,但卻是依賴新的“促銷”微服務(wù)。
下一個指導(dǎo)原則是關(guān)于開發(fā)者決定解耦服務(wù)順序的其他方式讽挟。這意味著他們不總是能夠避免要反向依賴原單體系統(tǒng)懒叛。如果新的服務(wù)最終需要回調(diào)單體系統(tǒng),我建議從單體中暴露一個新的API耽梅,在新的服務(wù)中通過一個“防腐”層來調(diào)用該API以確保單體系統(tǒng)的概念不會浸染微服務(wù)薛窥。要盡量確保這個API按照定義良好的域慨念和結(jié)構(gòu)定義,即使單體系統(tǒng)內(nèi)部實現(xiàn)可能不同(注:該新的API可以理解成是一個適配器眼姐,它按照新的微服務(wù)定義良好的業(yè)務(wù)域概念設(shè)計诅迷,但它需要實現(xiàn)單體系統(tǒng)中老的域概念到新的域概念的適配。通過這個API使得拆分出來的微服務(wù)對單體系統(tǒng)中舊的域概念透明妥凳,防止了舊的域概念“入侵”竟贯。該API起到了防腐層隔離的作用)。在這種不好的情況下逝钥,交付團(tuán)隊可能承受改變單體系統(tǒng)帶來的成本和難度的問題屑那,需要配合單體系統(tǒng)的發(fā)布一起測試發(fā)布的新的系統(tǒng)。
黏連性功能早拆分
假設(shè)現(xiàn)在交付團(tuán)隊可以很愉快的構(gòu)建微服務(wù)了艘款,并且準(zhǔn)備好了解決棘手的問題持际。然他們發(fā)現(xiàn)接下來的功能拆分不依賴單體系統(tǒng)是不可能的。存在這個問題的根本原因常常是因為單體系統(tǒng)內(nèi)的功能域概念設(shè)計部完整哗咆,沒有良好定義蜘欲,單體系統(tǒng)內(nèi)許多其他的功能依賴它。為了能夠繼續(xù)晌柬,開發(fā)者需要識別這類黏連性功能姥份,分解成定義良好的域概念郭脂,然后把這些域概念具體化到不同的服務(wù)中。
比如澈歉,在一個Web單體系統(tǒng)中“會話”的概念是最常用的耦合因子之一展鸡。 在那個在線零售的例子中,會話常常就是一個籃子埃难,裝有許多屬性莹弊,從涉及不同域邊界的用戶偏好如發(fā)貨和支付設(shè)置等,到用戶的意圖和交互涡尘,如當(dāng)前訪問頁面忍弛,點擊的產(chǎn)品和意向清單等。除非我們對當(dāng)前“會話”概念解耦考抄,分解及具體化细疚,否則我們將為解耦未來的諸多功能而疲于奔命,因為他們會因為這個不嚴(yán)謹(jǐn)?shù)臅捀拍詈蛦误w系統(tǒng)“糾纏”在一起座泳。我也不鼓勵在單體系統(tǒng)之外創(chuàng)建“會話”服務(wù)惠昔,因為它也只會導(dǎo)致和目前在單體進(jìn)程中存在的相似的緊密耦合幕与。而且挑势,情況會更糟糕,因為這種耦合是進(jìn)程外跨網(wǎng)絡(luò)的啦鸣。
開發(fā)人員可以從逐步從黏連性功能中提取出微服務(wù)潮饱,一次一個。比如诫给, 重構(gòu)“消費者意向清單”香拉,并提取出來創(chuàng)建一個新的服務(wù),然后重構(gòu)“消費者支付偏好”中狂,產(chǎn)生一個新的微服務(wù)凫碌。如此重復(fù)。
使用依賴和結(jié)構(gòu)化代碼分析工具胃榕,比如Structure101盛险,來識別單體系統(tǒng)中耦合度最高,約束最大的功能因子勋又。
垂直拆分并盡早切分?jǐn)?shù)據(jù)
從單體中把功能拆分出來主要是為了能夠單獨發(fā)布這些功能苦掘。第一個原則就是指導(dǎo)開發(fā)人員進(jìn)行如何拆分。單體系統(tǒng)經(jīng)常是由緊密集成的多層楔壤,甚至是彼此依賴脆弱而且需要同時發(fā)布的多個(子)系統(tǒng)組成鹤啡。比如,在線零售系統(tǒng)是由一個或多個面向客戶的在線購物應(yīng)用蹲嚣,一個實現(xiàn)許多業(yè)務(wù)功能的后端系統(tǒng)以及用于保存狀態(tài)的中心化集成的數(shù)據(jù)存儲組成递瑰。
許多拆分都是企圖從提取出面向用戶的組件入手祟牲,同時拆分出幾個面板服務(wù)為開發(fā)者提供友好的新式用戶界面的API。然而抖部,數(shù)據(jù)依然維持在一個schema和一個存儲系統(tǒng)中疲眷。這種方法可以快速獲勝,比如可以更頻繁的改變用戶界面您朽。但是當(dāng)設(shè)計核心功能時狂丝,交互團(tuán)隊只能以單體系統(tǒng)和其數(shù)據(jù)存儲變更最慢的部分效率進(jìn)行。簡單來說哗总,數(shù)據(jù)沒有拆分几颜,就不是微服務(wù)架構(gòu)。把所有數(shù)據(jù)保存在同一個數(shù)據(jù)存儲里也是不符合去中心化數(shù)據(jù)管理微服務(wù)特征讯屈。
為此蛋哭,我們的策略就是把功能垂直移出,將核心功能和數(shù)據(jù)解耦涮母,并且把所有前端應(yīng)用都重定向到新的服務(wù)API谆趾。
多個應(yīng)用共享中心化數(shù)據(jù)是切分拆分后服務(wù)所使用的數(shù)據(jù)的主要障礙。交付團(tuán)隊需要采用適合他們環(huán)境的數(shù)據(jù)遷移策略叛本,這取決于他們是否能夠同時重定向和遷移所有的數(shù)據(jù)讀寫者沪蓬。Stripe的四階段數(shù)據(jù)遷移策略是其中之一,它被應(yīng)用到要求逐步遷移與數(shù)據(jù)庫集成的應(yīng)用来候,同時所有系統(tǒng)都可以持續(xù)運行的環(huán)境中跷叉。
避免僅僅拆分前端用戶面板和后端服務(wù)而不拆分?jǐn)?shù)據(jù)。
拆分重要且頻繁變化的業(yè)務(wù)
把功能從單體系統(tǒng)中拆分出來是件困難的事情营搅。我聽到過Neal Ford用周密的器官手術(shù)對此做過類比云挟。在在線零售應(yīng)用中,拆分出一個功能需要把該功能涉及的數(shù)據(jù)转质、邏輯和用戶接口組件仔細(xì)地剝離出來园欣,然后重定向到新的服務(wù)中。這需要花費不少的工作量休蟹,開發(fā)者需要基于他們獲得的好處沸枯,比如提高效率,擴大規(guī)模等持續(xù)評估拆分的成本鸡挠。舉例來說辉饱,如果交互團(tuán)隊目標(biāo)是加速對已有的被困于單體系統(tǒng)中功能的修改,那么他們必須識別出一直被修改的最多的功能然后把它拿出來拣展。把那些不斷變化的代碼分離出來彭沼。這些代碼正在獲得開發(fā)人員大量“關(guān)愛”,但又在束縛他們快速發(fā)布價值备埃。交互團(tuán)隊可以分析代碼提交模式找出以往變化最多的代碼姓惑, 然后結(jié)合產(chǎn)品路線圖及其組合來了解最期望的在不久的將來亦最受關(guān)注的功能褐奴。開發(fā)人員需要與業(yè)務(wù)和產(chǎn)品經(jīng)理來交談以了解對他們來說真正重要的差異化的功能。
拿在線零售系統(tǒng)的例子來說于毙,“客戶個性化”功能需要反復(fù)進(jìn)行試驗以便為客戶提供最好的體驗敦冬。所以它是一個好的拆分候選項。它是一項對業(yè)務(wù)唯沮,對用戶體驗很重要而且會頻繁變化的功能脖旱。
使用社交代碼分析工具如CodeScene發(fā)現(xiàn)最活躍的組件。如果編譯系統(tǒng)在每次代碼提交的時候恰好會觸及或者自動產(chǎn)生代碼介蛉,請確保過濾掉了這些“雜音信號”萌庆。把這些頻繁變化的代碼和產(chǎn)品路線圖即將發(fā)生的變更相對應(yīng)然后找出需要拆分的交叉點。
拆分功能币旧,而不是代碼
不管什么時候践险,開發(fā)人員想從已有系統(tǒng)里頭剝離服務(wù)有兩種方式:代碼萃取和功能重寫。
通常缺省的情況下吹菱,服務(wù)提取或者單體分解被假定為重用原來已有的實現(xiàn)并把它摘取出來放入單獨的服務(wù)中巍虫。這樣做的部分原因是我們對自己設(shè)計和編寫的代碼存在認(rèn)知偏差。不管過程如何痛苦結(jié)果如何不完美鳍刷,付出的勞動會使我們對代碼產(chǎn)生感情占遥。事實上,這被稱作為宜家效應(yīng)倾剿。不幸的是筷频,這種認(rèn)知偏差將會妨礙單體系統(tǒng)分解的工作。它會導(dǎo)致開發(fā)人員前痘,甚至包括技術(shù)經(jīng)理即使萃取成本高但價值低也要重用代碼。
作為一種選擇担忧,交互團(tuán)隊可以重寫功能芹缔,而廢除老的代碼。重寫為他們提供一個機會來重新審視業(yè)務(wù)功能瓶盛,啟動與業(yè)務(wù)會話最欠,簡化其往業(yè)務(wù)流程,挑戰(zhàn)隨著時間推移在老的系統(tǒng)形成的陳舊的假設(shè)和約束惩猫。這也為技術(shù)更新芝硬,為使用對具體服務(wù)最適合的技術(shù)棧及編程語言實現(xiàn)服務(wù)的機會。
就在線零售系統(tǒng)來說轧房,“定價”和“促銷”功能是一塊復(fù)雜的智能化代碼拌阴。它能夠動態(tài)配置應(yīng)用定價促銷規(guī)則,基于諸如消費者行為奶镶、忠誠度及產(chǎn)品包等各種因素提供折扣和優(yōu)惠迟赃。
上述功能比較適合代碼萃取重用陪拘。然而,“用戶Profile”是一個簡單的CRUD功能纤壁,其主要由系樣板式的系列化左刽,處理存儲和配置的代碼組成。所以它比較適合棄用老代碼而重寫酌媒。
根據(jù)我的經(jīng)驗欠痴,在大部分分解場景中,團(tuán)隊最好重新實現(xiàn)新的功能而廢棄老的代碼秒咨。但因為下面的原因斋否,可以考慮高成本低價值的重用:
存在大量的處理環(huán)境依賴的樣板式代碼,比如在運行時訪問應(yīng)用配置拭荤,訪問數(shù)據(jù)茵臭,緩存,或者是使用老的框架構(gòu)建的舅世。這些樣板式代碼大部分需要重寫旦委。而新的運行微服務(wù)的框架與十幾年前的老框架差別巨大,需要使用幾乎不同的樣板式代碼雏亚;
很有可能已有的功能不是圍繞清晰的域慨念構(gòu)建的缨硝。這會導(dǎo)致沒有反映新的域模型而需要進(jìn)行大重構(gòu)的數(shù)據(jù)結(jié)構(gòu)傳輸和存儲;
長期遺留的代碼罢低,經(jīng)歷了許多次變更迭代查辩,可能具有很高級別的代碼毒性和較低的重用價值。
除非是關(guān)聯(lián)的网持,和清晰的域概念保持一致的宜岛,具有高知識產(chǎn)權(quán)的功能,我強烈建議對其重寫功舀,棄用老的代碼萍倡。
使用代碼毒性分析工具如CheckStyle來決定重用還是重寫
先大后小
從遺留的單體系統(tǒng)中尋找域邊界是一門藝術(shù)也是一門科學(xué)。作為一般規(guī)則辟汰,應(yīng)用域驅(qū)動技術(shù)尋找定義微服務(wù)邊界的“有界上下文”是一個很好的起點列敲。我承認(rèn),我經(jīng)程看到從大的單體到真正小的服務(wù)的“矯枉過正”戴而。設(shè)計這些小服務(wù)是受已有的規(guī)范化的數(shù)據(jù)視圖啟發(fā)和驅(qū)動的。這種識別服務(wù)邊界的方法幾乎總會圍繞創(chuàng)建翩蘸、讀取所意、修改和刪除資源產(chǎn)生大量的弱服務(wù),從而形成“寒武紀(jì)生命大爆炸”。對于微服務(wù)架構(gòu)的新手來說扁眯,這會產(chǎn)生一個高摩擦的環(huán)境壮莹,最終導(dǎo)致無法使那些服務(wù)進(jìn)行獨立發(fā)布和運行。這會創(chuàng)建一個難于調(diào)試的分布式系統(tǒng)姻檀,一個跨事務(wù)因而難于保持一致性的分布式系統(tǒng)命满,一個對于相對組織運維成熟度來說過于復(fù)雜的系統(tǒng)。盡管有一些關(guān)于微服務(wù)應(yīng)該多“微”的探討绣版,如團(tuán)隊的大小胶台,重寫服務(wù)的時間以及什么樣的行為必須封裝等,我的建議是微服務(wù)的大小取決于交互運維團(tuán)隊能夠獨立發(fā)布杂抽,監(jiān)控和運維多少服務(wù)诈唬。開始可以是圍繞邏輯域概念的大服務(wù),當(dāng)團(tuán)隊運維就緒的話缩麸,再分拆成多個服務(wù)铸磅。
就分解在線零售系統(tǒng)來說,開發(fā)人員開始可以使“購買”服務(wù)既包含包含購物袋上下文功能也包含購買的功能杭朱,比如“結(jié)賬”阅仔。隨著他們能夠成立更小的團(tuán)隊,能夠發(fā)布大量的服務(wù)弧械,他們可以把“購物袋”分離出一個單獨的服務(wù)八酒。
使用Richardson Maturity Model L3(REST成熟度模型)和超鏈接來確保未來的服務(wù)拆分不會影響調(diào)用者。比如刃唐,調(diào)用者能夠發(fā)現(xiàn)如何結(jié)賬而不需要提前知道羞迷。
以原子性演進(jìn)方式遷移
傳統(tǒng)的單體應(yīng)用被分解成設(shè)計優(yōu)美的微服務(wù),然后讓單體應(yīng)用消失的無影蹤的想法有點荒唐画饥,可以說是不可取的衔瓮。任何經(jīng)驗豐富的工程師都可以分享一些關(guān)于嘗試遺留系統(tǒng)遷移和改進(jìn)的故事。這些嘗試都是在抱著對最終完成過分樂觀的狀態(tài)下計劃和開始的荒澡,但大部分都是在足夠好的時間點被放棄了报辱。這些長期努力的計劃之所以取消是因為情況發(fā)生了一些大的變化,比如項目費用用完了单山;組織目標(biāo)轉(zhuǎn)移到其他方向上了;支持的領(lǐng)導(dǎo)層離職了幅疼。所以現(xiàn)實的做法是如何讓單體應(yīng)用踏上微服務(wù)之旅米奸。我們稱之為“架構(gòu)原子演進(jìn)式遷移”,這種方式的遷移每一步都是完整的爽篷,也是可以回撤悴晰。這一點,在我們談到針對整個架構(gòu)的改善和服務(wù)解耦的增量迭代的方法時尤為重要。每個遷移增量必須使我們更好地朝架構(gòu)目標(biāo)前進(jìn)一步铡溪。借用“演進(jìn)式架構(gòu)”適應(yīng)度函數(shù)說法漂辐,每一次原子性遷移之后,架構(gòu)適應(yīng)度函數(shù)應(yīng)該產(chǎn)生一個更接近于架構(gòu)目標(biāo)的值棕硫。
讓我來使用一個例子描述下這點髓涯。 想象一下,微服務(wù)架構(gòu)目標(biāo)是提高開發(fā)人員修改整體系統(tǒng)哈扮,交付價值的速度纬纪。團(tuán)隊決定基于OAuth2.0協(xié)議把終端用戶驗證功能解耦到一個獨立服務(wù)中。這個服務(wù)用來替換已存在的(老的架構(gòu)中的)客戶端應(yīng)用用戶驗證功能和作為新的微服務(wù)架構(gòu)中的用戶驗證滑肉。讓我們把這個演進(jìn)式的增量稱之為“驗證服務(wù)引入”包各。引入該服務(wù)的一個方式就是先完成這些步驟:
(1) 構(gòu)建Auth服務(wù), 實現(xiàn)OAuth 2.0協(xié)議靶庙。
(2)增加一條新的驗證路徑到單體系統(tǒng)的后端調(diào)用新構(gòu)建的Auth服務(wù)问畅,處理終端用戶請求。
假如團(tuán)隊到此為止六荒,轉(zhuǎn)而去構(gòu)建其他的服務(wù)和功能护姆,這會使得整個架構(gòu)處于熵增狀態(tài)。在這種情況下恬吕,有兩種方法驗證用戶签则,一種是通過新的OAuth 2.0,一種是通過老的用戶密碼/會話铐料。這個時候渐裂,實際上團(tuán)隊離快速變化的總的目標(biāo)更遠(yuǎn)了。任何新的單體代碼開發(fā)人員都需要處理兩條代碼路徑钠惩,增加了他們理解代碼的認(rèn)知負(fù)擔(dān)柒凉,降低了修改測試代碼的速度。
然而篓跛,作為我們的一個原子性演進(jìn)單元膝捞,團(tuán)隊可以增加下面的步驟:
(3)替換老的用戶驗證調(diào)用
(4)去除單體系統(tǒng)中老的用戶驗證代碼
至此,我們可以說團(tuán)隊已經(jīng)接近架構(gòu)目標(biāo)了愧沟。
單體拆分的一個原子單元包括:
拆分新的服務(wù)
重定向所有消費者(服務(wù)消費者)到新的用戶
移除單體系統(tǒng)中老的代碼
反模式:解耦新的服務(wù)蔬咬,新的消費者使用新的服務(wù),但老的代碼永遠(yuǎn)不退休沐寺。
我經(jīng)常發(fā)現(xiàn)團(tuán)隊只構(gòu)建新的功能但不讓老的代碼退休就結(jié)束一個從單體系統(tǒng)功能的遷移林艘,然后宣布全部完成。這就是上面描述的反模式混坞。之所以存在這種情況的原因是狐援,a)只關(guān)注引入一個新功能的短期好處钢坦;b)退休老的代碼所需要總的工作量和構(gòu)建新服務(wù)的優(yōu)先級有競爭。為了做正確的事情啥酱,我們要盡可能的努力按原子性步驟去做爹凹。
使用這種遷移方法,我們可以把遷移之旅分成一段段更短的旅途镶殷,能夠安穩(wěn)的停下禾酱,然后重新開始,確保整個旅行的順利批钠,最終“消滅”單體宇植。