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