爲什麼要在服務層設計讀寫分離?

作者:陳葉皓(攜程郵輪研發部軟件架構師)

我的架構師同事問我:“爲什麼你總說要在服務層實現讀寫分離,我們已經在數據庫實現了讀寫分離,是不是已經夠用”。以下是我的解釋,

在做網站性能優化的時候,我常常忘記還有數據庫讀寫分離這件事,因爲數據庫讀寫分離,對性能帶來的提高太有限了,實際上,就是一倍(一臺服務器變成兩臺服務器)。當你的網站業務發展,如果從無到有地使用數據庫讀寫分離,提高了一倍的服務能力,你很快就需要想新的優化方案。實際上,數據庫的讀寫分離,更像是數據安全的一個副產品,用一臺數據庫服務器不安全(怕數據丟失),用一臺服務器作爲備份,既然有了兩臺服務器,就充分利用吧,於是有了“讀寫分離”,提高一倍也是好的。

 

於是,能夠十倍百倍提高性能的方案出現了,緩存加服務器集羣,這是最常用且有效的提高網站訪問量的設計。使用共享緩存(memcached,redis)可以獲得十到幾十倍的性能提升,使用進程內緩存,可以得到百倍的性能提升;集羣中增加一倍的服務器,可以增加一倍的計算能力,服務更多的併發請求。等一下,上面所說的方案,其實只對“讀”操作纔有效,對“寫”操作可以說是毫無用處。

那麼有什麼辦法可以提高“寫”操作的性能,在架構部署的設計方面,我的答案是,“沒有”。

從硬件入手,可以使用SSD硬盤。願意替換底層數據庫,可以使用hbase或者cassandra,都不在今天討論的範圍。我想說的是,既然使用緩存和增加服務器,對於“寫”操作沒有優化作用,在一開始,“寫”操作相關的服務,就不該和“讀”操作一起,被分配到數量龐大的計算機集羣裏。

想象這樣的架構設計,我有一個“讀”服務的集羣,一共4臺服務器,我有一臺“寫”服務器(另一臺備用,故障時切換)。當我的網站訪問量上升,我增加“讀”服務器集羣到8臺,簡單就能應付問題。因爲“讀”服務是狀態無關的,增加到100臺也不會帶來錯誤的數據,這是一個重要的思想,狀態無關的服務,纔可以放心地水平擴展,事實上,狀態無關的服務,通常只有“讀”服務。

那麼當“寫”服務撐不住的時候,怎麼辦,嗯。。。總會有辦法,反正不是加緩存或者是使用集羣,這個可以做架構師面試題。

然後我解釋一下爲什麼不該在集羣裏面運行“寫”服務,我把“寫”服務分爲兩種。

1.       和“狀態”(可能發生衝突的情形)弱相關,比如用戶提供內容(UGC)的操作,每個用戶提交自己的評論,或者發佈自己的微博,不太容易發生衝突。對於這類“寫”服務,部署在集羣裏面勉強可行,雖然沒帶來什麼好處,但也沒有引入錯誤

2.       和“狀態”(可能發生衝突的情形)強相關,比如包含庫存操作的電商網站,上千人“秒殺”熱門商品,允許這樣的操作在集羣內併發,是架構師自己作死的節奏啊

明白了這個道理,你就知道我之前爲什麼說是“一臺”寫服務器,只有一臺服務器,纔可以保證在“秒殺”場景下,不會在沒有庫存的情況下繼續售賣成功。

細心的讀者(嗯,就是你)會繼續追問,在一臺服務器的情況下,現在都是多核併發編程,保證串行操作也不是容易的事啊。問得太好了,我這大半年寫的系列文章,都是爲了解決這個問題,你需要的是actor模型。異步編程加上進程內的消息隊列,可以高效地對併發操作進行串行的處理。

結論,使用服務器集羣提高性能只對“讀”服務有效,對“寫”服務無效,“寫”服務器應該使用主/從模式,同一時間只使用一臺服務器。在“寫”服務器內部,使用支持actor模型的編程語言,保證關鍵操作的串行。最後老生常談,支持actor模型的編程語言是:Erlang,Go,Scala,F#

原文鏈接:http://techshow.ctrip.com/archives/784.html

發佈了2 篇原創文章 · 獲贊 36 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章