共計 4582 個字符,預計需要花費 12 分鐘才能閱讀完成。
這篇文章給大家介紹如何解決億級用戶的分布式數(shù)據(jù)庫數(shù)據(jù)存儲問題,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
一、MySQL 復制
1.MySQL 的主從復制
MySQL 的主從復制,就是將 MySQL 主數(shù)據(jù)庫中的數(shù)據(jù)復制到從數(shù)據(jù)庫中去。
主要目的是實現(xiàn)數(shù)據(jù)庫讀寫分離,寫操作訪問主數(shù)據(jù)庫,讀操作訪問從數(shù)據(jù)庫,從而使數(shù)據(jù)庫具有更強大的訪問負載能力,支撐更多的用戶訪問。
它的主要的復制原理是:當應用程序客戶端發(fā)送一條更新命令到數(shù)據(jù)庫的時候,數(shù)據(jù)庫會把這條更新命令同步記錄到 Binlog 中,然后由另外一個線程從 Binlog 中讀取這條日志,然后通過遠程通訊的方式將它復制到從服務器上面去,從服務器獲得這條更新日志后,將其加入到自己的 Relay log 中,然后由另外一個 SQL 執(zhí)行線程從 Relay log 中讀取這條新的日志,并把它在本地的數(shù)據(jù)庫中重新執(zhí)行一遍。
這樣當客戶端應用程序執(zhí)行一個 update 命令的時候,這個命令會在主數(shù)據(jù)庫和從數(shù)據(jù)庫上同步執(zhí)行,從而實現(xiàn)了主數(shù)據(jù)庫向從數(shù)據(jù)庫的復制,讓從數(shù)據(jù)庫和主數(shù)據(jù)庫保持一樣的數(shù)據(jù)。
2.MySQL 的一主多從復制
MySQL 的主從復制是一種數(shù)據(jù)同步機制,除了可以將一個主數(shù)據(jù)庫中的數(shù)據(jù)同步復制到一個從數(shù)據(jù)庫上,還可以將一個主數(shù)據(jù)庫上的數(shù)據(jù)同步復制到多個從數(shù)據(jù)庫上,也就是所謂的 MySQL 的一主多從復制。
多個從數(shù)據(jù)庫關(guān)聯(lián)到主數(shù)據(jù)庫后,將主數(shù)據(jù)庫上的 Binlog 日志同步地復制到了多個從數(shù)據(jù)庫上。通過執(zhí)行日志,讓每個從數(shù)據(jù)庫的數(shù)據(jù)都和主數(shù)據(jù)庫上的數(shù)據(jù)保持了一致。這里面的數(shù)據(jù)更新操作表示的是所有數(shù)據(jù)庫的更新操作,除了不包括 SELECT 之類的查詢讀操作,其他的 INSERT、DELETE、UPDATE 這樣的 DML 寫操作,以及 CREATE TABLE、DROPT ABLE、ALTER TABLE 等 DDL 操作也都可以同步復制到從數(shù)據(jù)庫上去。
3. 一主多從復制的優(yōu)點
一主多從復制有四大優(yōu)點,分別是分攤負載、專機專用、便于冷備和高可用。
a. 分攤負載
將只讀操作分布在多個從數(shù)據(jù)庫上,從而將負載分攤到多臺服務器上。
b. 專機專用
可以針對不同類型的查詢,使用不同的從服務器。
c. 便于進行冷備
即使數(shù)據(jù)庫進行了一主多從的復制,在一些極端的情況下。也可能會導致整個數(shù)據(jù)中心的數(shù)據(jù)服務器都丟失。所以通常說來很多公司會對數(shù)據(jù)做冷備,但是進行冷備的時候有一個困難點在于,數(shù)據(jù)庫如果正在進行寫操作,冷備的數(shù)據(jù)就可能不完整,數(shù)據(jù)文件可能處于損壞狀態(tài)。使用一主多從的復制就就可以實現(xiàn)零停機時間的備份。只需要關(guān)閉數(shù)據(jù)的數(shù)據(jù)復制進程,文件就處于關(guān)閉狀態(tài)了,然后進行數(shù)據(jù)文件拷貝,拷貝完成后再重新打開數(shù)據(jù)復制就可以了。
d. 高可用
如果一臺服務器宕機了,只要不發(fā)請求給這臺服務器就不會出問題。當這臺服務器恢復的時候,重新發(fā)請求到這臺服務器。所以,在一主多從的情況下,某一臺從服務器宕機不可用,對整個系統(tǒng)的影響是非常小的。
4.MySQL 的主主復制
但是一主多從只能夠?qū)崿F(xiàn)從服務器上的這些優(yōu)點,當主數(shù)據(jù)庫宕機不可用的時候,數(shù)據(jù)依然是不能夠?qū)懭氲模驗閿?shù)據(jù)不能夠?qū)懭氲綇姆掌魃厦嫒ィ瑥姆掌魇侵蛔x的。
為了解決主服務器的可用性問題,我們可以使用 MySQL 的主主復制方案。所謂的主主復制方案是指兩臺服務器都當作主服務器,任何一臺服務器上收到的寫操作都會復制到另一臺服務器上。
如上主主復制原理圖,當客戶端程序?qū)χ鞣掌?A 進行數(shù)據(jù)更新操作的時候,主服務器 A 會把更新操作寫入到 Binlog 日志中。然后 Binlog 會將數(shù)據(jù)日志同步到主服務器 B,寫入到主服務器的 Relay log 中,然后執(zhí) Relay log,獲得 Relay log 中的更新日志,執(zhí)行 SQL 操作寫入到數(shù)據(jù)庫服務器 B 的本地數(shù)據(jù)庫中。B 服務器上的更新也同樣通過 Binlog 復制到了服務器 A 的 Relay log 中,然后通過 Relay log 將數(shù)據(jù)更新到服務器 A 中。
通過這種方式,服務器 A 或者 B 任何一臺服務器收到了數(shù)據(jù)的寫的操作都會同步更新到另一臺服務器,實現(xiàn)了數(shù)據(jù)庫主主復制。主主復制可以提高系統(tǒng)的寫可用,實現(xiàn)寫操作的高可用。
5.MySQL 的主主失效恢復
使用 MySQL 服務器實現(xiàn)主主復制時,數(shù)據(jù)庫服務器失效該如何應對?
正常情況下用戶會寫入到主服務器 A 中,然后數(shù)據(jù)從 A 復制到主服務器 B 上。當主服務器 A 失效的時候,寫操作會被發(fā)送到主服務器 B 中去,數(shù)據(jù)從 B 服務器復制到 A 服務器。
主主失效的維護過程如下:
最開始的時候,所有的主服務器都可以正常使用,當主服務器 A 失效的時候,進入故障狀態(tài),應用程序檢測到主服務器 A 失效,檢測到這個失效可能需要幾秒鐘或者幾分鐘的時間,然后應用程序需要進行失效轉(zhuǎn)移,將寫操作發(fā)送到備份主服務器 B 上面去,將讀操作發(fā)送到 B 服務器對應的從服務器上面去。
一段時間后故障結(jié)束,A 服務器需要重建失效期間丟失的數(shù)據(jù),也就是把自己當作從服務器從 B 服務器上面去同步數(shù)據(jù)。同步完成后系統(tǒng)才能恢復正常。這個時候 B 服務器是用戶的主要訪問服務器,A 服務器當作備份服務器。
5.MySQL 復制注意事項
使用 MySQL 進行主主復制的時候需要注意的事項如下:
a. 不要對兩個數(shù)據(jù)庫同時進行數(shù)據(jù)寫操作,因為這種情況會導致數(shù)據(jù)沖突。
b. 復制只是增加了數(shù)據(jù)的讀并發(fā)處理能力,并沒有增加寫并發(fā)的能力和系統(tǒng)存儲能力。
c. 更新數(shù)據(jù)表的結(jié)構(gòu)會導致巨大的同步延遲。
需要更新表結(jié)構(gòu)的操作,不要寫入到到 Binlog 中,要關(guān)閉更新表結(jié)構(gòu)的 Binlog。如果要對表結(jié)構(gòu)進行更新,應該由運維工程師 DBA 對所有主從數(shù)據(jù)庫分別手工進行數(shù)據(jù)表結(jié)構(gòu)的更新操作。
二、數(shù)據(jù)分片
數(shù)據(jù)復制只能提高數(shù)據(jù)讀并發(fā)操作能力,并不能提高數(shù)據(jù)寫操作并發(fā)的能力以及數(shù)據(jù)整個的存儲容量,也就是并不能提高數(shù)據(jù)庫總存儲記錄數(shù)。如果我們數(shù)據(jù)庫的寫操作也有大量的并發(fā)請求需要滿足,或者是我們的數(shù)據(jù)表特別大,單一的服務器甚至連一張表都無法存儲。解決方案就是數(shù)據(jù)分片。
1. 數(shù)據(jù)分片介紹
a. 主要目標:將一張數(shù)據(jù)表切分成較小的片,不同的片存儲到不同的服務器上面去,通過分片的方式使用多臺服務器存儲一張數(shù)據(jù)表,避免一臺服務器記錄存儲處理整張數(shù)據(jù)表帶來的存儲及訪問壓力。
b. 主要特點:數(shù)據(jù)庫服務器之間互相獨立,不共享任何信息,即使有部分服務器故障,也不影響整個系統(tǒng)的可用性。第二個特點是通過分片鍵定位分片,也就是說一個分片存儲到哪個服務器上面去,到哪個服服務器上面去查找,是通過分片鍵進行路由分區(qū)算法計算出來的。在 SQL 語句里面,只要包含分片鍵,就可以訪問特定的服務器,而不需要連接所有的服務器,跟其他的服務器進行通信。
. 主要原理:將數(shù)據(jù)以某種方式進行切分,通常就是用剛才提到的分片鍵的路由算法。通過分片鍵,根據(jù)某種路由算法進行計算,使每臺服務器都只存儲一部分數(shù)據(jù)。
2. 硬編碼實現(xiàn)數(shù)據(jù)分片
如圖例子,通過應用程序硬編碼的方式實現(xiàn)數(shù)據(jù)分片。假設我們的數(shù)據(jù)庫將數(shù)據(jù)表根據(jù)用戶 ID 進行分片,分片的邏輯是用戶 ID 為奇數(shù)的數(shù)據(jù)存儲在服務器 2 中,用戶 ID 為偶數(shù)的數(shù)據(jù)存儲在服務器 1 中。那么,應用程序在編碼的時候,就可以直接通過用戶 ID 進行哈希計算,通常是余數(shù)計算。如果余數(shù)為奇數(shù)就連接到服務器 2 上,如果余數(shù)為偶數(shù),就連接到服務器 1 上,這樣就實現(xiàn)了一張用戶表分片在兩個服務器上。
這種硬編碼主要的缺點在于,數(shù)據(jù)庫的分片邏輯是應用程序自身實現(xiàn)的,應用程序需要耦合數(shù)據(jù)庫分片邏輯,不利于應用程序的維護和擴展。一個簡單的解決辦法就是將映射關(guān)系存儲在外面。
3. 映射表外部存儲
應用程序在連接數(shù)據(jù)庫進行 SQL 操作的時候,通過查找外部的數(shù)據(jù)存儲查詢自己應該連接到哪臺服務器上面去,然后根據(jù)返回的服務器的編號,連接對應的服務器執(zhí)行相應的操作。在這個例子中,用戶 ID=33 查是 2,用戶 ID=94 查也是 2,它們根據(jù)查找到的用戶服務器的編號,連接對應的服務器,將數(shù)據(jù)寫入到對應的服務器分片中。
4. 數(shù)據(jù)分片的挑戰(zhàn)及解決方案
數(shù)據(jù)庫分片面臨如圖的挑戰(zhàn):
現(xiàn)在有一些專門的分布式數(shù)據(jù)庫中間件來解決上述這些問題,比較知名的有 Mycat。Mycat 是一個專門的分布式數(shù)據(jù)庫中間件,應用程序像連接數(shù)據(jù)庫一樣的連接 Mycat,而數(shù)據(jù)分片的操作完全交給了 Mycat 去完成。
如下這個例子中,有 3 個分片數(shù)據(jù)庫服務器,數(shù)據(jù)庫服務器 dn1、dn2 和 dn3,它們的分片規(guī)則是根據(jù) prov 字段進行分片。那么,當我們執(zhí)行一個查詢操作”select * from orders where prov=’wuhan’“的時候,Mycat 會根據(jù)分片規(guī)則將這條 SQL 操作路由到 dn1 這個服務器節(jié)點上。dn1 執(zhí)行數(shù)據(jù)查詢操作返回結(jié)果后,Mycat 再返回給應用程序。通過使用 Mycat 這樣的分布式數(shù)據(jù)庫中間件,應用程序可以透明的無感知的使用分片數(shù)據(jù)庫。同時,Mycat 還一定程度上支持分片數(shù)據(jù)庫的聯(lián)合 join 查詢以及數(shù)據(jù)庫事務。
5. 分片數(shù)據(jù)庫擴容伸縮
一開始,數(shù)據(jù)量還不是太多,兩個數(shù)據(jù)庫服務器就夠了。但是隨著數(shù)據(jù)的不斷增長,可能需要增加第三個第四個第五個甚至更多的服務器。在增加服務器的過程中,分片規(guī)則需要改變。分片規(guī)則改變后,以前寫入到原來的數(shù)據(jù)庫中的數(shù)據(jù),根據(jù)新的分片規(guī)則,可能要訪問新的服務器,所以還需要進行數(shù)據(jù)遷移。
不管是更改路由算法規(guī)則,還是進行數(shù)據(jù)遷移,都是一些比較麻煩和復雜的事情。因此在實踐中通常的做法是數(shù)據(jù)分片使用邏輯數(shù)據(jù)庫,也就是說一開始雖然只需要兩個服務器就可以完成數(shù)據(jù)分片存儲,但是依然在邏輯上把它切分成多個邏輯數(shù)據(jù)庫。具體的操作辦法,本文不用大篇幅進行闡述了。
三、數(shù)據(jù)庫部署方案
1. 單一服務和單一數(shù)據(jù)庫
這是最簡單的部署方案。應用服務器可能有多個,但是它們完成的功能是單一的功能。多個完成單一功能的服務器,通過負載均衡對外提供服務。它們只連一臺單一數(shù)據(jù)庫服務器,這是應用系統(tǒng)早期用戶量比較低的時候的一種架構(gòu)方法。
2. 主從復制實現(xiàn)伸縮
如果對系統(tǒng)的可用性和對數(shù)據(jù)庫的訪問性能提出更高要求的時候,就可以通過數(shù)據(jù)庫的主從復制進行初步的伸縮。通過主從復制,實現(xiàn)一主多從。應用服務器的寫操作連接主數(shù)據(jù)庫,讀操作從從服務器上進行讀取。
3. 兩個 Web 服務及兩個數(shù)據(jù)庫
隨著業(yè)務更加復雜,為了提供更高的數(shù)據(jù)庫處理能力,可以進行數(shù)據(jù)的業(yè)務分庫。數(shù)據(jù)的業(yè)務分庫是一種邏輯上的,是基于功能的一種分割,將不同用途的數(shù)據(jù)表存儲在不同的物理數(shù)據(jù)庫上面去。
在這個例子中,有產(chǎn)品類目服務和用戶服務,兩個應用服務器集群,對應的也將數(shù)據(jù)庫也拆分成兩個,一個叫做類目數(shù)據(jù)庫,一個叫做用戶數(shù)據(jù)庫。每個數(shù)據(jù)庫依然使用主從復制。通過業(yè)務分庫的方式,在同一個系統(tǒng)中,提供了更多的數(shù)據(jù)庫存儲,同時也就提供了更強大的數(shù)據(jù)訪問能力,同時也使系統(tǒng)變得更加簡單,系統(tǒng)的耦合變得更低。
根據(jù)不同數(shù)據(jù)的訪問特點,使用不同的解決方案進行應對。比如說類目數(shù)據(jù)庫,也許通過主從復制就能夠滿足所有的訪問要求。但是如果用戶量特別大,進行主從復制或主主復制,還是不能夠滿足數(shù)據(jù)存儲以及寫操作的訪問壓力,這時候就就可以對用戶數(shù)據(jù)庫進行數(shù)據(jù)分片存儲了。同時每個分片數(shù)據(jù)庫也使用主從復制的方式進行部署。
關(guān)于如何解決億級用戶的分布式數(shù)據(jù)庫數(shù)據(jù)存儲問題就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。