來自:不止思考(微訊號:bzsikao)
在網際網路專案中,當業務規模越來越大,資料也越來越多,隨之而來的就是資料庫壓力會越來越大。
我們可能會採取各種方式去最佳化,比如之前文章提到的快取方案,SQL最佳化等等,除了這些方式以外,這裡再分享幾個針對資料庫最佳化的常規手段:「資料讀寫分離」與「資料庫Sharding」。這兩點基本上是大中型網際網路專案中應用的非常普遍的方案了。
下麵我們來詳細看一看,
一、從讀寫分離到CQRS
(圖片來源阿裡雲)
由於網際網路業務場景,大多數是讀多寫少,因此進行資料庫的讀寫分離是一件非常簡單且有效率的方案。
讀寫分離簡單點來說就是把對資料的讀操作和寫操作進行分開來,讓這兩種操作去訪問不同的資料庫,這樣的話,就可以減輕資料庫的壓力了。
例如上圖中,資料庫會有一個「主實體」,這個主要用來提供寫操作的(偶爾也會承擔一點讀操作),除了「主實體」以外,還會有多個「從實體」(在圖中顯示的是 只讀實體),「從實體」的功能只是用來承擔讀操作的。
那上面就出現了多個資料庫了,在多個資料庫之間的資料是怎麼保證一致性的呢?
其實,我們常用的資料庫就自帶這類同步功能,比如 Mysql,它自己有一個master-slave功能,可以實現主庫與從庫資料的自動同步,是基於二進位制日誌複製來實現的。在主庫進行的寫操作,會形成二進位制日誌,然後Mysql會把這個日誌非同步的同步到從庫上,從庫再自動執行一遍這個二進位制日誌,那麼資料就跟主庫一致了。
除了Mysql以外,像Oracle等商業資料庫都有類似的功能,甚至是網路上還有很多開源的第三方資料同步工具,也有很多成熟好用的。
好了,「主實體」與「從實體」之間的資料同步問題解決了,那現在還有一個問題就是,專案中是怎樣讓 寫請求 去訪問「主實體」,讓 讀請求 去訪問「從實體」的,這個路由規則是怎麼實現的呢?
常規的有2種方式:
使用編碼方式
這個方式主要是靠開發同學在編碼的時候,根據讀寫不同的操作需求,去呼叫不同的資料源。例如在資料操作層(DAO層)將讀資料與寫資料分開為兩個方法(函式),然後為這兩個方法分別指定不同的資料庫即可。
但是這種方式有點硬編碼的味道了,而且對開發同學而言還得額外關註這個事情,多了一個編碼成本且容易不小心忽略掉。
使用中介軟體
這種方式就是在後端資料庫的前面,前置一個 資料庫代理服務,如下圖的:MySQL-Proxy 是Mysql提供的一個中介軟體,用於實現讀寫分離請求,但這個元件實際用的人不多,我們可以選擇其它的一些開源的元件替代,例如:MyCat、ProxySQL 等等,但大致的原理比較類似,透過這個圖很容易理解這個樣式。
好了,基礎的讀寫分離就講完了,但感覺這個方式雖然實用是實用,就是不怎麼有逼格。
OK,想要有逼格是吧,滿足你,那我們就來聊一聊另一個有逼格的讀寫分離概念: 「 CQRS 」
CQRS:Command Query Responsibility Segregation
命令(增刪改)和查詢的責任分離
我們還是先看圖,透過上圖可以簡單的理解一下CQRS
CQRS 重點強調的就是 Query(讀) 和 Command(寫)的分離,在業務上將職責分離清晰,Command 主要做業務邏輯的執行,Query來負責資料查詢和展示。同時 這兩種操作是基於不同的資料源,甚至是一個是資料庫,另外一個是NoSQL都可以,Query去查詢的資料源可以直接按照領域模型進行儲存,而並不是按照資料模型去儲存,這樣查詢出來就立即可以展示,而不用轉換,且查詢效率高。
其實CQRS是由鼎鼎大名的 Martin Fowler 提出,搞計算機的應該都認識。想要更深入的去學習CQRS,可以翻看Martin Fowler公開的資料。
二、Sharding(分庫分表)
上面講完了資料庫的讀寫分離,現在我們來聊一下資料庫的Sharding。
隨著資料庫裡的資料越來越大,單表查詢的效能已經不能滿足業務要求了,這個時候就需要進行分表處理了,將大表拆分為若干個小表,不同的分表中資料也不一樣,這樣可以分散查詢壓力,提高處理效率。
然而,當表越來越多,所有的資料都在一個資料庫上時,網路IO以及檔案IO也都會集中在一個資料庫上,可能會超過單臺伺服器的容量, CPU、記憶體、檔案IO、網路IO 都會成為系統的瓶頸,QPS/TPS也會超過單資料庫實體的處理極限。那麼這個時候就需要對資料庫進行分片處理。
因為分表和分庫的思路類似,因此下麵統一來聊技術方案。
其實分庫分表只是我們通俗的便於理解的說話,正確的描述應該是:資料分片
資料的分片主要有2種樣式:
-
垂直拆分
-
水平拆分
兩種拆分應用的場景是不同的:
垂直拆分,是指按照業務模組進行拆分。簡單來講,就是把業務緊密的模組的欄位/表放在一起,放在同一個資料庫或者伺服器上。將不同業務的欄位/表進行獨立,拆到不同的資料庫或者伺服器上。比如一個遊戲系統中,可以將玩家基本資訊與道具公會等資訊進行拆分。
如圖示例:
(圖片來源網路)
水平拆分,是指純粹的按照某種資料規則/格式進行拆分。例如 按照資料唯一ID的雜湊雜湊拆分、按照資料的日期拆分、按照某種範圍拆分等等。水平拆分需要註意的是,隨著資料動態的變化,分片數量可能需要隨之動態調整,另外就是水平分片是沒有考慮業務特徵的,因此在進行業務彙總查詢或者分片中事物處理的時候就比較麻煩一些。
如圖示例:
另外,在實際應用中,兩種拆分樣式一般會結合在一起使用,效果更佳。
以上就是資料庫效能最佳化之「資料讀寫分離」與「資料庫Sharding」方法,歡迎大家一起交流。
本文原創釋出於微信公眾號「 不止思考 」,歡迎關註,交流網際網路認知、專案管理、大資料、Web、區塊鏈技術。
●編號404,輸入編號直達本文
●輸入m獲取文章目錄
Web開發
更多推薦《18個技術類微信公眾號》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。