一.使用中間件的好處
使用中間件對於主讀寫分離新增一個從數據庫節點來說,可以不用修改代碼,達到新增節點數據庫而不影響到代碼的修改。因為如果不用中間件,那么在代碼中自己是先讀寫分離,如果新增節點,
你進行寫操作時,你的輪詢求模的數據量就要修改。但是中間件的維護也很麻煩的。
二.各種中間件
1.MYSQL官方的mysqlProxy,它可以實現讀寫分離,但是它使用率很低,搞笑的是MySQL官方都不推薦使用。
2.Amoeba:這是阿里巴巴工程司寫的,是開源的。使用也很少。
3.阿里開源的cobar,缺點查詢回來的數據沒有排序,和分頁,這些都要自己處理,用的少。
5.mycat:是根據cobar改造的。用的還算比較多
6.ShardingJDBC:這是當當網的。這近幾年比較流行,比較牛逼。
注意:如果我們單純的做讀寫分離,一般都會選擇用SpringAOP去做。並不是一定使用中間件就一定好。
讀寫分離做完,我們數據庫的壓力就解決了嗎?
並沒有,做完讀寫分離,我們都知道知識一個或幾個主庫,多個從庫,每個數據庫里面的數據都是一樣的。只是一份復制。
這樣做的好處就是:
1。數據庫可以備份。
2.減輕數據庫的壓力。
數據庫的壓力問題就緩解了嗎?並沒有緩解的特別厲害,當你這真正的高並發,大數據量來的時候,你做讀寫分離也不夠用的。MySQL單表能承受多少數據量呢?
實踐來看的話,大概也就7000W-1億,這根據字段量,和字段里面存的東西,這數據是根據業務走的,不一定那么精確。
當達到這個數量級的時候你的多表關聯查詢什么的,即便優化到位,我說的優化,第一是索引一定要設置合理,第二SQL優化,但是SQL優化做的很有限。
到這個數據量你去關聯那么兩三個表,基本都是在5S,10S甚至更長的時間。
這時候就要考慮別的辦法了。走到這一步,那該怎么辦呢?
那么就要進行分庫分表:
1.垂直拆分:
基於領域模型做數據的垂直切分是一種最佳實踐。如將訂單、用戶、支付等領域模型划分到不同的DB庫里面。前提必須各領域數據之間join展示場景較少,在這種情況下分庫能獲得很高的價值,同時各個系統之間的擴展性得到很大程度的提高。
缺點:如果在拆分之前,系統中很多列表和詳情頁所需的數據是可以通過sql join來完成的。而拆分后,數據庫可能是分布式在不同實例和不同的主機上,join將變得非常麻煩。而且基於架構規范,性能,安全性等方面考慮,一般是禁止跨庫join的。
那該怎么辦呢?首先要考慮下垂直分庫的設計問題,如果可以調整,那就優先調整。
解決辦法:
1.建立全局表:系統中可能出現所有模塊都可能會依賴到的一些表。比較類似我們理解的“數據字典”。為了避免跨庫join查詢,我們可以將這類表在其他每個數據庫中均保存一份。這種做法叫做建立全局表
同時,這類數據通常也很少發生修改(幾乎不會),一般不用太擔心“一致性”問題。
2.進行數據同步:比如,用戶庫中的tab_a表和訂單庫中tbl_b有關聯,可以定時將指定的表做同步。當然,同步本來會對數據庫帶來一定的影響,需要性能影響和數據時效性中取得一個平衡。這樣來避免復雜的跨庫查詢。
3.系統層面組裝:調用不同模塊的組件或者服務,獲取到數據並進行字段拼裝。不要想着這很容易,實踐起來可真沒有那么容易,尤其是數據庫設計上存在問題但又無法輕易調整的時候。具體情況通常會比較復雜。
組裝的時候要避免循環調用服務,循環RPC,循環查詢數據庫,最好一次性返回所有信息,在代碼里做組裝。
4.適當的進行字段冗余:比如“訂單表”中保存“賣家Id”的同時,將賣家的“Name”字段也冗余,這樣查詢訂單詳情的時候就不需要再去查詢“賣家用戶表”。
如下圖:
拆分前:
拆分后:
這樣的話能夠緩解一下壓力,我們還可以對每一個獨立的DB在進行讀寫分離。
當然拆分也會出現問題的。比如說分布式事務。比如支付系統支付失敗了回滾,那么你訂單系統也要回滾的。但是你們都不在同一個庫里面,這是就需要分布式事務了。
如果走到這一步,你的系統還是緩解不了壓力,那么說明你這系統比較厲害了。說明你公司在你的行業里面能叫的上名字的了。
那么我們就要進行水平拆分了。
2.水平拆分:垂直切分緩解了原來單集群(所有的數據庫都存在一張表里,)的壓力,但是在搶購時依然捉襟見肘。原有的訂單模型已經無法滿足業務需求,於是就要進行水平分表也稱為橫向分表,
比較容易理解,就是將表中不同的數據行按照一定規律分布到不同的數據庫表中(這些表保存在同一個數據庫中),這樣來降低單表數據量,優化查詢性能。
最常見的方式就是通過主鍵或者時間等字段進行Hash和取模后拆分。
如下圖:
如果數據壓力還是比較大怎么呢?,還能怎么辦,繼續進行水平拆分咯,比如,user(1)user(2)user(3)繼續驚醒水平拆分。
水平拆分所帶來的問題:
1.常見分片規則問題
1。一致性hash:依據Sharding Key對5取模,根據余數將數據散落到目標表中。比如將數據均勻的分布在5張user表中,如下圖:
2.范圍切分:比如按照時間區間或ID區間來切分。
優點:單表大小可控,天然水平擴展。
缺點:無法解決集中寫入瓶頸的問題
如下圖:
3.將ID和庫的Mapping關系記錄在一個單獨的庫中。
優點:ID和庫的Mapping算法可以隨意更改。
缺點:引入額外的單點。
如下圖:
數據遷移問題
很少有項目會在初期就開始考慮分片設計的,一般都是在業務高速發展面臨性能和存儲的瓶頸時才會提前准備。因此,不可避免的就需要考慮歷史數據遷移的問題。
一般做法就是通過程序先讀出歷史數據,這些數據量非常大,不涉及事務,實時性要求低,這是你就要考慮一下非關系數據庫了,比如MongoDB,Hbase,這些數據庫
擴展性非常好,這些NoSQL天然就是分片的。彈性非常好。然后按照指定的分片規則再將數據寫入到各個分片節點中。
這里還要知道一下什么是OLTP,OLAP:
OLTP(on-line transaction processing) 主要是執行基本日常的事務處理,比如數據庫記錄的增刪查改。比如在銀行的一筆交易記錄,就是一個典型的事務。
OLTP的特點一般有:
1.實時性要求高。我記得之前上大學的時候,銀行異地匯款,要隔天才能到賬,而現在是分分鍾到賬的節奏,說明現在銀行的實時處理能力大大增強。
2.數據量不是很大,生產庫上的數據量一般不會太大,而且會及時做相應的數據處理與轉移。
3.交易一般是確定的,比如銀行存取款的金額肯定是確定的,所以OLTP是對確定性的數據進行存取
4.高並發,並且要求滿足ACID原則。比如兩人同時操作一個銀行卡賬戶,比如大型的購物網站秒殺活動時上萬的QPS請求。
聯機分析處理OLAP(On-Line Analytical Processing) 是數據倉庫系統的主要應用,支持復雜的分析操作,側重決策支持,並且提供直觀易懂的查詢結果。典型的應用就是復雜的動態的報表系統。
OLAP的特點一般有:
1.實時性要求不是很高,比如最常見的應用就是天級更新數據,然后出對應的數據報表。
2.數據量大,因為OLAP支持的是動態查詢,所以用戶也許要通過將很多數據的統計后才能得到想要知道的信息,例如時間序列分析等等,所以處理的數據量很大;
3.OLAP系統的重點是通過數據提供決策支持,所以查詢一般都是動態,自定義的。所以在OLAP中,維度的概念特別重要。一般會將用戶所有關心的維度數據,存入對應數據平台
跨分片的排序分頁
在分庫分表的情況下,為了快速(分頁)查詢數據,分表策略的選擇就顯得非常重要了,需要盡最大限度將需要跨范圍查詢的數據盡量集中,多數情況下在我們做了最大限度的努力之后,數據仍然可能是分布式的。
為了進一步提高查詢的性能,維持查詢的中間變量信息是我們在分庫分表模式下提高分頁查詢速度的另一個手段:我們每次翻頁查詢時,通過中間信息的分析,就可以直接定位到目標表的目標位置,通過這種方式提供了近似於在單表模式下的分頁查詢能力。
但另一方面也需要在業務上做出一定的犧牲:限制查詢區段,提高檢索速度。
如下圖:
跨分片的函數處理
在使用Max、Min、Sum、Count之類的函數進行統計和計算的時候,需要先在每個分片數據源上執行相應的函數處理,然后再將各個結果集進行二次處理,最終再將處理結果返回。
跨分片join
Join是關系型數據庫中最常用的特性,但是在分片集群中,join也變得非常復雜。應該盡量避免跨分片的join查詢(這種場景,比上面的跨分片分頁更加復雜,而且對性能的影響很大)。
通常有以下幾種方式來避免:
1.全局表
全局表的概念之前在“垂直分庫”時提過。基本思想一致,就是把一些類似數據字典又可能會產生join查詢的表信息放到各分片中,從而避免跨分片的join。
2.ER分片
在關系型數據庫中,表之間往往存在一些關聯的關系。如果我們可以先確定好關聯關系,並將那些存在關聯關系的表記錄存放在同一個分片上,那么就能很好的避免跨分片join問題。在一對多關系的情況下,我們通常會選擇按照數據較多的那一方進行拆分。
3.內存計算
隨着spark內存計算的興起,理論上來講,很多跨數據源的操作問題看起來似乎都能夠得到解決。可以將數據丟給spark集群進行內存計算,最后將計算結果返回。
總結
並非所有表都需要水平拆分,要看增長的類型和速度,水平拆分是大招,拆分后會增加開發的復雜度,不到萬不得已不使用。
在大規模並發的業務上,盡量做到在線查詢和離線查詢隔離,交易查詢和運營/客服查詢隔離。
拆分維度的選擇很重要,要盡可能在解決拆分前問題的基礎上,便於開發。
數據庫沒你想象的那么堅強,需要保護,盡量使用簡單的、良好索引的查詢,這樣數據庫整體可控,也易於長期容量規划以及水平擴展。