分库分表读写分离
為什么要分庫分表和讀寫分離?
類似淘寶網(wǎng)這樣的網(wǎng)站,海量數(shù)據(jù)的存儲(chǔ)和訪問成為了系統(tǒng)設(shè)計(jì)的瓶頸問題,日益增長(zhǎng)的業(yè)務(wù)數(shù)據(jù),無疑對(duì)數(shù)據(jù)庫造成了相當(dāng)大的負(fù)載,同時(shí)對(duì)于系統(tǒng)的穩(wěn)定性和擴(kuò)展性提出很高的要求。隨著時(shí)間和業(yè)務(wù)的發(fā)展,數(shù)據(jù)庫中的表會(huì)越來越多,表中的數(shù)據(jù)量也會(huì)越來越大,相應(yīng)地,數(shù)據(jù)操作的開銷也會(huì)越來越大;另外,無論怎樣升級(jí)硬件資源,單臺(tái)服務(wù)器的資源(CPU、磁盤、內(nèi)存、網(wǎng)絡(luò)IO、事務(wù)數(shù)、連接數(shù))總是有限的,最終數(shù)據(jù)庫所能承載的數(shù)據(jù)量、數(shù)據(jù)處理能力都將遭遇瓶頸。分表、分庫和讀寫分離可以有效地減小單臺(tái)數(shù)據(jù)庫的壓力。
MySQ一主多從,讀寫分離;寫主庫,讀從庫(所有的數(shù)據(jù)庫的數(shù)據(jù)都是一樣的)
數(shù)據(jù)一樣的,那么當(dāng)數(shù)據(jù)量太大的時(shí)查詢還是很慢的
分庫分表的原因
分庫(根據(jù)用戶的ID分庫)
所有數(shù)據(jù)庫的表結(jié)構(gòu)是一樣的,但存儲(chǔ)的數(shù)據(jù)完全不同
真實(shí)的開發(fā)環(huán)境以用戶的ID進(jìn)行分離,每一個(gè)庫的數(shù)據(jù)量小,查詢就很快了
無法解決問題:當(dāng)一個(gè)數(shù)據(jù)庫中表中數(shù)據(jù)量過大的時(shí)候,查詢依然很慢
分表(根據(jù)存儲(chǔ)數(shù)據(jù)的時(shí)間來分)
當(dāng)一個(gè)數(shù)據(jù)庫的數(shù)據(jù)量過大時(shí),必須進(jìn)行表拆分
分表主要是基于數(shù)據(jù)表的某個(gè)字段來將一個(gè)表拆分為多個(gè)子表,即一個(gè)表中的數(shù)據(jù)行拆分到多個(gè)子表中去保存,子表存放到同一個(gè)數(shù)據(jù)庫的不同表或者不同的數(shù)據(jù)庫中。
分庫分表帶來的問題及解決辦法
任何事情都有兩面性,分庫分表也不例外,如果采用分庫分表,會(huì)引入新的的問題
1、分布式事務(wù)問題
使用分布式事務(wù)中間件解決,具體是通過最終一致性還是強(qiáng)一致性分布式事務(wù),看業(yè)務(wù)需求,這里就不多說。
2、跨節(jié)點(diǎn)關(guān)聯(lián)查詢 Join 問題
切分之前,我們可以通過Join來完成。而切分之后,數(shù)據(jù)可能分布在不同的節(jié)點(diǎn)上,此時(shí)Join帶來的問題就比較麻煩了,考慮到性能,盡量避免使用Join查詢。
解決這個(gè)問題的一些方法:
全局表
全局表,也可看做是 “數(shù)據(jù)字典表”,就是系統(tǒng)中所有模塊都可能依賴的一些表,為了避免跨庫Join查詢,可以將 這類表在每個(gè)數(shù)據(jù)庫中都保存一份。這些數(shù)據(jù)通常
很少會(huì)進(jìn)行修改,所以也不擔(dān)心一致性的問題。
字段冗余
利用空間換時(shí)間,為了性能而避免join查詢。例:訂單表保存userId時(shí)候,也將userName冗余保存一份,這樣查詢訂單詳情時(shí)就不需要再去查詢"買家user表"了。
數(shù)據(jù)組裝
在系統(tǒng)層面,分兩次查詢。第一次查詢的結(jié)果集中找出關(guān)聯(lián)數(shù)據(jù)id,然后根據(jù)id發(fā)起第二次請(qǐng)求得到關(guān)聯(lián)數(shù)據(jù)。最后將獲得到的數(shù)據(jù)進(jìn)行字段拼裝。
3、跨節(jié)點(diǎn)分頁、排序、函數(shù)問題
跨節(jié)點(diǎn)多庫進(jìn)行查詢時(shí),會(huì)出現(xiàn)Limit分頁、Order by排序等問題。分頁需要按照指定字段進(jìn)行排序,當(dāng)排序字段就是分片字段時(shí),通過分片規(guī)則就比較容易定位到指定的分片;
當(dāng)排序字段非分片字段時(shí),就變得比較復(fù)雜了。需要先在不同的分片節(jié)點(diǎn)中將數(shù)據(jù)進(jìn)行排序并返回,然后將不同分片返回的結(jié)果集進(jìn)行匯總和再次排序,最終返回給用戶。
4、全局主鍵避重問題
如果都用主鍵自增肯定不合理,如果用UUID那么無法做到根據(jù)主鍵排序,所以我們可以考慮通過雪花ID來作為數(shù)據(jù)庫的主鍵,
5、數(shù)據(jù)遷移問題
采用雙寫的方式,修改代碼,所有涉及到分庫分表的表的增、刪、改的代碼,都要對(duì)新庫進(jìn)行增刪改。同時(shí),再有一個(gè)數(shù)據(jù)抽取服務(wù),不斷地從老庫抽數(shù)據(jù),往新庫寫,
邊寫邊按時(shí)間比較數(shù)據(jù)是不是最新的。
當(dāng)業(yè)務(wù)系統(tǒng)的數(shù)據(jù)容量接近或超過單臺(tái)服務(wù)器的容量、QPS/TPS接近或超過單個(gè)數(shù)據(jù)庫實(shí)例的處理極限等此時(shí),往往是采用垂直和水平結(jié)合的數(shù)據(jù)拆分方法,把數(shù)據(jù)服務(wù)和數(shù)據(jù)存儲(chǔ)分布到多臺(tái)數(shù)據(jù)庫服務(wù)器上
讀寫分離
什么是讀寫分離
讀寫分離的實(shí)質(zhì)是將應(yīng)用程序?qū)?shù)據(jù)庫的讀寫操作分配到多個(gè)數(shù)據(jù)庫服務(wù)器上,從而降低單臺(tái)數(shù)據(jù)庫的訪問壓力。
讀寫分離一般通過配置主從數(shù)據(jù)庫的方式,數(shù)據(jù)的讀取來自從庫,對(duì)數(shù)據(jù)庫增加修改刪除操作主庫。
為什么要讀寫分離呢?
通過數(shù)據(jù)庫中間件,可以對(duì)數(shù)據(jù)庫進(jìn)行水平擴(kuò)展,由原來單臺(tái)數(shù)據(jù)庫擴(kuò)展到多臺(tái)數(shù)據(jù)庫,數(shù)據(jù)庫中間件通過路由規(guī)則將數(shù)據(jù)的訪問請(qǐng)求路由到其中一臺(tái)數(shù)據(jù)庫上
- 因?yàn)閿?shù)據(jù)庫的“寫”(寫10000條數(shù)據(jù)到oracle可能要3分鐘)操作是比較耗時(shí)的。
- 但是數(shù)據(jù)庫的“讀”(從oracle讀10000條數(shù)據(jù)可能只要5秒鐘)。
- 所以讀寫分離,解決的是,數(shù)據(jù)庫的寫入,影響了查詢的效率。
- 降低了數(shù)據(jù)訪問的瓶頸和單臺(tái)數(shù)據(jù)庫的壓力。通過數(shù)據(jù)庫中間件還可以將DBA和研發(fā)進(jìn)行解耦,提升DBA運(yùn)維效率。
讀寫分離方案
- 當(dāng)數(shù)據(jù)庫讀遠(yuǎn)大于寫,查詢多的情況,就可以考慮主數(shù)據(jù)負(fù)責(zé)寫操作,從數(shù)據(jù)庫負(fù)責(zé)讀操作,一主多重,從而把數(shù)據(jù)讀寫分離
- 可以結(jié)合redis等緩存來配合分擔(dān)數(shù)據(jù)的讀操作,大大的降低后端數(shù)據(jù)庫的壓力
總結(jié)
- 上一篇: 树hash树BtreeB+tree
- 下一篇: 基于Docker部署Nginx