微服務(wù)遷移之旅

微服務(wù)拆分之道

——Zhamak Dehghani

原文

解耦何物粉洼,何時解耦

當(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)簽而不是一種描述”坟冲。


Figure 1: Services encapsulate business capabilities, expose data and functionality through self-serve APIs

旅行指南

在開始深入了解本指南之前,認(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)鍵問題针肥。


Figure 2: Warming up with a simple capability that has a small radius of change to build our operational readiness

最小化對單體系統(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)。

Figure 3: Decouple the service that doesn’t require a dependency back to the monolith first and minimize changes to the monolith

黏連性功能早拆分

假設(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ù)。


Figure 4: Identify the most coupling concept and decouple, deconstruct and reify into concrete domain services

使用依賴和結(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)境中跷叉。

Figure 5: Decouple capability with its data to a microservice exposing a new interface, modify and redirect consumers to the new API

避免僅僅拆分前端用戶面板和后端服務(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ù)唯沮,對用戶體驗很重要而且會頻繁變化的功能脖旱。

Figure 6: Identify and decouple the capability that matters most: creates most value for business and customer, while changing regularly

使用社交代碼分析工具如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)的功能,我強烈建議對其重寫功舀,棄用老的代碼萍倡。


Figure 7: Reuse and Extract high value code with low toxicity, Rewrite and Retire low value code with high toxicity

使用代碼毒性分析工具如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ù)八酒。


Figure 8: Decouple macro services around rich domain concepts and when ready, breakdown services to smaller domain concepts

使用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)了愧沟。


Figure 9: Evolve the architecture towards microservices with atomic steps of architecture evolution where after each step the overall architecture is improved towards its goal even though intermediary code changes might take it further away from its fitness objective

單體拆分的一個原子單元包括:

拆分新的服務(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)的停下禾酱,然后重新開始,確保整個旅行的順利批钠,最終“消滅”單體宇植。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市埋心,隨后出現(xiàn)的幾起案子指郁,更是在濱河造成了極大的恐慌,老刑警劉巖拷呆,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闲坎,死亡現(xiàn)場離奇詭異,居然都是意外死亡茬斧,警方通過查閱死者的電腦和手機腰懂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來项秉,“玉大人绣溜,你說我怎么就攤上這事÷Π” “怎么了怖喻?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岁诉。 經(jīng)常有香客問我锚沸,道長,這世上最難降的妖魔是什么涕癣? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任哗蜈,我火速辦了婚禮,結(jié)果婚禮上坠韩,老公的妹妹穿的比我還像新娘距潘。我一直安慰自己,他們只是感情好只搁,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布绽昼。 她就那樣靜靜地躺著,像睡著了一般须蜗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天明肮,我揣著相機與錄音菱农,去河邊找鬼。 笑死柿估,一個胖子當(dāng)著我的面吹牛循未,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秫舌,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼的妖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了足陨?” 一聲冷哼從身側(cè)響起嫂粟,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎墨缘,沒想到半個月后星虹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡镊讼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年宽涌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝶棋。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡卸亮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出玩裙,到底是詐尸還是另有隱情兼贸,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布献酗,位于F島的核電站寝受,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏罕偎。R本人自食惡果不足惜很澄,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颜及。 院中可真熱鬧甩苛,春花似錦、人聲如沸俏站。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肄扎。三九已至墨林,卻和暖如春赁酝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旭等。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工酌呆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搔耕。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓隙袁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弃榨。 傳聞我的和親對象是個殘疾皇子菩收,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容