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

分庫(kù)分表實(shí)戰(zhàn):竿頭日上-千萬(wàn)級(jí)數(shù)據(jù)優(yōu)化之讀寫(xiě)分離

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
訂單緩存方案上線之后,我們以為又開(kāi)啟了歲月安好的日子,但是,在一周后的某一天,DBA直接跑來(lái)了,DBA直接說(shuō):“l(fā)eader讓我直接找你,是這樣的,上次加了緩存優(yōu)化后,效果確實(shí)不錯(cuò),但是我發(fā)現(xiàn)訂單查詢sql在今天的12:00至12:05之間有大量的慢sql,查詢時(shí)間超過(guò)了2.5s?!?/div>

前 言

訂單緩存方案上線之后,我們以為又開(kāi)啟了歲月安好的日子,但是,在一周后的某一天,DBA直接跑來(lái)了,DBA直接說(shuō):“l(fā)eader讓我直接找你,是這樣的,上次加了緩存優(yōu)化后,效果確實(shí)不錯(cuò),但是我發(fā)現(xiàn)訂單查詢sql在今天的12:00至12:05之間有大量的慢sql,查詢時(shí)間超過(guò)了2.5s。”

這個(gè)時(shí)候,我們立馬開(kāi)啟了排查問(wèn)題模式,首先,check了一下上次加的緩存,發(fā)現(xiàn)緩存正常,然后接著根據(jù)DBA提供的信息搜索日志,此時(shí),發(fā)現(xiàn)在這個(gè)時(shí)間段訂單請(qǐng)求量突增,大概是平常訂單請(qǐng)求量的2到3倍,然后經(jīng)過(guò)了解,發(fā)現(xiàn)在這個(gè)時(shí)間段內(nèi),營(yíng)銷(xiāo)系統(tǒng)那邊做了一些活動(dòng),導(dǎo)致訂單請(qǐng)求量突增。

說(shuō)白了就是做了促銷(xiāo)活動(dòng)后,大量下單的用戶會(huì)不斷刷新訂單來(lái)查詢訂單的信息,比如看一下訂單是否開(kāi)始配送,此時(shí)大量的請(qǐng)求會(huì)打到了MySQL上去,此時(shí)單庫(kù)又抗不了這么讀請(qǐng)求,就導(dǎo)致了數(shù)據(jù)庫(kù)負(fù)載很高,從而嚴(yán)重降低了MySQL的查詢效率。

現(xiàn)在我們緩存也加過(guò)了,但是數(shù)據(jù)庫(kù)負(fù)載還是很高,此時(shí)該怎么辦呢?

其實(shí)也很簡(jiǎn)單,既然單個(gè)庫(kù)扛不住,那就搞2個(gè)庫(kù)一起來(lái)抗唄,因?yàn)閷?duì)于外賣(mài)訂單來(lái)說(shuō)是典型的讀多寫(xiě)少的場(chǎng)景,所以,在這個(gè)場(chǎng)景下,我們可以搞個(gè)一主兩從的架構(gòu)來(lái)進(jìn)行優(yōu)化,就像這樣:

也就是寫(xiě)數(shù)據(jù)走主庫(kù),而讀數(shù)據(jù)走從庫(kù),可以看到,此時(shí)由于我們搞了2個(gè)從庫(kù),這2個(gè)從庫(kù)可以一起來(lái)抗大量的讀請(qǐng)求。

非常關(guān)鍵的一點(diǎn)就是,從庫(kù)會(huì)通過(guò)主從復(fù)制,從主庫(kù)中不斷的同步數(shù)據(jù),以此來(lái)保證從庫(kù)的數(shù)據(jù)和主庫(kù)是一模一樣的,所以想要實(shí)現(xiàn)讀寫(xiě)分離,那么,就先要了解主從復(fù)制是怎么玩兒的。

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

我們以mysql一主兩從架構(gòu)為例,也就是一個(gè)master節(jié)點(diǎn)下有兩個(gè)slave節(jié)點(diǎn),在這套架構(gòu)下,寫(xiě)請(qǐng)求統(tǒng)一交給master節(jié)點(diǎn)處理,而讀請(qǐng)求交給slave節(jié)點(diǎn)處理。

為了保證slave節(jié)點(diǎn)和master節(jié)點(diǎn)的數(shù)據(jù)一致性,master節(jié)點(diǎn)在寫(xiě)入數(shù)據(jù)之后,同時(shí)會(huì)把數(shù)據(jù)復(fù)制一份到自己的各個(gè)slave節(jié)點(diǎn)上。

在復(fù)制的過(guò)程中一共會(huì)使用到三個(gè)線程,一個(gè)是binlog dump線程,位于master節(jié)點(diǎn)上,另外兩個(gè)線程分別是I/O線程和SQL線程,它們都分別位于slave節(jié)點(diǎn)上,如下圖:

結(jié)合圖片,我們一起來(lái)看下主從復(fù)制的核心流程:

(1)當(dāng)master節(jié)點(diǎn)接收到一個(gè)寫(xiě)請(qǐng)求時(shí),這個(gè)寫(xiě)請(qǐng)求可能是增刪改操作,此時(shí)會(huì)把寫(xiě)請(qǐng)求的操作都記錄到binlog日志中。

(2)master節(jié)點(diǎn)會(huì)把數(shù)據(jù)復(fù)制給slave節(jié)點(diǎn),如圖中的slave01節(jié)點(diǎn)和slave02節(jié)點(diǎn),這個(gè)過(guò)程,首先得要每個(gè)slave節(jié)點(diǎn)連接到master節(jié)點(diǎn)上,當(dāng)slave節(jié)點(diǎn)連接到master節(jié)點(diǎn)上時(shí),master節(jié)點(diǎn)會(huì)為每一個(gè)slave節(jié)點(diǎn)分別創(chuàng)建一個(gè)binlog dump線程,用于向各個(gè)slave節(jié)點(diǎn)發(fā)送binlog日志。

(3)binlog dump線程會(huì)讀取master節(jié)點(diǎn)上的binlog日志,然后將binlog日志發(fā)送給slave節(jié)點(diǎn)上的I/O線程。

(4)slave節(jié)點(diǎn)上的I/O線程接收到binlog日志后,會(huì)將binlog日志先寫(xiě)入到本地的relaylog中,relaylog中就保存了binlog日志。

(5)slave節(jié)點(diǎn)上的SQL線程,會(huì)來(lái)讀取relaylog中的binlog日志,將其解析成具體的增刪改操作,把這些在master節(jié)點(diǎn)上進(jìn)行過(guò)的操作,重新在slave節(jié)點(diǎn)上也重做一遍,達(dá)到數(shù)據(jù)還原的效果,這樣就可以保證master節(jié)點(diǎn)和slave節(jié)點(diǎn)的數(shù)據(jù)一致性了。

主從復(fù)制的有幾種模式?

mysql的主從復(fù)制,分為全同步復(fù)制、異步復(fù)制、半同步復(fù)制和增強(qiáng)半同步復(fù)制 這四種。

全同步復(fù)制

首先,全同步復(fù)制,就是當(dāng)主庫(kù)執(zhí)行完一個(gè)事務(wù)之后,要求所有的從庫(kù)也都必須執(zhí)行完該事務(wù),才可以返回處理結(jié)果給客戶端;因此,雖然全同步復(fù)制數(shù)據(jù)一致性得到保證了,但是主庫(kù)完成一個(gè)事物需要等待所有從庫(kù)也完成,性能就比較低了。

異步復(fù)制

而異步復(fù)制,當(dāng)主庫(kù)提交事物后,會(huì)通知binlog dump線程發(fā)送binlog日志給從庫(kù),一旦binlog dump線程將binlog日志發(fā)送給從庫(kù)之后,不需要等到從庫(kù)也同步完成事務(wù),主庫(kù)就會(huì)將處理結(jié)果返回給客戶端。

因?yàn)橹鲙?kù)只管自己執(zhí)行完事務(wù),就可以將處理結(jié)果返回給客戶端,而不用關(guān)心從庫(kù)是否執(zhí)行完事務(wù),這就可能導(dǎo)致短暫的主從數(shù)據(jù)不一致的問(wèn)題了,比如剛在主庫(kù)插入的新數(shù)據(jù),如果馬上在從庫(kù)查詢,就可能查詢不到。

而且,當(dāng)主庫(kù)提交事物后,如果宕機(jī)掛掉了,此時(shí)可能binlog還沒(méi)來(lái)得及同步給從庫(kù),這時(shí)候如果為了恢復(fù)故障切換主從節(jié)點(diǎn)的話,就會(huì)出現(xiàn)數(shù)據(jù)丟失的問(wèn)題,所以異步復(fù)制雖然性能高,但數(shù)據(jù)一致性上是較弱的。

mysql主從復(fù)制,默認(rèn)采用的就是異步復(fù)制這種復(fù)制策略。

半同步復(fù)制

半同步復(fù)制,顧名思義就是在同步和異步中做了折中選擇,我們可以結(jié)合著MySQL官網(wǎng)來(lái)看下是半同步主從復(fù)制的過(guò)程,來(lái)看下這樣圖:

當(dāng)主庫(kù)提交事務(wù)后,至少還需要一個(gè)從庫(kù)返回接受到binlog日志,并成功寫(xiě)入到relaylog的消息,這個(gè)時(shí)候,主庫(kù)才會(huì)將處理結(jié)果返回給客戶端。

相比前2種復(fù)制方式,半同步復(fù)制較好地兼顧了數(shù)據(jù)一致性以及性能損耗的問(wèn)題。

同時(shí),半同步復(fù)制也存在以下幾個(gè)問(wèn)題:

  • 半同步復(fù)制的性能,相比異步復(fù)制而言有所下降,相比于異步復(fù)制是不需要等待任何從庫(kù)是否接收到數(shù)據(jù)的響應(yīng),而半同步復(fù)制則需要等待至少一個(gè)從庫(kù)確認(rèn)接收到binlog日志的響應(yīng),性能上是損耗更大的。
  • 主庫(kù)等待從庫(kù)響應(yīng)的最大時(shí)長(zhǎng)是可以配置的,如果超過(guò)了配置的時(shí)間,半同步復(fù)制就會(huì)變成異步復(fù)制,那么,異步復(fù)制的問(wèn)題同樣也就會(huì)出現(xiàn)了。
  • 在MySQL 5.7.2之前的版本中,半同步復(fù)制存在著幻讀問(wèn)題的。

當(dāng)主庫(kù)成功提交事物并處于等待從庫(kù)確認(rèn)的過(guò)程中,這個(gè)時(shí)候,從庫(kù)都還沒(méi)來(lái)得及返回處理結(jié)果給客戶端,但因?yàn)橹鲙?kù)存儲(chǔ)引擎內(nèi)部已經(jīng)提交事務(wù)了,所以,其他客戶端是可以到從主庫(kù)中讀到數(shù)據(jù)的。

但是,如果下一秒主庫(kù)突然掛了,就像這樣圖一樣:

此時(shí),下一次請(qǐng)求過(guò)來(lái),因?yàn)橹鲙?kù)掛了,就只能把請(qǐng)求切換到從庫(kù)中,因?yàn)閺膸?kù)還沒(méi)從主庫(kù)同步完數(shù)據(jù),所以,從庫(kù)中當(dāng)然就讀不到這條數(shù)據(jù)了,和上一秒讀取數(shù)據(jù)的結(jié)果對(duì)比,就造成了幻讀的現(xiàn)象了。

增強(qiáng)半同步復(fù)制

最后,增強(qiáng)半同步復(fù)制,是mysql 5.7.2后的版本對(duì)半同步復(fù)制做的一個(gè)改進(jìn),原理上幾乎是一樣的,主要是解決幻讀的問(wèn)題。

主庫(kù)配置了參數(shù) rpl_semi_sync_master_wait_point = AFTER_SYNC 后,主庫(kù)在存儲(chǔ)引擎提交事物前,必須先收到從庫(kù)數(shù)據(jù)同步完成的確認(rèn)信息后,才能提交事務(wù),以此來(lái)解決幻讀問(wèn)題。

可以參考下MySQL官網(wǎng)是怎么描述增強(qiáng)半同步主從復(fù)制過(guò)程的:

主從延遲問(wèn)題和常規(guī)解決方案

主庫(kù)寫(xiě)入的速度是很快的,因?yàn)橹鲙?kù)是多線程并發(fā)寫(xiě)入的,但是,從庫(kù)是單線程從主庫(kù)拉取數(shù)據(jù)的,所以從庫(kù)從主庫(kù)復(fù)制數(shù)據(jù)的速度,就比較慢了,從而產(chǎn)生了主從延遲的問(wèn)題。

mysql 從 5.6版本開(kāi)始,就支持多線程復(fù)制,但是5.6版本是基于庫(kù)級(jí)別去操作,也就是說(shuō)會(huì)給每個(gè)數(shù)據(jù)庫(kù)開(kāi)啟一個(gè)線程,不同庫(kù)處理時(shí)在同一時(shí)間內(nèi)是互不影響的;但是,當(dāng)業(yè)務(wù)的壓力集中到一個(gè)庫(kù)時(shí),又會(huì)回到和單線程復(fù)制一樣的狀況了。

直到mysql 5.7版本,開(kāi)始引入了基于組提交(group_commit)的概念,這個(gè)時(shí)候才 真正 支持多路復(fù)制功能,官方稱為enhanced multi-threaded slave(簡(jiǎn)稱MTS),所以,推薦大家盡可能選擇MySQL 5.7之后的版本。

而主庫(kù)掛載的從庫(kù)數(shù)量過(guò)多,也會(huì)導(dǎo)致主從復(fù)制延遲的問(wèn)題,一般我們是建議一個(gè)主庫(kù)掛載從庫(kù)的數(shù)量,在3~5個(gè)比較合適。

另外,我們執(zhí)行的SQL語(yǔ)句中,如果慢SQL語(yǔ)句過(guò)多,也會(huì)導(dǎo)致主從復(fù)制延遲,比如,我們工作中會(huì)遇到批量插入的場(chǎng)景,如果一批插入的數(shù)據(jù)量過(guò)大,就容易造成執(zhí)行時(shí)間過(guò)長(zhǎng)。

假如,從執(zhí)行完一份 批量插入數(shù)據(jù)的SQL語(yǔ)句開(kāi)始,到在從庫(kù)上能查到這些數(shù)據(jù)的這個(gè)過(guò)程中,如果耗費(fèi)了10秒,就導(dǎo)致主從庫(kù)之間就延遲10秒了;所以,SQL優(yōu)化會(huì)是一個(gè)常態(tài)化的工作,可以通過(guò)慢SQL日志或監(jiān)控平臺(tái)監(jiān)控慢SQL,如果單個(gè)數(shù)據(jù)寫(xiě)入時(shí)間過(guò)長(zhǎng)的話,可以將一批數(shù)據(jù)分片分批次寫(xiě)入。

最后,如果出現(xiàn)網(wǎng)絡(luò)延遲或者機(jī)器的性能比較差,也會(huì)導(dǎo)致主從復(fù)制延遲的問(wèn)題,這種情況沒(méi)什么可說(shuō)的,及時(shí)優(yōu)化網(wǎng)絡(luò)提升機(jī)器性能就行了。

讀寫(xiě)分離實(shí)戰(zhàn)

讀寫(xiě)分離配置核心組件流程圖:

| 讀寫(xiě)分離配置步驟

(1)配置文件中配置主從庫(kù)連接信息

(2)注入數(shù)據(jù)源

(3)數(shù)據(jù)源切換上下文,其中使用了ThreadLocal保存當(dāng)前線程的數(shù)據(jù)源

(4)繼承AbstractRoutingDataSource類重寫(xiě)determineCurrentLookupKey方法實(shí)現(xiàn)數(shù)據(jù)源動(dòng)態(tài)切換

(5)創(chuàng)建讀庫(kù)的自定義注解

(6)切面類

(7)需要走讀庫(kù)的業(yè)務(wù)方法上添加@ReadOnly注解,那么執(zhí)行這些業(yè)務(wù)方法時(shí)就會(huì)被切面攔截修改數(shù)據(jù)源從而走讀庫(kù)進(jìn)行查詢。

(8)寫(xiě)主庫(kù)、讀從庫(kù)的效果

1)生成訂單

2)查詢訂單

責(zé)任編輯:武曉燕 來(lái)源: 石杉的架構(gòu)筆記
相關(guān)推薦

2022-07-07 09:33:06

MySQL查詢數(shù)據(jù)優(yōu)化

2022-07-04 23:24:28

sql優(yōu)化監(jiān)控

2022-07-08 08:57:36

數(shù)據(jù)優(yōu)化垂直拆分數(shù)據(jù)庫(kù)

2022-01-26 07:59:07

緩存分庫(kù)分表

2022-01-28 08:59:59

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

2022-12-05 07:51:24

數(shù)據(jù)庫(kù)分庫(kù)分表讀寫(xiě)分離

2019-05-13 15:00:14

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

2020-01-03 16:30:14

數(shù)據(jù)庫(kù)讀寫(xiě)分離分庫(kù)

2022-07-05 21:31:21

索引SQL分庫(kù)分表

2022-09-26 08:28:22

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

2022-10-13 17:43:10

MySQL存放數(shù)據(jù)

2022-10-10 17:37:59

分庫(kù)分表訂單業(yè)務(wù)

2021-10-27 09:55:55

Sharding-Jd分庫(kù)分表Java

2021-09-08 09:48:39

數(shù)據(jù)庫(kù)工具技術(shù)

2018-07-26 14:50:00

數(shù)據(jù)庫(kù)MySQL大表優(yōu)化

2024-12-26 08:37:39

2018-06-01 14:00:00

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

2019-01-29 14:55:50

數(shù)據(jù)庫(kù)中間件分庫(kù)分表

2020-07-30 17:59:34

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

2018-07-11 20:07:06

數(shù)據(jù)庫(kù)MySQL索引優(yōu)化
點(diǎn)贊
收藏

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