技術趨勢關鍵詞:分布式架構+微服務架構(針對移動互聯網)+一體式架構(前兩者結合+UI等敏捷開發)
【譯者的話】otto.de是德國的一家網上購物網站,本篇前半部分主要介紹了幾個系統架構以及它們的優缺點,后半部分主要講解otto.de的微服務架構。
在我們開始開發otto.de網上商店時,我們選擇了分布式垂直架構。之前的工作經驗告訴我們,一體化架構(monolithic architecture)不能夠滿足不斷增長的需求。爆發式增長的數據,持續提高的負載和對系統的擴展,所有的這些強迫我們去重新思考網站的架構。微服務分布式事務?
這篇文章將會描述我們的解決辦法,還有我們這么做的原因。
在項目剛開始的時候,團隊通常會考慮使用什么編程語言和合適的架構。當談到服務端應用時,Java和Spring框架,Ruby on rails或者類似的框架通常會成為團隊的選擇。
選擇了語言和框架后,經過一段時間的開發,一個簡單的應用誕生了。微服務分布式,與此同時,一體式架構(macro-architecture)毫無爭議的成為了團隊的選擇。但是,這種架構的缺點也漸漸地浮出了水面:
當然,這并不是說一個新的應用一開始就變得巨大而混亂。在最開始的時候,新應用結構清晰,簡單易懂,可擴展性也高,它能夠很輕松的解決需求問題。在接下來的一段時間中,越來越多的代碼被編寫。微服務架構和分布式架構的區別?為了應對日益增長的復雜度,系統被分層,抽象,模塊,服務和框架被引入到系統中,最終變成了我們看到的樣子。
即便是中型的應用(比如說一個50000的Java應用),一體化架構也會漸漸地變得令人討厭,更不用說那些對擴展性要求較高的應用了。
最終,曾經輕量簡潔的應用將會變成下一代開發者的噩夢。
問題的關鍵在于,如何避免這種類型的開發,并且將輕量應用好的那部分保留下來。基于DDD的微服務架構設計。換句話說,我們如何能夠獲得一個可持續發展的架構,這個架構在多年之后依舊能夠讓開發者保持高效開發。
在軟件的開發過程中,有許多關于結構化代碼的概念:函數,方法,類,庫,框架等等。這些概念并不是程序運行所必須的,發明他們的原因是為了幫助開發者更好的理解他們的應用。
目前軟件開發者已經理解了這些概念,一個問題接踵而來:為什么這些概念僅僅被應用于一個軟件?是什么阻礙我們將應用拆分成多個低耦合的部分?
有三件事情我們需要牢記在心:
如果我們放手不管,由多個小型模塊組成的系統并不會出現,一個巨大而混亂的系統將會取而代之。這時候,致命的問題已然出現,然而悔之晚矣。
正常情況下,一個系統是否需要被擴展,是否需要處理巨大的代碼庫在初期是非常清楚的。然后當你遇到以上提到的障礙,你要么沒嘗試解決他們,要么只能沉淪在無盡的苦果中。
在OTTO,在最開始的時候就花費了大量時間去建立4個跨職能的團隊,根據前面提到的康威定律,一個項目屬于4個團隊,最終就能產生一個由4模塊組成的應用,這樣就避免了一體化應用的誕生。
因為我們之前操作過大型的一體化應用,操作的復雜性對于我們似乎是一個可以被解決的問題---操作200個一體化應用和操作200個更小型的系統沒有太大的區別。
初始消耗可以通過標準化和自動化來克服。因為我們沒有提到云服務,你還需要做相關的基礎操作來啟動自動化服務。雖然有些麻煩,但做過一次后,一切將自動化,你會獲得巨大的便利。
如何將一體化應用轉變為由多個小模塊組成的應用?首先,讓我們仔細想想一個應用能夠從哪些維度進行擴展。
縱向分解是一個非常自然而通用的方法,以至于常常被開發者所忽略。相比于把所有的功能集中到單一的應用中,我們將應用分解成了多個小模塊,它們相互獨立,互不影響。
我們可以根據業務域來分解系統。舉個例子來說,在otto.de我們就講網上商城分解成了11個不同的垂直模塊:后勤辦公室,產品,訂單等等。
每一個垂直模塊屬于一個單一團隊,它們有獨立的前端,后端和數據存儲。在模塊之間共享代碼是嚴令禁止的。當然,在特殊的情況下,如果我們需要分享代碼,我們會建立一個開源的項目來解決該問題。
因此,每個垂直模塊是一個獨立自主的系統,就像Stefan Tikov在Substainable Architecture中提到的那樣。
一個垂直模塊依舊可能成為一個相對大型的一體化應用,因此我們需要繼續對垂直模塊進行拆分。一種方法是將一個垂直模塊分解成更多的垂直模塊,另外一種方法是通過分布式計算將系統分解成多個模塊,不同的是這些模塊運行在他們自己的進程中,并且通過REST來傳遞信息。
在這種情況下,應用不僅僅被垂直分解,同時還會被水平分解。這種架構中,請求到達應用后,對請求的處理會被分布于多個模塊中,然后每一模塊產生的結果匯總成一個響應,發送回請求者。
這些模塊并不會共享一個數據庫架構,因為這樣做會導致模塊間的緊密耦合:數據結構的改變會使得一個模塊不能夠被獨立的部署。
當系統需要處理大量的數據,或者當一個分布式的應用被操作時,分片是很恰當的選擇。比如說,分片非常適合向全球范圍提供服務的應用。
因為我們暫時沒有利用到分片這個概念,在這篇文章就不再詳細描述了。
每當服務器承受不了巨大的負載壓力時,負載均衡就會容重登場。通過對一個應用拷貝多次,同時利用負載均衡器將負載分解來緩解壓力。
在負載均衡中,不同實例的應用通常會分時使用同一個數據庫,數據庫因此成為了系統的瓶頸,但是我們可以通過制定良好的擴展策略來避免這個問題。相比于關系數據庫,NoSQL能夠很好的處理擴展性的問題,這也就是NoSQL能夠在軟件世界中占據一畝三分地的原因之一。
所有以上提到的辦法能夠組合在一起,能夠達到任何級別的可擴展性。
當你沒有相應的需求時,組合的結果會變得有點太復雜。幸運地是,開發者并不需要在一開始的時候就制定龐大的計劃,相反,他們可以循序漸進,一步步朝著目標架構前進。
舉個例子來說,在otto.de,架構一開始是4個垂直模塊加上負載均衡,在過去的三年里,產生了更多的垂直模塊。在此期間,某些模塊變得非常的巨大笨重。因此,我們引入了微服務架構,同時通過擴展垂直模塊來建立分布式計算。
微服務最近變得非常的流行。微服務是一種架構風格,它能夠根據業務域將系統分解成多個細粒度,獨立的模塊。
在這種情況下,微服務可以是一個小的垂直模塊,或者是分布式計算機構中的一個服務。與傳統方法的不同之處在于應用的大小:一個微服務僅僅實現了一個業務域中的幾個功能,它結構清晰,一個開發者能夠很輕松的掌握它。
一個微服務非常的小,因此多個微服務能夠運行在單一的服務器上。我們對“Fat JARs”有豐富的經驗,通常能通過執行java –jar <file>來執行它們。如果需要的話,也能開啟一個Jetty或者類似的服務器。
為了簡化不同微服務的部署和操作問題,每一個服務器運行在獨立的Docker容器中。
REST和微服務架構是一個很好的組合,它適合于構建大型的系統。一個微服務可以負責提供REST資源,超媒體(hypermedia)可以用來解決服務發現的問題,在涉及到接口的版本控制,服務部署獨立性的情況下,媒體類型(media type)有很大的幫助。
總而言之,微服務架構有許多的好處,比如說:
微服務架構遵守敏捷開發的原則。一個不能完全滿足用戶的新特性不僅可以被迅速的創建,而且還能夠被快速的銷毀。
在微服務架構中,哪一部分將難以改變?內部模塊的擴展已經不再是關鍵問題,最難以改變的事情是有關微服務架構的決定,比如說如何將微服務整合到系統的方法,或者模塊間傳輸信息協議的選擇。
因此,otto.de嚴格區分了微架構(micro-architecture)和宏架構(macro-architecture)。微架構都是關于垂直架構或者微服務架構的內部結構,并且全部交由各自的團隊全權處理。
但是,明確宏架構的大體方向是有價值的:
我們的架構已經熬過了一輪軟件開發周期,與此同時,我們開始標準化微服務使用的方式。
目前為止,我已經詳細說明了許多有關系統分解的內容。但是,用戶體驗是我們的系統的最終目標,我們希望我們的應用保持一致性,感覺就像是一個整體。
因此,問題來了:我們如何能夠集成一個分布式的系統,同時讓用戶意識不到我們架構的分布特性。
對于前端集成,最簡單的辦法就是使用超鏈接。
每一個服務負責不同的頁面,頁面的導航通過鏈接來實現。
使用AJAX的目的也很明顯,它能夠通過Javascript重新加載頁面的不同內容,并且將他們整合在特定的頁面。
主要注意的是,服務之間涉及到的依賴非常的小,服務互相之間需要對使用的URL和媒體類型(media type)保持一致性。
當然,圖片在不同頁面的顯示也需要保持一致性。除此之外,分布式的服務需要對他們各自的Javascript庫和版本保持一致。
為了保持一致性,在我們的系統中,靜態資源,比如說CSS,JS和圖片都是通過一個中央資源服務器來進行傳輸。
在垂直架構,共享資源的部署和版本控制是一個完全不同的話題,這需要一篇獨立的文章來詳細解釋。在這里我們不做過多解釋,我們只需要記住,共享資源的同時保持服務獨立是具有非常大的挑戰性。
有一種不太知名的方法,它能整合不同服務的資源到同一個站點。這種方法我們稱之為Server-Side Includes或者是Edge-Side Includes。大多數的Web服務器或者反向代理都只支持這個功能。
這項技術非常的簡單:一個服務插入插入一條帶有URL的包含語句(include statement)。然后這個URL會被web服務器或者反向代理解析,代理根據URL獲取到一個響應,然后用這個響應代替頁面中的包含語句。
在我們的商城中,每一個頁面都包含了來自搜索&導航服務(SAN)的導航信息:
<html>...<esi:include src=“/san/...“ />...</html>
反向代理(我們使用了Varnish)解析了頁面,然后將URL分解出來,SAN根據URL提供相應的HTML片段。
然后Varnish代理用這個HTML片段取代包含語句,并將重新生成的頁面發送回用戶。
在這種方式下,用戶根本意識不到頁面是由多個來自不同服務的片段組成的。
以上提到的技術僅僅解決了前端集成問題,現在我們來談談服務端集成。不同的服務之間需要共同的數據,但是他們又不能共享同一個數據庫,因此我們想了一些辦法來處理這個問題。
數據拷貝就是一個辦法。比如說,其他的服務需要關于產品的數據,它們就會定期的向負責產品數據的垂直模塊(Product)請求數據,這樣產品數據的更新能夠很迅速的被其他服務檢測到。
我們沒有使用任何的消息隊列來向客戶端推送(push)數據。相反的,每當服務需要更新數據時,它們會輪詢(poll)Atom Feed。
值得一提的是,某些不好的事情必須犧牲服務的可用性來避免,我們在開發過程中不得不面對這個矛盾。
理論上來說,在某些情況下,我們可以避免數據的拷貝,這樣服務就能夠同步使用其他的服務了。一個購物籃并不需要保存額外的產品信息,相反它可以直接向產品模塊請求數據。
我們并沒有這么做,為什么呢?
我們長期和垂直架構打交道,我們非常明確的知道,在早期的時候,嚴格的界限會使得微服務的開發,測試,遷移變得更加獨立,方便。
按照以上羅列的辦法,經過三年的工作后,我們變得經驗豐富。
回顧往事,如果我早點做這些事情,我們的一體化系統會變得更加的精細。現在,otto.de的未來屬于微服務。
原文鏈接:?On Monoliths and Microservices?
隨著DevOps、持續交付等理念的深入人心,微服務(Microservices)架構開始走進我們的視野。微服務是用一組小服務的方式來構建一個應用,服務獨立運行在不同的進程中,服務之間通過輕量的通訊機制(如RESTful接口)來交互,并且服務可以通過自動化部署方式獨立部署。正因為微服務架構中的服務之間是相互獨立的,所以不同的服務可以使用不同的語言來開發,或者根據業務的需求使用不同類型的數據庫。3月底,來自ThoughtWorks的James Lewis和Martin Fowler分享了他們對微服務架構的理解以及看法。文章中作者詳細介紹了微服務的特點以及相對于傳統架構的微服務架構的優勢。
在James看來,傳統的整體風格的架構在構建部署和擴展伸縮方面有很大的局限性,傳統的整體(monolithic)風格的架構一般分為三部分:客戶端用戶界面(HTML頁面和JavaScript程序)、數據庫、服務端應用程序。服務端程序負責處理HTTP請求、執行業務邏輯、加載和更新數據庫數據、查詢和填充HTML頁面,這個服務端應用就像是一塊鐵板,笨重且不可拆分,系統中任何程序的改變都需要整個應用重新構建和部署新版本。另外傳統的整體風格的架構在進行水平擴展時也只能整個系統擴展,而不能針對某一個功能模塊進行擴展。而微服務架構可以完美的解決統一風格架構所遇到的種種問題。微服務架構將系統以組件化的方式分解為多個服務,服務之間相對獨立且松耦合,單一功能的改變只需要重新構建部署相應的服務即可。
傳統的開發模式在分工時往往以技術為單位,比如UI團隊、服務端團隊和數據庫團隊,這樣的分工可能會導致任何功能上的改變都需要跨團隊溝通和協調。而微服務則倡導圍繞服務來分工,不同的服務可以采用不同的技術來實現,一個團隊中應該包含開發所需的所有技能,比如用戶體驗、數據庫、項目管理。
傳統的軟件開發常常以項目為周期,一旦項目開發完成即交付給運維部門,而在微服務架構中,一個團隊應該去把控產品的整個生命周期,而不只是開發,這其實也是DevOps的核心理念,所以微服務中的每一個服務都是一個產品,而不是一個項目。
微服務架構拋棄了ESB復雜的業務規則編排、消息路由等功能,微服務架構中服務是高內聚的,每個服務都會處理相應的業務,所有的業務邏輯應該盡量在服務內部處理,且服務間的通信盡可能的輕量化,比如使用Restful的方式。
傳統的軟件開發中經常會使用同一個技術平臺來解決所有的問題,而經驗表明使用合適的工具做合適的事情會讓開發變得事半功倍。微服務架構天生就具有這樣的特性,我們可以使用Node.js來開發一個簡單的報表頁面,使用C++來編寫一個實時聊天組件。
微服務架構的引入為多樣化持久保存數據提供可能,持久層可以使用傳統關系數據庫和NoSQL。不同于傳統的應用,微服務架構中,我們可以為每個服務選擇一個新的適合業務邏輯的數據庫系統,比如MongoDB、PostgreSQL。這樣做的好處是顯而易見的,首先我們可以根據業務類型(讀多還是寫多等)來決定使用哪種類型的數據庫,其次這樣可以減小單個數據庫的負載。
就James的文章來看,微服務架構主要有以下幾個優點:
James的文章在社區引起了廣泛的討論,近日,Contino公司的CTO Benjamin Wootton在highscalability上撰文表示微服務并沒有想象中的那么好,并建議開發者在選用此架構時一定要慎重。Benjamin認為微服務架構時可能會面臨下面一些挑戰:
每一種架構都有其優缺點,當然微服務也包括在內。我們需要根據項目業務和團隊情況來選擇合適的架構,微服務才剛剛開始發展,這也是順應PaaS、持續交付、DevOps等新技術理念下的產物,期待微服務架構能得到更廣泛的應用。關于微服務,如果您有新的見解,歡迎與我們分享。
感謝楊賽對本文的審校。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态