自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL分庫分表會(huì)帶來哪些問題?

數(shù)據(jù)庫 MySQL
分庫分表能有效的環(huán)節(jié)單機(jī)和單庫帶來的性能瓶頸和壓力,突破網(wǎng)絡(luò)IO、硬件資源、連接數(shù)的瓶頸,同時(shí)也帶來了一些問題。下面將描述這些技術(shù)挑戰(zhàn)以及對(duì)應(yīng)的解決思路。

分庫分表能有效的環(huán)節(jié)單機(jī)和單庫帶來的性能瓶頸和壓力,突破網(wǎng)絡(luò)IO、硬件資源、連接數(shù)的瓶頸,同時(shí)也帶來了一些問題。下面將描述這些技術(shù)挑戰(zhàn)以及對(duì)應(yīng)的解決思路。

[[272325]]

1、事務(wù)一致性問題

分布式事務(wù)

當(dāng)更新內(nèi)容同時(shí)分布在不同庫中,不可避免會(huì)帶來跨庫事務(wù)問題。跨分片事務(wù)也是分布式事務(wù),沒有簡單的方案,一般可使用"XA協(xié)議"和"兩階段提交"處理。

分布式事務(wù)能最大限度保證了數(shù)據(jù)庫操作的原子性。但在提交事務(wù)時(shí)需要協(xié)調(diào)多個(gè)節(jié)點(diǎn),推后了提交事務(wù)的時(shí)間點(diǎn),延長了事務(wù)的執(zhí)行時(shí)間。導(dǎo)致事務(wù)在訪問共享資源時(shí)發(fā)生沖突或死鎖的概率增高。隨著數(shù)據(jù)庫節(jié)點(diǎn)的增多,這種趨勢會(huì)越來越嚴(yán)重,從而成為系統(tǒng)在數(shù)據(jù)庫層面上水平擴(kuò)展的枷鎖。

最終一致性

對(duì)于那些性能要求很高,但對(duì)一致性要求不高的系統(tǒng),往往不苛求系統(tǒng)的實(shí)時(shí)一致性,只要在允許的時(shí)間段內(nèi)達(dá)到最終一致性即可,可采用事務(wù)補(bǔ)償?shù)姆绞健Ec事務(wù)在執(zhí)行中發(fā)生錯(cuò)誤后立即回滾的方式不同,事務(wù)補(bǔ)償是一種事后檢查補(bǔ)救的措施,一些常見的實(shí)現(xiàn)方法有:對(duì)數(shù)據(jù)進(jìn)行對(duì)賬檢查,基于日志進(jìn)行對(duì)比,定期同標(biāo)準(zhǔn)數(shù)據(jù)來源進(jìn)行同步等等。事務(wù)補(bǔ)償還要結(jié)合業(yè)務(wù)系統(tǒng)來考慮。

2、跨節(jié)點(diǎn)關(guān)聯(lián)查詢 join 問題

切分之前,系統(tǒng)中很多列表和詳情頁所需的數(shù)據(jù)可以通過sql join來完成。而切分之后,數(shù)據(jù)可能分布在不同的節(jié)點(diǎn)上,此時(shí)join帶來的問題就比較麻煩了,考慮到性能,盡量避免使用join查詢。

跨節(jié)點(diǎn)關(guān)聯(lián)查詢 join 問題

切分之前,系統(tǒng)中很多列表和詳情頁所需的數(shù)據(jù)可以通過sql join來完成。而切分之后,數(shù)據(jù)可能分布在不同的節(jié)點(diǎn)上,此時(shí)join帶來的問題就比較麻煩了,考慮到性能,盡量避免使用join查詢。

解決這個(gè)問題的一些方法:

1)全局表

全局表,也可看做是"數(shù)據(jù)字典表",就是系統(tǒng)中所有模塊都可能依賴的一些表,為了避免跨庫join查詢,可以將這類表在每個(gè)數(shù)據(jù)庫中都保存一份。這些數(shù)據(jù)通常很少會(huì)進(jìn)行修改,所以也不擔(dān)心一致性的問題。

2)字段冗余

一種典型的反范式設(shè)計(jì),利用空間換時(shí)間,為了性能而避免join查詢。例如:訂單表保存userId時(shí)候,也將userName冗余保存一份,這樣查詢訂單詳情時(shí)就不需要再去查詢"買家user表"了。

但這種方法適用場景也有限,比較適用于依賴字段比較少的情況。而冗余字段的數(shù)據(jù)一致性也較難保證,就像上面訂單表的例子,買家修改了userName后,是否需要在歷史訂單中同步更新呢?這也要結(jié)合實(shí)際業(yè)務(wù)場景進(jìn)行考慮。

3)數(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)行字段拼裝。

4)ER分片

關(guān)系型數(shù)據(jù)庫中,如果可以先確定表之間的關(guān)聯(lián)關(guān)系,并將那些存在關(guān)聯(lián)關(guān)系的表記錄存放在同一個(gè)分片上,那么就能較好的避免跨分片join問題。在1:1或1:n的情況下,通常按照主表的ID主鍵切分。如下圖所示:

Mysql數(shù)據(jù)庫-分庫分表都帶來的哪些問題?

這樣一來,Data Node1上面的order訂單表與orderdetail訂單詳情表就可以通過orderId進(jìn)行局部的關(guān)聯(lián)查詢了,Data Node2上也一樣。

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)行匯總和再次排序,最終返回給用戶。如圖所示:

Mysql數(shù)據(jù)庫-分庫分表都帶來的哪些問題?

上圖中只是取第一頁的數(shù)據(jù),對(duì)性能影響還不是很大。但是如果取得頁數(shù)很大,情況則變得復(fù)雜很多,因?yàn)楦鞣制?jié)點(diǎn)中的數(shù)據(jù)可能是隨機(jī)的,為了排序的準(zhǔn)確性,需要將所有節(jié)點(diǎn)的前N頁數(shù)據(jù)都排序好做合并,最后再進(jìn)行整體的排序,這樣的操作時(shí)很耗費(fèi)CPU和內(nèi)存資源的,所以頁數(shù)越大,系統(tǒng)的性能也會(huì)越差。

在使用Max、Min、Sum、Count之類的函數(shù)進(jìn)行計(jì)算的時(shí)候,也需要先在每個(gè)分片上執(zhí)行相應(yīng)的函數(shù),然后將各個(gè)分片的結(jié)果集進(jìn)行匯總和再次計(jì)算,最終將結(jié)果返回。如圖所示:

Mysql數(shù)據(jù)庫-分庫分表都帶來的哪些問題?

4、全局主鍵避重問題

在分庫分表環(huán)境中,由于表中數(shù)據(jù)同時(shí)存在不同數(shù)據(jù)庫中,主鍵值平時(shí)使用的自增長將無用武之地,某個(gè)分區(qū)數(shù)據(jù)庫自生成的ID無法保證全局唯一。因此需要單獨(dú)設(shè)計(jì)全局主鍵,以避免跨庫主鍵重復(fù)問題。有一些常見的主鍵生成策略:

1)UUID

UUID標(biāo)準(zhǔn)形式包含32個(gè)16進(jìn)制數(shù)字,分為5段,形式為8-4-4-4-12的36個(gè)字符,例如:550e8400-e29b-41d4-a716-446655440000

UUID是主鍵是最簡單的方案,本地生成,性能高,沒有網(wǎng)絡(luò)耗時(shí)。但缺點(diǎn)也很明顯,由于UUID非常長,會(huì)占用大量的存儲(chǔ)空間;另外,作為主鍵建立索引和基于索引進(jìn)行查詢時(shí)都會(huì)存在性能問題,在InnoDB下,UUID的無序性會(huì)引起數(shù)據(jù)位置頻繁變動(dòng),導(dǎo)致分頁。

2)結(jié)合數(shù)據(jù)庫維護(hù)主鍵ID表

在數(shù)據(jù)庫中建立 sequence 表:

  1. CREATE TABLE `sequence` (  
  2.  `id` bigint(20) unsigned NOT NULL auto_increment,  
  3.  `stub` char(1) NOT NULL default '',  
  4.  PRIMARY KEY (`id`),  
  5.  UNIQUE KEY `stub` (`stub`)  
  6. ) ENGINE=MyISAM; 

stub字段設(shè)置為唯一索引,同一stub值在sequence表中只有一條記錄,可以同時(shí)為多張表生成全局ID。sequence表的內(nèi)容,如下所示:

  1. +-------------------+------+  
  2. | id | stub |  
  3. +-------------------+------+  
  4. | 72157623227190423 | a |  
  5. +-------------------+------+  

使用 MyISAM 存儲(chǔ)引擎而不是 InnoDB,以獲取更高的性能。MyISAM使用的是表級(jí)別的鎖,對(duì)表的讀寫是串行的,所以不用擔(dān)心在并發(fā)時(shí)兩次讀取同一個(gè)ID值。

當(dāng)需要全局唯一的64位ID時(shí),執(zhí)行:

  1. REPLACE INTO sequence (stub) VALUES ('a');  
  2. SELECT LAST_INSERT_ID();  

這兩條語句是Connection級(jí)別的,select last_insert_id() 必須與 replace into 在同一數(shù)據(jù)庫連接下才能得到剛剛插入的新ID。

使用replace into代替insert into好處是避免了表行數(shù)過大,不需要另外定期清理。

此方案較為簡單,但缺點(diǎn)也明顯:存在單點(diǎn)問題,強(qiáng)依賴DB,當(dāng)DB異常時(shí),整個(gè)系統(tǒng)都不可用。配置主從可以增加可用性,但當(dāng)主庫掛了,主從切換時(shí),數(shù)據(jù)一致性在特殊情況下難以保證。另外性能瓶頸限制在單臺(tái)MySQL的讀寫性能。

flickr團(tuán)隊(duì)使用的一種主鍵生成策略,與上面的sequence表方案類似,但更好的解決了單點(diǎn)和性能瓶頸的問題。

這一方案的整體思想是:建立2個(gè)以上的全局ID生成的服務(wù)器,每個(gè)服務(wù)器上只部署一個(gè)數(shù)據(jù)庫,每個(gè)庫有一張sequence表用于記錄當(dāng)前全局ID。表中ID增長的步長是庫的數(shù)量,起始值依次錯(cuò)開,這樣能將ID的生成散列到各個(gè)數(shù)據(jù)庫上。如下圖所示:

Mysql數(shù)據(jù)庫-分庫分表都帶來的哪些問題?

由兩個(gè)數(shù)據(jù)庫服務(wù)器生成ID,設(shè)置不同的auto_increment值。第一臺(tái)sequence的起始值為1,每次步長增長2,另一臺(tái)的sequence起始值為2,每次步長增長也是2。結(jié)果第一臺(tái)生成的ID都是奇數(shù)(1, 3, 5, 7 ...),第二臺(tái)生成的ID都是偶數(shù)(2, 4, 6, 8 ...)。

這種方案將生成ID的壓力均勻分布在兩臺(tái)機(jī)器上。同時(shí)提供了系統(tǒng)容錯(cuò),第一臺(tái)出現(xiàn)了錯(cuò)誤,可以自動(dòng)切換到第二臺(tái)機(jī)器上獲取ID。但有以下幾個(gè)缺點(diǎn):系統(tǒng)添加機(jī)器,水平擴(kuò)展時(shí)較復(fù)雜;每次獲取ID都要讀寫一次DB,DB的壓力還是很大,只能靠堆機(jī)器來提升性能。

可以基于flickr的方案繼續(xù)優(yōu)化,使用批量的方式降低數(shù)據(jù)庫的寫壓力,每次獲取一段區(qū)間的ID號(hào)段,用完之后再去數(shù)據(jù)庫獲取,可以大大減輕數(shù)據(jù)庫的壓力。如下圖所示:

Mysql數(shù)據(jù)庫-分庫分表都帶來的哪些問題?

還是使用兩臺(tái)DB保證可用性,數(shù)據(jù)庫中只存儲(chǔ)當(dāng)前的最大ID。ID生成服務(wù)每次批量拉取6個(gè)ID,先將max_id修改為5,當(dāng)應(yīng)用訪問ID生成服務(wù)時(shí),就不需要訪問數(shù)據(jù)庫,從號(hào)段緩存中依次派發(fā)0~5的ID。當(dāng)這些ID發(fā)完后,再將max_id修改為11,下次就能派發(fā)6~11的ID。于是,數(shù)據(jù)庫的壓力降低為原來的1/6。

3)Snowflake分布式自增ID算法

Twitter的snowflake算法解決了分布式系統(tǒng)生成全局ID的需求,生成64位的Long型數(shù)字,組成部分:

  • 第一位未使用
  • 接下來41位是毫秒級(jí)時(shí)間,41位的長度可以表示69年的時(shí)間
  • 5位datacenterId,5位workerId。10位的長度最多支持部署1024個(gè)節(jié)點(diǎn)
  • 最后12位是毫秒內(nèi)的計(jì)數(shù),12位的計(jì)數(shù)順序號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒產(chǎn)生4096個(gè)ID序列
Mysql數(shù)據(jù)庫-分庫分表都帶來的哪些問題?

這樣的好處是:毫秒數(shù)在高位,生成的ID整體上按時(shí)間趨勢遞增;不依賴第三方系統(tǒng),穩(wěn)定性和效率較高,理論上QPS約為409.6w/s(1000*2^12),并且整個(gè)分布式系統(tǒng)內(nèi)不會(huì)產(chǎn)生ID碰撞;可根據(jù)自身業(yè)務(wù)靈活分配bit位。

不足就在于:強(qiáng)依賴機(jī)器時(shí)鐘,如果時(shí)鐘回?fù)?,則可能導(dǎo)致生成ID重復(fù)。

綜上

結(jié)合數(shù)據(jù)庫和snowflake的唯一ID方案,可以參考業(yè)界較為成熟的解法:Leaf——美團(tuán)點(diǎn)評(píng)分布式ID生成系統(tǒng),并考慮到了高可用、容災(zāi)、分布式下時(shí)鐘等問題。

5、數(shù)據(jù)遷移、擴(kuò)容問題

當(dāng)業(yè)務(wù)高速發(fā)展,面臨性能和存儲(chǔ)的瓶頸時(shí),才會(huì)考慮分片設(shè)計(jì),此時(shí)就不可避免的需要考慮歷史數(shù)據(jù)遷移的問題。一般做法是先讀出歷史數(shù)據(jù),然后按指定的分片規(guī)則再將數(shù)據(jù)寫入到各個(gè)分片節(jié)點(diǎn)中。此外還需要根據(jù)當(dāng)前的數(shù)據(jù)量和QPS,以及業(yè)務(wù)發(fā)展的速度,進(jìn)行容量規(guī)劃,推算出大概需要多少分片(一般建議單個(gè)分片上的單表數(shù)據(jù)量不超過1000W)

如果采用數(shù)值范圍分片,只需要添加節(jié)點(diǎn)就可以進(jìn)行擴(kuò)容了,不需要對(duì)分片數(shù)據(jù)遷移。如果采用的是數(shù)值取模分片,則考慮后期的擴(kuò)容問題就相對(duì)比較麻煩。

責(zé)任編輯:華軒 來源: 今日頭條
相關(guān)推薦

2022-05-25 08:06:37

MySQL分庫分表

2025-03-03 12:30:00

import *代碼開發(fā)

2025-01-07 08:20:49

2021-10-29 07:25:32

分庫分表技巧

2020-11-18 09:39:02

MySQL數(shù)據(jù)庫SQL

2024-02-21 12:17:00

2022-10-11 17:51:49

分庫分表數(shù)據(jù)庫

2020-07-30 17:59:34

分庫分表SQL數(shù)據(jù)庫

2018-09-21 15:50:58

數(shù)據(jù)庫MySQL分庫分表

2019-11-12 09:54:20

分庫分表數(shù)據(jù)

2019-05-13 15:00:14

MySQLMyCat數(shù)據(jù)庫

2021-08-31 20:21:11

VitessMySQL分庫

2023-08-11 08:59:49

分庫分表數(shù)據(jù)數(shù)據(jù)庫

2020-01-07 09:40:25

數(shù)據(jù)庫MySQLRedis

2021-03-17 16:15:55

數(shù)據(jù)MySQL 架構(gòu)

2023-09-26 00:45:11

MySQL拆表分片

2022-07-11 08:16:47

NewSQL關(guān)系數(shù)據(jù)庫系統(tǒng)

2025-04-01 08:45:00

2024-07-26 00:16:11

2020-07-28 09:04:09

NewSQL分庫分表
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)