MySQL會(huì)丟數(shù)據(jù)嗎?

      網(wǎng)友投稿 846 2025-03-31

      在業(yè)務(wù)高峰期臨時(shí)提升性能的方法。


      WAL機(jī)制保證只要redo log和binlog保證持久化到磁盤,就能確保Mysql異常重啟后,數(shù)據(jù)可以恢復(fù)。

      binlog的寫入機(jī)制

      事務(wù)執(zhí)行過程中:

      先把日志寫到binlog cache

      事務(wù)提交時(shí),再把binlog cache寫到binlog文件

      一個(gè)事務(wù)的binlog不該被拆開,不論事務(wù)多大,也要確保一次性寫入。這就涉及binlog cache的保存問題。

      系統(tǒng)給binlog cache分配了一片內(nèi)存,每個(gè)線程一個(gè),但是共用同一份binlog文件。參數(shù) binlog_cache_size控制單個(gè)線程內(nèi)binlog cache所占內(nèi)存的大小。若超過該參數(shù)值,就要暫存到磁盤。

      事務(wù)提交時(shí),執(zhí)行器把binlog cache里的完整事務(wù)寫入binlog,并清空binlog cache。

      binlog寫盤狀態(tài)

      TODO

      圖中的:

      write

      把日志寫入到文件系統(tǒng)的page cache,并沒有把數(shù)據(jù)持久化到磁盤,所以速度較快

      fsync

      將數(shù)據(jù)持久化到磁盤。一般認(rèn)為fsync才占磁盤的IOPS

      write 和fsync的時(shí)機(jī),由參數(shù)sync_binlog控制:

      sync_binlog=0,每次提交事務(wù)都只write,不fsync

      sync_binlog=1,每次提交事務(wù)都會(huì)執(zhí)行fsync

      sync_binlog=N(N>1),每次提交事務(wù)都write,但累積N個(gè)事務(wù)后才fsync

      因此,在出現(xiàn)I/O瓶頸的場(chǎng)景,將sync_binlog設(shè)置成一個(gè)較大值,可提升性能。在實(shí)際的業(yè)務(wù)場(chǎng)景中,考慮到丟失日志量的可控性,一般不建議將這個(gè)參數(shù)設(shè)成0,推薦將其設(shè)置為100~1000中的某個(gè)數(shù)值。

      但將sync_binlog設(shè)置為N,對(duì)應(yīng)的風(fēng)險(xiǎn)是:若主機(jī)發(fā)生異常重啟,會(huì)丟失最近N個(gè)事務(wù)的binlog日志。

      redo log的寫入機(jī)制

      接下來,我們?cè)僬f說redo log的寫入機(jī)制。

      事務(wù)在執(zhí)行過程中,生成的redo log是要先寫到redo log buffer的。

      那redo log buffer的內(nèi)容,是不是每次生成后都要直接持久化到磁盤呢?

      不需要。

      若事務(wù)執(zhí)行期間Mysql異常重啟,那這部分日志就丟了。由于事務(wù)也尚未提交,所以這時(shí)日志丟了也沒有損失。

      那事務(wù)還沒提交時(shí),redo log buffer中的部分日志有沒有可能被持久化到磁盤呢?

      會(huì)有。

      這個(gè)問題,要從redo log可能存在的三種狀態(tài)說起。這三種狀態(tài),對(duì)應(yīng)的就是圖2 中的三個(gè)顏色塊。

      MySQL redo log存儲(chǔ)狀態(tài)

      TODO

      三種狀態(tài):

      存在redo log buffer

      物理上是在MySQL進(jìn)程內(nèi)存

      寫到磁盤(write),但還沒持久化(fsync)

      物理上是在文件系統(tǒng)的page cache

      持久化到磁盤,即hard disk

      日志寫到redo log buffer很快,wirte到page cache也差不多,但持久化到磁盤就很慢了。

      InnoDB提供innodb_flush_log_at_trx_commit參數(shù)控制redo log的寫入策略:

      0,每次事務(wù)提交時(shí)都只是把redo log留在redo log buffer中

      1,每次事務(wù)提交時(shí)都將redo log直接持久化到磁盤

      2,每次事務(wù)提交時(shí)都只是把redo log寫到page cache

      InnoDB的一個(gè)后臺(tái)線程,會(huì)每隔1s把redo log buffer中的日志,調(diào)用write寫到文件系統(tǒng)的page cache,然后調(diào)用fsync持久化到磁盤。

      事務(wù)執(zhí)行中間過程的redo log也是直接寫在redo log buffer,這些redo log也會(huì)被后臺(tái)線程一起持久化到磁盤。即一個(gè)沒有提交的事務(wù)的redo log,也可能已經(jīng)持久化到磁盤。

      除了后臺(tái)線程每s一次的輪詢操作,還有兩種場(chǎng)景會(huì)讓一個(gè)未提交的事務(wù)的redo log寫入磁盤:

      redo log buffer占用的空間即將達(dá)到 innodb_log_buffer_size的一半,后臺(tái)線程會(huì)主動(dòng)寫盤

      由于這個(gè)事務(wù)并未提交,所以這個(gè)寫盤動(dòng)作只是write,沒有調(diào)用fsync,即只留在文件系統(tǒng)的page cache。

      并行的事務(wù)提交時(shí),順帶將該事務(wù)的redo log buffer持久化到磁盤

      假設(shè)一個(gè)事務(wù)A執(zhí)行到一半,已經(jīng)寫了一些redo log到buffer,這時(shí)另外一個(gè)線程的事務(wù)B提交,若innodb_flush_log_at_trx_commit是1,則事務(wù)B要把redo log buffer里的日志全部持久化到磁盤。這時(shí),就會(huì)帶上事務(wù)A在redo log buffer里的日志一起持久化到磁盤。

      兩階段提交的過程,時(shí)序上redo log先prepare,再寫binlog,最后再把redo log commit。

      若把innodb_flush_log_at_trx_commit置1,則redo log在prepare階段就要持久化一次,因?yàn)橛幸粋€(gè)崩潰恢復(fù)邏輯是要依賴于prepare 的redo log,再加上binlog來恢復(fù)的。

      每s一次的后臺(tái)輪詢刷盤,再加上崩潰恢復(fù),InnoDB就認(rèn)為redo log在commit時(shí)無需fsync,只write到文件系統(tǒng)的page cache就夠了。

      通常我們說MySQL的“雙1”配置,指的就是sync_binlog、innodb_flush_log_at_trx_commit都是1。即一個(gè)事務(wù)完整提交前,需要等待兩次刷盤:

      redo log(prepare 階段)

      binlog

      那這意味著我從MySQL看到TPS是2w,每秒就會(huì)寫四萬次磁盤。但我用工具測(cè)試,磁盤能力也就2w左右,怎么能實(shí)現(xiàn)2w TPS?

      得用組提交(group commit)來解釋了。

      日志邏輯序列號(hào)(log sequence number,LSN)

      LSN單調(diào)遞增,對(duì)應(yīng)redo log的寫入點(diǎn)。比如寫入length長(zhǎng)度的redo log, 則LSN+length。

      LSN也會(huì)寫到InnoDB的數(shù)據(jù),以確保數(shù)據(jù)頁(yè)不會(huì)被多次執(zhí)行重復(fù)的redo log。

      如圖3所示,是三個(gè)并發(fā)事務(wù)(trx1, trx2, trx3)在prepare 階段,都寫完redo log buffer,持久化到磁盤的過程,對(duì)應(yīng)的LSN分別是50、120 和160。

      redo log 組提交

      TODO

      trx1第一個(gè)到達(dá),被選為這組的leader

      等trx1要開始寫盤,組里已經(jīng)有了三個(gè)事務(wù),LSN也變成了160

      trx1去寫盤時(shí),帶的就是LSN=160。所以,等trx1返回時(shí),所有LSN≤160的redo log,都已被持久化到磁盤

      這時(shí),trx2和trx3就可直接返回

      所以,一次組提交里,組員越多,節(jié)約磁盤IOPS效果越好。但若只有單線程壓測(cè),則只能老老實(shí)實(shí)地一個(gè)事務(wù)對(duì)應(yīng)一次持久化操作。

      在并發(fā)更新場(chǎng)景下,第一個(gè)事務(wù)寫完redo log buffer后,接下來這個(gè)fsync越晚調(diào)用,組員可能越多,節(jié)約IOPS效果越好。

      為了讓一次fsync帶的組員更多,MySQL采取優(yōu)化:拖時(shí)間。

      兩階段提交

      寫binlog實(shí)際上分成兩步:

      先把binlog從binlog cache中寫到磁盤上的binlog文件

      調(diào)用fsync持久化

      MySQL為了讓組提交效果更好,把redo log做fsync的時(shí)間拖到了step1后面:

      兩階段提交細(xì)化

      這樣的話,binlog也可以組提交。上圖的step4時(shí),若有多個(gè)事務(wù)的binlog已經(jīng)寫完,也是一起持久化的,這樣也能減少IOPS。

      一般step3執(zhí)行很快,所以binlog的write、fsync間隔時(shí)間很短,導(dǎo)致能集合到一起持久化的binlog較少,因此binlog的組提交的效果通常不如redo log的效果。

      若想提升binlog組提交效果,可設(shè)置:

      binlog_group_commit_sync_delay參數(shù)

      延遲多少微秒后才調(diào)用fsync

      binlog_group_commit_sync_no_delay_count參數(shù)

      累積多少次以后才調(diào)用fsync

      這兩個(gè)條件是或的關(guān)系,即只要有一個(gè)滿足條件就會(huì)調(diào)用fsync。

      這樣的話,binlog_group_commit_sync_delay = 0 時(shí),binlog_group_commit_sync_no_delay_count就無效了。

      WAL是減少磁盤寫,可每次提交事務(wù)都要寫redo log和binlog,這磁盤的讀寫次數(shù)也沒變少呀?s所以現(xiàn)在就能理解了,WAL主要得益于:

      redo log 和 binlog都是順序?qū)?,磁盤的順序?qū)懕入S機(jī)寫速度要快

      組提交機(jī)制,可大幅度降低磁盤IOPS

      所以,若MySQL出現(xiàn)IO性能瓶頸,可通過如下方法優(yōu)化:

      設(shè)置 binlog_group_commit_sync_delay 、binlog_group_commit_sync_no_delay_count,減少binlog寫盤次數(shù)

      該方案是基于“額外的故意等待”來實(shí)現(xiàn)的,因此可能會(huì)增加語(yǔ)句的響應(yīng)時(shí)間,但不會(huì)丟數(shù)據(jù)

      將sync_binlog 設(shè)為大于1的值(推薦100~1000)

      風(fēng)險(xiǎn)是,主機(jī)掉電時(shí)會(huì)丟binlog日志。

      將innodb_flush_log_at_trx_commit設(shè)為2

      風(fēng)險(xiǎn)是,主機(jī)掉電的時(shí)候會(huì)丟數(shù)據(jù)。

      不推薦把innodb_flush_log_at_trx_commit 設(shè)成0。因?yàn)榇藭r(shí)表示redo log只保存在內(nèi)存,這樣MySQL本身異常重啟也會(huì)丟數(shù)據(jù),風(fēng)險(xiǎn)太大。而redo log寫到文件系統(tǒng)的page cache的速度是很快的,所以將該參數(shù)設(shè)成2跟設(shè)成0性能差不多,但這樣做MySQL異常重啟時(shí)就不會(huì)丟數(shù)據(jù)了。

      小結(jié)

      MySQL是“怎么保證redo log和binlog是完整的”。

      crash-safe

      執(zhí)行一個(gè)update后,再執(zhí)行hexdump直接查看ibd文件內(nèi)容,為什么沒有看到數(shù)據(jù)有改變?

      可能因?yàn)閃AL。update語(yǔ)句執(zhí)行完后,InnoDB只保證寫完了redo log、內(nèi)存,可能還沒來得及將數(shù)據(jù)寫磁盤。

      為什么binlog cache是每個(gè)線程自己維護(hù)的,而redo log buffer是全局共用?

      binlog不能“被打斷”。一個(gè)事務(wù)的binlog必須連續(xù)寫,因此要整個(gè)事務(wù)完成后,再一起寫到文件。

      而redo log沒有這個(gè)要求,中間有生成的日志可以寫到redo log buffer。redo log buffer中的內(nèi)容還能“搭便車”,其他事務(wù)提交的時(shí)候可以被一起寫到磁盤。

      事務(wù)執(zhí)行期間,還沒到提交階段,若發(fā)生crash,redo log肯定丟了,這會(huì)不會(huì)導(dǎo)致主備不一致呢?

      MySQL會(huì)丟數(shù)據(jù)嗎?

      不會(huì)。因?yàn)榇藭r(shí)binlog還在binlog cache,沒發(fā)給備庫(kù)。crash之后,redo log和binlog都沒有了,從業(yè)務(wù)角度看這個(gè)事務(wù)也沒有提交,所以數(shù)據(jù)是一致的。

      若binlog寫完盤以后發(fā)生crash,這時(shí)還沒給客戶端答復(fù)就重啟了。等客戶端再重連進(jìn)來,發(fā)現(xiàn)事務(wù)已經(jīng)提交成功了,這是不是bug?

      不是。設(shè)想一下更極端場(chǎng)景,整個(gè)事務(wù)都提交成功,redo log commit完成了,備庫(kù)也收到binlog并執(zhí)行了。但主庫(kù)和客戶端網(wǎng)絡(luò)斷了,導(dǎo)致事務(wù)成功的包返回不回去,這時(shí)客戶端也會(huì)收到“網(wǎng)絡(luò)斷開”的異常。這種也只能算是事務(wù)成功的,不能認(rèn)為是bug。

      實(shí)際上DB的crash-safe保證的是:

      如果客戶端收到事務(wù)成功的消息,事務(wù)就一定持久化了

      如果客戶端收到事務(wù)失?。ū热缰麈I沖突、回滾等)的消息,事務(wù)就一定失敗了

      如果客戶端收到“執(zhí)行異?!钡南?,應(yīng)用需要重連后通過查詢當(dāng)前狀態(tài)來繼續(xù)后續(xù)的邏輯。此時(shí)DB只需要保證內(nèi)部(數(shù)據(jù)和日志之間,主庫(kù)和備庫(kù)之間)一致即可。

      MySQL

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:Word2013文檔中插入分隔符(分節(jié)符)的方法(Word文檔分隔符)
      下一篇:【云享專家公開課】Lesson 3:以 Scrapyd為例詳解Python項(xiàng)目操作
      相關(guān)文章
      毛片亚洲AV无码精品国产午夜| 在线观看亚洲AV每日更新无码| 99亚偷拍自图区亚洲| 久久久亚洲AV波多野结衣 | 国外亚洲成AV人片在线观看| 国产亚洲综合视频| 苍井空亚洲精品AA片在线播放 | 久久亚洲国产成人精品无码区| 一区二区三区亚洲视频| 国产亚洲午夜精品| 国产精品久久亚洲一区二区| 国产亚洲精品美女久久久久| 亚洲风情亚Aⅴ在线发布| 亚洲youwu永久无码精品| 亚洲欧美日韩综合久久久| 亚洲国产精品无码久久| 亚洲AV无码一区二区三区牲色| 九九精品国产亚洲AV日韩| 亚洲AV日韩精品一区二区三区| mm1313亚洲精品国产| 亚洲精品专区在线观看| 中文字幕亚洲综合久久菠萝蜜| 亚洲人成人网站色www| 亚洲VA中文字幕无码毛片| 亚洲成在人天堂一区二区| 亚洲人成在线电影| 亚洲视频免费在线观看| 亚洲精品国产手机| 亚洲精品人成网在线播放影院| 亚洲永久网址在线观看| 精品久久久久亚洲| 国产精品亚洲mnbav网站 | 国产成人精品亚洲日本在线| 亚洲日韩精品无码专区加勒比☆| 中文无码亚洲精品字幕| 国产精品亚洲综合一区在线观看| 亚洲精品成人网久久久久久| 亚洲色中文字幕无码AV| 亚洲欧洲日韩不卡| 亚洲国产激情在线一区| 久久久亚洲精华液精华液精华液|