成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

進(jìn)來(lái)抄作業(yè):一次完美的分庫(kù)分表實(shí)踐!

運(yùn)維 數(shù)據(jù)庫(kù)運(yùn)維
幾年前我曾經(jīng)服務(wù)過(guò)的一家電商公司,隨著業(yè)務(wù)增長(zhǎng)我們每天的訂單量很快從 30 萬(wàn)單增長(zhǎng)到了 100 萬(wàn)單,訂單總量也突破了一億。

[[360800]] 

圖片來(lái)自 Pexels

當(dāng)時(shí)用的 MySQL 數(shù)據(jù)庫(kù)。根據(jù)監(jiān)控,我們的每秒最高訂單量已經(jīng)達(dá)到了 2000 筆(不包括秒殺,秒殺 TPS 已經(jīng)上萬(wàn)了。秒殺我們有一套專門(mén)的解決方案,詳見(jiàn)《秒殺系統(tǒng)設(shè)計(jì)~億級(jí)用戶》)。

不過(guò),直到此時(shí),訂單系統(tǒng)還是單庫(kù)單表,幸好當(dāng)時(shí)數(shù)據(jù)庫(kù)服務(wù)器配置不錯(cuò),我們的系統(tǒng)才能撐住這么大的壓力。

業(yè)務(wù)量還在快速增長(zhǎng),再不重構(gòu)系統(tǒng)早晚出大事,我們花了一天時(shí)間快速制定了重構(gòu)方案。

重構(gòu)?說(shuō)這么高大上,不就是分庫(kù)分表嗎?的確,就是分庫(kù)分表。不過(guò)除了分庫(kù)分表,還包括管理端的解決方案,比如運(yùn)營(yíng),客服和商務(wù)需要從多維度查詢訂單數(shù)據(jù),分庫(kù)分表后,怎么滿足大家的需求?

分庫(kù)分表后,上線方案和數(shù)據(jù)不停機(jī)遷移方案都需要慎重考慮。為了保證系統(tǒng)穩(wěn)定,還需要考慮相應(yīng)的降級(jí)方案。

為什么要分庫(kù)分表?

當(dāng)數(shù)據(jù)庫(kù)產(chǎn)生性能瓶頸:IO 瓶頸或 CPU 瓶頸。兩種瓶頸最終都會(huì)導(dǎo)致數(shù)據(jù)庫(kù)的活躍連接數(shù)增加,進(jìn)而達(dá)到數(shù)據(jù)庫(kù)可承受的最大活躍連接數(shù)閾值。

終會(huì)導(dǎo)致應(yīng)用服務(wù)無(wú)連接可用,造成災(zāi)難性后果??梢韵葟拇a,SQL,索引幾方面進(jìn)行優(yōu)化。如果這幾方面已經(jīng)沒(méi)有太多優(yōu)化的余地,就該考慮分庫(kù)分表了。

IO 瓶頸

第一種:磁盤(pán)讀 IO 瓶頸。

由于熱點(diǎn)數(shù)據(jù)太多,數(shù)據(jù)庫(kù)緩存完全放不下,查詢時(shí)會(huì)產(chǎn)生大量的磁盤(pán) IO,查詢速度會(huì)比較慢,這樣會(huì)導(dǎo)致產(chǎn)生大量活躍連接,最終可能會(huì)發(fā)展成無(wú)連接可用的后果。

可以采用一主多從,讀寫(xiě)分離的方案,用多個(gè)從庫(kù)分?jǐn)偛樵兞髁俊;蛘卟捎梅謳?kù)+水平分表(把一張表的數(shù)據(jù)拆成多張表來(lái)存放,比如訂單表可以按 user_id 來(lái)拆分)的方案。

第二種:磁盤(pán)寫(xiě) IO 瓶頸。

由于數(shù)據(jù)庫(kù)寫(xiě)入頻繁,會(huì)產(chǎn)生頻繁的磁盤(pán)寫(xiě)入 IO 操作,頻繁的磁盤(pán) IO 操作導(dǎo)致產(chǎn)生大量活躍連接,最終同樣會(huì)發(fā)展成無(wú)連接可用的后果。

這時(shí)只能采用分庫(kù)方案,用多個(gè)庫(kù)來(lái)分?jǐn)倢?xiě)入壓力。再加上水平分表的策略,分表后,單表存儲(chǔ)的數(shù)據(jù)量會(huì)更小,插入數(shù)據(jù)時(shí)索引查找和更新的成本會(huì)更低,插入速度自然會(huì)更快。

CPU 瓶頸

SQL 問(wèn)題:如果 SQL 中包含 join,group by,order by,非索引字段條件查詢等增加 CPU 運(yùn)算的操作,會(huì)對(duì) CPU 產(chǎn)生明顯的壓力。

這時(shí)可以考慮 SQL 優(yōu)化,創(chuàng)建適當(dāng)?shù)乃饕?,也可以把一些?jì)算量大的SQL邏輯放到應(yīng)用中處理。

單表數(shù)據(jù)量太大:由于單張表數(shù)據(jù)量過(guò)大,比如超過(guò)一億,查詢時(shí)遍歷樹(shù)的層次太深或者掃描的行太多,SQL 效率會(huì)很低,也會(huì)非常消耗 CPU。這時(shí)可以根據(jù)業(yè)務(wù)場(chǎng)景水平分表。

分庫(kù)分表方案

分庫(kù)分表主要有兩種方案:

①利用 MyCat,KingShard 這種代理中間件分庫(kù)分表。

好處是和業(yè)務(wù)代碼耦合度很低,只需做一些配置即可,接入成本低。缺點(diǎn)是這種代理中間件需要單獨(dú)部署,所以從調(diào)用連路上又多了一層。

而且分庫(kù)分表邏輯完全由代理中間件管理,對(duì)于程序員完全是黑盒,一旦代理本身出問(wèn)題(比如出錯(cuò)或宕機(jī)),會(huì)導(dǎo)致無(wú)法查詢和存儲(chǔ)相關(guān)業(yè)務(wù)數(shù)據(jù),引發(fā)災(zāi)難性的后果。

如果不熟悉代理中間件源碼,排查問(wèn)題會(huì)非常困難。曾經(jīng)有公司使用 MyCat,線上發(fā)生故障后,被迫修改方案,三天三夜才恢復(fù)系統(tǒng)。CTO 也廢了!

②利用 Sharding-Jdbc,TSharding 等以 Jar 包形式呈現(xiàn)的輕量級(jí)組件分庫(kù)分表。

缺點(diǎn)是,會(huì)有一定的代碼開(kāi)發(fā)工作量,對(duì)業(yè)務(wù)有一些侵入性。好處是對(duì)程序員透明,程序員對(duì)分庫(kù)分表邏輯的把控會(huì)更強(qiáng),一旦發(fā)生故障,排查問(wèn)題會(huì)比較容易。

穩(wěn)妥起見(jiàn),我們選用了第二種方案,使用更輕量級(jí)的 Sharding-Jdbc。

做系統(tǒng)重構(gòu)前,我們首先要確定重構(gòu)的目標(biāo),其次要對(duì)未來(lái)業(yè)務(wù)的發(fā)展有一個(gè)預(yù)期。這個(gè)可以找相關(guān)業(yè)務(wù)負(fù)責(zé)人了解,根據(jù)目標(biāo)和業(yè)務(wù)預(yù)期來(lái)確定重構(gòu)方案。

例如,我們希望經(jīng)過(guò)本次重構(gòu),系統(tǒng)能支撐兩年,兩年內(nèi)不再大改。業(yè)務(wù)方預(yù)期兩年內(nèi)日單量達(dá)到 1000 萬(wàn),相當(dāng)于兩年后日訂單量要翻 10 倍。

根據(jù)上面的數(shù)據(jù),我們分成了 16 個(gè)數(shù)據(jù)庫(kù)。按日訂單量 1000 萬(wàn)來(lái)算,每個(gè)庫(kù)平均的日訂單量就是 62.5 萬(wàn)(1000 萬(wàn)/16),每秒最高訂單量理論上在 1250 左右( 2000*(62.5/100) )。

這樣數(shù)據(jù)庫(kù)的壓力基本上是可控的,而且基本不會(huì)浪費(fèi)服務(wù)器資源。

每個(gè)庫(kù)分了 16 張表,即便按照每天 1000 萬(wàn)的訂單量,兩年總單量是 73 億(73 億=1000 萬(wàn)*365*2),每個(gè)庫(kù)的數(shù)據(jù)量平均是 4.56 億(4.56 億=73 億/16),每張表的數(shù)據(jù)量平均是 2850 萬(wàn)(2850 萬(wàn)=4.56 億/16)。

可以看到未來(lái)兩到三年每張表的數(shù)據(jù)量也不算多,完全在可控范圍。

分庫(kù)分表主要是為了用戶端下單和查詢使用,按 user_id 的查詢頻率最高,其次是 order_id。

所以我們選擇 user_id 做為 sharding column,按 user_id 做 hash,將相同用戶的訂單數(shù)據(jù)存儲(chǔ)到同一個(gè)數(shù)據(jù)庫(kù)的同一張表中。

這樣用戶在網(wǎng)頁(yè)或者 App 上查詢訂單時(shí)只需要路由到一張表就可以獲取用戶的所有訂單了,這樣就保證了查詢性能。

另外我們?cè)谟唵?ID(order_id)里摻雜了用戶 ID(user_id)信息。

簡(jiǎn)單來(lái)說(shuō),order_id 的設(shè)計(jì)思路就是,將 order_id 分為前后兩部分,前面的部分是 user_id,后面的部分是具體的訂單編號(hào),兩部分組合在一起就構(gòu)成了 order_id。

這樣我們很容易從 order_id 解析出 user_id。通過(guò) order_id 查詢訂單時(shí),先從 order_id 中解析出 user_id,然后就可以根據(jù) user_id 路由到具體的庫(kù)表了。

另外,數(shù)據(jù)庫(kù)分成 16 個(gè),每個(gè)庫(kù)分 16 張表還有一個(gè)好處。16 是 2 的 N 次冪,所以 hash 值對(duì) 16 取模的結(jié)果與 hash 值和 16 按位“與運(yùn)算”的結(jié)果是一樣的。

我們知道位運(yùn)算基于二進(jìn)制,跨過(guò)各種編譯和轉(zhuǎn)化直接到最底層的機(jī)器語(yǔ)言,效率自然遠(yuǎn)高于取模運(yùn)算。

有讀者可能會(huì)問(wèn),查詢直接查數(shù)據(jù)庫(kù),會(huì)不會(huì)有性能問(wèn)題?是的。所以我們?cè)谏蠈蛹恿?Redis,Redis 做了分片集群,用于存儲(chǔ)活躍用戶最近 50 條訂單。

這樣一來(lái),只有少部分在 Redis 查不到訂單的用戶請(qǐng)求才會(huì)到數(shù)據(jù)庫(kù)查詢訂單,這樣就減小了數(shù)據(jù)庫(kù)查詢壓力,而且每個(gè)分庫(kù)還有兩個(gè)從庫(kù),查詢操作只走從庫(kù),進(jìn)一步分?jǐn)偭嗣總€(gè)分庫(kù)的壓力。

有讀者可能還會(huì)問(wèn),為什么沒(méi)采用一致性 hash 方案?用戶查詢最近 50 條之前的訂單怎么辦?請(qǐng)繼續(xù)往后看!

管理端技術(shù)方案

分庫(kù)分表后,不同用戶的訂單數(shù)據(jù)散落在不同的庫(kù)和表中,如果需要根據(jù)用戶 ID 之外的其他條件查詢訂單。

例如,運(yùn)營(yíng)同學(xué)想從后臺(tái)查出某天 iphone7 的訂單量,就需要從所有數(shù)據(jù)庫(kù)的表中查出數(shù)據(jù)然后在聚合到一起。

這樣代碼實(shí)現(xiàn)非常復(fù)雜,而且查詢性能也會(huì)很差。所以我們需要一種更好的方案來(lái)解決這個(gè)問(wèn)題。

我們采用了 ES(ElasticSearch)+HBase 組合的方案,將索引與數(shù)據(jù)存儲(chǔ)隔離。

可能參與條件檢索的字段都會(huì)在 ES 中建一份索引,例如商家,商品名稱,訂單日期等。所有訂單數(shù)據(jù)全量保存到 HBase 中。

我們知道 HBase 支持海量存儲(chǔ),而且根據(jù) Rowkey 查詢速度超快。而 ES 的多條件檢索能力非常強(qiáng)大??梢哉f(shuō),這個(gè)方案把 ES 和 HBase 的優(yōu)點(diǎn)發(fā)揮地淋漓盡致。

看一下該方案的查詢過(guò)程:先根據(jù)輸入條件去 ES 相應(yīng)的索引上查詢符合條件的 Rowkey 值,然后用 Rowkey 值去 HBase 查詢,后面這一步查詢速度極快,查詢時(shí)間幾乎可以忽略不計(jì)。

如下圖:

 

該方案,解決了管理端通過(guò)各種字段條件查詢訂單的業(yè)務(wù)需求,同時(shí)也解決了商家端按商家 ID 和其他條件查詢訂單的需求。如果用戶希望查詢最近 50 條訂單之前的歷史訂單,也同樣可以用這個(gè)方案。

每天產(chǎn)生數(shù)百萬(wàn)的訂單數(shù)據(jù),如果管理后臺(tái)想查到最新的訂單數(shù)據(jù),就需要頻繁更新 ES 索引。在海量訂單數(shù)據(jù)的場(chǎng)景下,索引頻繁更新會(huì)不會(huì)對(duì) ES 產(chǎn)生太大壓力?

ES 索引有一個(gè) segment(片段)的概念。ES 把每個(gè)索引分成若干個(gè)較小的 segment 片段。

每一個(gè) segement 都是一個(gè)完整的倒排索引,在搜索查詢時(shí)會(huì)依次掃描相關(guān)索引的所有 segment。

每次 refresh(刷新索引) 的時(shí)候,都會(huì)生成一個(gè)新的 segement,因此 segment 實(shí)際上記錄了索引的一組變化值。由于每次索引刷新只涉及個(gè)別 segement 片段,更新索引的成本就很低了。

所以,即便默認(rèn)的索引刷新(refresh)間隔只有 1 秒鐘,ES 也能從容應(yīng)對(duì)。

不過(guò),由于每個(gè) segement 的存儲(chǔ)和掃描都需要占用一定的內(nèi)存和 CPU 等資源,因此 ES 后臺(tái)進(jìn)程需要不斷的進(jìn)行 segement 合并來(lái)減少 segement 的數(shù)量,從而提升掃描效率以及降低資源消耗。

MySQL 中的訂單數(shù)據(jù)需要實(shí)時(shí)同步到 Hbase 和 ES 中,那么同步方案是什么?

我們利用 Canal 實(shí)時(shí)獲取 MySQL 庫(kù)表中的增量訂單數(shù)據(jù),然后把訂單數(shù)據(jù)推到消息隊(duì)列 RocketMQ 中,消費(fèi)端獲取消息后把數(shù)據(jù)寫(xiě)到 Hbase,并在 ES 更新索引。

 

上面是 Canal 的原理圖:

  • Canal 模擬 mysql slave 的交互協(xié)議,把自己偽裝成 mysql 的從庫(kù)。
  • 向 mysql master 發(fā)送 dump 協(xié)議。
  • mysql master 收到 dump 協(xié)議,發(fā)送 binary log 給 slave(Canal)。
  • Canal 解析 binary log 字節(jié)流對(duì)象,根據(jù)應(yīng)用場(chǎng)景對(duì) binary log 字節(jié)流做相應(yīng)的處理。

為了保證數(shù)據(jù)一致性,不丟失數(shù)據(jù)。我們使用了 RocketMQ 的事務(wù)型消息,保證消息一定能成功發(fā)送。另外,在 Hbase 和 ES 都操作成功后才做 ack 操作,保證消息正常消費(fèi)。

不停機(jī)數(shù)據(jù)遷移

在互聯(lián)網(wǎng)行業(yè),很多系統(tǒng)的訪問(wèn)量很高,即便在凌晨?jī)扇c(diǎn)也有一定的訪問(wèn)量。由于數(shù)據(jù)遷移導(dǎo)致服務(wù)暫停,是很難被業(yè)務(wù)方接受的!下面就聊一下在用戶無(wú)感知的前提下,我們的不停機(jī)數(shù)據(jù)遷移方案!

數(shù)據(jù)遷移過(guò)程我們要注意哪些關(guān)鍵點(diǎn)呢?

  • 保證遷移后數(shù)據(jù)準(zhǔn)確不丟失,即每條記錄準(zhǔn)確而且不丟失記錄。
  • 不影響用戶體驗(yàn),尤其是訪問(wèn)量高的 C 端業(yè)務(wù)需要不停機(jī)平滑遷移。
  • 保證遷移后的系統(tǒng)性能和穩(wěn)定性。

常用的數(shù)據(jù)遷移方案主要包括:掛從庫(kù),雙寫(xiě)以及利用數(shù)據(jù)同步工具三種方案,下面分別做一下介紹。

掛從庫(kù)

在主庫(kù)上建一個(gè)從庫(kù)。從庫(kù)數(shù)據(jù)同步完成后,將從庫(kù)升級(jí)成主庫(kù)(新庫(kù)),再將流量切到新庫(kù)。

這種方式適合表結(jié)構(gòu)不變,而且空閑時(shí)間段流量很低,允許停機(jī)遷移的場(chǎng)景。一般發(fā)生在平臺(tái)遷移的場(chǎng)景,如從機(jī)房遷移到云平臺(tái),從一個(gè)云平臺(tái)遷移到另一個(gè)云平臺(tái)。

大部分中小型互聯(lián)網(wǎng)系統(tǒng),空閑時(shí)段訪問(wèn)量很低。在空閑時(shí)段,幾分鐘的停機(jī)時(shí)間,對(duì)用戶影響很小,業(yè)務(wù)方是可以接受的。

所以我們可以采用停機(jī)遷移的方案,步驟如下:

  • 新建從庫(kù)(新數(shù)據(jù)庫(kù)),數(shù)據(jù)開(kāi)始從主庫(kù)向從庫(kù)同步。
  • 數(shù)據(jù)同步完成后,找一個(gè)空閑時(shí)間段。為了保證主從數(shù)據(jù)庫(kù)數(shù)據(jù)一致,需要先停掉服務(wù),然后再把從庫(kù)升級(jí)為主庫(kù)。
  • 如果訪問(wèn)數(shù)據(jù)庫(kù)用的是域名,直接解析域名到新數(shù)據(jù)庫(kù)(從庫(kù)升級(jí)成的主庫(kù)),如果訪問(wèn)數(shù)據(jù)庫(kù)用的是 IP,將 IP 改成新數(shù)據(jù)庫(kù) IP。

最后啟動(dòng)服務(wù),整個(gè)遷移過(guò)程完成。

這種遷移方案的優(yōu)勢(shì)是遷移成本低,遷移周期短。缺點(diǎn)是,切換數(shù)據(jù)庫(kù)過(guò)程需要停止服務(wù)。

我們的并發(fā)量比較高,而且又做了分庫(kù)分表,表結(jié)構(gòu)也變了,所以不能采取這種方案!

雙寫(xiě)

老庫(kù)和新庫(kù)同時(shí)寫(xiě)入,然后將老數(shù)據(jù)批量遷移到新庫(kù),最后流量切換到新庫(kù)并關(guān)閉老庫(kù)讀寫(xiě)。

這種方式適合數(shù)據(jù)結(jié)構(gòu)發(fā)生變化,不允許停機(jī)遷移的場(chǎng)景。一般發(fā)生在系統(tǒng)重構(gòu)時(shí),表結(jié)構(gòu)發(fā)生變化,如表結(jié)構(gòu)改變或者分庫(kù)分表等場(chǎng)景。

有些大型互聯(lián)網(wǎng)系統(tǒng),平常并發(fā)量很高,即便是空閑時(shí)段也有相當(dāng)?shù)脑L問(wèn)量。幾分鐘的停機(jī)時(shí)間,對(duì)用戶也會(huì)有明顯的影響,甚至導(dǎo)致一定的用戶流失,這對(duì)業(yè)務(wù)方來(lái)說(shuō)是無(wú)法接受的。

所以我們需要考慮一種用戶無(wú)感知的不停機(jī)遷移方案,聊一下我們的具體遷移方案,步驟如下:

①代碼準(zhǔn)備。在服務(wù)層對(duì)訂單表進(jìn)行增刪改的地方,要同時(shí)操作新庫(kù)(分庫(kù)分表后的數(shù)據(jù)庫(kù)表)和老庫(kù),需要修改相應(yīng)的代碼(同時(shí)寫(xiě)新庫(kù)和老庫(kù))。

準(zhǔn)備遷移程序腳本,用于做老數(shù)據(jù)遷移。準(zhǔn)備校驗(yàn)程序腳本,用于校驗(yàn)新庫(kù)和老庫(kù)的數(shù)據(jù)是否一致。

②開(kāi)啟雙寫(xiě),老庫(kù)和新庫(kù)同時(shí)寫(xiě)入。

注意:

  • 任何對(duì)數(shù)據(jù)庫(kù)的增刪改都要雙寫(xiě);對(duì)于更新操作,如果新庫(kù)沒(méi)有相關(guān)記錄,需要先從老庫(kù)查出記錄,將更新后的記錄寫(xiě)入新庫(kù)。
  • 為了保證寫(xiě)入性能,老庫(kù)寫(xiě)完后,可以采用消息隊(duì)列異步寫(xiě)入新庫(kù)。

③利用腳本程序,將某一時(shí)間戳之前的老數(shù)據(jù)遷移到新庫(kù)。

注意:

  • 時(shí)間戳一定要選擇開(kāi)啟雙寫(xiě)后的時(shí)間點(diǎn),比如開(kāi)啟雙寫(xiě)后 10 分鐘的時(shí)間點(diǎn),避免部分老數(shù)據(jù)被漏掉。
  • 遷移過(guò)程遇到記錄沖突直接忽略,因?yàn)榈?2 步的更新操作,已經(jīng)把記錄拉到了新庫(kù)。
  • 遷移過(guò)程一定要記錄日志,尤其是錯(cuò)誤日志,如果有雙寫(xiě)失敗的情況,我們可以通過(guò)日志恢復(fù)數(shù)據(jù),以此來(lái)保證新老庫(kù)的數(shù)據(jù)一致。

④第 3 步完成后,我們還需要通過(guò)腳本程序檢驗(yàn)數(shù)據(jù),看新庫(kù)數(shù)據(jù)是否準(zhǔn)確以及有沒(méi)有漏掉的數(shù)據(jù)。

⑤數(shù)據(jù)校驗(yàn)沒(méi)問(wèn)題后,開(kāi)啟雙讀,起初給新庫(kù)放少部分流量,新庫(kù)和老庫(kù)同時(shí)讀取。

由于延時(shí)問(wèn)題,新庫(kù)和老庫(kù)可能會(huì)有少量數(shù)據(jù)記錄不一致的情況,所以新庫(kù)讀不到時(shí)需要再讀一遍老庫(kù)。

⑥然后再逐步將讀流量切到新庫(kù),相當(dāng)于灰度上線的過(guò)程。遇到問(wèn)題可以及時(shí)把流量切回老庫(kù)。

⑦讀流量全部切到新庫(kù)后,關(guān)閉老庫(kù)寫(xiě)入(可以在代碼里加上熱配置開(kāi)關(guān)),只寫(xiě)新庫(kù)。

⑧遷移完成,后續(xù)可以去掉雙寫(xiě)雙讀相關(guān)無(wú)用代碼。


利用數(shù)據(jù)同步工具 

我們可以看到上面雙寫(xiě)的方案比較麻煩,很多數(shù)據(jù)庫(kù)寫(xiě)入的地方都需要修改代碼。有沒(méi)有更好的方案呢?

我們還可以利用 Canal,DataBus 等工具做數(shù)據(jù)同步。以阿里開(kāi)源的 Canal 為例。

利用同步工具,就不需要開(kāi)啟雙寫(xiě)了,服務(wù)層也不需要編寫(xiě)雙寫(xiě)的代碼,直接用 Canal 做增量數(shù)據(jù)同步即可。

相應(yīng)的步驟就變成了:

①代碼準(zhǔn)備。準(zhǔn)備 Canal 代碼,解析 binary log 字節(jié)流對(duì)象,并把解析好的訂單數(shù)據(jù)寫(xiě)入新庫(kù)。

準(zhǔn)備遷移程序腳本,用于做老數(shù)據(jù)遷移。準(zhǔn)備校驗(yàn)程序腳本,用于校驗(yàn)新庫(kù)和老庫(kù)的數(shù)據(jù)是否一致。

②運(yùn)行 Canal 代碼,開(kāi)始增量數(shù)據(jù)(線上產(chǎn)生的新數(shù)據(jù))從老庫(kù)到新庫(kù)的同步。

③利用腳本程序,將某一時(shí)間戳之前的老數(shù)據(jù)遷移到新庫(kù)。注意:時(shí)間戳一定要選擇開(kāi)始運(yùn)行 Canal 程序后的時(shí)間點(diǎn)(比如運(yùn)行 Canal 代碼后 10 分鐘的時(shí)間點(diǎn)),避免部分老數(shù)據(jù)被漏掉。

遷移過(guò)程一定要記錄日志,尤其是錯(cuò)誤日志,如果有些記錄寫(xiě)入失敗,我們可以通過(guò)日志恢復(fù)數(shù)據(jù),以此來(lái)保證新老庫(kù)的數(shù)據(jù)一致。

④第 3 步完成后,我們還需要通過(guò)腳本程序檢驗(yàn)數(shù)據(jù),看新庫(kù)數(shù)據(jù)是否準(zhǔn)確以及有沒(méi)有漏掉的數(shù)據(jù)。

⑤數(shù)據(jù)校驗(yàn)沒(méi)問(wèn)題后,開(kāi)啟雙讀,起初給新庫(kù)放少部分流量,新庫(kù)和老庫(kù)同時(shí)讀取。

由于延時(shí)問(wèn)題,新庫(kù)和老庫(kù)可能會(huì)有少量數(shù)據(jù)記錄不一致的情況,所以新庫(kù)讀不到時(shí)需要再讀一遍老庫(kù)。

逐步將讀流量切到新庫(kù),相當(dāng)于灰度上線的過(guò)程。遇到問(wèn)題可以及時(shí)把流量切回老庫(kù)。

⑥讀流量全部切到新庫(kù)后,將寫(xiě)入流量切到新庫(kù)(可以在代碼里加上熱配置開(kāi)關(guān):由于切換過(guò)程 Canal 程序還在運(yùn)行,仍然能夠獲取老庫(kù)的數(shù)據(jù)變化并同步到新庫(kù),所以切換過(guò)程不會(huì)導(dǎo)致部分老庫(kù)數(shù)據(jù)無(wú)法同步新庫(kù)的情況)。

⑦關(guān)閉 Canal 程序。

⑧遷移完成。

擴(kuò)容縮容方案

需要對(duì)數(shù)據(jù)重新 hash 取模,再將原來(lái)多個(gè)庫(kù)表的數(shù)據(jù)寫(xiě)入擴(kuò)容后的庫(kù)表中。整體擴(kuò)容方案和上面的不停機(jī)遷移方案基本一致。采用雙寫(xiě)或者 Canal 等數(shù)據(jù)同步方案都可以。

更好的分庫(kù)分表方案

通過(guò)前面的描述,不難看出我們的分庫(kù)分表方案有一些缺陷,比如采用 hash 取模的方式會(huì)產(chǎn)生數(shù)據(jù)分布不均勻的情況,擴(kuò)容縮容也非常麻煩。

這些問(wèn)題可以用一致性 hash 方案解決?;谔摂M節(jié)點(diǎn)設(shè)計(jì)原理的一致性 hash 可以讓數(shù)據(jù)分布更均勻。

而且一致性 hash 采用環(huán)形設(shè)計(jì)思路,在增減節(jié)點(diǎn)時(shí),使得數(shù)據(jù)遷移的成本會(huì)更低,只需要遷移臨近節(jié)點(diǎn)的數(shù)據(jù)。

不過(guò)需要擴(kuò)容時(shí)基本上要成倍擴(kuò)容,在 hash 環(huán)上每個(gè)節(jié)點(diǎn)間隙都增加新的節(jié)點(diǎn),這樣才能分?jǐn)偹性泄?jié)點(diǎn)的訪問(wèn)和存儲(chǔ)壓力。

由于篇幅原因,這里不詳細(xì)介紹一致性 hash 了,網(wǎng)上有很多相關(guān)資料,大家有興趣可以仔細(xì)研究一下。

降級(jí)方案

在大促期間訂單服務(wù)壓力過(guò)大時(shí),可以將同步調(diào)用改為異步消息隊(duì)列方式,來(lái)減小訂單服務(wù)壓力并提高吞吐量。

大促時(shí)某些時(shí)間點(diǎn)瞬間生成訂單量很高。我們采取異步批量寫(xiě)數(shù)據(jù)庫(kù)的方式,來(lái)減少數(shù)據(jù)庫(kù)訪問(wèn)頻次,進(jìn)而降低數(shù)據(jù)庫(kù)的寫(xiě)入壓力。

詳細(xì)步驟:后端服務(wù)接到下單請(qǐng)求,直接放進(jìn)消息隊(duì)列,訂單服務(wù)取出消息后,先將訂單信息寫(xiě)入 Redis,每隔 100ms 或者積攢 10 條訂單,批量寫(xiě)入數(shù)據(jù)庫(kù)一次。

前端頁(yè)面下單后定時(shí)向后端拉取訂單信息,獲取到訂單信息后跳轉(zhuǎn)到支付頁(yè)面。

用這種異步批量寫(xiě)入數(shù)據(jù)庫(kù)的方式大幅減少了數(shù)據(jù)庫(kù)寫(xiě)入頻次,從而明顯降低了訂單數(shù)據(jù)庫(kù)寫(xiě)入壓力。

不過(guò),因?yàn)橛唵问钱惒綄?xiě)入數(shù)據(jù)庫(kù)的,就會(huì)存在數(shù)據(jù)庫(kù)訂單和相應(yīng)庫(kù)存數(shù)據(jù)暫時(shí)不一致的情況,以及用戶下單后不能及時(shí)查到訂單的情況。

因?yàn)楫吘故墙导?jí)方案,可以適當(dāng)降低用戶體驗(yàn),我們保證數(shù)據(jù)最終一致即可。

根據(jù)系統(tǒng)壓力情況,可以在大促開(kāi)始時(shí)開(kāi)啟異步批量寫(xiě)的降級(jí)開(kāi)關(guān),大促結(jié)束后再關(guān)閉降級(jí)開(kāi)關(guān)。

流程如下圖:

 

作者:二馬讀書(shū)

編輯:陶家龍

出處:轉(zhuǎn)載自公眾號(hào)二馬讀書(shū)(ID:ermadushu)

 

責(zé)任編輯:武曉燕 來(lái)源: 二馬讀書(shū)
相關(guān)推薦

2020-10-15 14:05:30

PostgreSQL升級(jí)開(kāi)發(fā)

2021-10-25 09:16:27

MySQL分庫(kù)分表

2020-12-11 10:40:13

PostgreSQL數(shù)據(jù)庫(kù)GitLab

2019-11-12 09:54:20

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

2019-04-18 14:06:35

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

2021-10-21 06:39:41

限流熔斷系統(tǒng)

2021-07-27 06:37:03

HTTP協(xié)議消息

2024-07-26 00:16:11

2024-05-21 08:40:21

分庫(kù)分表源碼

2022-07-03 10:21:19

MYSQL存儲(chǔ)緩沖池

2020-07-30 17:59:34

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

2021-05-08 18:50:57

分庫(kù)分表中間件

2020-09-27 08:00:49

分庫(kù)分表

2019-01-29 15:25:11

阿里巴巴數(shù)據(jù)庫(kù)分庫(kù)分表

2017-06-12 11:09:56

計(jì)數(shù)架構(gòu)數(shù)據(jù)庫(kù)

2024-08-13 17:09:00

架構(gòu)分庫(kù)分表開(kāi)發(fā)

2022-06-22 07:32:53

Sharding分庫(kù)數(shù)據(jù)源

2022-06-30 07:34:46

分庫(kù)分表外賣訂單系統(tǒng)

2021-08-31 20:21:11

VitessMySQL分庫(kù)

2023-08-11 08:59:49

分庫(kù)分表數(shù)據(jù)數(shù)據(jù)庫(kù)
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 久久不卡 | 久草网址 | 色久影院 | 在线视频中文字幕 | 久久久久久久久国产 | 亚洲视频在线观看 | 久久久91精品国产一区二区三区 | 国产精品日日夜夜 | 97国产爽爽爽久久久 | 在线看亚洲 | 日本一区二区不卡视频 | 国产在线网址 | 欧美一区二区视频 | 欧美成人综合 | 日韩av在线一区二区 | 五十女人一级毛片 | 午夜影院操 | h视频在线免费 | www.久久99| 中文字幕在线视频一区二区三区 | 在线一区观看 | 天堂免费看片 | 亚洲欧美日本国产 | 亚洲国产精品一区二区三区 | 精品国产视频 | 久久国产高清 | 国产精品美女久久久久aⅴ国产馆 | 中文字幕一区二区三区日韩精品 | 午夜精品一区 | 一区二区欧美在线 | 亚洲一二三区不卡 | 成人国产在线视频 | 欧美日韩一区在线 | 免费看国产精品视频 | 欧美一区二区三区久久精品视 | 国产一区二区三区在线 | 欧美日日日日bbbbb视频 | 久草热8精品视频在线观看 午夜伦4480yy私人影院 | 欧美日韩精品免费 | 成人免费精品 | 黄网免费看 |