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

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

個人架構師同事問我:「爲何你總說要在服務層實現讀寫分離,咱們已經在數據庫實現了讀寫分離,是否是已經夠用」。如下是個人解釋,面試

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

 

因而,可以十倍百倍提升性能的方案出現了,緩存加服務器集羣,這是最經常使用且有效的提升網站訪問量的設計。使用共享緩存(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

相關文章
相關標籤/搜索