從業務場景看分庫分表
網際網路行業中,業務場景通常寫少讀多的情況居多,在MySQL的使用前期,讀性能大多可以通過SQL優化來解決,但随着業務的持續發展,單純依靠SQL的查詢優化會越來越難以達到業務服務要求。
是以,量級較大的業務場景,MySQL的讀壓力往往會首先成為系統瓶頸所在。
此時,在資料庫層面,DBA通常會建議通過橫向擴充備庫節點的方式,采用讀寫分離技術來提升業務系統的讀性能、讀并發能力。
以上是典型的網際網路讀寫分離需求。
除了這種多見的讀瓶頸問題,在大型網站和海量資料的業務場景,資料庫常見的性能瓶頸下面的兩地問題會更加突出:
一是大量的并發讀寫操作,導緻單庫出現負載壓力過大;
二是單表存儲資料量過大,導緻查詢效率低下。
該種情況,由于業務的讀寫請求較高,MySQL在主從之間的資料同步容易引發主從延遲問題。改進的做法是,我們可能會架構設計上,需要敦促業務在寫入主庫之前最好将同一份資料落到緩存,以避免高并發場景下從從庫中擷取不到指定資料的情況發生。
如果寫壓力進一步擴大,并且資料量急劇快速增長,DB寫節點即主庫就會成為整個系統的瓶頸。在MySQL的日常營運中,如果DB中表和表之間的資料很多是沒有關系的,或者根本不需要表關聯Join操作,我們可以考慮按照業務把不同的資料放到不同的伺服器中,即垂直分庫或叫垂直切分。
不過需要注意的是,垂直分庫無法解決單表資料量過大的問題,由于單一業務的資料資訊仍然落盤在單表中,如果單表資料量太大,就會極大地影響SQL執行的性能。
由此,在MySQL應用領域,水準分表也是網際網路場景應對高并發、單表資料量過大的解決方案之一。
分表在本質上可以概括為業務表在邏輯上公用一個路由結構,實體上分散存儲。這就是常說的Sharding分片或者分區。
比如以使用者ID字段user_id按照一定政策(hash、range等),将表中資料拆分到多個子表中(分片或分區),以確定子表中資料量在讀寫性能可接受的範圍内。每個子表的結構都一樣,每個表的資料都不一樣,沒有交集,所有表的并集是全量資料。
水準分表主要用于業務架構無法繼續垂直細分、資料庫中單張表資料量太大、查詢性能下降的場景。
應該使用哪一種方式來實施資料庫分庫分表,需要從資料庫的瓶頸所在和項目的業務角度進行綜合考慮。如果資料庫是因為表太多而造成海量資料,并且項目的各項業務邏輯劃厘清晰、耦合度較低,建議優先使用垂直切分。
如果資料庫中的表并不多,但單表的資料量很大且資料熱度很高,這種情況之下就應該選擇水準切分。
在現實項目中,往往是這兩種情況兼而有之,綜合使用了垂直與水準切分,我們首先對資料庫進行垂直切分,然後針對一部分表進行水準切分。
但是,采用分庫分表也會引入新的問題。
分庫分表存在的問題及注意點
l跨庫Join問題
分庫分表後,表之間的關聯操作将受到限制,無法join位于不同分庫的表,也無法join分表粒度不同的表,結果導緻原本一次查詢能夠完成的業務可能需要多次查詢才能完成。
是以,分庫分表的設計,需要結合業務資料的關聯場景,适當考慮資料的備援和拆分政策。比如:根據之前表之間的關系,将相關表以相同的拆分政策,確定關聯資料存放到一個分片上。或者使用表級備援将基礎資料在所有庫都寫一份。使用字段備援:把需要join的字段備援在各個表中,這樣有些字段就不用join去查詢了。再者就是在應用邏輯層進行資料組裝:将原來的請求分兩次查詢,在第一次查詢的結果集中找出關聯資料id,然後根據id發起第二次請求得到關聯資料,最後将獲得到的資料進行字段拼裝。
l 排序合并問題
由于資料的分庫、分片導緻的分散存儲,原來的業務請求會引發結果集合并、排序問題。尤其是當排序字段不是分片字段的似乎,問題會變得比更加複雜。
需要先在不同的分片節點中将資料進行排序并傳回,然後将不同分片傳回的結果集進行彙總和再次排序,最終傳回給使用者。
是以,分庫分表,還需要考慮業務具體的排序場景,盡量保障排序字段和分布鍵一緻,確定請求通過分片規則就比較容易定位到指定的分片。
l 遷移和擴容問題
遷移和擴容,屬于DB日常營運中正常場景。分庫分表後,如果資料采用的是數值範圍range分片,那麼我們隻需要添加節點就可以進行擴容;但如果采用的是數值hash取模分片,由于擴容涉及資料重分布過程,擴容相對比較麻煩。
是以,分庫分表,需要根據業務目前、預期的資料量、QPS來進行容量規劃,推算
出大概需要多少分片,盡量減少後續擴容及遷移的發生。
l分布式事務問題
由于分庫分表之後,業務需要跨庫跨分片進行SQL請求,類似分布式事務的問題就會出現。為了確定事務的原子性,事務的送出需要協調多個節點,加大事務的執行時間及複雜性。
是以,對于性能要求很高,但對一緻性要求不高的系統,在分庫分表設計的實時候可能需要采用事務補償的方式,将實時一緻性轉化為最終一緻性,結合業務系統比如對資料進行對賬檢查、基于日志進行對比等進行事後補償。
總 結
分庫分表作為一種橫向擴充的解決方案,問題還是比較明顯的:
從運維側來看:會極大的加大系統的複雜度、運維成本相對較高;
從業務側來看:會極大增加開發編碼工作量,并使業務邏輯複雜化。
是以,如果無需分片,則盡量避免分庫分表;如果确實到了需要分庫分表的情況,相對分庫分表的通用方案,如果采用分布式中間件或原生分布式資料庫,業務側無需花大量的工作來處理如何分片和分片後的問題,有更多的時間原本該是專注于業務的應用。