基於雲的應用與運行在私有資料中心的應用之間最大的差別就是可擴充性。 雲提供了按需擴展的能力,能夠根據負載的波動對應用進行擴展和收縮。 但是傳統應用要充分發揮雲的優勢,並不是簡單地將應用部署到雲上就萬事大吉,而是需要根據雲的特點圍繞可擴充性重新進行架構設計, 近日AppDynamics的開發佈道者Dustin.Whittle撰文闡述了適合雲端部署的應用架構,對我們傳統應用往雲端部署有很大的啟發和借鑒意義。
應用的架構
Dustin.Whittle給出了雲應用的示例架構,它具有高度的可擴充性,如下圖所示:
在這個圖中,應用按照階層式理念進行了拆分,分別介紹如下:
用戶端層:用戶端層包含了針對目標平臺的使用者介面,可能會包括基於Web的、移動端的甚至是胖用戶端的使用者介面。 一般來講,這可能會是Web應用,包含諸如使用者管理、會話管理、頁面構建等功能,但是其他用戶端所發起的交互都需要以RESTful服務的形式調用伺服器。
服務:伺服器包含了快取服務以及聚合(aggregate)服務,其中快取服務中持有記錄系統(system of record)中最新的已知狀態,而聚集服務會直接與記錄系統交互,並且會執行一些破壞性的操作(會改變記錄系統中的狀態 )。
記錄系統:記錄系統是領域特定的服務端,它會驅動業務功能,可能會包括客戶管理系統、採購系統、預定系統等等,這些很可能是遺留系統,你的應用需要與其進行交互。 聚集服務要負責將你的應用從這些特有的記錄系統中抽象出來,並為你的應用提供一致的前端介面。
ESB:當記錄系統發生資料變化的時候,它需要觸發到指定主題(topic)的事件,這就是事件驅動架構(event-driven architecture,EDA) 能夠影回應用的地方了:當記錄系統進行了一項其他系統可能感興趣的變更時,它會觸發一個事件,任何關注記錄系統的其他系統會監聽到這個事件,並作出對應的回應。 這也是使用使用主題(topic)而不是佇列(queue)的原因:佇列支援點對點(point-to- point)的消息,而主題支援發佈-訂閱(publish-subscribe)的消息或事件。 當與遺留系統進行集成時,我們很期望這些遺留的系統能夠免遭負載的影響。 因此,我們實現了一個緩存系統,這個緩存系統維持了記錄系統中所有最新的已知狀態。 緩存系統會使用EDA的規則監聽記錄系統的變化,它會更新自己所保存資料的版本,從而保證與記錄系統中的資料相匹配。 這是一個很強大的策略,不過會將一致性模型變為最終一致性,也就是說如果你在社交媒體上發佈一條狀態的話,你的朋友可能在幾秒鐘甚至幾分鐘之後才能看到,資料最終是一致的,但有時你所看到的與你的朋友所看到的並不一致。 如果能接受這種一致性的話,就能在很大程度上實現可擴充性的收益。
NoSQL:在資料存儲方面,有很多的可選方案,但如果要存儲大量資料的話,使用NoSQL存儲能夠更容易地擴展。 有多種NoSQL存儲可供選擇,不過這要匹配所存儲資料的特點,如MongoDB適合存儲可搜索的資料,Neo4j適合存儲高度互相關聯的資料,而Cassandra適合存儲鍵/值對, 像Solr這樣的搜索索引有利於加速對經常訪問資料的查詢。
將應用拆分為多個層的時候,最好的模式就是使用面向服務架構(service-oriented architecture,SOA)。 要實現這一點,可以使用SOAP,也可以使用REST,但是REST更為合適,因為它可擴充性更強。 作者接下來對 REST的理念進行了深入的闡述,InfoQ上關於REST已有很多相關的文章,如這裡和這裡,甚至包括Roy Fielding經典博士論文的中譯本,所以這裡不再贅述。 不過,作者在這裡特別強調了RESTful Web服務能夠保持無狀態性(stateless)。 無狀態是實現可擴充性的關鍵需求,因為無狀態,所以請求可以由任何一個伺服器回應。 如果你在服務層上需要更多的容量時,只需要為該層添加虛擬機器即可,而不需關注用戶端狀態保持的問題,負載可以很容易地重新分配。
部署到雲端
前面介紹了基於雲的應用架構,接下來作者闡述了這樣的應用該如何部署到雲端。
RESTful Web服務要部署到Web容器中,並且要位於資料存儲之前。 這些Web服務是沒有狀態的,只會反映其暴露的底層資料的狀態,因此可以根據需要部署任意數量的伺服器。 在基於雲的部署中,開始時可以開啟足夠的實例以應對日常的需求,然後配置彈性策略,從而根據負載增加或減少伺服器的數量。 衡量飽和度的最好指標就是服務的回應時間。 另外還需要考慮這些服務所使用的底層資料存儲的性能。 示例的部署圖如下所示:
如果在雲部署時有EDA的需求,那麼就需要部署ESB,作者給出的建議是根據功能對ESB進行分區(partitioning),這樣一個segment的過大負載不會影響到其他的segment。 如下圖所示:
這種分離使System 1的負載與System 2的負載實現了隔離。 如果System 1產生的負載拖慢了ESB,它只會影響到自己的segment,並不會影響到System 2的segment,因為它部署在其他硬體上。 如果ESB產品支援的話,我們還可以給指定的segment添加伺服器來實現擴展。
基於雲的應用與傳統應用有著很大的差別,因為它有著不同的擴充性需求。 基於雲的應用必須有足夠的彈性以應對伺服器的添加與移除,必須松耦合,必須盡可能的無狀態,必須預先規劃失敗的情況,並且必須能夠從幾台伺服器擴展到成千上萬台伺服器。
針對雲應用並沒有唯一正確的架構,但是本文所闡述的RESTful服務以及事件驅動架構卻是經過實踐檢驗有效的架構。 作者認為REST和EDA是實現雲端可擴展應用的基本工具。
目前,國內許多傳統的軟體廠商正在逐漸往雲端遷移,希望本文所闡述的架構理念能夠為讀者提供一些借鑒。