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

CTO 問我,為什么不按照教材上的 3NF 來設(shè)計(jì)數(shù)據(jù)庫?

開發(fā) 數(shù)據(jù)庫
數(shù)據(jù)冗余在大數(shù)據(jù)量與高并發(fā)量的數(shù)據(jù)庫設(shè)計(jì)中使用極其廣泛,今天重點(diǎn)講講冗余表的設(shè)計(jì)。

有水友問我說,學(xué)校學(xué)數(shù)據(jù)庫,都講究“范式設(shè)計(jì)”,為什么很多互聯(lián)網(wǎng)公司數(shù)據(jù)庫都搞“反范式”設(shè)計(jì)呢?

什么是數(shù)據(jù)庫范式設(shè)計(jì)?

  • 1NF:字段原子性;
  • 2NF:所有字段必須依賴主鍵;
  • 3NF:所有字段必須直接依賴主鍵;

為什么要搞數(shù)據(jù)庫范式設(shè)計(jì)?

減少數(shù)據(jù)冗余,減少數(shù)據(jù)依賴,確保數(shù)據(jù)一致性與完整性。

為什么很多互聯(lián)網(wǎng)公司數(shù)據(jù)庫都搞“反范式”設(shè)計(jì)?

任何脫離業(yè)務(wù)的數(shù)據(jù)庫設(shè)計(jì)都是耍流氓。

很多互聯(lián)網(wǎng)業(yè)務(wù)場(chǎng)景,數(shù)據(jù)的一致性與完整性并不是主要矛盾,大數(shù)據(jù)量與高并發(fā)量才是瓶頸,針對(duì)這兩個(gè)要素的設(shè)計(jì)才是核心,常見的典型“反范式”設(shè)計(jì)有:

  • 字段拆分,提升性能;
  • 放棄外鍵,減少JOIN,提升性能;

畫外音:數(shù)據(jù)庫范式設(shè)計(jì),大量依賴JOIN。

  • 最終一致性,提升性能;
  • 放棄事務(wù),犧牲一致性與完整性,提升性能;
  • 異步更新,犧牲一致性,提升性能;
  • 數(shù)據(jù)冗余,犧牲一致性,提升性能;
  • ...

特別是數(shù)據(jù)冗余,在大數(shù)據(jù)量與高并發(fā)量的數(shù)據(jù)庫設(shè)計(jì)中使用極其廣泛,今天重點(diǎn)講講冗余表的設(shè)計(jì)。

為什么會(huì)需要冗余表?

數(shù)據(jù)量很大的時(shí)候,數(shù)據(jù)庫往往要進(jìn)行水平切分,水平切分會(huì)有一個(gè)patition key,通過patition key的查詢能夠直接定位到庫,但是非patition key上的查詢可能就需要掃描多個(gè)庫了。

例如訂單表,業(yè)務(wù)上對(duì)用戶和商家都有訂單查詢需求:

  • Order(oid, info_detail)
  • T(buyer_id, seller_id, oid)

如果用buyer_id來分庫,seller_id的查詢就需要掃描多庫;如果用seller_id來分庫,buyer_id的查詢就需要掃描多庫。

這類業(yè)務(wù)“高吞吐量低延時(shí)”的查詢需求,往往是通過“數(shù)據(jù)冗余”的方式來滿足的,就是所謂的“冗余表”:

  • T1(buyer_id, seller_id, oid)
  • T2(seller_id, buyer_id, oid)

同一個(gè)數(shù)據(jù),冗余兩份,一份以buyer_id來分庫,滿足買家的查詢需求;一份以seller_id來分庫,滿足賣家的查詢需求。

冗余表如何實(shí)現(xiàn)?

常見的方案有三種。

方案一:服務(wù)同步寫法。

顧名思義,由服務(wù)層同步寫冗余數(shù)據(jù):

  • 業(yè)務(wù)方調(diào)用服務(wù),新增數(shù)據(jù);
  • 服務(wù)先插入T1數(shù)據(jù);
  • 服務(wù)再插入T2數(shù)據(jù);
  • 服務(wù)返回業(yè)務(wù)方新增數(shù)據(jù)成功;

優(yōu)點(diǎn):

  • 不復(fù)雜,服務(wù)層由單次寫,變兩次寫;
  • 雙寫成功才返回,數(shù)據(jù)一致性相對(duì)較高;

缺點(diǎn):

  • 要插入兩次,請(qǐng)求的處理時(shí)間增加;
  • 數(shù)據(jù)仍可能不一致,寫入T1完成后服務(wù)重啟,則數(shù)據(jù)不會(huì)寫入T2;

如果系統(tǒng)對(duì)處理時(shí)間比較敏感,引出常用的第二種方案。

方案二:服務(wù)異步寫法。

數(shù)據(jù)的雙寫并不再由服務(wù)來完成,服務(wù)層異步發(fā)出一個(gè)消息,通過MQ發(fā)送給一個(gè)專門的數(shù)據(jù)復(fù)制服務(wù)來寫入冗余數(shù)據(jù),如上圖1-6流程:

1....

2.服務(wù)先插入T1數(shù)據(jù);

3.服務(wù)向MQ發(fā)送一個(gè)異步消息;

...

6. 異步插入T2數(shù)據(jù);

優(yōu)點(diǎn):服務(wù)只插入1次,請(qǐng)求處理時(shí)間短。

缺點(diǎn):

  • 系統(tǒng)的復(fù)雜性增加了,多引入了兩個(gè)新組件,MQ與異步服務(wù);
  • 業(yè)務(wù)線返回成功時(shí),數(shù)據(jù)還不一定異步插入到T2中,因此數(shù)據(jù)有一個(gè)不一致時(shí)間窗口,這個(gè)窗口很短,最終是一致的;
  • 在消息總線丟失消息時(shí),冗余表數(shù)據(jù)仍可能不一致;

如果想解除“數(shù)據(jù)冗余”對(duì)系統(tǒng)的耦合,引出常用的第三種方案。

方案三:線下異步寫法。

數(shù)據(jù)的雙寫不再由服務(wù)層來完成,而是由線下的一個(gè)服務(wù)或者任務(wù)來完成,最常見的,就是利用DTS這類異步數(shù)據(jù)同步服務(wù),完成數(shù)據(jù)的冗余。

優(yōu)點(diǎn):

  • 數(shù)據(jù)雙寫與業(yè)務(wù)完全解耦;
  • 服務(wù)只插入1次,請(qǐng)求處理時(shí)間短;

缺點(diǎn):

  • 業(yè)務(wù)線返回成功時(shí),數(shù)據(jù)還不一定異步插入到T2中,因此數(shù)據(jù)有一個(gè)不一致時(shí)間窗口,這個(gè)窗口很短,最終是一致的;
  • 數(shù)據(jù)的一致性依賴于線下服務(wù)或者任務(wù)的可靠性;

可以看到,由于冗余表的插入不具備事務(wù)性,不管哪一種方案,都有可能出現(xiàn)T1插入成功,T2插入失敗的情況,從而喪失“最終一致性”特性,那怎么辦呢?

如何保證冗余表數(shù)據(jù)的最終一致性?

常見的有四種方案。

方案一:線下定期掃描正反冗余表全部數(shù)據(jù)。

如上圖所示,線下啟動(dòng)一個(gè)離線的掃描工具,不停地比對(duì)正表T1和反表T2,如果發(fā)現(xiàn)數(shù)據(jù)不一致,就進(jìn)行補(bǔ)償修復(fù)。

優(yōu)點(diǎn):

  • 比較簡(jiǎn)單,開發(fā)代價(jià)?。?/li>
  • 線上服務(wù)無需修改,修復(fù)工具與線上服務(wù)解耦;

缺點(diǎn):

  • 掃描效率低,會(huì)掃描大量的“已經(jīng)能夠保證一致”的數(shù)據(jù);
  • 由于掃描的數(shù)據(jù)量大,掃描一輪的時(shí)間比較長(zhǎng),即數(shù)據(jù)如果不一致,不一致的時(shí)間窗口比較長(zhǎng);

優(yōu)化思路:定期掃描全量數(shù)據(jù)太低效,有沒有一種只掃描“可能存在不一致可能性”的增量數(shù)據(jù),以提高效率的優(yōu)化方法呢?

方法二:線下掃描增量數(shù)據(jù)。

每次只掃描增量的日志數(shù)據(jù),就能夠極大提高效率,縮短數(shù)據(jù)不一致的時(shí)間窗口,如上圖1-4流程所示:

1. 寫入正表T1;

2. 寫入日志log1;

3. 寫入反表T2;

4. 寫入日志log2;

然后通過一個(gè)離線的掃描工具,不停的比對(duì)日志log1和日志log2,如果發(fā)現(xiàn)數(shù)據(jù)不一致,就進(jìn)行補(bǔ)償修復(fù)。

優(yōu)點(diǎn):

  • 比較簡(jiǎn)單,開發(fā)代價(jià)小;
  • 數(shù)據(jù)掃描效率高,只掃描增量數(shù)據(jù);

缺點(diǎn):

  • 線上服務(wù)略有修改,但代價(jià)不高,多寫了2條日志;
  • 雖然比方法一更實(shí)時(shí),但時(shí)效性還是不高,不一致窗口取決于掃描的周期;

優(yōu)化思路:有沒有實(shí)時(shí)檢測(cè)一致性并進(jìn)行修復(fù)的方法呢?

方法三:實(shí)時(shí)線上“消息對(duì)”檢測(cè)。

這次不是寫日志了,而是向消息總線發(fā)送消息,如上圖1-4流程所示:

1. 寫入正表T1;

2. 發(fā)送消息msg1;

3. 寫入反表T2;

4. 發(fā)送消息msg2;

正常情況下,msg1和msg2的接收時(shí)間應(yīng)該在N秒以內(nèi),如不然,則進(jìn)行補(bǔ)償修復(fù)。

優(yōu)點(diǎn):效率高,實(shí)時(shí)性高。

缺點(diǎn):相對(duì)復(fù)雜。

方案四:人工修復(fù)法。

項(xiàng)目上線時(shí)間太緊,沒時(shí)間搞一致性設(shè)計(jì)哇!

雖然插入不是原子的,奈何出現(xiàn)的概率低啊!

即使出現(xiàn)了,用戶也不一定能發(fā)現(xiàn)呀!

用戶發(fā)現(xiàn)了,找客服也不是找我呀!

找我,一個(gè)DBA工單就修復(fù)啦!

于是,大量的公司,不考慮正表和反表的數(shù)據(jù)一致性,事后發(fā)現(xiàn),事后人工修復(fù)。

總結(jié)

(1) 數(shù)據(jù)庫范式設(shè)計(jì),是為減少數(shù)據(jù)冗余,減少數(shù)據(jù)依賴,確保數(shù)據(jù)一致性與完整性而提出的;

(2) 很多互聯(lián)網(wǎng)業(yè)務(wù)場(chǎng)景,大數(shù)據(jù)量與高并發(fā)量才是瓶頸,故經(jīng)常采用“數(shù)據(jù)冗余”這類反范式設(shè)計(jì);

(3) 數(shù)據(jù)冗余的常見方式有三種:

  •  服務(wù)同步寫
  •  服務(wù)異步寫
  •  線下異步寫

(4) 修復(fù)冗余數(shù)據(jù)一致性的常見方案有四種:

  •  線下定期掃全量
  •  線下定期掃增量
  •  線上實(shí)時(shí)“消息對(duì)”檢測(cè)
  •  躺平,人工修復(fù)

知其然,知其所以然。

思路比結(jié)論更重要。

責(zé)任編輯:趙寧寧 來源: 架構(gòu)師之路
相關(guān)推薦

2020-12-04 09:11:50

CTOAPI網(wǎng)關(guān)

2015-06-23 13:56:30

數(shù)據(jù)庫設(shè)計(jì)面向?qū)ο?/a>

2017-11-30 08:56:14

數(shù)據(jù)庫中間件架構(gòu)師

2017-11-27 06:01:37

數(shù)據(jù)庫中間件中間層

2011-05-19 11:01:14

ERWin數(shù)據(jù)庫設(shè)計(jì)

2024-10-25 09:19:18

2010-06-12 17:16:46

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

2012-04-28 10:07:43

數(shù)據(jù)庫數(shù)據(jù)庫設(shè)計(jì)

2020-11-13 09:22:32

Docker數(shù)據(jù)庫容器

2018-11-29 14:30:42

數(shù)據(jù)庫外鍵約束應(yīng)用程序

2013-03-20 11:25:47

數(shù)據(jù)庫數(shù)據(jù)庫設(shè)計(jì)

2013-03-20 11:33:31

2013-03-20 13:25:53

數(shù)據(jù)庫數(shù)據(jù)庫設(shè)計(jì)

2013-03-20 13:35:12

數(shù)據(jù)庫數(shù)據(jù)庫設(shè)計(jì)

2020-03-27 16:05:49

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

2022-06-30 18:17:00

數(shù)據(jù)集云數(shù)據(jù)建模計(jì)數(shù)據(jù)倉庫

2020-07-16 07:52:09

Docker容器數(shù)據(jù)庫

2013-03-20 13:16:15

2020-03-04 10:05:33

關(guān)系數(shù)據(jù)庫居住權(quán)

2022-01-06 14:45:10

數(shù)據(jù)庫連接池IO
點(diǎn)贊
收藏

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