成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)

本篇文章帶大家了解一下MySQL的相關(guān)知識(shí),深入聊聊MySQL基礎(chǔ)架構(gòu)與日志系統(tǒng),希望對(duì)大家有所幫助!

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)

一、MySQL基礎(chǔ)架構(gòu)

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)
MySQL可以分為Server層和存儲(chǔ)引擎層兩部分

Server層包括連接器、查詢(xún)緩存、分析器、優(yōu)化器、執(zhí)行器等,涵蓋MySQL的大多數(shù)核心服務(wù)功能,以及所有的內(nèi)置函數(shù)(如日期、時(shí)間、數(shù)學(xué)和加密函數(shù)等),所有跨存儲(chǔ)引擎的功能都在這一層實(shí)現(xiàn),比如存儲(chǔ)過(guò)程、觸發(fā)器、視圖等

存儲(chǔ)引擎負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和提取。其架構(gòu)模式是插件式的,支持InnoDB、MyISAM、Memory等多個(gè)存儲(chǔ)引擎。現(xiàn)在最常用的存儲(chǔ)引擎是InnoDB,它從MySQL 5.5.5版本開(kāi)始成為了默認(rèn)存儲(chǔ)引擎。可以通過(guò)在SQL語(yǔ)句中使用engin=memory來(lái)指定使用內(nèi)存引擎執(zhí)行

不同的存儲(chǔ)引擎共用一個(gè)Server層

1、連接器

連接器負(fù)責(zé)跟客戶(hù)端建立連接、獲取權(quán)限、維持和管理連接。連接命令一般是:

mysql -h$ip -P$port -u$user -p

連接命令中的mysql是客戶(hù)端工具,用來(lái)跟服務(wù)端建立連接。在完成TCP握手后,連接器就要開(kāi)始認(rèn)證身份

  • 如果用戶(hù)名或密碼不對(duì),就會(huì)收到一個(gè)"Access denied for user"的錯(cuò)誤,然后客戶(hù)端程序結(jié)束執(zhí)行
  • 如果用戶(hù)名密碼認(rèn)證通過(guò),連接器回到權(quán)限表里面查出你擁有的權(quán)限。之后,這個(gè)連接里面的權(quán)限判斷邏輯,都將依賴(lài)于此時(shí)讀到的權(quán)限

這就意味著,一個(gè)用戶(hù)成功建立連接后,即使用管理員帳號(hào)對(duì)這個(gè)用戶(hù)的權(quán)限做了修改,也不會(huì)影響已經(jīng)存在連接的權(quán)限。修改完成后,只有再新建的連接才會(huì)使用新的權(quán)限設(shè)置

連接完成后,如果你沒(méi)有后續(xù)的動(dòng)作,這個(gè)連接就處于空閑狀態(tài),可以在show processlist命令中看到它

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)

Command為Sleep表示此連接是一個(gè)空閑連接

客戶(hù)端如果太長(zhǎng)時(shí)間沒(méi)動(dòng)靜,連接器就會(huì)自動(dòng)將它斷開(kāi)。這個(gè)時(shí)間是由參數(shù)wait_timeout控制的。默認(rèn)值是8小時(shí)

如果在連接被斷開(kāi)之后,客戶(hù)端再次發(fā)送請(qǐng)求的話(huà),就會(huì)收到一個(gè)錯(cuò)誤提示:Lost connection to MySQL server during query。這時(shí)候就需要重新連接,然后在執(zhí)行請(qǐng)求了

數(shù)據(jù)庫(kù)里面,長(zhǎng)連接是指連接成功后,如果客戶(hù)端持續(xù)有請(qǐng)求,則一直使用同一個(gè)連接。短連接則是指每次執(zhí)行完很少的幾次查詢(xún)就斷開(kāi)連接,下次查詢(xún)?cè)僦匦陆⒁粋€(gè)

建立連接的過(guò)程通常是比較復(fù)雜的,所以建議盡量使用長(zhǎng)連接

但是全部使用長(zhǎng)連接后,有些時(shí)候MySQL占用內(nèi)存漲得特別快,這是因?yàn)镸ySQL在執(zhí)行過(guò)程中臨時(shí)使用的內(nèi)存是管理在連接對(duì)象里面的。這些資源會(huì)在連接斷開(kāi)的時(shí)候才釋放。所以如果長(zhǎng)連接累計(jì)下來(lái),可能導(dǎo)致內(nèi)存占用太大,被系統(tǒng)強(qiáng)行殺掉(OOM),從現(xiàn)象看就是MySQL異常重啟了

可以通過(guò)以下兩種方案解決這個(gè)問(wèn)題:

1.定期斷開(kāi)長(zhǎng)連接。使用一段時(shí)間,或者程序里面判斷執(zhí)行過(guò)一個(gè)占用內(nèi)存的大查詢(xún)后,斷開(kāi)連接,之后要查詢(xún)?cè)僦剡B

2.如果使用的是MySQL5.7或更新版本,可以在每次執(zhí)行一個(gè)比較大的操作后,通過(guò)執(zhí)行mysql_reset_connection來(lái)重新初始化連接資源。這個(gè)過(guò)程不需要重連和重新做權(quán)限驗(yàn)證,但是會(huì)將連接恢復(fù)到剛剛創(chuàng)建完時(shí)的狀態(tài)

2、查詢(xún)緩存

建立連接完成后,可以執(zhí)行select語(yǔ)句了。MySQL拿到一個(gè)查詢(xún)請(qǐng)求后,會(huì)先到查詢(xún)緩存看看,之前是不是執(zhí)行過(guò)這條語(yǔ)句。之前執(zhí)行過(guò)的語(yǔ)句及其結(jié)果可能會(huì)以key-value對(duì)的形式,被直接緩存在內(nèi)存中。key是查詢(xún)的語(yǔ)句,value是查詢(xún)的結(jié)果。如果查詢(xún)能夠直接在這個(gè)緩存中找到key,那么這個(gè)value就會(huì)被直接返回給客戶(hù)端

如果語(yǔ)句不在查詢(xún)緩存中,就會(huì)繼續(xù)后面的執(zhí)行階段。執(zhí)行完成后,執(zhí)行結(jié)果會(huì)被存入查詢(xún)緩存中。如果查詢(xún)命中緩存,MySQL不需要執(zhí)行后面的復(fù)雜操作,就可以直接返回結(jié)果,這個(gè)效率很高

但是大多數(shù)情況下不建議使用查詢(xún)緩存,因?yàn)椴樵?xún)緩存的失效非常頻繁,只要對(duì)一個(gè)表的更新,這個(gè)表上所有的查詢(xún)緩存都會(huì)被清空。對(duì)于更新壓力大的數(shù)據(jù)庫(kù)來(lái)說(shuō),查詢(xún)緩存的命中率會(huì)非常低

可以將參數(shù)query_cache_type設(shè)置成DEMAND,這樣對(duì)于默認(rèn)的SQL語(yǔ)句都不使用查詢(xún)緩存。而對(duì)于確定要是查詢(xún)緩存的語(yǔ)句,可以用SQL_CACHE顯示指定,如下面這條語(yǔ)句一樣:

select SQL_CACHE * from T where ID=10;

MySQL8.0版本直接將查詢(xún)緩存的整塊功能刪掉了

3、分析器

如果沒(méi)有命中查詢(xún)緩存,就要開(kāi)始真正執(zhí)行語(yǔ)句了。MySQL首先要對(duì)SQL語(yǔ)句做解析

分析器會(huì)先做詞法分析。輸入的是由多個(gè)字符串和空格組成的一條SQL語(yǔ)句,MySQL需要識(shí)別出里面的字符串分別是什么,代表什么

select * from T where ID=10;

MySQL從輸入的select這個(gè)關(guān)鍵字識(shí)別出來(lái),這是一個(gè)查詢(xún)語(yǔ)句。它也要把字符串T識(shí)別成表名T,把字符串ID識(shí)別成列ID

做完了這些識(shí)別以后,就要做語(yǔ)法分析。根據(jù)詞法分析的結(jié)果,語(yǔ)法分析器會(huì)根據(jù)語(yǔ)法規(guī)則,判斷這個(gè)SQL語(yǔ)句是否滿(mǎn)足MySQL語(yǔ)法。如果語(yǔ)法不對(duì),就會(huì)收到"You have an error in your SQL syntax"的錯(cuò)誤提示

4、優(yōu)化器

經(jīng)過(guò)了分析器,在開(kāi)始執(zhí)行之前,還要先經(jīng)過(guò)優(yōu)化器的處理

優(yōu)化器是在表里面有多個(gè)索引的時(shí)候,決定使用哪個(gè)索引;或者在一個(gè)語(yǔ)句有多表關(guān)聯(lián)的時(shí)候,決定各個(gè)表的連接順序

5、執(zhí)行器

優(yōu)化器階段完成后,這個(gè)語(yǔ)句的執(zhí)行方案就確定下來(lái)了,然后進(jìn)入執(zhí)行器階段,開(kāi)始執(zhí)行語(yǔ)句

開(kāi)始執(zhí)行的時(shí)候,要先判斷一下你對(duì)這個(gè)表T有沒(méi)有執(zhí)行查詢(xún)的權(quán)限,如果沒(méi)有,就會(huì)返回沒(méi)有權(quán)限的錯(cuò)誤,如下所示

mysql> select * from T where ID=10; ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

如果有權(quán)限,就打開(kāi)表繼續(xù)執(zhí)行。打開(kāi)表的時(shí)候,執(zhí)行器就會(huì)根據(jù)表的引擎定義,去使用這個(gè)引擎提供的接口

比如在表T中,ID字段沒(méi)有索引,那么執(zhí)行器的執(zhí)行流程是這樣的:

1.調(diào)用InnoDB引擎接口取這個(gè)表的第一行,判斷ID值是不是10,如果不是則跳過(guò),如果是則將這個(gè)行存在結(jié)果集中

2.調(diào)用引擎接口取下一行,重復(fù)相同的判斷邏輯,直到取到這個(gè)表的最后一行

3.執(zhí)行器將上述遍歷過(guò)程中所有滿(mǎn)足條件的行組成的記錄集作為結(jié)果集返回給客戶(hù)端

在數(shù)據(jù)庫(kù)的慢查詢(xún)?nèi)罩局锌吹揭粋€(gè)rows_examined的字段,表示這個(gè)語(yǔ)句執(zhí)行過(guò)程掃描了多少行。這個(gè)值就是在執(zhí)行器每次調(diào)用引擎獲取數(shù)據(jù)行的時(shí)候累加的

在有些場(chǎng)景下,執(zhí)行器調(diào)用一次,在引起內(nèi)部則掃描了多行,因此引擎掃描行數(shù)跟rows_examined并不是完全相同的

二、日志系統(tǒng)

表T的創(chuàng)建語(yǔ)句如下,這個(gè)表有一個(gè)主鍵ID和一個(gè)整型字段c:

create table T(ID int primary key, c int);

如果要將ID=2這一行的值加1,SQL語(yǔ)句如下:

update T set c=c+1 where ID=2;

1、redo log(重做日志)

在MySQL中,如果每次的更新操作都需要寫(xiě)進(jìn)磁盤(pán),然后磁盤(pán)也要找到對(duì)應(yīng)的那條記錄,然后再更新,整個(gè)過(guò)程IO成本、查找成本都很高。MySQL里常說(shuō)的WAL技術(shù),全稱(chēng)是Write-Ahead Logging,它的關(guān)鍵點(diǎn)就是先寫(xiě)日志,再寫(xiě)磁盤(pán)

當(dāng)有一條記錄需要更新的時(shí)候,InnoDB引擎就會(huì)把記錄寫(xiě)到redo log里面,并更新buffer pool的page,這個(gè)時(shí)候更新就算完成了

buffer pool是物理頁(yè)的緩存,對(duì)InnoDB的任何修改操作都會(huì)首先在buffer pool的page上進(jìn)行,然后這樣的頁(yè)面將被標(biāo)記為臟頁(yè)并被放到專(zhuān)門(mén)的flush list上,后續(xù)將由專(zhuān)門(mén)的刷臟線程階段性的將這些頁(yè)面寫(xiě)入磁盤(pán)

InnoDB的redo log是固定大小的,比如可以配置為一組4個(gè)文件,每個(gè)文件的大小是1GB,從頭開(kāi)始寫(xiě),寫(xiě)到末尾就又回到開(kāi)頭循環(huán)寫(xiě)

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)
write pos是當(dāng)前記錄的位置,一邊寫(xiě)一邊后移,寫(xiě)到第3號(hào)文件末尾后就回到0號(hào)文件開(kāi)頭。check point是當(dāng)前要擦除的位置,也是往后推移并且循環(huán)的,擦除記錄前要把記錄更新到數(shù)據(jù)文件

write pos和check point之間空著的部分,可以用來(lái)記錄新的操作。如果write pos追上check point,這時(shí)候不能再執(zhí)行新的更新,需要停下來(lái)擦掉一些記錄,把check point推進(jìn)一下

有了redo log,InnoDB就可以保證即使數(shù)據(jù)庫(kù)發(fā)生異常重啟,之前提交的記錄都不會(huì)丟失,這個(gè)能力稱(chēng)為crash-safe

2、binlog(歸檔日志)

MySQL整體來(lái)看就有兩塊:一塊是Server層,主要做的是MySQL功能層面的事情;還有一塊是引擎層,負(fù)責(zé)存儲(chǔ)相關(guān)的具體事宜。redo log是InnoDB引擎特有的日志,而Server層也有自己的日志,稱(chēng)為binlog

為什么會(huì)有兩份日志?

因?yàn)樽铋_(kāi)始MySQL里并沒(méi)有InnoDB引擎。MySQL自帶的引擎是MyISAM,但是MyISAM沒(méi)有crash-safe的能力,binlog日志只能用于歸檔。而InnoDB是以插件形式引入MySQL的,既然只依靠binlog是沒(méi)有crash-safe能力的,所以InnoDB使用redo log來(lái)實(shí)現(xiàn)crash-safe能力

binlog的日志格式:

binlog的格式有三種:STATEMENT,ROW,MIXED

1)、STATEMENT模式

binlog里面記錄的就是SQL語(yǔ)句的原文。優(yōu)點(diǎn)是并不需要記錄每一行的數(shù)據(jù)變化,減少了binlog日志量,節(jié)約IO,提高性能。缺點(diǎn)是在某些情況下會(huì)導(dǎo)致master-slave中的數(shù)據(jù)不一致(如sleep()函數(shù), last_insert_id(),以及user-defined functions(udf)等會(huì)出現(xiàn)問(wèn)題)

2)、ROW模式

不記錄每條SQL語(yǔ)句的上下文信息,僅需記錄哪條數(shù)據(jù)被修改了,修改成什么樣了。而且不會(huì)出現(xiàn)某些特定情況下的存儲(chǔ)過(guò)程或function或trigger的調(diào)用和觸發(fā)無(wú)法被正確復(fù)制的問(wèn)題。缺點(diǎn)是會(huì)產(chǎn)生大量的日志,尤其是alter table的時(shí)候會(huì)讓日志暴漲

3)、MIXED模式

以上兩種模式的混合使用,一般的復(fù)制使用STATEMENT模式保存binlog,對(duì)于STATEMENT模式無(wú)法復(fù)制的操作使用ROW模式保存binlog,MySQL會(huì)根據(jù)執(zhí)行的SQL語(yǔ)句選擇日志保存方式

3、redo log和binlog日志的不同

1.redo log是InnoDB引擎特有的;binlog是MySQL的Server層實(shí)現(xiàn)的,所有引擎都可以使用

2.redo log是物理日志,記錄的是在某個(gè)數(shù)據(jù)也上做了什么修改;binlog是邏輯日志,記錄的是這個(gè)語(yǔ)句的原始邏輯,比如給ID=2這一行的c字段加1

3.redo log是循環(huán)寫(xiě)的,空間固定會(huì)用完;binlog是可以追加寫(xiě)入的,binlog文件寫(xiě)到一定大小后會(huì)切換到下一個(gè),并不會(huì)覆蓋以前的日志

4、兩階段提交

執(zhí)行器和InnoDB引擎在執(zhí)行這個(gè)update語(yǔ)句時(shí)的內(nèi)部流程:

1.執(zhí)行器先找到引擎取ID=2這一行。ID是主鍵,引擎直接用樹(shù)搜索找到這一行。如果ID=2這一行所在的數(shù)據(jù)也本來(lái)就在內(nèi)存中,就直接返回給執(zhí)行器;否則,需要先從磁盤(pán)讀入內(nèi)存,然后再返回

2.執(zhí)行器拿到引擎給的行數(shù)據(jù),把這個(gè)值加上1,得到新的一行數(shù)據(jù),再調(diào)用引擎接口寫(xiě)入這行新數(shù)據(jù)

3.引擎將這行新數(shù)據(jù)更新到內(nèi)存中,同時(shí)將這個(gè)更新操作記錄到redo log里面,此時(shí)redo log處于prepare狀態(tài)。然后告知執(zhí)行器執(zhí)行完成了,隨時(shí)可以提交事務(wù)

4.執(zhí)行器生成這個(gè)操作的binlog,并把binlog寫(xiě)入磁盤(pán)

5.執(zhí)行器調(diào)用引擎的提交事務(wù)接口,引擎把剛剛寫(xiě)入的redo log改成提交狀態(tài),更新完成

update語(yǔ)句的執(zhí)行流程圖如下,圖中淺色框表示在InnoDB內(nèi)部執(zhí)行的,深色框表示是在執(zhí)行器中執(zhí)行的

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)

將redo log的寫(xiě)入拆成了兩個(gè)步驟:prepare和commit,這就是兩階段提交

由于redo log和binlog是兩個(gè)獨(dú)立的邏輯,如果不用兩階段提交,要么就是先寫(xiě)完redo log再寫(xiě)binlog,或者先寫(xiě)完binlog再寫(xiě)redo log

1.先寫(xiě)完redo log再寫(xiě)binlog。如果在redo log寫(xiě)完,binlog還沒(méi)有寫(xiě)完的時(shí)候,MySQL進(jìn)程異常重啟。由于redo log寫(xiě)完之后,系統(tǒng)即使崩潰,仍然能夠把數(shù)據(jù)恢復(fù)回來(lái),所以恢復(fù)后這一行c的值是1。但是由于binlog還沒(méi)寫(xiě)完就crash了,這時(shí)候binlog里面就沒(méi)有記錄這個(gè)語(yǔ)句,binlog中記錄的這一行c的值為0

2.先寫(xiě)binlog后寫(xiě)redo log。如果在binlog寫(xiě)完之后crash,由于redo log還沒(méi)寫(xiě),崩潰恢復(fù)以后這個(gè)事務(wù)無(wú)效,所以這一行的c的值是0。但是binlog里面已經(jīng)記錄了把c從0改成1這個(gè)日志。所以,在之后binlog來(lái)恢復(fù)的時(shí)候就多了一個(gè)事務(wù)出來(lái),恢復(fù)出來(lái)的這一行c的值就是1

如果不使用兩階段提交,那么數(shù)據(jù)庫(kù)的狀態(tài)就有可能和用它的日志恢復(fù)出來(lái)的庫(kù)的狀態(tài)不一致。redo log和binlog都可以用于表示事務(wù)的提交狀態(tài),而兩階段提交就是讓這兩個(gè)狀態(tài)保持邏輯上的一致

redo log用于保證crash-safe能力。innodb_flush_log_at_trx_commit這個(gè)參數(shù)設(shè)置成1的時(shí)候,表示每次事務(wù)的redo log都直接持久化到磁盤(pán),這樣可以保證MySQL異常重啟之后數(shù)據(jù)不丟失

sync_binlog這個(gè)參數(shù)設(shè)置成1的時(shí)候,表示每次事務(wù)的binlog都持久化到磁盤(pán),這樣可以保證MySQL異常重啟之后binlog不丟失

三、MySQL刷臟頁(yè)

1、刷臟頁(yè)的場(chǎng)景

當(dāng)內(nèi)存數(shù)據(jù)頁(yè)跟磁盤(pán)數(shù)據(jù)頁(yè)不一致的時(shí)候,我們稱(chēng)這個(gè)內(nèi)存頁(yè)為臟頁(yè)。內(nèi)存數(shù)據(jù)寫(xiě)入到磁盤(pán)后,內(nèi)存和磁盤(pán)行的數(shù)據(jù)頁(yè)的內(nèi)容就一致了,稱(chēng)為干凈頁(yè)

  • 第一種場(chǎng)景是,InnoDB的redo log寫(xiě)滿(mǎn)了,這時(shí)候系統(tǒng)會(huì)停止所有更新操作,把checkpoint往前推進(jìn),redo log留出空間可以繼續(xù)寫(xiě)
    聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)
    checkpoint位置從CP推進(jìn)到CP’,就需要將兩個(gè)點(diǎn)之間的日志對(duì)應(yīng)的所有臟頁(yè)都flush到磁盤(pán)上。之后,上圖中從write pos到CP’之間就是可以再寫(xiě)入的redo log的區(qū)域

  • 第二種場(chǎng)景是,系統(tǒng)內(nèi)存不足。當(dāng)需要新的內(nèi)存頁(yè),而內(nèi)存不夠用的時(shí)候,就要淘汰一些數(shù)據(jù)頁(yè),空出內(nèi)存給別的數(shù)據(jù)頁(yè)使用。如果淘汰的是臟頁(yè),就要先將臟頁(yè)寫(xiě)到磁盤(pán)

這時(shí)候不能直接把內(nèi)存淘汰掉,下次需要請(qǐng)求的時(shí)候,從磁盤(pán)讀入數(shù)據(jù)頁(yè),然后拿redo log出來(lái)應(yīng)用不就行了?

這里是從性能考慮的。如果刷臟頁(yè)一定會(huì)寫(xiě)盤(pán),就保證了每個(gè)數(shù)據(jù)頁(yè)有兩種狀態(tài):一種是內(nèi)存里存在,內(nèi)存里就肯定是正確的結(jié)果,直接返回;另一種是內(nèi)存里沒(méi)有數(shù)據(jù),就可以肯定數(shù)據(jù)文件上是正確的結(jié)果,讀入內(nèi)存后返回。這樣的效率最高

  • 第三種場(chǎng)景是,MySQL認(rèn)為系統(tǒng)空閑的時(shí)候刷臟頁(yè),當(dāng)然在系統(tǒng)忙的時(shí)候也要找時(shí)間刷一點(diǎn)臟頁(yè)
  • 第四種場(chǎng)景是,MySQL正常關(guān)閉的時(shí)候會(huì)把內(nèi)存的臟頁(yè)都flush到磁盤(pán)上,這樣下次MySQL啟動(dòng)的時(shí)候,就可以直接從磁盤(pán)上讀數(shù)據(jù),啟動(dòng)速度會(huì)很快

redo log寫(xiě)滿(mǎn)了,要flush臟頁(yè),出現(xiàn)這種情況的時(shí)候,整個(gè)系統(tǒng)就不能再接受更新了,所有的更新都必須堵住

內(nèi)存不夠用了,要先將臟頁(yè)寫(xiě)到磁盤(pán),這種情況是常態(tài)。InnoDB用緩沖池管理內(nèi)存,緩沖池中的內(nèi)存頁(yè)有三種狀態(tài):

  • 第一種是還沒(méi)有使用的
  • 第二種是使用了并且是干凈頁(yè)
  • 第三種是使用了并且是臟頁(yè)

InnoDB的策略是盡量使用內(nèi)存,因此對(duì)于一個(gè)長(zhǎng)時(shí)間運(yùn)行的庫(kù)來(lái)說(shuō),未被使用的頁(yè)面很少

當(dāng)要讀入的數(shù)據(jù)頁(yè)沒(méi)有在內(nèi)存的時(shí)候,就必須到緩沖池中申請(qǐng)一個(gè)數(shù)據(jù)頁(yè)。這時(shí)候只能把最久不使用的數(shù)據(jù)頁(yè)從內(nèi)存中淘汰掉:如果要淘汰的是一個(gè)干凈頁(yè),就直接釋放出來(lái)復(fù)用;但如果是臟頁(yè),即必須將臟頁(yè)先刷到磁盤(pán),變成干凈頁(yè)后才能復(fù)用

刷頁(yè)雖然是常態(tài),但是出現(xiàn)以下兩種情況,都是會(huì)明顯影響性能的:

  • 一個(gè)查詢(xún)要淘汰的臟頁(yè)個(gè)數(shù)太多,會(huì)導(dǎo)致查詢(xún)的響應(yīng)時(shí)間明顯變長(zhǎng)
  • 日志寫(xiě)滿(mǎn),更新全部堵住,寫(xiě)性能跌為0,這種情況對(duì)敏感業(yè)務(wù)來(lái)說(shuō),是不能接受的

2、InnoDB刷臟頁(yè)的控制策略

首先,要正確地告訴InnoDB所在主機(jī)的IO能力,這樣InnoDB才能知道需要全力刷臟頁(yè)的時(shí)候,可以刷多快。參數(shù)為innodb_io_capacity,建議設(shè)置成磁盤(pán)的IOPS

InnoDB的刷盤(pán)速度就是考慮臟頁(yè)比例和redo log寫(xiě)盤(pán)速度。參數(shù)innodb_max_dirty_pages_pct是臟頁(yè)比例上限,默認(rèn)值是75%。臟頁(yè)比例是通過(guò)Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到的,SQL語(yǔ)句如下:

mysql>  select VARIABLE_VALUE into @a from performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty'; select VARIABLE_VALUE into @b from performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total'; select @a/@b;

四、日志相關(guān)問(wèn)題

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)

問(wèn)題一:在兩階段提交的不同時(shí)刻,MySQL異常重啟會(huì)出現(xiàn)什么現(xiàn)象

如果在圖中時(shí)刻A的地方,也就是寫(xiě)入redo log處于prepare階段之后、寫(xiě)binlog之前,發(fā)生了崩潰,由于此時(shí)binlog還沒(méi)寫(xiě),redo log也還沒(méi)提交,所以崩潰恢復(fù)的時(shí)候,這個(gè)事務(wù)會(huì)回滾。這時(shí)候,binlog還沒(méi)寫(xiě),所以也不會(huì)傳到備庫(kù)

如果在圖中時(shí)刻B的地方,也就是binlog寫(xiě)完,redo log還沒(méi)commit前發(fā)生崩潰,那崩潰恢復(fù)的時(shí)候MySQL怎么處理?

崩潰恢復(fù)時(shí)的判斷規(guī)則:

1)如果redo log里面的事務(wù)是完整的,也就是已經(jīng)有了commit標(biāo)識(shí),則直接提交

2)如果redo log里面的事務(wù)只有完整的prepare,則判斷對(duì)應(yīng)的事務(wù)binlog是否存在并完整

a.如果完整,則提交事務(wù)

b.否則,回滾事務(wù)

時(shí)刻B發(fā)生崩潰對(duì)應(yīng)的就是2(a)的情況,崩潰恢復(fù)過(guò)程中事務(wù)會(huì)被提交

問(wèn)題二:MySQL怎么知道binlog是完整的?

一個(gè)事務(wù)的binlog是有完整格式的:

  • statement格式的binlog,最后會(huì)有COMMIT
  • row格式的binlog,最后會(huì)有一個(gè)XID event

問(wèn)題三:redo log和binlog是怎么關(guān)聯(lián)起來(lái)的?

它們有一個(gè)共同的數(shù)據(jù)字段,叫XID。崩潰恢復(fù)的時(shí)候,會(huì)按順序掃描redo log:

  • 如果碰到既有prepare、又有commit的redo log,就直接提交
  • 如果碰到只有prepare、而沒(méi)有commit的redo log,就拿著XID去binlog找對(duì)應(yīng)的事務(wù)

問(wèn)題四:redo log一般設(shè)置多大?

如果是現(xiàn)在常見(jiàn)的幾個(gè)TB的磁盤(pán)的話(huà),redo log設(shè)置為4個(gè)文件、每個(gè)文件1GB

問(wèn)題五:正常運(yùn)行中的實(shí)例,數(shù)據(jù)寫(xiě)入后的最終落盤(pán),是從redo log更新過(guò)來(lái)的還是從buffer pool更新過(guò)來(lái)的呢?

redo log并沒(méi)有記錄數(shù)據(jù)頁(yè)的完整數(shù)據(jù),所以它并沒(méi)有能力自己去更新磁盤(pán)數(shù)據(jù)頁(yè),也就不存在數(shù)據(jù)最終落盤(pán)是由redo log更新過(guò)去的情況

1.如果是正常運(yùn)行的實(shí)例的話(huà),數(shù)據(jù)頁(yè)被修改以后,跟磁盤(pán)的數(shù)據(jù)頁(yè)不一致,稱(chēng)為臟頁(yè)。最終數(shù)據(jù)落盤(pán),就是把內(nèi)存中的數(shù)據(jù)頁(yè)寫(xiě)盤(pán)。這個(gè)過(guò)程,甚至與redo log毫無(wú)關(guān)系

2.在崩潰恢復(fù)場(chǎng)景中,InnoDB如果判斷到一個(gè)數(shù)據(jù)頁(yè)可能在崩潰恢復(fù)的時(shí)候丟失了更新,就會(huì)將它對(duì)到內(nèi)存,然后讓redo log更新內(nèi)存內(nèi)容。更新完成后,內(nèi)存頁(yè)變成臟頁(yè),就回到了第一種情況的狀態(tài)

問(wèn)題六:redo log buffer是什么?是先修改內(nèi)存,還是先寫(xiě)redo log文件?

在一個(gè)事務(wù)的更新過(guò)程中,日志是要寫(xiě)多次的。比如下面這個(gè)事務(wù):

begin;insert into t1 ...insert into t2 ...commit;

這個(gè)事務(wù)要往兩個(gè)表中插入記錄,插入數(shù)據(jù)的過(guò)程中,生成的日志都得先保存起來(lái),但又不能在還沒(méi)commit的時(shí)候就直接寫(xiě)到redo log文件里

所以,redo log buffer就是一塊內(nèi)存,用來(lái)先存redo日志的。也就是說(shuō),在執(zhí)行第一個(gè)insert的時(shí)候,數(shù)據(jù)的內(nèi)存被修改了,redo log buffer也寫(xiě)入了日志。但是,真正把日志寫(xiě)到redo log文件,是在執(zhí)行commit語(yǔ)句的時(shí)候做的

五、MySQL是怎么保證數(shù)據(jù)不丟的?

只要redo log和binlog保證持久化到磁盤(pán),就能確保MySQL異常重啟后,數(shù)據(jù)可以恢復(fù)

1、binlog的寫(xiě)入機(jī)制

事務(wù)執(zhí)行過(guò)程中,先把日志寫(xiě)到binlog cache,事務(wù)提交的時(shí)候,再把binlog cache寫(xiě)到binlog文件中。一個(gè)事務(wù)的binlog是不能被拆開(kāi)的,因此不論這個(gè)事務(wù)多大,也要確保一次性寫(xiě)入

系統(tǒng)給binlog cache分配了一片內(nèi)存,每個(gè)線程一個(gè),參數(shù)binlog_cache_size用于控制單個(gè)線程內(nèi)binlog cache所占內(nèi)存的大小。如果超過(guò)了這個(gè)參數(shù)規(guī)定的大小,就要暫存到磁盤(pán)

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

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)
每個(gè)線程有自己binlog cache,但是共用一份binlog文件

  • 圖中的write,指的就是把日志寫(xiě)入到文件系統(tǒng)的page cache,并沒(méi)有把數(shù)據(jù)持久化到磁盤(pán),所以速度比較快
  • 圖中的fsync,才是將數(shù)據(jù)持久化到磁盤(pán)的操作。一般情況下認(rèn)為fsync才占磁盤(pán)的IOPS

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

  • sync_binlog=0的時(shí)候,表示每次提交事務(wù)都只write,不fsync
  • sync_binlog=1的時(shí)候,表示每次提交事務(wù)都會(huì)執(zhí)行fsync
  • sync_binlog=N(N>1)的時(shí)候,表示每次提交事務(wù)都write,但累積N個(gè)事務(wù)后才fsync

因此,在出現(xiàn)IO瓶頸的場(chǎng)景中,將sync_binlog設(shè)置成一個(gè)比較大的值,可以提升性能,對(duì)應(yīng)的風(fēng)險(xiǎn)是:如果主機(jī)發(fā)生異常重啟,會(huì)丟失最近N個(gè)事務(wù)的binlog日志

2、redo log的寫(xiě)入機(jī)制

事務(wù)在執(zhí)行過(guò)程中,生成的redo log是要先寫(xiě)到redo log buffer的。redo log buffer里面的內(nèi)容不是每次生成后都要直接持久化到磁盤(pán),也有可能在事務(wù)還沒(méi)提交的時(shí)候,redo log buffer中的部分日志被持久化到磁盤(pán)

redo log可能存在三種狀態(tài),對(duì)應(yīng)下圖的三個(gè)顏色塊

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)

這三張狀態(tài)分別是:

  • 存在redo log buffer中,物理上是在MySQL進(jìn)程內(nèi)存中,就是圖中紅色的部分
  • 寫(xiě)到磁盤(pán),但是沒(méi)有持久化,物理上是在文件系統(tǒng)的page cache里面,也就是圖中黃色的部分
  • 持久化到磁盤(pán),對(duì)應(yīng)的是hard disk,也就是圖中的綠色部分

日志寫(xiě)到redo log buffer和write到page cache都是很快的,但是持久化到磁盤(pán)的速度就慢多了

為了控制redo log的寫(xiě)入策略,InnoDB提供了innodb_flush_log_at_trx_commit參數(shù),它有三種可能取值:

  • 設(shè)置為0的時(shí)候,表示每次事務(wù)提交時(shí)都只是把redo log留在redo log buffer中
  • 設(shè)置為1的時(shí)候,表示每次事務(wù)提交時(shí)都將redo log直接持久化到磁盤(pán)
  • 設(shè)置為2的時(shí)候,表示每次事務(wù)提交時(shí)都只是把redo log寫(xiě)到page cache

InnoDB有一個(gè)后臺(tái)線程,每隔1秒,就會(huì)把redo log buffer中的日志,調(diào)用write寫(xiě)到文件系統(tǒng)的page cache,然后調(diào)用fsync持久化到磁盤(pán)。事務(wù)執(zhí)行中間過(guò)程的redo log也是直接寫(xiě)在redo log buffer中的,這些redo log也會(huì)被后臺(tái)線程一起持久化到磁盤(pán)。也就是說(shuō),一個(gè)沒(méi)有提交的事務(wù)的redo log也是可能已經(jīng)持久化到磁盤(pán)的

還有兩種場(chǎng)景會(huì)讓一個(gè)沒(méi)有提交的事務(wù)的redo log寫(xiě)入到磁盤(pán)中

1.redo log buffer占用的空間即將達(dá)到innodb_log_buffer_size一半的時(shí)候,后臺(tái)線程會(huì)主動(dòng)寫(xiě)盤(pán)。由于事務(wù)并沒(méi)有提交,所以這個(gè)寫(xiě)盤(pán)動(dòng)作只是write,而沒(méi)有調(diào)用fsync,也就是只留在文件系統(tǒng)的page cache

2.并行的事務(wù)提交的時(shí)候,順帶將這個(gè)事務(wù)的redo log buffer持久化到磁盤(pán)。假設(shè)一個(gè)事務(wù)A執(zhí)行到一半,已經(jīng)寫(xiě)了一些redo log到buffer中,這時(shí)候有另外一個(gè)線程的事務(wù)B提交,如果innodb_flush_log_at_trx_commit設(shè)置的是1,事務(wù)B要把redo log buffer里的日志全部持久化到磁盤(pán)。這時(shí)候,就會(huì)帶上事務(wù)A在redo log buffer里的日志一起持久化到磁盤(pán)

兩階段提交,時(shí)序上redo log先prepare,再寫(xiě)binlog,最后再把redo log commit。如果把innodb_flush_log_at_trx_commit設(shè)置成1,那么redo log在prepare階段就要持久化一次

MySQL的雙1配置,指的就是sync_binlog和innodb_flush_log_at_trx_commit都設(shè)置成1。也就是說(shuō),一個(gè)事務(wù)完整提交前,需要等待兩次刷盤(pán),一次是redo log(prepare階段),一次是binlog

3、組提交機(jī)制

日志邏輯序列號(hào)LSN是單調(diào)遞增的,用來(lái)對(duì)應(yīng)redo log的一個(gè)個(gè)寫(xiě)入點(diǎn),每次寫(xiě)入長(zhǎng)度為length的redo log,LSN的值就會(huì)加上length。LSN也會(huì)寫(xiě)到InnoDB的數(shù)據(jù)頁(yè)中,來(lái)確保數(shù)據(jù)頁(yè)不會(huì)被多次執(zhí)行重復(fù)的redo log

聊聊MySQL的基礎(chǔ)架構(gòu)和日志系統(tǒng)
上圖是三個(gè)并發(fā)事務(wù)在prepare階段,都寫(xiě)完redo log buffer,持久化到磁盤(pán)的過(guò)程,對(duì)應(yīng)的LSN分別是50、120和160

1.trx1是第一個(gè)到達(dá)的,會(huì)被選為這組的leader

2.等trx1要開(kāi)始寫(xiě)盤(pán)的時(shí)候,這個(gè)組里面已經(jīng)有了三個(gè)事務(wù),這時(shí)候LSN也變成了160

3.trx1去寫(xiě)盤(pán)的時(shí)候,帶的就是LSN=160,因此等trx1返回時(shí),所有LSN小于等于160的redo log,都已經(jīng)被持久化到磁盤(pán)

4.這時(shí)候trx2和trx3就可以直接返回了

一個(gè)組提交里面,組員越多,節(jié)約磁盤(pán)IOPS的效果要好

為了讓一次fsync帶的組員

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
国产小便视频在线播放| 国产日产欧产精品精品蜜芽| 够了够了到高C了好多水视频| 给个网站2021年直接进入的| 国产精品成人网站| 婚后失控BY南城非梦| 久久精品无码一区二区日韩AV| 蜜芽亚洲AV无码精品国产| 欧美金发尤物大战黑人| 色噜噜狠狠狠狠色综合久一| 午夜精品久久久久久久| 亚洲人成无码网站| 18款禁用免费安装的软件APP | 大陆少妇XXXX做受| 国产精品美女久久久久网站浪潮| 激情视频传媒一区二区| 美女露100%双奶头无遮挡图片| 人妻跪趴高撅肥臀| 未满十八18禁止免费无码网站| 亚洲AV无码专区国产乱码在线观 | 成年轻人电影WWW无码| 国产AV精品白浆一区二| 精品国产_亚洲人成在线| 奶酥1V2双C高| 熟妇人妻中文字幕无码老熟妇| 亚洲AV永久无码精品一区二区国 | 纯肉高H爽文粗大| 国产一二三四区乱码免费| 老师穿着旗袍肉色丝袜让我玩| 女性裸体无遮挡啪啪网站| 公园小树中老年交易图片| 国产毛片精选好视频| 插我一区二区在线观看| 国产亚洲日韩在线三区| 在线国内永久免费CRM| 久久6久久66热这里只是精品 | 日韩精品久久久久久久电影蜜臀| 性色AV一区二区三区天美传媒| 又色又爽又黄的视频APP软件下| 成人无码区免费AⅤ片黄瓜视频| 国语对白刺激在线视频国产网红| 免费A级毛片无码无遮挡内射| 少妇伦子伦情品无吗| 亚洲欧洲日产国码无码AV一| JAPANESETUBE日本护| 国产欧美亚洲精品第一页| 迷迷糊糊挺进岳身体| 他的白月光H1∨1笔趣阁| 亚洲中文字幕无码一区二区三区| 春色校园亚洲愉拍自拍| 久久精品国产99久久久小说| 日产精品久久久久久久| 亚洲人成人无码WWW影院| 成人AV片无码免费网站| 久久精品国产清自在天天线| 色狠狠久久AV五月综合| 一本加勒比HEZYO无码专区| 粉嫩丰满人妻内射| 老湿机香蕉久久久久久| 无码人妻精品一区二区三区免费看| 中文字幕AV无码不卡免费 | 擦老太BBB擦BBB擦BBB擦| 激情伊人五月天久久综合| 人妻JapanXXXX精品HD| 亚洲欧美中文日韩V在线观看不卡 亚洲欧美中文日韩V在线观看 | 免费天堂无码人妻成人AV电影| 无码熟妇人妻AV影音先锋| 久久精品WWW人人做人人爽| 日本入室强伦姧在线观看| 亚洲女人天堂成人AV在线| 厨房掀开馊了裙子挺进电影| 邻居少妇张开腿让我爽了一夜视频| 无码人妻ΑⅤ免费一区二区三区| 97人妻碰碰碰久久久久禁片| 极品粉嫩小泬白浆20P| 日韩人妻在线一区二区三区| 中国熟妇人妻XXXXXHD| 国产亚洲美女精品久久久久| 日产乱码一二三区别免费下载| 岳今晚让我玩个够肥水一体探岳体 | 亚洲精品乱码久久久久久中文字幕| 得到超级肉禽系统的小说怎么办| 麻豆一二三区AV精品传媒| 亚洲AV片不卡无码潮| 大BBW大BBW超大BBW| 内射骚妇高清AV电影| 亚洲日韩AV一区二区三区中文 | 亚洲AV无码一区二区三区人区| 成人伊人亚洲人综合网| 免费天堂无码人妻成人AV电影| 亚洲女人人体ASS| 国产人与ZOXXXX另类| 三个男人换着躁我一| ACG性奴成熟人妻全彩漫画| 久久精品国产精品青草| 西西人体444WWW高清大胆| 粉嫩av.一区二区三区免费| 欧美最猛黑人XXXXWWW| 又大又黄又爽视频一区二区| 极品AV麻豆国产在线观看| 无码激情亚洲一区| 丰满少妇熟女高潮流白浆| 漂亮人妻熟睡中被公侵犯中文版| 中文无码热在线视频| 久久久久久精品免费不卡| 亚洲精品乱码日本按摩久久久久| 国产又黄又大又粗视频| 无码精品H动漫成人影院| 丰满的继牳3中文字幕系列免费| 琪琪午夜成人理论福利片美容院| 最新的国产成人精品2022| 巨熟乳波霸若妻在线播放| 亚洲国产精品高清久久久| 刺激交换经历过程小说| 欧美精品双插重口在线播放| 余生请多指教在线观看免费全集| 精品人妻一区二区三区四区九九 | 亚洲日韩AV无码一区二区三区| 好紧我太爽了视频免费国产| 午夜亚洲AⅤ无码高潮片在线观看| 国产AⅤ激情无码久久男男剧| 色婷婷亚洲一区二区综合| 锕锕锕锕锕锕好大好深APP| 欧洲VODAFONEWIFI喷| JEALOUSVUE日本人护士| 欧美群交性爱视频| 99久久99久久精品国产片| 拧花蒂尿用力按凸起喷水尿AV| 13学生小美女洗澡裸体视频| 男男gv在线观看| 91精品人妻一区二区三区蜜桃 | 女人大胆张开荫道口∞| 2021久久精品国产99国产精| 巨大黑人XXXXX高潮| 中国老女人老熟女人BB操| 免费无码又爽又高潮视频| 99久久免费国产精品四虎99久久精品免费看国产一区二区 | S货叫大点声C烂你的SB视频| 人妻AV中文字幕一区二区三区| 扒开腿挺进湿润的花苞HD视频| 日本JAPANESE 30成熟| 成人毛片女人18女人免费| 爽到高潮无码视频在线观看| 国产精品毛片无遮挡高清| 亚洲AV无码一区二区三区系列| 精品成品国色天香卡一卡三 | 久久天堂综合亚洲伊人HD妓女| 在线精品自偷自拍无码中文| 哦┅┅快┅┅用力啊┅┅村妇| YY111111少妇影院免费观| 三妻四妾免费观看完整版高清| 国产福利一区二区久久| 亚洲AV无码成人精品涩涩| 久久成人国产精品无码| 正文畸情~内裤奇缘小说| 欧洲乱码一卡2卡三卡4卡高清| 大学生酒店呻吟在线观看| 无码人妻AV免费一区二区三区 | 欧美性大战久久久久久久| 大胸美女污污污WWW网站| 无线乱码不卡一二三四破解版| 狠狠婷婷色五月中文字幕| 一区二区三区国产精品保安| 欧美群交XXXCOM| 国产GAYSEXCHINA男外| 亚洲AV永久无码精品主页丝瓜| 久久天天躁狠狠躁夜夜AV| CHINESE中年熟妇FREE| 天美传媒蜜桃传媒精东| 极品粉嫩小泬无遮挡20P| 一区二区三区国产精品保安| 欧亚专线欧洲S码W MY| 国产成人精品免费视频网页大全| 亚洲高清毛片一区二区| 蜜桃av中文字幕在线| 大色堂午夜福利国产TV6080| 亚洲AV无码国产一区二区三区四 | 欧美最厉害的喷水VIDEOS| 公车人妻中出中文字幕| 亚洲国产AV无码男人的天堂| 免费AV一区二区三区| 公车上玩弄白嫩少妇| 亚洲精品国产AV天美传媒| 男男AV纯肉无码免费播放无码| 风流老太婆大BBWBBWHD视| 亚洲欧美日韩精品成人| 亲子伦AV一区的三区| 国产日韩综合一区二区性色AV | 美女脱个精光扒开尿口图片无遮挡 | 国产强伦姧在线观看无码 | 成人精品一区二区三区网站| 亚洲AV无码一区二区三区网站| 男人的天堂在线视频| 国产AⅤ激情无码久久久无码| 亚洲中文无码永久免| 日韩AⅤ无码大片无码片| 精品国产乱码一区二区三区| 八戒八戒神马影院在线4| 亚洲AV永久无码精品无码自慰 | 啊灬啊灬啊灬快灬高潮少妇|