Microservice Anti-patterns
在最近的一次Microservices Practitioner Summit中,原Netflix工程師介紹了一種越來越常見的對Microservice的誤用。簡單地說,大家在搭建一個基于Microservice的服務(wù)時常常依賴同一套類庫,進而使得Microservice中的各個子服務(wù)無法選擇最適合的技術(shù)。
如果您不知道Microservice是什么,請首先閱讀我的另一篇文章《Microservice簡介》。
在本文中,我們就將以該演講的內(nèi)容作為引子,介紹一下當前業(yè)界對于Microservice的一系列誤用方式。
?
Distributed Monolith
不知道大家是否喜歡看看各公司所辦的各種會議?,F(xiàn)在不像10年前只有微軟,Intel等幾家公司辦的TechED,IDF等會議了。越來越多的公司喜歡舉辦會議、論壇等活動,以吸引越來越多的優(yōu)秀開發(fā)人員一起討論最新技術(shù)和業(yè)界發(fā)展趨勢。因此我先說點題外話,希望如果大家感興趣請自己尋找一下自己覺得有趣的會議。我相信大家都是喜歡技術(shù)的人。這樣一方面能提高自己的能力,另一方面也對國內(nèi)的技術(shù)環(huán)境有幫助,利人利己。
好,讓我們回到原題。在該工程師的演講中,他提出了近期較為常見的一種對Microservice的誤用:很多公司或個人都認為將一個Monolith的服務(wù)拆分成一系列子服務(wù),就能夠被稱為是基于Microservice的服務(wù)了。的確,這種變化引入了Microservice的一系列優(yōu)點:由于各個子服務(wù)之間擁有了確切的邊界,因此它們將能夠更容易地獨立發(fā)展,而且我們也可以更容易地對該子服務(wù)進行擴容:
但是這種子服務(wù)組織方式并不能完全地稱為Microservice:其丟掉了Microservice的技術(shù)靈活性。在Microservice中創(chuàng)建一個子服務(wù)的方式主要分為兩種:從原有的服務(wù)上剝離,以及新建服務(wù)。
在從原有服務(wù)上剝離時,我們常常會選擇讓新創(chuàng)建的子服務(wù)使用原有的技術(shù),以減少創(chuàng)建子服務(wù)的工作量。這其實并沒有太多的問題,畢竟這種剝離在原有服務(wù)的基礎(chǔ)上提高了各子服務(wù)的獨立性。雖然說此時我們所使用的技術(shù)并不是最合適的,但是的確是最有效率的創(chuàng)建子服務(wù)的方式。
而新建一個Microservice子服務(wù)就不一樣了。在創(chuàng)建一個新的子服務(wù)時,軟件開發(fā)人員常常需要自行編寫該子服務(wù)所包含的所有代碼。因此此時我們應(yīng)該盡量選擇最合適的技術(shù),以獲取最高的開發(fā)效率。
但是誤用就出現(xiàn)在這里。在創(chuàng)建一個新的Microservice子服務(wù)時,軟件開發(fā)人員常常偏向于使用之前所使用的各種技術(shù)。這是軟件開發(fā)人員對已使用技術(shù)所保留的一種慣性:軟件開發(fā)人員在之前對這些類庫的使用中知曉了其可以用來完成某些功能,而并沒有過多地關(guān)注實現(xiàn)這些功能的復雜程度。就像我在《Cassandra簡介》一文中說的那樣,技術(shù)選型是一個非常嚴謹?shù)倪^程。該過程常常需要進行大量的研究,并根據(jù)開發(fā)的難易程度,用戶基數(shù),活躍程度以及成功案例來決定是否使用該技術(shù)。而軟件開發(fā)人員的這種技術(shù)慣性則常常是導致項目最終失去控制的一個原因。
在這些共有的技術(shù)越積越多的情況下,我們的Microservice服務(wù)就越來越容易引入剛剛Netflix工程師所提到的錯誤:在Microservice中廣泛使用類庫特有技術(shù)。我們知道,某些類庫會提供一系列特有的功能,以用來提高執(zhí)行效率,提供更高的安全性等。但是這些技術(shù)常常并不是行業(yè)規(guī)范,因此也會導致其無法與其它類庫兼容。這會導致Microservice中的各個子服務(wù)之間存在著一種隱式的契約:為了有效地在各個子服務(wù)之間進行通訊,Microservice中的各個子服務(wù)需要使用特定的技術(shù)。
如果我們在Microservice中引入這種特定的技術(shù),那么該技術(shù)將會逐漸擴展到Microservice的所有子服務(wù)中:
這樣Microservice中的所有子服務(wù)最終將使用同一個技術(shù)集,進而限制了其它子服務(wù)所能夠選擇的技術(shù)。如果我們?nèi)斡蛇@種情況發(fā)展,那么到最后Microservice中的所有子服務(wù)都將綁定于一整套固定的技術(shù)集之上,并無法再選用最為合適的技術(shù)。而最終的結(jié)果就是,我們的Monolith服務(wù)的確轉(zhuǎn)化為基于Microservice的服務(wù),但是其使用的技術(shù)集還是原來的技術(shù)集。這種服務(wù)組織方式并沒有提高開發(fā)效率,反而增加了在各個Microservice子服務(wù)之間相互溝通的成本,降低了整個服務(wù)對單一請求的響應(yīng)速度??傮w來說,得不償失。
而真正應(yīng)該在Microservice子服務(wù)之間存在的,是明確指定的契約和協(xié)議,而不應(yīng)該是如何實現(xiàn)這些子服務(wù)。
其實一個決策常常是在權(quán)衡各方面優(yōu)劣才做出的。Microservice的優(yōu)勢無非就是具有更好的橫向擴展能力(Scalability),更靈活的技術(shù)選擇,更簡單的子服務(wù)實現(xiàn)邏輯,更清晰的子服務(wù)邊界以及更好的子服務(wù)復用性。但是缺點也一樣明顯:子服務(wù)之間相互通訊所導致的單一請求執(zhí)行效率降低,子服務(wù)邊界所帶來的代碼組織靈活性降低等。如果我們丟掉了靈活的技術(shù)選擇,那么更簡單的子服務(wù)實現(xiàn)邏輯所帶來的高效開發(fā)及更好的維護性就將無從說起。最終所導致的結(jié)果就是:使用Microservice組織子服務(wù)不會為我們帶來額外的好處。
這里還有一個懸而未決的問題,那就是從Monolith剝離出來的各個子服務(wù)常常使用同一個技術(shù)集。是的。在這種情況下,我們要盡量控制這些技術(shù)集的擴散,并在需要時逐漸移除對這些技術(shù)集的依賴。
?
功能邊界不清
我相信有些讀者已經(jīng)對Microservice有些研究了,甚至嘗試過在服務(wù)實現(xiàn)中使用它。最容易遇到麻煩的一點便是對單個請求進行處理時的性能問題。
無論是瀏覽器還是JS類庫,都擁有一個請求超時的概念。在發(fā)送一個請求之后,如果服務(wù)長時間沒有對該請求進行響應(yīng),那么瀏覽器或JS類庫都會將該請求識別為超時。而且從用戶使用的角度來講,他也并不希望一個請求長時間沒有響應(yīng)。因此在一個基于Microservice的服務(wù)中,我們常常需要讓整個服務(wù)能夠快速有效地響應(yīng)用戶的請求。
一個提升性能的方法就是合并請求。如果說用戶對一個服務(wù)的使用需要固定順序的一系列調(diào)用,那么我們就可以通過將這些調(diào)用合并到一起,從而減少反復通訊所造成的損耗:
上圖展示了這種通過合并調(diào)用提高性能的方法。在用戶嘗試找到特定種類下的所有商品時,我們需要通過查找所有的商品種類以確定該商品種類的ID,進而通過該商品種類的ID得到該商品種類下的各種商品。為了能夠合并調(diào)用,我們需要提供一個新的API,以允許軟件開發(fā)人員通過商品種類名稱直接完成調(diào)用,而對商品ID的查詢等執(zhí)行邏輯都放在服務(wù)端去執(zhí)行。這樣用戶就只需要發(fā)送一個請求,而不是三個請求,進而縮短了整個流程的運行時間。
但是這樣還是有問題,那就是我們所新引入的API已經(jīng)將商品種類以及商品這兩個概念包含在同一個子服務(wù)中了。這種包含了過多概念的子服務(wù)常常成長為一個包含了過多功能的子服務(wù),也即是Microservice中的Monolith。
而一個較為正確的解決方案則是:就像我在《Microservice簡介》一文中已經(jīng)提到過的那樣,我們在必要時應(yīng)該提供一個Gateway,并在Gateway中添加合并在一起的API。這樣由于Gateway常常和與其關(guān)聯(lián)的各個子服務(wù)處于同一個數(shù)據(jù)中心中,因此其內(nèi)部通訊效率常常比用戶通過瀏覽器訪問快很多。這樣我們既保證了各個子服務(wù)可以獨立地發(fā)展,又能提高用戶的訪問效率:
而且在該Gateway中,我們也常??梢酝ㄟ^緩存等一系列技術(shù)手段來提高運行效率。
反過來啊,我們也別走到另外一個誤區(qū)里面,那就是建立太多的層次。我能理解一個數(shù)據(jù)庫作為一個獨立的層次的必要性,畢竟數(shù)據(jù)庫常常與其它服務(wù)實例處于不同的服務(wù)實例上。但是如果在縱向上添加太多的層次,那么在處理用戶所發(fā)出的一個請求時就需要經(jīng)過過多的消息轉(zhuǎn)發(fā),從而使得對消息的處理時間變長:
當然,Gateway也是其中的一個層次,因此不要為每個子服務(wù)添加一個Gateway,而是要有一個整體的規(guī)劃:
總之,在如何切割子服務(wù)時我們常常需要在腦中保持是否用戶的請求能被快速響應(yīng)這一個問題。在Microservice中,API的粒度過細,以及內(nèi)部調(diào)用過多是最具有殺傷力,也最容易出現(xiàn)的問題。
?
過于強調(diào)Microservice
的確Microservice這個詞在國外很火。很多公司都將自己的產(chǎn)品是基于Microservice來組織的作為一個賣點。這的確能夠幫助很多銷售人員解釋公司產(chǎn)品所具有的一系列優(yōu)勢。但是作為一個開發(fā)人員,我們不要被這個觀點所迷惑。原因就是因為,直接開發(fā)基于Microservice的服務(wù)所需要的初始開發(fā)成本較Monolith的開發(fā)成本高很多。直到產(chǎn)品的規(guī)模達到一定程度,Microservice的優(yōu)勢才能夠發(fā)揮出來:
而一個產(chǎn)品常常需要經(jīng)由PoC才能變成真正的版本,而且在產(chǎn)品的初期,我們所需要解決的常常不是這個產(chǎn)品需要具有多大的擴展性,而是我們需要有足夠的錢來支撐這個產(chǎn)品的持續(xù)研發(fā)。因此在產(chǎn)品演變的過程中,功能性需求常常在開發(fā)的初期占首要地位,而像橫向擴展能力等非功能性需求在后期才會變得越來越重要。所以在開發(fā)一個全新產(chǎn)品時,如果我們過于注重通過Microservice來組織各個子服務(wù),那么軟件開發(fā)人員在整個項目的初始階段的開發(fā)效率將非常低下。相反地,我們需要在開始實現(xiàn)時盡量注意各個組成之間的隔離。這樣一旦需要從Monolith轉(zhuǎn)化為Microservice,我們只需要將這些代碼根據(jù)其所在的包進行剝離即可。
當然,如果我們已經(jīng)開發(fā)過按照Microservice組織的服務(wù),而且有一系列子服務(wù)可以被重用,那么我們完全可以通過重用之前Microservice服務(wù)所使用的框架來開始這個服務(wù)的開發(fā)。此時Microservice服務(wù)的開發(fā)效率并不會低多少,甚至還可能在非常短的時間之內(nèi)擁有比Monolith開發(fā)更高的效率:
所以說,我們的第一要務(wù)并不是使用Microservice,而是通過它來為業(yè)務(wù)目標服務(wù)。將Microservice置于業(yè)務(wù)目標之前,反而常常在項目初期成為一塊絆腳石。
?
沒有使用Continuous Delivery
因為我一直在外企,所以對Continuous Delivery平臺的使用還是相對較多的。但是從國內(nèi)某些廠商,甚至是較大的廠商使用Microservice搭建服務(wù)時,常常會出現(xiàn)不使用Continuous Delivery平臺的情況出現(xiàn)。這樣就會導致一個問題,搭建測試環(huán)境及生產(chǎn)環(huán)境會非常麻煩。
Microservice的一個重要優(yōu)勢就是提高了開發(fā)效率。反過來,如果軟件開發(fā)人員和測試人員每天需要為如何搭建一個開發(fā)及測試環(huán)境發(fā)愁,那么使用Microservcie開發(fā)又得到了什么好處呢?
當然啊,工作上的事情有些說不清,所以咱們也不多說什么。只能說,Continuous Delivery能夠提高我們的開發(fā)效率。如果您是個決策者,而且剛好看到這篇文章,那么請您一定認真地考慮這一點。其實搭建一個Jenkins環(huán)境也并不是非常困難,所需要的物理機也并不是很多。而且您還能夠在災難恢復等眾多非功能性需求上獲得一系列好處。
?
對,最后提一句,這篇文章和InfoQ上最近的一篇文章有關(guān):http://www.infoq.com/news/2016/03/microservices-anti-patterns。熟悉我的讀者可能知道我喜歡攢文章,隔幾個月再發(fā)布,因為這樣可以根據(jù)一段時間的經(jīng)驗對自己所寫的內(nèi)容進行一次校驗。只不過我看這篇文章同樣提到了這個演講,所以為了避免不必要的解釋,就提前發(fā)了
?
?
轉(zhuǎn)載請注明原文地址并標明轉(zhuǎn)載:http://www.cnblogs.com/loveis715/p/5315860.html
商業(yè)轉(zhuǎn)載請事先與我聯(lián)系:silverfox715@sina.com
公眾號一定幫忙別標成原創(chuàng),因為協(xié)調(diào)起來太麻煩了。。。
轉(zhuǎn)載于:https://www.cnblogs.com/loveis715/p/5315860.html
總結(jié)
以上是生活随笔為你收集整理的Microservice Anti-patterns的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu2041java
- 下一篇: 软件工程个人作业03