(六) 分庫分表與叢集
分庫分表
一、為什麼要分庫分表
關係型資料庫以Mysql為例,單機的儲存能力、連線數是有限的,它自身就很容易會成為系統的瓶頸。當單表資料量在百萬以裡時,我們還可以通過新增從庫、優化索引提升效能。一旦資料量朝著千萬以上趨勢增長,再怎麼優化資料庫,很多操作效能仍下降嚴重。為了減少資料庫的負擔,提升資料庫響應速度,縮短查詢時間,這時候就需要進行分庫分表。
二、如何分庫分表
分庫分表就是要將大量資料分散到多個數據庫中,使每個資料庫中資料量小響應速度快,以此來提升資料庫整體效能。核心理念就是對資料進行切分( Sharding ),以及切分後如何對資料的快速定位與整
合。針對資料切分型別,大致可以分為:垂直(縱向)切分和水平(橫向)切分兩種。
1、垂直切分
垂直切分又細分為"垂直分庫" 和 "垂直分表"
垂直分庫:垂直分庫是基於業務分類的,和我們常聽到的微服務治理觀念很相似,每一個獨立的服務都擁有自己的資料庫,需要不同業務的資料需介面呼叫。而垂直分庫也是按照業務分類進行劃分,每個業務有獨立數
據庫,這個比較好理解。
垂直分表:是基於資料表的列為依據切分的,是一種大表拆小表的模式
資料庫是以行為單位將資料載入到記憶體中,這樣拆分以後核心表大多是訪問頻率較高的欄位,而且欄位長度也都較短,可以載入更多資料到記憶體中,增加查詢的命中率,減少磁碟IO,以此來提升資料庫效能。
垂直切分優點:
1 業務間解耦,不同業務的資料進行獨立的維護、監控、擴充套件
2 在高併發場景下,一定程度上緩解了資料庫的壓力
垂直切分缺點:
1 提升了開發的複雜度,由於業務的隔離性,很多表無法直接訪問,必須通過介面方式聚合資料,
2 分散式事務管理難度增加
3 資料庫還是存在單表資料量過大的問題,並未根本上解決,需要配合水平切分
2、水平切分
垂直切分還是會存在單表資料量過大的問題,當我們的應用已經無法在細粒度的垂直切分時,依舊存在單庫讀寫、儲存效能瓶頸,這時就要配合水平切分一起了。
水平切分將一張大資料量的表,切分成多個表結構相同,而每個表只佔原表一部分資料,然後按不同的條件分散到多個數據庫中.
水平切分又分:"庫內分表" 和 "分庫分表"
庫內分表: 雖然將表拆分,但子表都還是在同一個資料庫例項中,只是解決了單一表資料量過大的問題,並沒有將拆分後的表分佈到不同機器的庫上,還在競爭同一個物理機的CPU、記憶體、網路IO. 這種對高併發下的場景不太友好,
因為資料庫連線有限制,還要去競爭同一個物理機的CPU、記憶體、網路IO.
分庫分表
分庫分表則是將切分出來的子表,分散到不同的資料庫中,從而使得單個表的資料量變小,達到分散式的效果。
優點:
1 解決高併發時單庫資料量過大的問題,提升系統穩定性和負載能力
2 業務系統改造的工作量不是很大
缺點:
1 跨分片的事務一致性難以保證
2 跨庫的join關聯查詢效能較差
3 擴容的難度和維護量較大。
三、資料該往哪個庫的表存?
1 按照"時間區間" 或 "ID區間"來切分,舉個栗子:假如我們切分的是使用者表,可以定義每個庫的 User表裡只存10000條資料,第一個庫userId從1 ~ 9999,第二個庫10000 ~ 20000,第三個庫20001~ 30000......以此類推。
優點:
單表資料量是可控的
水平擴充套件簡單隻需增加節點即可,無需對其他分片的資料進行遷移
能快速定位要查詢的資料在哪個庫
缺點:
由於連續分片可能存在資料熱點,如果按時間欄位分片,有些分片儲存最近時間段內的資料,可能會被頻繁的讀寫,而有些分片儲存的歷史資料,則很少被查詢。
2、hash取模
hash取模mod(對hash結果取餘數 (hash() mod N))的切分方式比較常見,還拿 User表 舉例,對資料庫從0到N-1進行編號,對 User表 中 userId 欄位進行取模,得到餘數 i , i=0 存第一個庫, i=1 存第二個庫, i=2 存第三個庫....以此類推。
這樣同一個使用者的資料都會存在同一個庫裡,用 userId 作為條件查詢就很好定位了。
優點:
資料分片相對比較均勻,不易出現某個庫併發訪問的問題。
缺點:
但這種演算法存在一些問題,當某一臺機器宕機,本應該落在該資料庫的請求就無法得到正確的處。
理,這時宕掉的例項會被踢出叢集,此時演算法變成hash(userId) mod N-1,使用者資訊可能就不再在同一個庫中。
叢集
1、主從複製原理
MySQL的複製是通過binlog功能實現的,具體分為3個執行緒。
- 主節點:dump 執行緒,負責採集 binlog 資料與同步庫 IO 執行緒互動。
- 從節點:IO 執行緒將獲取到的資料轉儲成 relaylog 檔案(relaylog內部儲存的內容與binlog一致)
- 從節點:slave 執行緒將 relaylog 的資料讀取出來,然後寫入到資料庫中。
2 bin log日誌和replay日誌
bin log:記錄所有資料得更改,可用於本機資料恢復與主從同步
relay log中繼日誌:
1 Mysql主節點將binlog寫入本地,從節點定時請求增量binlog, 主節點將binlog同步到從節點;
2 從節點單獨程序會將binlog拷貝至本地relaylog中
3 從節點定時重放relay log
1)bin log 的三種模式:
1.statement level模式
每一條會修改資料的sql都會記錄到master的bin-log中。slave在複製的時候sql程序會解析成和原來master端執行過的相同的sql來再次執行
優點:statement level下的優點,首先就是解決了row level下的缺點,不需要記錄每一行資料的變化,減少bin-log日誌量,節約io,提高效能。因為他只需要記錄在master上所執行的語句的細節,以及執行語句時候的上下文的資訊。
缺點:由於它是記錄的執行語句,所以為了讓這些語句在slave端也能正確執行,那麼他還必須記錄每條語句在執行的時候的一些相關資訊,也就是上下文資訊,以保證所有語句在slave端被執行的時候能夠得到和在master端執行時候相同的
結果。還有修改資料的時候使用了某些特定的函式或者功能,複製時比較困難。
2.rowlevel模式
日誌中會記錄成每一行資料被修改的形式,然後在slave端再對相同的資料進行修改。
優點:bin-log中可以不記錄執行的sql語句的上下文相關的資訊,僅僅只需要記錄那一條記錄被修改了,修改成什麼樣了。所以row level的日誌的內容會非常清楚的記錄下每一行資料修改的細節。
而且不會出現某些特定情況下的儲存過程,或function,以及trigger的呼叫和觸發無法被正確複製的問題。
缺點:row level下,所有的執行的語句當記錄到日誌中的時候,都將以每行記錄的修改記錄,這樣可能會產生大量的日誌內容,比如有這樣一條update語句:update product set owner_member_id='d'
where owner_member_id='a',執行之後,日誌中記錄的不是這條update語句所對應的事件(mysql是以事件的形式來記錄bin-log日誌),而是這條語句所更新的每一條記錄的變化情況,這樣就記錄成很多條記
錄被更新的很多事件。自然,bin-log日誌的量會很大
3.mixed模式
實際上就是前兩種模式的結合,像遇到表結構變更的時候就會以statement模式來記錄,如果sql語句確實就是update或者delete 等修改資料的語句,那麼還是會記錄所有行的變更
主從同步延遲的原因及解決辦法
mysql 用主從同步的方法進行讀寫分離,減輕主伺服器的壓力的做法現在在業內做的非常普遍。一個伺服器開放N個連結給客戶端來連線的, 這樣有會有大併發的更新操作, 但是從服務
器的裡面讀取binlog 的執行緒僅有一個, 當某個SQL在從伺服器上執行的時間稍長 或者由於某個SQL要進行鎖表就會導致,主伺服器的SQL大量積壓,未被同步到從伺服器裡。這就導致了主從不一致, 也就是
主從延遲。
2、主從同步延遲的解決辦法
實際上主從同步延遲根本沒有什麼一招制敵的辦法, 因為所有的SQL必須都要在從伺服器裡面執行一遍,但是主伺服器如果不斷的有更新操作源源不斷的寫入, 那麼一旦有延遲產生, 那麼延遲加重的可能性就會原來越大。
當然我們可以做一些緩解的措施。
a. 我們知道因為主伺服器要負責更新操作, 他對安全性的要求比從伺服器高, 所有有些設定可以修改,比如sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之類的設定,而slave則不需要這麼高的數
據安全,完全可以講sync_binlog設定為0或者關閉binlog,innodb_flushlog,innodb_flush_log_at_trx_commit 也可以設定為0來提高sql的執行效率 這個能很大程度上提高效率。另外就是使用比主庫更好的硬體裝置作為slave。
b. 就是把,一臺從伺服器當度作為備份使用, 而不提供查詢, 那邊他的負載下來了, 執行relay log裡面的SQL效率自然就高了。
c. 增加從伺服器嘍,這個目的還是分散讀的壓力, 從而降低伺服器負載。
