MySQL分布式设计
1. 簡(jiǎn)介
- 對(duì)數(shù)據(jù)庫(kù)進(jìn)行性能優(yōu)化
1.1 復(fù)制集
- 復(fù)制集(Replication)
- 數(shù)據(jù)庫(kù)中數(shù)據(jù)相同,起到備份作用
- 高可用 High Available HA
1.2 分布式
- 分布式(Distribution)
- 數(shù)據(jù)庫(kù)中數(shù)據(jù)不同,共同組成完整的數(shù)據(jù)集合
- 通常每個(gè)節(jié)點(diǎn)被稱為一個(gè)分片(shard)
- 高吞吐 High Throughput
- 復(fù)制集與分布式可以單獨(dú)使用,也可以組合使用(即每個(gè)分片都組建一個(gè)復(fù)制集)
1.3 主從
- 關(guān)于主(Master)從(Slave)
- 這個(gè)概念是從使用的角度來(lái)闡述問(wèn)題的
- 主節(jié)點(diǎn) -> 表示程序在這個(gè)節(jié)點(diǎn)上最先更新數(shù)據(jù)
- 從節(jié)點(diǎn) -> 表示這個(gè)節(jié)點(diǎn)的數(shù)據(jù)是要通過(guò)復(fù)制主節(jié)點(diǎn)而來(lái)
- 復(fù)制集 可選 主從、主主、主主從從
- 分布式 每個(gè)分片都是主,組合使用復(fù)制集的時(shí)候,復(fù)制集的是從
2. 復(fù)制
1.1 簡(jiǎn)介
1. 定義
也叫主從同步,數(shù)據(jù)備份,是一個(gè)異步的復(fù)制過(guò)程
2. 本質(zhì)
slave從master獲取Binary log,然后再在自己身上完全順序的執(zhí)行日志中所記錄的各種操作
MySQL服務(wù)器之間的主從同步是基于二進(jìn)制日志機(jī)制,主服務(wù)器使用二進(jìn)制日志來(lái)記錄數(shù)據(jù)庫(kù)的變動(dòng)情況,從服務(wù)器通過(guò)讀取和執(zhí)行該日志文件來(lái)保持和主服務(wù)器的數(shù)據(jù)一致。
3. 原理
復(fù)制分成三步:
下圖描述了這一過(guò)程:
-
該過(guò)程的第一部分就是master記錄二進(jìn)制日志。在每個(gè)事務(wù)更新數(shù)據(jù)完成之前,master在二日志記錄這些改變。MySQL將事務(wù)串行的寫入二進(jìn)制日志,即使事務(wù)中的語(yǔ)句都是交叉執(zhí)行的。在事件寫入二進(jìn)制日志完成后,master通知存儲(chǔ)引擎提交事務(wù)。
-
下一步就是slave將master的binary log拷貝到它自己的中繼日志。首先,slave開(kāi)始一個(gè)工作線程——I/O線程。I/O線程在master上打開(kāi)一個(gè)普通的連接,然后開(kāi)始binlog dump process。Binlog dump process從master的二進(jìn)制日志中讀取事件,如果已經(jīng)跟上master,它會(huì)睡眠并等待master產(chǎn)生新的事件。I/O線程將這些事件寫入中繼日志。
-
SQL slave thread處理該過(guò)程的最后一步。SQL線程從中繼日志讀取事件,更新slave的數(shù)據(jù),使其與master中的數(shù)據(jù)一致。只要該線程與I/O線程保持一致,中繼日志通常會(huì)位于OS的緩存中,所以中繼日志的開(kāi)銷很小。
-
此外,在master中也有一個(gè)工作線程:和其它MySQL的連接一樣,slave在master中打開(kāi)一個(gè)連接也會(huì)使得master開(kāi)始一個(gè)線程。
-
利用主從在達(dá)到高可用的同時(shí),也可以通過(guò)讀寫分離提供吞吐量。
-
讀寫分離對(duì)事務(wù)是否有影響
對(duì)于寫操作包括開(kāi)啟事務(wù)和提交或回滾要在一臺(tái)機(jī)器上執(zhí)行,分散到多臺(tái)master執(zhí)行后數(shù)據(jù)庫(kù)原生的單機(jī)事務(wù)就失效了。
對(duì)于事務(wù)中同時(shí)包含讀寫操作,與事務(wù)隔離級(jí)別設(shè)置有關(guān),如果事務(wù)隔離級(jí)別為read-uncommitted 或者 read-committed,讀寫分離沒(méi)影響,如果隔離級(jí)別為repeatable-read、serializable,讀寫分離就有影響,因?yàn)樵趕lave上會(huì)看到新數(shù)據(jù),而正在事務(wù)中的master看不到新數(shù)據(jù)。
3. 作用
對(duì)數(shù)據(jù)進(jìn)行備份,也就是主從同步后, 當(dāng)主服務(wù)器宕機(jī)后,可以從從服務(wù)器中選一臺(tái)當(dāng)主服務(wù)器,提高可用性;當(dāng)從服務(wù)器宕機(jī)后,不會(huì)有任何影響,體現(xiàn)了 高可用,數(shù)據(jù)安全
可以增加從服務(wù)器來(lái)提高數(shù)據(jù)庫(kù)的讀取性能
讀寫分離實(shí)現(xiàn)后,有兩臺(tái)服務(wù)器,分?jǐn)偭俗x取數(shù)據(jù)庫(kù)服務(wù)器的壓力,提高了吞吐量,實(shí)現(xiàn)了高性能
5. 常用架構(gòu)
5.1 主從架構(gòu)
1. 簡(jiǎn)介
在多加幾臺(tái)數(shù)據(jù)庫(kù)服務(wù)器的基礎(chǔ)上實(shí)現(xiàn)了讀寫分離,把多態(tài)數(shù)據(jù)庫(kù)服務(wù)器分為一臺(tái)主服務(wù)器(master)和多臺(tái)從服務(wù)器(slave),master負(fù)責(zé)write操作,slave負(fù)責(zé)read操作,一臺(tái)主服務(wù)器對(duì)應(yīng)多臺(tái)從服務(wù)器。
2. 原理
2. 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
缺點(diǎn):
3. 應(yīng)用場(chǎng)景
微博:微博寫微博和讀微博的人比例大概是1:10
5.2 主備架構(gòu)
1. 簡(jiǎn)介
實(shí)質(zhì)就是開(kāi)多個(gè)數(shù)據(jù)庫(kù)服務(wù)器,都是master,都可以writer和read,一旦主庫(kù)掛了,就啟用備庫(kù)
2. 原理
3. 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 高可用,數(shù)據(jù)安全
缺點(diǎn): - 單庫(kù)讀寫,性能一般
4. 應(yīng)用場(chǎng)景
阿里云,美團(tuán)大企業(yè),性能可以通過(guò)多個(gè)服務(wù)器來(lái)解決
5. 問(wèn)題
既然主備互為備份,為什么不采用雙主方案,提供兩臺(tái)Master進(jìn)行負(fù)載均衡
- 因?yàn)橛醒舆t,會(huì)出現(xiàn)臟數(shù)據(jù),數(shù)據(jù)不一致
- 雖然兩邊執(zhí)行的修改有先后順序,但由于 Replication 是異步的實(shí)現(xiàn)機(jī)制,同樣可能導(dǎo)致晚做的修改被做的修改所覆蓋
- 不僅B庫(kù)數(shù)據(jù)錯(cuò)誤,且A&B庫(kù)數(shù)據(jù)不一致
- 主備架構(gòu)搭建除了配置雙主同步,還需要配置第三故障轉(zhuǎn)移/高可用方案
5.3 高可用復(fù)合架構(gòu)
1. 簡(jiǎn)介
在主從架構(gòu)的基礎(chǔ)上,進(jìn)行主庫(kù)的備份:主從架構(gòu)+主備架構(gòu)
2. 原理
3. 優(yōu)缺點(diǎn)
- 讀寫分離,提高吞吐量
- 主從庫(kù)實(shí)現(xiàn)了高可用HA:主庫(kù)宕機(jī)后,去找從庫(kù),同理,從庫(kù)宕機(jī),去找主庫(kù)
- 提高了吞吐量
A庫(kù)宕機(jī)的情況:
2. 讀寫分離
2.1 Django實(shí)現(xiàn)MySQL讀寫分離
1. Docker安裝運(yùn)行MySQL從機(jī)
提示:
- 搭建一主一從的主從同步。
- 主服務(wù)器:ubuntu操作系統(tǒng)中的MySQL。
- 從服務(wù)器:Docker容器中的MySQL。
1.獲取MySQL鏡像
- 主從同步盡量保證多臺(tái)MySQL的版本相同或相近。
2.指定MySQL從機(jī)配置文件
- 在使用Docker安裝運(yùn)行MySQL從機(jī)之前,需要準(zhǔn)備好從機(jī)的配置文件。
- 為了快速準(zhǔn)備從機(jī)的配置文件,直接把主機(jī)的配置文件拷貝到從機(jī)中。
3.修改MySQL從機(jī)配置文件
- 編輯 ~/mysql_slave/mysql.conf.d/mysqld.cnf文件。
- 由于主從機(jī)都在同一個(gè)電腦中,所以選擇使用不同的端口號(hào)區(qū)分主從機(jī),從機(jī)端口號(hào)是8306。
4.Docker 安裝運(yùn)行 MySQL 從機(jī)
- MYSQL_ROOT_PASSWORD:創(chuàng)建 root 用戶的密碼為 123456。
5.測(cè)試從機(jī)是否創(chuàng)建成功
$ mysql -uroot -p123456 -h127.0.0.1 --port=83062. 主從同步實(shí)現(xiàn)
1.配置主機(jī)( ubuntu 中 MySQL)
- 配置文件如有修改,需要重啟主機(jī)。
sudo service mysql restart
首先, 進(jìn)入主機(jī)的配置文件所在地:
cd /etc/mysql/mysql.conf.d/
進(jìn)入后找到 mysqld.cnf 文件, 對(duì)其進(jìn)行修改:
修改內(nèi)容如下所示:
# 開(kāi)啟日志: 把下面的代碼注釋去掉 general_log_file = /var/log/mysql/mysql.log general_log = 1# 主機(jī)唯一編號(hào) server-id = 1# 二進(jìn)制日志文件 log_bin = /var/log/mysql/mysql-bin.log2.從機(jī)備份主機(jī)原有數(shù)據(jù)
- 在做主從同步時(shí),如果從機(jī)需要主機(jī)上原有數(shù)據(jù),就要先復(fù)制一份到從機(jī)。
3.主從同步實(shí)現(xiàn)
1.創(chuàng)建用于從服務(wù)器同步數(shù)據(jù)的帳號(hào)
# 登錄到主機(jī) $ mysql –uroot –pmysql# 創(chuàng)建從機(jī)賬號(hào) $ GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by 'slave';# 刷新權(quán)限 $ FLUSH PRIVILEGES;2.展示 ubuntu 中 MySQL 主機(jī)的二進(jìn)制日志信息
$ SHOW MASTER STATUS;3.Docker 中 MySQL 從機(jī)連接 ubuntu 中 MySQL 主機(jī)
# 登錄到從機(jī) $ mysql -uroot -p123456 -h 127.0.0.1 --port=8306# 從機(jī)連接到主機(jī) $ change master to master_host='127.0.0.1', master_user='slave', master_password='slave',master_log_file='mysql-bin.000250', master_log_pos=990250;# 開(kāi)啟從機(jī)服務(wù) $ start slave;# 展示從機(jī)服務(wù)狀態(tài) $ show slave status \G;測(cè)試:
在主機(jī)中新建一個(gè)數(shù)據(jù)庫(kù)后,直接在從機(jī)查看是否存在。
- 在mall.utils.db_router.py中實(shí)現(xiàn)讀寫路由
- 在 dev.py 文件中配置如下參數(shù)
2.2 falsk實(shí)現(xiàn)讀寫分離
- 需求分析:
sqlchemy并沒(méi)有像django-orm一樣內(nèi)置完善的讀寫分離方案,但是提供了可以自定義的接口:我們可以借此對(duì)flask-sqlchemy進(jìn)行二次開(kāi)發(fā),實(shí)現(xiàn)讀寫分離 - 思路分析:
- 實(shí)現(xiàn)自定義的session類(SignallingSession),繼承SignllingSession類
- 重寫`get_bind方法,根據(jù)讀寫需求選擇對(duì)應(yīng)的數(shù)據(jù)庫(kù)地址
- 實(shí)現(xiàn)自定義的SQLAlchemy類,繼承與SQLAlchemy類
- 重寫create_session方法,在內(nèi)部實(shí)現(xiàn)自定義的Session類
- 實(shí)現(xiàn)自定義的session類(SignallingSession),繼承SignllingSession類
- 虛擬機(jī)搭建好Mysql主從,可以直接用于測(cè)試使用
- 主數(shù)據(jù)庫(kù)端口 3306
- 從數(shù)據(jù)庫(kù)接口 8306
2.2 項(xiàng)目集成
- 將工具包routting_db導(dǎo)入common/models中,其中的`routing_sqlchemy.py文件實(shí)現(xiàn)了讀寫分離
- 在app/settings/config.py文件中設(shè)計(jì)值主從數(shù)據(jù)庫(kù)的URL地址
- 在app/__init__.py文件中使用自定義SQLAchemy類
2. 分片(sharding)
2.1 簡(jiǎn)介
1. 分庫(kù)分表前的問(wèn)題
任何問(wèn)題都是太大或者太小的問(wèn)題,這里面對(duì)的數(shù)據(jù)量太大的問(wèn)題。
-
用戶請(qǐng)求量太大
因?yàn)閱畏?wù)器TPS,內(nèi)存,IO都是有限的。 解決方法:分散請(qǐng)求到多個(gè)服務(wù)器上; 其實(shí)用戶請(qǐng)求和執(zhí)行一個(gè)sql查詢是本質(zhì)是一樣的,都是請(qǐng)求一個(gè)資源,只是用戶請(qǐng)求還會(huì)經(jīng)過(guò)網(wǎng)關(guān),路由,http服務(wù)器等。
-
單庫(kù)太大
單個(gè)數(shù)據(jù)庫(kù)處理能力有限;單庫(kù)所在服務(wù)器上磁盤空間不足;單庫(kù)上操作的IO瓶頸 解決方法:切分成更多更小的庫(kù)
-
單表太大
CRUD都成問(wèn)題;索引膨脹,查詢超時(shí) 解決方法:切分成多個(gè)數(shù)據(jù)集更小的表。
2. 分庫(kù)分表的方式方法
-
一般就是垂直切分和水平切分,這是一種結(jié)果集描述的切分方式,是物理空間上的切分。 從面臨的問(wèn)題,開(kāi)始解決,闡述: 首先是用戶請(qǐng)求量太大,就堆機(jī)器搞定
-
然后是單個(gè)庫(kù)太大,這時(shí)要看是因?yàn)楸矶喽鴮?dǎo)致數(shù)據(jù)多,還是因?yàn)閱螐埍砝锩娴臄?shù)據(jù)多。 如果是因?yàn)楸矶喽鴶?shù)據(jù)多,使用垂直切分,根據(jù)業(yè)務(wù)切分成不同的庫(kù)。
-
如果是因?yàn)閱螐埍淼臄?shù)據(jù)量太大,這時(shí)要用水平切分,即把表的數(shù)據(jù)按某種規(guī)則切分成多張表,甚至多個(gè)庫(kù)上的多張表。 分庫(kù)分表的順序應(yīng)該是先垂直分,后水平分。 因?yàn)榇怪狈指?jiǎn)單,更符合處理現(xiàn)實(shí)世界問(wèn)題的方式。
3. 分片簡(jiǎn)介
-
需求分析:
- 用戶請(qǐng)求量太大,會(huì)導(dǎo)致web應(yīng)用無(wú)法及時(shí)響應(yīng)->分布式服務(wù)器(分散請(qǐng)求到多個(gè)服務(wù)器上)
- 表單太大,會(huì)導(dǎo)致CRUD都成問(wèn)題,索引膨脹,查詢超時(shí)->拆分表
- 單庫(kù)太大,會(huì)導(dǎo)致單庫(kù)磁盤空間不足:處理能力有限,出現(xiàn)IO瓶頸->拆分庫(kù)
-
作用
- 分片也成為數(shù)據(jù)拆分(Shareding),其主要工作就是對(duì)單庫(kù)單表進(jìn)行拆分,多苦多表共同組成完整的數(shù)據(jù)集合
- 分片可以提高吞吐量,同一時(shí)間數(shù)據(jù)的讀寫完成量更多,擴(kuò)充單機(jī)存儲(chǔ)量的容量/讀寫速度上限
-
分類
- 垂直拆分:字段太多
- 水平拆分
- 使用頻率(常用字段/不常用字段)
- 垂直分庫(kù),分表–blind–key–來(lái)實(shí)現(xiàn),修改數(shù)據(jù)庫(kù)
- HASH取模 離散化
去用戶id,然后hash取模,飛陪到不同的數(shù)據(jù)庫(kù)上,遮掩
-
注意點(diǎn)
-
不要輕易分庫(kù)分表,因?yàn)榉制瑫?huì)帶來(lái) 諸多分布式問(wèn)題, 讓應(yīng)用的復(fù)雜度大量增加
-
應(yīng)避免"過(guò)度設(shè)計(jì)"和"過(guò)早優(yōu)化", 先盡力去做其他優(yōu)化,例如:升級(jí)硬件、升級(jí)網(wǎng)絡(luò)、讀寫分離、索引優(yōu)化、緩存設(shè)計(jì)等等。
-
當(dāng)數(shù)據(jù)量達(dá)到單表瓶頸時(shí)候(參考值: 單表記錄1000W+/硬盤100G+),再考慮分庫(kù)分表
-
如果需要進(jìn)行分庫(kù)分表, 優(yōu)先考慮垂直拆分
* 地理區(qū)域 分布式問(wèn)題* 分布式事務(wù) * 跨Join/排序/分頁(yè)方案一:* 不需要分方案二:* 二階段事務(wù)session_options = {“twoparse}* begin:xl* prepare:二階段預(yù)提交* commit:真正提交方案三:* ebay* 狀態(tài)字段* 1. 表中定義狀態(tài)字段2. 兩個(gè)系統(tǒng)定義 ***消息接口***3. -
分庫(kù)訪問(wèn)
- flask-sqlalchemy通過(guò)
-
水平拆分:記錄太多
3. 垂直拆分
3.1 垂直分表
1. 簡(jiǎn)介
- 也就是“大表拆小表”,基于列字段進(jìn)行的。一般是表中的字段較多,將不常用的, 數(shù)據(jù)較大,長(zhǎng)度較長(zhǎng)(比如text類型字段)的拆分到“擴(kuò)展表“。 一般是針對(duì)那種幾百列的大表,也避免查詢時(shí),數(shù)據(jù)量太大造成的“跨頁(yè)”問(wèn)題。
- 按 字段 將一張表拆分成多張表
- 對(duì)于字段較多的表, 每條記錄占用的空間也會(huì)較多, 導(dǎo)致每次從硬盤中讀取的記錄以及查詢緩存可緩存的記錄數(shù)量較少, 影響查詢查詢效率
- 針對(duì)字段多的表就可以采用垂直分表來(lái)進(jìn)行拆分, 這樣可以減少表體積, 提高查詢效率
2. 拆分規(guī)則
- 相關(guān)性
- 可以將字段根據(jù) 業(yè)務(wù)邏輯 和 使用的相關(guān)性 進(jìn)行分表劃分
- 如: 用戶名和密碼經(jīng)常配合使用, 將其分到用戶認(rèn)證表, 生日和郵箱等個(gè)人信息經(jīng)常一起訪問(wèn), 將其分到用戶信息表
- 使用頻率
- 可以將字段根據(jù) 常用 和 不常用 進(jìn)行劃分, 并進(jìn)行分表處理
- 如: 原始用戶表中包含了多個(gè)字段, 其中有常用的昵稱、手機(jī)號(hào)等字段, 也包含不常用的郵箱、生日等字段, 可以根據(jù)使用頻率將其分為兩張表: 用戶基礎(chǔ)信息表 和 用戶其他信息表
- 項(xiàng)目中的應(yīng)用
- 用戶數(shù)據(jù)垂直分表 user_basic& user_profile
- 文章數(shù)據(jù)垂直分表 article_basic & article_content (文章內(nèi)容較長(zhǎng)且只在詳情頁(yè)才需要)
3.2 垂直分庫(kù)
1. 簡(jiǎn)介
-
垂直分庫(kù)針對(duì)的是一個(gè)系統(tǒng)中的不同業(yè)務(wù)進(jìn)行拆分,比如用戶User一個(gè)庫(kù),商品Producet一個(gè)庫(kù),訂單Order一個(gè)庫(kù)。 切分后,要放在多個(gè)服務(wù)器上,而不是一個(gè)服務(wù)器上。為什么? 我們想象一下,一個(gè)購(gòu)物網(wǎng)站對(duì)外提供服務(wù),會(huì)有用戶,商品,訂單等的CRUD。沒(méi)拆分之前, 全部都是落到單一的庫(kù)上的,這會(huì)讓數(shù)據(jù)庫(kù)的單庫(kù)處理能力成為瓶頸。按垂直分庫(kù)后,如果還是放在一個(gè)數(shù)據(jù)庫(kù)服務(wù)器上, 隨著用戶量增大,這會(huì)讓單個(gè)數(shù)據(jù)庫(kù)的處理能力成為瓶頸,還有單個(gè)服務(wù)器的磁盤空間,內(nèi)存,tps等非常吃緊。 所以我們要拆分到多個(gè)服務(wù)器上,這樣上面的問(wèn)題都解決了,以后也不會(huì)面對(duì)單機(jī)資源問(wèn)題。
-
數(shù)據(jù)庫(kù)業(yè)務(wù)層面的拆分,和服務(wù)的“治理”,“降級(jí)”機(jī)制類似,也能對(duì)不同業(yè)務(wù)的數(shù)據(jù)分別的進(jìn)行管理,維護(hù),監(jiān)控,擴(kuò)展等。 數(shù)據(jù)庫(kù)往往最容易成為應(yīng)用系統(tǒng)的瓶頸,而數(shù)據(jù)庫(kù)本身屬于“有狀態(tài)”的,相對(duì)于Web和應(yīng)用服務(wù)器來(lái)講,是比較難實(shí)現(xiàn)“橫向擴(kuò)展”的。 數(shù)據(jù)庫(kù)的連接資源比較寶貴且單機(jī)處理能力也有限,在高并發(fā)場(chǎng)景下,垂直分庫(kù)一定程度上能夠突破IO、連接數(shù)及單機(jī)硬件資源的瓶頸。
- 將一個(gè)數(shù)據(jù)庫(kù)中的多張表拆分到多個(gè)數(shù)據(jù)庫(kù)(服務(wù)器節(jié)點(diǎn))中
- 注意點(diǎn):
- 由于 本地事務(wù)不支持跨庫(kù)操作, 所以應(yīng)該將 有相關(guān)聯(lián)性的表放在同一個(gè)庫(kù)中
- 如: 如果后續(xù)項(xiàng)目垂直分庫(kù), 將用戶相關(guān)的放在數(shù)據(jù)庫(kù)1, 文章相關(guān)的放在數(shù)據(jù)庫(kù)2
3.3 分庫(kù)訪問(wèn)
-
flask-sqlalchemy 通過(guò)配置 SQLALCHEMY_BINDS允許設(shè)置多個(gè)數(shù)據(jù)庫(kù)URI, 并且每個(gè)模型類可以 __bind_key__屬性 設(shè)置自己對(duì)應(yīng)訪問(wèn)的數(shù)據(jù)庫(kù)
-
示例場(chǎng)景如下: 項(xiàng)目進(jìn)行了分庫(kù)處理, 包含兩個(gè)庫(kù) db1 和 db2, 用戶表t_user存儲(chǔ)在db1中, 而地址表t_adr存儲(chǔ)在db2中
4. 水平拆分
4.1 水平分表
- 將 一張表的記錄 拆分到多張表中
- 對(duì)于記錄較多的表, 會(huì)出現(xiàn) 索引膨脹, 查詢超時(shí) 等問(wèn)題, 影響用戶體驗(yàn)
- 針對(duì)數(shù)據(jù)量巨大的單張表(比如訂單表),按照某種規(guī)則(RANGE,HASH取模等),切分到多張表里面去。 但是這些表還是在同一個(gè)庫(kù)中,所以庫(kù)級(jí)別的數(shù)據(jù)庫(kù)操作還是有IO瓶頸。不建議采用。
4.2 水平分庫(kù)分表
- 水平分表后, 將分表分散放在多個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)中
- 將單張表的數(shù)據(jù)切分到多個(gè)服務(wù)器上去,每個(gè)服務(wù)器具有相應(yīng)的庫(kù)與表,只是表中數(shù)據(jù)集合不同。 水平分庫(kù)分表能夠有效的緩解單機(jī)和單庫(kù)的性能瓶頸和壓力,突破IO、連接數(shù)、硬件資源等的瓶頸。
4.3 水平分庫(kù)分表拆分規(guī)則
-
ID范圍/RANGE
- 從0到10000一個(gè)表,10001到20000一個(gè)表;
- 從 0 到 100W 一個(gè)表,100W+1 到 200W 一個(gè)表。
-
HASH取模 離散化
- 取用戶id,然后hash取模,分配到不同的數(shù)據(jù)庫(kù)上。這樣可以同時(shí)向多個(gè)表中插入數(shù)據(jù), 提高并發(fā)能力, 同時(shí)由于用戶id進(jìn)行了離散處理, 不會(huì)出現(xiàn)ID沖突的問(wèn)題
- 一個(gè)商場(chǎng)系統(tǒng),一般都是將用戶,訂單作為主表,然后將和它們相關(guān)的作為附表,這樣不會(huì)造成跨庫(kù)事務(wù)之類的問(wèn)題。 取用戶id,然后hash取模,分配到不同的數(shù)據(jù)庫(kù)上。
-
業(yè)務(wù)
- 按照業(yè)務(wù)將數(shù)據(jù)進(jìn)行分類并拆分, 如文章包含金融、科技等多個(gè)分類, 可以每個(gè)分類的數(shù)據(jù)拆分到一張表中。
-
地理區(qū)域
比如按照華東,華南,華北這樣來(lái)區(qū)分業(yè)務(wù),七牛云等云服務(wù)應(yīng)該就是如此。
-
時(shí)間
按照時(shí)間切分,就是將6個(gè)月前,甚至一年前的數(shù)據(jù)切出去放到另外的一張表,因?yàn)殡S著時(shí)間流逝,這些表的數(shù)據(jù) 被查詢的概率變小,所以沒(méi)必要和“熱數(shù)據(jù)”放在一起,這個(gè)也是“冷熱數(shù)據(jù)分離”。
4.4 數(shù)據(jù)庫(kù)定向查詢
- 如果進(jìn)行了水平拆分, 在沒(méi)有精確過(guò)濾條件的情況下, 可能需要到多個(gè)數(shù)據(jù)庫(kù)中依次查詢目標(biāo)數(shù)據(jù)
*可以對(duì) RoutingSession 進(jìn)行二次開(kāi)發(fā), 提供方法進(jìn)行 數(shù)據(jù)庫(kù)定向查詢 - 應(yīng)用場(chǎng)景如下: 對(duì)用戶表進(jìn)行水平分庫(kù)分表, 用戶數(shù)據(jù)分別保存在 db1.t_user 和 db2.t_user 中, 項(xiàng)目的其他數(shù)據(jù)保存在數(shù)據(jù)庫(kù) test 中
5. 分布式問(wèn)題
5.1 分布式失去問(wèn)題
- 事務(wù)支持
- 分庫(kù)分表后,就成了分布式事務(wù)了。如果依賴數(shù)據(jù)庫(kù)本身的分布式事務(wù)管理功能去執(zhí)行事務(wù),將付出高昂的性能代價(jià);
- 如果由應(yīng)用程序去協(xié)助控制,形成程序邏輯上的事務(wù),又會(huì)造成編程方面的負(fù)擔(dān)。
- 本地事務(wù)不支持跨庫(kù)操作
- 解決辦法從簡(jiǎn)單到復(fù)雜有三種
1. 方案一
- 將有關(guān)聯(lián)的表放在一個(gè)數(shù)據(jù)庫(kù)中
- 同庫(kù)操作可以使用一個(gè)事務(wù)
- 如用戶表&用戶頻道表, 文章基本信息表&文章內(nèi)容表放在一起
2. 方案二
-
Mysql從5.6開(kāi)始支持分布式事務(wù)
-
核心是二階段提交協(xié)議(簡(jiǎn)稱 2PC協(xié)議 / XA協(xié)議)
-
分布式事務(wù)會(huì)提供一個(gè) 事務(wù)管理器 來(lái)對(duì) 各數(shù)據(jù)庫(kù)的本地事務(wù)進(jìn)行統(tǒng)一管理, 只有各本地事務(wù)都向管理器 預(yù)提交 成功后, 事務(wù)管理器才會(huì)統(tǒng)一執(zhí)行提交處理, 否則統(tǒng)一進(jìn)行回滾處理
-
sqlalchemy 也支持分布式事務(wù)
- 只需要在創(chuàng)建 SQLAlchemy對(duì)象時(shí), 設(shè)置參數(shù) session_options={'twophase': True}即可
-
設(shè)置后, 整個(gè)session的所有操作會(huì)被放入到一個(gè)分布式事務(wù)中, 并在整個(gè)分布式事務(wù)范圍內(nèi)保證原子性
- 注意點(diǎn):
- 分布式事務(wù)要在所有事務(wù)都"提交成功"的情況下才會(huì)正式提交, 如果參與的部分節(jié)點(diǎn)卡頓, 會(huì)影響整個(gè)事務(wù)的性能
3. 方案三
- 基于狀態(tài)/消息的最終一致性方案
- 對(duì)于 包含多個(gè)子系統(tǒng)的大型項(xiàng)目, 需要保證子系統(tǒng)之間的數(shù)據(jù)一致性
- 單個(gè)子系統(tǒng)往往不會(huì)操作所有數(shù)據(jù)庫(kù), 但是 每個(gè)子系統(tǒng)可以通過(guò)定義字段來(lái)記錄操作的狀態(tài), 每完成一個(gè)階段則更新相應(yīng)的狀態(tài)
- 如下單-付款流程中, 應(yīng)用A的下單事務(wù)完成后更新訂單狀態(tài)為 已下單, 應(yīng)用B付款事務(wù)完成后, 再通過(guò) 支付回調(diào)接口 通知應(yīng)用A 更新訂單狀態(tài)
- 應(yīng)用B還需要提供一個(gè) 支付查詢接口, 以便在用戶查詢或者訂單超時(shí)的情況下, 讓應(yīng)用A可以查詢訂單的支付情況
- ebay 提出的方案, 理論叫做 BASE
5.2 跨節(jié)點(diǎn) Join/排序/分頁(yè)
- 跨庫(kù)join
- 不支持的跨庫(kù)操作包括join/分組/聚合/排序
1. 方案一
- 分兩次查詢進(jìn)行, 在應(yīng)用端合并
2. 方案二
- 使用一些第三方方案(數(shù)據(jù)庫(kù)中間件)
- 開(kāi)源框架除了Mycat, 功能較少
- 需要一定學(xué)習(xí)成本, 二次開(kāi)發(fā)需要公司具有一定技術(shù)實(shí)力
- 以下為推薦的開(kāi)源框架:
MySQL Router:https://github.com/mysql/mysql-router
Atlas:https://github.com/Qihoo360/Atlas
Mycat:https://github.com/MyCATApache/Mycat-Server - 付費(fèi)框架推薦: 阿里DRDS
- 功能: 分庫(kù)分表、分布式JOIN/聚合/排序、分布式事務(wù)、平滑擴(kuò)容、讀寫分離, 全局唯一ID
- 基礎(chǔ)版: 14000+/年
- 一個(gè)字: 強(qiáng)!
分庫(kù)分表后表之間的關(guān)聯(lián)操作將受到限制,我們無(wú)法join位于不同分庫(kù)的表,也無(wú)法join分表粒度不同的表, 結(jié)果原本一次查詢能夠完成的業(yè)務(wù),可能需要多次查詢才能完成。 粗略的解決方法: 全局表:基礎(chǔ)數(shù)據(jù),所有庫(kù)都拷貝一份。 字段冗余:這樣有些字段就不用join去查詢了。 系統(tǒng)層組裝:分別查詢出所有,然后組裝起來(lái),較復(fù)雜。
3. 方案三
-
分庫(kù)分表方案產(chǎn)品
-
目前市面上的分庫(kù)分表中間件相對(duì)較多,其中基于代理方式的有MySQL Proxy和Amoeba, 基于Hibernate框架的是Hibernate Shards,基于jdbc的有當(dāng)當(dāng)sharding-jdbc, 基于mybatis的類似maven插件式的有蘑菇街的蘑菇街TSharding, 通過(guò)重寫spring的ibatis template類的Cobar Client。
-
還有一些大公司的開(kāi)源產(chǎn)品:
5.3 多庫(kù)結(jié)果集合并(group by,order by)
6. 項(xiàng)目應(yīng)用
-
主從
-
垂直分表
總結(jié)
以上是生活随笔為你收集整理的MySQL分布式设计的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【MATLAB-app】appdesig
- 下一篇: 泰山OFFICE技术讲座:微软雅黑字体故