關(guān)于讀寫(xiě)分離

讀寫(xiě)分離

什么是讀寫(xiě)分離匾委?

見(jiàn)名思意,根據(jù)讀寫(xiě)分離的名字诅炉,我們就可以知道:讀寫(xiě)分離主要是為了將對(duì)數(shù)據(jù)庫(kù)的讀寫(xiě)操作分散到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn)上蜡歹。 這樣的話,就能夠小幅提升寫(xiě)性能涕烧,大幅提升讀性能月而。

一般情況下,我們都會(huì)選擇一主多從议纯,也就是一臺(tái)主數(shù)據(jù)庫(kù)負(fù)責(zé)寫(xiě)父款,其他的從數(shù)據(jù)庫(kù)負(fù)責(zé)讀。主庫(kù)和從庫(kù)之間會(huì)進(jìn)行數(shù)據(jù)同步瞻凤,以保證從庫(kù)中數(shù)據(jù)的準(zhǔn)確性铛漓。這樣的架構(gòu)實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,并且也符合系統(tǒng)的寫(xiě)少讀多的特點(diǎn)鲫构。

如何實(shí)現(xiàn)讀寫(xiě)分離浓恶?

不論是使用哪一種讀寫(xiě)分離具體的實(shí)現(xiàn)方案,想要實(shí)現(xiàn)讀寫(xiě)分離一般包含如下幾步:

  1. 部署多臺(tái)數(shù)據(jù)庫(kù)结笨,選擇其中的一臺(tái)作為主數(shù)據(jù)庫(kù)包晰,其他的一臺(tái)或者多臺(tái)作為從數(shù)據(jù)庫(kù)。
  2. 保證主數(shù)據(jù)庫(kù)和從數(shù)據(jù)庫(kù)之間的數(shù)據(jù)是實(shí)時(shí)同步的炕吸,這個(gè)過(guò)程也就是我們常說(shuō)的主從復(fù)制伐憾。
  3. 系統(tǒng)將寫(xiě)請(qǐng)求交給主數(shù)據(jù)庫(kù)處理,讀請(qǐng)求交給從數(shù)據(jù)庫(kù)處理赫模。

落實(shí)到項(xiàng)目本身的話树肃,常用的方式有兩種:

1. 代理方式

我們可以在應(yīng)用和數(shù)據(jù)中間加了一個(gè)代理層。應(yīng)用程序所有的數(shù)據(jù)請(qǐng)求都交給代理層處理瀑罗,代理層負(fù)責(zé)分離讀寫(xiě)請(qǐng)求胸嘴,將它們路由到對(duì)應(yīng)的數(shù)據(jù)庫(kù)中。

提供類(lèi)似功能的中間件有 MySQL Router(官方斩祭, MySQL Proxy 的替代方案)劣像、Atlas(基于 MySQL Proxy)、MaxScale摧玫、MyCat耳奕。

關(guān)于 MySQL Router 多提一點(diǎn):在 MySQL 8.2 的版本中,MySQL Router 能自動(dòng)分辨對(duì)數(shù)據(jù)庫(kù)讀寫(xiě)/操作并把這些操作路由到正確的實(shí)例上。這是一項(xiàng)有價(jià)值的功能屋群,可以?xún)?yōu)化數(shù)據(jù)庫(kù)性能和可擴(kuò)展性闸婴,而無(wú)需在應(yīng)用程序中進(jìn)行任何更改。具體介紹可以參考官方博客:MySQL 8.2 – transparent read/write splitting芍躏。

2. 組件方式

在這種方式中邪乍,我們可以通過(guò)引入第三方組件來(lái)幫助我們讀寫(xiě)請(qǐng)求。

這也是我比較推薦的一種方式纸肉。這種方式目前在各種互聯(lián)網(wǎng)公司中用的最多的溺欧,相關(guān)的實(shí)際的案例也非常多喊熟。如果你要采用這種方式的話柏肪,推薦使用 sharding-jdbc ,直接引入 jar 包即可使用芥牌,非常方便烦味。同時(shí),也節(jié)省了很多運(yùn)維的成本壁拉。

你可以在 shardingsphere 官方找到 sharding-jdbc 關(guān)于讀寫(xiě)分離的操作谬俄。

主從復(fù)制原理是什么?

MySQL binlog(binary log 即二進(jìn)制日志文件) 主要記錄了 MySQL 數(shù)據(jù)庫(kù)中數(shù)據(jù)的所有變化(數(shù)據(jù)庫(kù)執(zhí)行的所有 DDL 和 DML 語(yǔ)句)弃理。因此溃论,我們根據(jù)主庫(kù)的 MySQL binlog 日志就能夠?qū)⒅鲙?kù)的數(shù)據(jù)同步到從庫(kù)中。

更具體和詳細(xì)的過(guò)程是這個(gè)樣子的(圖片來(lái)自于:《MySQL Master-Slave Replication on the Same Machine》):

  1. 主庫(kù)將數(shù)據(jù)庫(kù)中數(shù)據(jù)的變化寫(xiě)入到 binlog
  2. 從庫(kù)連接主庫(kù)
  3. 從庫(kù)會(huì)創(chuàng)建一個(gè) I/O 線程向主庫(kù)請(qǐng)求更新的 binlog
  4. 主庫(kù)會(huì)創(chuàng)建一個(gè) binlog dump 線程來(lái)發(fā)送 binlog 痘昌,從庫(kù)中的 I/O 線程負(fù)責(zé)接收
  5. 從庫(kù)的 I/O 線程將接收的 binlog 寫(xiě)入到 relay log 中钥勋。
  6. 從庫(kù)的 SQL 線程讀取 relay log 同步數(shù)據(jù)本地(也就是再執(zhí)行一遍 SQL )。

怎么樣辆苔?看了我對(duì)主從復(fù)制這個(gè)過(guò)程的講解算灸,你應(yīng)該搞明白了吧!

你一般看到 binlog 就要想到主從復(fù)制。當(dāng)然驻啤,除了主從復(fù)制之外菲驴,binlog 還能幫助我們實(shí)現(xiàn)數(shù)據(jù)恢復(fù)。

?? 拓展一下:

不知道大家有沒(méi)有使用過(guò)阿里開(kāi)源的一個(gè)叫做 canal 的工具骑冗。這個(gè)工具可以幫助我們實(shí)現(xiàn) MySQL 和其他數(shù)據(jù)源比如 Elasticsearch 或者另外一臺(tái) MySQL 數(shù)據(jù)庫(kù)之間的數(shù)據(jù)同步赊瞬。很顯然,這個(gè)工具的底層原理肯定也是依賴(lài) binlog贼涩。canal 的原理就是模擬 MySQL 主從復(fù)制的過(guò)程森逮,解析 binlog 將數(shù)據(jù)同步到其他的數(shù)據(jù)源。

另外磁携,像咱們常用的分布式緩存組件 Redis 也是通過(guò)主從復(fù)制實(shí)現(xiàn)的讀寫(xiě)分離褒侧。

?? 簡(jiǎn)單總結(jié)一下:

MySQL 主從復(fù)制是依賴(lài)于 binlog 。另外,常見(jiàn)的一些同步 MySQL 數(shù)據(jù)到其他數(shù)據(jù)源的工具(比如 canal)的底層一般也是依賴(lài) binlog 闷供。

如何避免主從延遲烟央?

讀寫(xiě)分離對(duì)于提升數(shù)據(jù)庫(kù)的并發(fā)非常有效,但是歪脏,同時(shí)也會(huì)引來(lái)一個(gè)問(wèn)題:主庫(kù)和從庫(kù)的數(shù)據(jù)存在延遲疑俭,比如你寫(xiě)完主庫(kù)之后,主庫(kù)的數(shù)據(jù)同步到從庫(kù)是需要時(shí)間的婿失,這個(gè)時(shí)間差就導(dǎo)致了主庫(kù)和從庫(kù)的數(shù)據(jù)不一致性問(wèn)題钞艇。這也就是我們經(jīng)常說(shuō)的 主從同步延遲

如果我們的業(yè)務(wù)場(chǎng)景無(wú)法容忍主從同步延遲的話豪硅,應(yīng)該如何避免呢(注意:我這里說(shuō)的是避免而不是減少延遲)哩照?

這里提供兩種我知道的方案(能力有限,歡迎補(bǔ)充)懒浮,你可以根據(jù)自己的業(yè)務(wù)場(chǎng)景參考一下飘弧。

強(qiáng)制將讀請(qǐng)求路由到主庫(kù)處理

既然你從庫(kù)的數(shù)據(jù)過(guò)期了,那我就直接從主庫(kù)讀取嘛砚著!這種方案雖然會(huì)增加主庫(kù)的壓力次伶,但是,實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單稽穆,也是我了解到的使用最多的一種方式冠王。

比如 Sharding-JDBC 就是采用的這種方案。通過(guò)使用 Sharding-JDBC 的 HintManager 分片鍵值管理器舌镶,我們可以強(qiáng)制使用主庫(kù)柱彻。

延遲讀取

還有一些朋友肯定會(huì)想既然主從同步存在延遲,那我就在延遲之后讀取啊乎折,比如主從同步延遲 0.5s,那我就 1s 之后再讀取數(shù)據(jù)绒疗。這樣多方便啊骂澄!方便是方便吓蘑,但是也很扯淡。

不過(guò)坟冲,如果你是這樣設(shè)計(jì)業(yè)務(wù)流程就會(huì)好很多:對(duì)于一些對(duì)數(shù)據(jù)比較敏感的場(chǎng)景磨镶,你可以在完成寫(xiě)請(qǐng)求之后沽翔,避免立即進(jìn)行請(qǐng)求操作悔据。比如你支付成功之后,跳轉(zhuǎn)到一個(gè)支付成功的頁(yè)面勃教,當(dāng)你點(diǎn)擊返回之后才返回自己的賬戶(hù)私痹。

總結(jié)

關(guān)于如何避免主從延遲脐嫂,我們這里介紹了兩種方案统刮。實(shí)際上,延遲讀取這種方案沒(méi)辦法完全避免主從延遲账千,只能說(shuō)可以減少出現(xiàn)延遲的概率而已侥蒙,實(shí)際項(xiàng)目中一般不會(huì)使用。

總的來(lái)說(shuō)匀奏,要想不出現(xiàn)延遲問(wèn)題鞭衩,一般還是要強(qiáng)制將那些必須獲取最新數(shù)據(jù)的讀請(qǐng)求都交給主庫(kù)處理。如果你的項(xiàng)目的大部分業(yè)務(wù)場(chǎng)景對(duì)數(shù)據(jù)準(zhǔn)確性要求不是那么高的話娃善,這種方案還是可以選擇的论衍。

什么情況下會(huì)出現(xiàn)主從延遲?如何盡量減少延遲聚磺?

我們?cè)谏厦娴膬?nèi)容中也提到了主從延遲以及避免主從延遲的方法坯台,這里我們?cè)賮?lái)詳細(xì)分析一下主從延遲出現(xiàn)的原因以及應(yīng)該如何盡量減少主從延遲。

要搞懂什么情況下會(huì)出現(xiàn)主從延遲咧最,我們需要先搞懂什么是主從延遲捂人。

MySQL 主從同步延時(shí)是指從庫(kù)的數(shù)據(jù)落后于主庫(kù)的數(shù)據(jù)御雕,這種情況可能由以下兩個(gè)原因造成:

  1. 從庫(kù) I/O 線程接收 binlog 的速度跟不上主庫(kù)寫(xiě)入 binlog 的速度矢沿,導(dǎo)致從庫(kù) relay log 的數(shù)據(jù)滯后于主庫(kù) binlog 的數(shù)據(jù);
  2. 從庫(kù) SQL 線程執(zhí)行 relay log 的速度跟不上從庫(kù) I/O 線程接收 binlog 的速度酸纲,導(dǎo)致從庫(kù)的數(shù)據(jù)滯后于從庫(kù) relay log 的數(shù)據(jù)捣鲸。

與主從同步有關(guān)的時(shí)間點(diǎn)主要有 3 個(gè):

  1. 主庫(kù)執(zhí)行完一個(gè)事務(wù),寫(xiě)入 binlog闽坡,將這個(gè)時(shí)刻記為 T1栽惶;
  2. 從庫(kù) I/O 線程接收到 binlog 并寫(xiě)入 relay log 的時(shí)刻記為 T2;
  3. 從庫(kù) SQL 線程讀取 relay log 同步數(shù)據(jù)本地的時(shí)刻記為 T3疾嗅。

結(jié)合我們上面講到的主從復(fù)制原理外厂,可以得出:

  • T2 和 T1 的差值反映了從庫(kù) I/O 線程的性能和網(wǎng)絡(luò)傳輸?shù)男剩@個(gè)差值越小說(shuō)明從庫(kù) I/O 線程的性能和網(wǎng)絡(luò)傳輸效率越高代承。
  • T3 和 T2 的差值反映了從庫(kù) SQL 線程執(zhí)行的速度汁蝶,這個(gè)差值越小,說(shuō)明從庫(kù) SQL 線程執(zhí)行速度越快论悴。

那什么情況下會(huì)出現(xiàn)出從延遲呢掖棉?這里列舉幾種常見(jiàn)的情況:

  1. 從庫(kù)機(jī)器性能比主庫(kù)差:從庫(kù)接收 binlog 并寫(xiě)入 relay log 以及執(zhí)行 SQL 語(yǔ)句的速度會(huì)比較慢(也就是 T2-T1 和 T3-T2 的值會(huì)較大),進(jìn)而導(dǎo)致延遲膀估。解決方法是選擇與主庫(kù)一樣規(guī)格或更高規(guī)格的機(jī)器作為從庫(kù)幔亥,或者對(duì)從庫(kù)進(jìn)行性能優(yōu)化,比如調(diào)整參數(shù)察纯、增加緩存帕棉、使用 SSD 等针肥。
  2. 從庫(kù)處理的讀請(qǐng)求過(guò)多:從庫(kù)需要執(zhí)行主庫(kù)的所有寫(xiě)操作,同時(shí)還要響應(yīng)讀請(qǐng)求香伴,如果讀請(qǐng)求過(guò)多祖驱,會(huì)占用從庫(kù)的 CPU、內(nèi)存瞒窒、網(wǎng)絡(luò)等資源捺僻,影響從庫(kù)的復(fù)制效率(也就是 T2-T1 和 T3-T2 的值會(huì)較大,和前一種情況類(lèi)似)崇裁。解決方法是引入緩存(推薦)匕坯、使用一主多從的架構(gòu),將讀請(qǐng)求分散到不同的從庫(kù)拔稳,或者使用其他系統(tǒng)來(lái)提供查詢(xún)的能力葛峻,比如將 binlog 接入到 Hadoop、Elasticsearch 等系統(tǒng)中巴比。
  3. 大事務(wù):運(yùn)行時(shí)間比較長(zhǎng)术奖,長(zhǎng)時(shí)間未提交的事務(wù)就可以稱(chēng)為大事務(wù)。由于大事務(wù)執(zhí)行時(shí)間長(zhǎng)轻绞,并且從庫(kù)上的大事務(wù)會(huì)比主庫(kù)上的大事務(wù)花費(fèi)更多的時(shí)間和資源采记,因此非常容易造成主從延遲。解決辦法是避免大批量修改數(shù)據(jù)政勃,盡量分批進(jìn)行唧龄。類(lèi)似的情況還有執(zhí)行時(shí)間較長(zhǎng)的慢 SQL ,實(shí)際項(xiàng)目遇到慢 SQL 應(yīng)該進(jìn)行優(yōu)化奸远。
  4. 從庫(kù)太多:主庫(kù)需要將 binlog 同步到所有的從庫(kù)既棺,如果從庫(kù)數(shù)量太多,會(huì)增加同步的時(shí)間和開(kāi)銷(xiāo)(也就是 T2-T1 的值會(huì)比較大懒叛,但這里是因?yàn)橹鲙?kù)同步壓力大導(dǎo)致的)丸冕。解決方案是減少?gòu)膸?kù)的數(shù)量,或者將從庫(kù)分為不同的層級(jí)薛窥,讓上層的從庫(kù)再同步給下層的從庫(kù)胖烛,減少主庫(kù)的壓力。
  5. 網(wǎng)絡(luò)延遲:如果主從之間的網(wǎng)絡(luò)傳輸速度慢拆檬,或者出現(xiàn)丟包洪己、抖動(dòng)等問(wèn)題,那么就會(huì)影響 binlog 的傳輸效率竟贯,導(dǎo)致從庫(kù)延遲答捕。解決方法是優(yōu)化網(wǎng)絡(luò)環(huán)境,比如提升帶寬屑那、降低延遲拱镐、增加穩(wěn)定性等艘款。
  6. 單線程復(fù)制:MySQL5.5 及之前,只支持單線程復(fù)制沃琅。為了優(yōu)化復(fù)制性能哗咆,MySQL 5.6 引入了 多線程復(fù)制,MySQL 5.7 還進(jìn)一步完善了多線程復(fù)制益眉。
  7. 復(fù)制模式:MySQL 默認(rèn)的復(fù)制是異步的晌柬,必然會(huì)存在延遲問(wèn)題。全同步復(fù)制不存在延遲問(wèn)題郭脂,但性能太差了年碘。半同步復(fù)制是一種折中方案,相對(duì)于異步復(fù)制展鸡,半同步復(fù)制提高了數(shù)據(jù)的安全性屿衅,減少了主從延遲(還是有一定程度的延遲)。MySQL 5.5 開(kāi)始莹弊,MySQL 以插件的形式支持 semi-sync 半同步復(fù)制涤久。并且,MySQL 5.7 引入了 增強(qiáng)半同步復(fù)制 忍弛。
  8. ……

《MySQL 實(shí)戰(zhàn) 45 講》這個(gè)專(zhuān)欄中的讀寫(xiě)分離有哪些坑响迂?這篇文章也有對(duì)主從延遲解決方案這一話題進(jìn)行探討,感興趣的可以閱讀學(xué)習(xí)一下剧罩。

分庫(kù)分表

讀寫(xiě)分離主要應(yīng)對(duì)的是數(shù)據(jù)庫(kù)讀并發(fā)栓拜,沒(méi)有解決數(shù)據(jù)庫(kù)存儲(chǔ)問(wèn)題座泳。試想一下:如果 MySQL 一張表的數(shù)據(jù)量過(guò)大怎么辦?

換言之惠昔,我們?cè)撊绾谓鉀Q MySQL 的存儲(chǔ)壓力呢?

答案之一就是 分庫(kù)分表挑势。

什么是分庫(kù)镇防?

分庫(kù) 就是將數(shù)據(jù)庫(kù)中的數(shù)據(jù)分散到不同的數(shù)據(jù)庫(kù)上,可以垂直分庫(kù)潮饱,也可以水平分庫(kù)来氧。

垂直分庫(kù) 就是把單一數(shù)據(jù)庫(kù)按照業(yè)務(wù)進(jìn)行劃分,不同的業(yè)務(wù)使用不同的數(shù)據(jù)庫(kù)香拉,進(jìn)而將一個(gè)數(shù)據(jù)庫(kù)的壓力分擔(dān)到多個(gè)數(shù)據(jù)庫(kù)啦扬。

舉個(gè)例子:說(shuō)你將數(shù)據(jù)庫(kù)中的用戶(hù)表、訂單表和商品表分別單獨(dú)拆分為用戶(hù)數(shù)據(jù)庫(kù)凫碌、訂單數(shù)據(jù)庫(kù)和商品數(shù)據(jù)庫(kù)扑毡。

水平分庫(kù) 是把同一個(gè)表按一定規(guī)則拆分到不同的數(shù)據(jù)庫(kù)中,每個(gè)庫(kù)可以位于不同的服務(wù)器上盛险,這樣就實(shí)現(xiàn)了水平擴(kuò)展瞄摊,解決了單表的存儲(chǔ)和性能瓶頸的問(wèn)題勋又。

舉個(gè)例子:訂單表數(shù)據(jù)量太大,你對(duì)訂單表進(jìn)行了水平切分(水平分表)换帜,然后將切分后的 2 張訂單表分別放在兩個(gè)不同的數(shù)據(jù)庫(kù)楔壤。

什么是分表?

分表 就是對(duì)單表的數(shù)據(jù)進(jìn)行拆分惯驼,可以是垂直拆分蹲嚣,也可以是水平拆分。

垂直分表 是對(duì)數(shù)據(jù)表列的拆分祟牲,把一張列比較多的表拆分為多張表端铛。

舉個(gè)例子:我們可以將用戶(hù)信息表中的一些列單獨(dú)抽出來(lái)作為一個(gè)表。

水平分表 是對(duì)數(shù)據(jù)表行的拆分疲眷,把一張行比較多的表拆分為多張表禾蚕,可以解決單一表數(shù)據(jù)量過(guò)大的問(wèn)題。

舉個(gè)例子:我們可以將用戶(hù)信息表拆分成多個(gè)用戶(hù)信息表狂丝,這樣就可以避免單一表數(shù)據(jù)量過(guò)大對(duì)性能造成影響换淆。

水平拆分只能解決單表數(shù)據(jù)量大的問(wèn)題,為了提升性能几颜,我們通常會(huì)選擇將拆分后的多張表放在不同的數(shù)據(jù)庫(kù)中倍试。也就是說(shuō),水平分表通常和水平分庫(kù)同時(shí)出現(xiàn)蛋哭。

什么情況下需要分庫(kù)分表县习?

遇到下面幾種場(chǎng)景可以考慮分庫(kù)分表:

  • 單表的數(shù)據(jù)達(dá)到千萬(wàn)級(jí)別以上,數(shù)據(jù)庫(kù)讀寫(xiě)速度比較緩慢谆趾。
  • 數(shù)據(jù)庫(kù)中的數(shù)據(jù)占用的空間越來(lái)越大躁愿,備份時(shí)間越來(lái)越長(zhǎng)。
  • 應(yīng)用的并發(fā)量太大沪蓬。

常見(jiàn)的分片算法有哪些彤钟?

分片算法主要解決了數(shù)據(jù)被水平分片之后,數(shù)據(jù)究竟該存放在哪個(gè)表的問(wèn)題跷叉。

  • 哈希分片:求指定 key(比如 id) 的哈希逸雹,然后根據(jù)哈希值確定數(shù)據(jù)應(yīng)被放置在哪個(gè)表中。哈希分片比較適合隨機(jī)讀寫(xiě)的場(chǎng)景云挟,不太適合經(jīng)常需要范圍查詢(xún)的場(chǎng)景梆砸。
  • 范圍分片:按照特性的范圍區(qū)間(比如時(shí)間區(qū)間、ID 區(qū)間)來(lái)分配數(shù)據(jù)园欣,比如 將 id1~299999 的記錄分到第一個(gè)庫(kù)帖世, 300000~599999 的分到第二個(gè)庫(kù)。范圍分片適合需要經(jīng)常進(jìn)行范圍查找的場(chǎng)景狮暑,不太適合隨機(jī)讀寫(xiě)的場(chǎng)景(數(shù)據(jù)未被分散鸡挠,容易出現(xiàn)熱點(diǎn)數(shù)據(jù)的問(wèn)題)。
  • 地理位置分片:很多 NewSQL 數(shù)據(jù)庫(kù)都支持地理位置分片算法搬男,也就是根據(jù)地理位置(如城市拣展、地域)來(lái)分配數(shù)據(jù)。
  • 融合算法:靈活組合多種分片算法缔逛,比如將哈希分片和范圍分片組合备埃。
  • ……

分庫(kù)分表會(huì)帶來(lái)什么問(wèn)題呢?

記住褐奴,你在公司做的任何技術(shù)決策按脚,不光是要考慮這個(gè)技術(shù)能不能滿足我們的要求,是否適合當(dāng)前業(yè)務(wù)場(chǎng)景敦冬,還要重點(diǎn)考慮其帶來(lái)的成本辅搬。

引入分庫(kù)分表之后,會(huì)給系統(tǒng)帶來(lái)什么挑戰(zhàn)呢脖旱?

  • join 操作:同一個(gè)數(shù)據(jù)庫(kù)中的表分布在了不同的數(shù)據(jù)庫(kù)中堪遂,導(dǎo)致無(wú)法使用 join 操作。這樣就導(dǎo)致我們需要手動(dòng)進(jìn)行數(shù)據(jù)的封裝萌庆,比如你在一個(gè)數(shù)據(jù)庫(kù)中查詢(xún)到一個(gè)數(shù)據(jù)之后溶褪,再根據(jù)這個(gè)數(shù)據(jù)去另外一個(gè)數(shù)據(jù)庫(kù)中找對(duì)應(yīng)的數(shù)據(jù)。不過(guò)践险,很多大廠的資深 DBA 都是建議盡量不要使用 join 操作猿妈。因?yàn)?join 的效率低,并且會(huì)對(duì)分庫(kù)分表造成影響巍虫。對(duì)于需要用到 join 操作的地方彭则,可以采用多次查詢(xún)業(yè)務(wù)層進(jìn)行數(shù)據(jù)組裝的方法。不過(guò)垫言,這種方法需要考慮業(yè)務(wù)上多次查詢(xún)的事務(wù)性的容忍度贰剥。
  • 事務(wù)問(wèn)題:同一個(gè)數(shù)據(jù)庫(kù)中的表分布在了不同的數(shù)據(jù)庫(kù)中,如果單個(gè)操作涉及到多個(gè)數(shù)據(jù)庫(kù)筷频,那么數(shù)據(jù)庫(kù)自帶的事務(wù)就無(wú)法滿足我們的要求了。這個(gè)時(shí)候前痘,我們就需要引入分布式事務(wù)了凛捏。關(guān)于分布式事務(wù)常見(jiàn)解決方案總結(jié),網(wǎng)站上也有對(duì)應(yīng)的總結(jié):https://javaguide.cn/distributed-system/distributed-transaction.html 芹缔。
  • 分布式 ID:分庫(kù)之后坯癣, 數(shù)據(jù)遍布在不同服務(wù)器上的數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)的自增主鍵已經(jīng)沒(méi)辦法滿足生成的主鍵唯一了最欠。我們?nèi)绾螢椴煌臄?shù)據(jù)節(jié)點(diǎn)生成全局唯一主鍵呢示罗?這個(gè)時(shí)候惩猫,我們就需要為我們的系統(tǒng)引入分布式 ID 了。關(guān)于分布式 ID 的詳細(xì)介紹&實(shí)現(xiàn)方案總結(jié)蚜点,網(wǎng)站上也有對(duì)應(yīng)的總結(jié):https://javaguide.cn/distributed-system/distributed-id.html 轧房。
  • 跨庫(kù)聚合查詢(xún)問(wèn)題:分庫(kù)分表會(huì)導(dǎo)致常規(guī)聚合查詢(xún)操作,如 group by绍绘,order by 等變得異常復(fù)雜奶镶。這是因?yàn)檫@些操作需要在多個(gè)分片上進(jìn)行數(shù)據(jù)匯總和排序,而不是在單個(gè)數(shù)據(jù)庫(kù)上進(jìn)行陪拘。為了實(shí)現(xiàn)這些操作厂镇,需要編寫(xiě)復(fù)雜的業(yè)務(wù)代碼,或者使用中間件來(lái)協(xié)調(diào)分片間的通信和數(shù)據(jù)傳輸左刽。這樣會(huì)增加開(kāi)發(fā)和維護(hù)的成本捺信,以及影響查詢(xún)的性能和可擴(kuò)展性。
  • ……

另外欠痴,引入分庫(kù)分表之后残黑,一般需要 DBA 的參與,同時(shí)還需要更多的數(shù)據(jù)庫(kù)服務(wù)器斋否,這些都屬于成本梨水。

分庫(kù)分表有沒(méi)有什么比較推薦的方案?

Apache ShardingSphere 是一款分布式的數(shù)據(jù)庫(kù)生態(tài)系統(tǒng)茵臭, 可以將任意數(shù)據(jù)庫(kù)轉(zhuǎn)換為分布式數(shù)據(jù)庫(kù)疫诽,并通過(guò)數(shù)據(jù)分片、彈性伸縮旦委、加密等能力對(duì)原有數(shù)據(jù)庫(kù)進(jìn)行增強(qiáng)奇徒。

ShardingSphere 項(xiàng)目(包括 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar)是當(dāng)當(dāng)捐入 Apache 的缨硝,目前主要由京東數(shù)科的一些巨佬維護(hù)摩钙。

ShardingSphere 絕對(duì)可以說(shuō)是當(dāng)前分庫(kù)分表的首選!ShardingSphere 的功能完善查辩,除了支持讀寫(xiě)分離和分庫(kù)分表胖笛,還提供分布式事務(wù)、數(shù)據(jù)庫(kù)治理宜岛、影子庫(kù)长踊、數(shù)據(jù)加密和脫敏等功能。

ShardingSphere 提供的功能如下:

ShardingSphere 的優(yōu)勢(shì)如下(摘自 ShardingSphere 官方文檔:https://shardingsphere.apache.org/document/current/cn/overview/):

  • 極致性能:驅(qū)動(dòng)程序端歷經(jīng)長(zhǎng)年打磨萍倡,效率接近原生 JDBC身弊,性能極致。
  • 生態(tài)兼容:代理端支持任何通過(guò) MySQL/PostgreSQL 協(xié)議的應(yīng)用訪問(wèn),驅(qū)動(dòng)程序端可對(duì)接任意實(shí)現(xiàn) JDBC 規(guī)范的數(shù)據(jù)庫(kù)阱佛。
  • 業(yè)務(wù)零侵入:面對(duì)數(shù)據(jù)庫(kù)替換場(chǎng)景帖汞,ShardingSphere 可滿足業(yè)務(wù)無(wú)需改造,實(shí)現(xiàn)平滑業(yè)務(wù)遷移凑术。
  • 運(yùn)維低成本:在保留原技術(shù)棧不變前提下翩蘸,對(duì) DBA 學(xué)習(xí)、管理成本低麦萤,交互友好鹿鳖。
  • 安全穩(wěn)定:基于成熟數(shù)據(jù)庫(kù)底座之上提供增量能力,兼顧安全性及穩(wěn)定性壮莹。
  • 彈性擴(kuò)展:具備計(jì)算翅帜、存儲(chǔ)平滑在線擴(kuò)展能力,可滿足業(yè)務(wù)多變的需求命满。
  • 開(kāi)放生態(tài):通過(guò)多層次(內(nèi)核涝滴、功能、生態(tài))插件化能力胶台,為用戶(hù)提供可定制滿足自身特殊需求的獨(dú)有系統(tǒng)歼疮。

另外,ShardingSphere 的生態(tài)體系完善诈唬,社區(qū)活躍韩脏,文檔完善,更新和發(fā)布比較頻繁铸磅。

艿艿之前寫(xiě)了一篇分庫(kù)分表的實(shí)戰(zhàn)文章赡矢,各位朋友可以看看:《芋道 Spring Boot 分庫(kù)分表入門(mén)》

分庫(kù)分表后阅仔,數(shù)據(jù)怎么遷移呢吹散?

分庫(kù)分表之后,我們?nèi)绾螌⒗蠋?kù)(單庫(kù)單表)的數(shù)據(jù)遷移到新庫(kù)(分庫(kù)分表后的數(shù)據(jù)庫(kù)系統(tǒng))呢八酒?

比較簡(jiǎn)單同時(shí)也是非常常用的方案就是停機(jī)遷移空民,寫(xiě)個(gè)腳本老庫(kù)的數(shù)據(jù)寫(xiě)到新庫(kù)中。比如你在凌晨 2 點(diǎn)羞迷,系統(tǒng)使用的人數(shù)非常少的時(shí)候界轩,掛一個(gè)公告說(shuō)系統(tǒng)要維護(hù)升級(jí)預(yù)計(jì) 1 小時(shí)。然后闭树,你寫(xiě)一個(gè)腳本將老庫(kù)的數(shù)據(jù)都同步到新庫(kù)中耸棒。

如果你不想停機(jī)遷移數(shù)據(jù)的話,也可以考慮雙寫(xiě)方案报辱。雙寫(xiě)方案是針對(duì)那種不能停機(jī)遷移的場(chǎng)景,實(shí)現(xiàn)起來(lái)要稍微麻煩一些。具體原理是這樣的:

  • 我們對(duì)老庫(kù)的更新操作(增刪改)碍现,同時(shí)也要寫(xiě)入新庫(kù)(雙寫(xiě))幅疼。如果操作的數(shù)據(jù)不存在于新庫(kù)的話,需要插入到新庫(kù)中昼接。 這樣就能保證爽篷,咱們新庫(kù)里的數(shù)據(jù)是最新的。
  • 在遷移過(guò)程慢睡,雙寫(xiě)只會(huì)讓被更新操作過(guò)的老庫(kù)中的數(shù)據(jù)同步到新庫(kù)逐工,我們還需要自己寫(xiě)腳本將老庫(kù)中的數(shù)據(jù)和新庫(kù)的數(shù)據(jù)做比對(duì)。如果新庫(kù)中沒(méi)有漂辐,那咱們就把數(shù)據(jù)插入到新庫(kù)泪喊。如果新庫(kù)有,舊庫(kù)沒(méi)有髓涯,就把新庫(kù)對(duì)應(yīng)的數(shù)據(jù)刪除(冗余數(shù)據(jù)清理)袒啼。
  • 重復(fù)上一步的操作,直到老庫(kù)和新庫(kù)的數(shù)據(jù)一致為止纬纪。

想要在項(xiàng)目中實(shí)施雙寫(xiě)還是比較麻煩的蚓再,很容易會(huì)出現(xiàn)問(wèn)題。我們可以借助上面提到的數(shù)據(jù)庫(kù)同步工具 Canal 做增量數(shù)據(jù)遷移(還是依賴(lài) binlog包各,開(kāi)發(fā)和維護(hù)成本較低)摘仅。

總結(jié)

  • 讀寫(xiě)分離主要是為了將對(duì)數(shù)據(jù)庫(kù)的讀寫(xiě)操作分散到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn)上。 這樣的話问畅,就能夠小幅提升寫(xiě)性能娃属,大幅提升讀性能。
  • 讀寫(xiě)分離基于主從復(fù)制按声,MySQL 主從復(fù)制是依賴(lài)于 binlog 膳犹。
  • 分庫(kù) 就是將數(shù)據(jù)庫(kù)中的數(shù)據(jù)分散到不同的數(shù)據(jù)庫(kù)上。分表 就是對(duì)單表的數(shù)據(jù)進(jìn)行拆分签则,可以是垂直拆分须床,也可以是水平拆分。
  • 引入分庫(kù)分表之后渐裂,需要系統(tǒng)解決事務(wù)豺旬、分布式 id、無(wú)法 join 操作問(wèn)題柒凉。
  • ShardingSphere 絕對(duì)可以說(shuō)是當(dāng)前分庫(kù)分表的首選族阅!ShardingSphere 的功能完善,除了支持讀寫(xiě)分離和分庫(kù)分表膝捞,還提供分布式事務(wù)坦刀、數(shù)據(jù)庫(kù)治理等功能。另外,ShardingSphere 的生態(tài)體系完善鲤遥,社區(qū)活躍沐寺,文檔完善,更新和發(fā)布比較頻繁盖奈。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末混坞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钢坦,更是在濱河造成了極大的恐慌究孕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爹凹,死亡現(xiàn)場(chǎng)離奇詭異厨诸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)逛万,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)泳猬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人宇植,你說(shuō)我怎么就攤上這事得封。” “怎么了指郁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵忙上,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我闲坎,道長(zhǎng)疫粥,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任腰懂,我火速辦了婚禮梗逮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绣溜。我一直安慰自己慷彤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布怖喻。 她就那樣靜靜地躺著底哗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锚沸。 梳的紋絲不亂的頭發(fā)上跋选,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音哗蜈,去河邊找鬼前标。 笑死坠韩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的候生。 我是一名探鬼主播同眯,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绽昼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼唯鸭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起硅确,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤目溉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后菱农,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體缭付,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年循未,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了陷猫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡的妖,死狀恐怖绣檬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嫂粟,我是刑警寧澤娇未,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站星虹,受9級(jí)特大地震影響零抬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宽涌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一平夜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卸亮,春花似錦忽妒、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至寝受,卻和暖如春坷牛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背很澄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工京闰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颜及,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓蹂楣,卻偏偏與公主長(zhǎng)得像俏站,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痊土,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容