HBase高并發(fā)原由之MySQL讀寫流程解析
2018-02-02 14:09:20
2341瀏覽
數(shù)據(jù)庫(kù)作為存儲(chǔ)系統(tǒng),所有業(yè)務(wù)訪問(wèn)數(shù)據(jù)的操作都會(huì)轉(zhuǎn)化為底層數(shù)據(jù)庫(kù)系統(tǒng)的IO行為(緩存系統(tǒng)也可以當(dāng)做是key-value的數(shù)據(jù)庫(kù)),本文主要介紹訪問(wèn)MySQL數(shù)據(jù)庫(kù)的IO流程以及IO相關(guān)的參數(shù)。
一、MySQL的文件
首先簡(jiǎn)單介紹一下MySQL的數(shù)據(jù)文件,MySQL數(shù)據(jù)庫(kù)包含如下幾種文件類型:
1)數(shù)據(jù)文件(datafile)
存放表中的具體數(shù)據(jù)的文件。
2)數(shù)據(jù)字典
記錄數(shù)據(jù)庫(kù)中所有innodb表的信息。
3)重做日志(redolog)
記錄數(shù)據(jù)庫(kù)變更記錄的文件,用于系統(tǒng)異常crash(掉電)后的恢復(fù)操作,可以配置多個(gè)(配置這個(gè)參數(shù)innodb_log_files_in_group)比如ib_logfile0、ib_logfile1。
4)回滾日志(undolog)
也存在于mysql的ibdata文件,用戶記錄事務(wù)的回滾操作。注在mysql5.6以上版本可以拆開出來(lái),單獨(dú)文件夾存在。
5)歸檔日志(binlog)
事務(wù)提交之后,記錄到歸檔日志中。
6)中繼日志(relaylog)
從master獲取到slave的中轉(zhuǎn)日志文件,sql_thread則會(huì)應(yīng)用relaylog并重放于從機(jī)器。
7)其他日志slowlolg,errorlog,querylog
這里慢日志也經(jīng)常用??梢越Y(jié)合pt-query-digest工具和anemometer一起展示出來(lái)。
對(duì)于以上文件的IO訪問(wèn)順序可以分為順序訪問(wèn)比如binlog,redolog,relaylog是順序讀寫,datafile,ibdatafile是隨機(jī)讀寫,這些IO訪問(wèn)的特點(diǎn)決定了在os配置磁盤信息時(shí)候,如何考慮分區(qū),比如順序?qū)懣梢缘膌og可以放到SAS盤,隨機(jī)讀寫的數(shù)據(jù)文件可以放到ssd或者fio高性能的存儲(chǔ)。
二、數(shù)據(jù)訪問(wèn)流程
數(shù)據(jù)庫(kù)訪問(wèn)分為兩種類型,一種是讀操作,另外一種是寫操作。
1)讀操作
createtablet(
idintnotnullprimarykey,
k1intnotnull,
datavarchar(50),
keyind_k1(k1)
)engine=innodbdefaultcharset=utf8;
以select*fromtabwherek1=1;為例。
讀操作的IO流程
1、查看緩存中是否存在id,
2、如果有則從內(nèi)存中訪問(wèn),否則要訪問(wèn)磁盤,
3、并將索引數(shù)據(jù)存入內(nèi)存,利用索引來(lái)訪問(wèn)數(shù)據(jù),
4、對(duì)于數(shù)據(jù)也會(huì)檢查數(shù)據(jù)是否存在于內(nèi)存,
5、如果沒有則訪問(wèn)磁盤獲取數(shù)據(jù),讀入內(nèi)存。
6、返回結(jié)果給用戶。
2)寫操作
為了保證數(shù)據(jù)寫入操作的安全性,數(shù)據(jù)庫(kù)系統(tǒng)設(shè)置了undo,redo保護(hù)機(jī)制,避免因?yàn)閛s或者數(shù)據(jù)庫(kù)系統(tǒng)異常導(dǎo)致的數(shù)據(jù)丟失或者不一致的異常情況發(fā)生。
以insertintotvalues(1,1,’shuiyi’);為例。
寫操作的IO流程
我們假定數(shù)據(jù)在內(nèi)存中,不考慮從磁盤中獲取數(shù)據(jù)的情形,大致的寫操作步驟:
1、先寫undolog,
2、在內(nèi)存更新數(shù)據(jù),這步操作就在內(nèi)存中形成了臟頁(yè),如果臟頁(yè)過(guò)多,checkpoint機(jī)制進(jìn)行刷新,innodb_max_dirty_pages_pct決定了刷新臟頁(yè)比例。innodb_io_capacity參數(shù)可以動(dòng)態(tài)調(diào)整刷新臟頁(yè)的數(shù)量,innodb_lru_scan_depth這個(gè)參數(shù)決定了刷新每個(gè)innodb_buffer_pool的臟頁(yè)數(shù)量。
3、記錄變更到redolog,prepare這里會(huì)寫事務(wù)id。innodb_flush_log_at_trx_commit決定了事務(wù)的刷盤方式。為0時(shí),logbuffer將每秒一次地寫入logfile中,并且logfile的flush(刷到磁盤)操作同時(shí)進(jìn)行。該模式下,在事務(wù)提交的時(shí)候,不會(huì)主動(dòng)觸發(fā)寫入磁盤的操作。為1,每次事務(wù)提交時(shí)MySQL都會(huì)把logbuffer的數(shù)據(jù)寫入logfile,并且flush(刷到磁盤)中去.為2,每次事務(wù)提交時(shí)MySQL都會(huì)把logbuffer的數(shù)據(jù)寫入logfile.但是flush(刷到磁盤)操作并不會(huì)同時(shí)進(jìn)行。該模式下,MySQL會(huì)每秒執(zhí)行一次flush(刷到磁盤)操作。
4、寫入binlog這里會(huì)寫入一個(gè)事務(wù)id這里有個(gè)sync_binlog參數(shù)決定多個(gè)事務(wù)進(jìn)行一次性提交。
5、redolog第二階段,這里會(huì)進(jìn)行判斷前2步是否成功,成功則默認(rèn)commit,否則rollback。刷入磁盤操作。這里是先從臟頁(yè)數(shù)據(jù)刷入到內(nèi)存2M大小的doublewritebuffer,然后是一次性從內(nèi)存的doublewritebuffer刷新到共享表空間的doublewritebuffer,這里產(chǎn)生了一次IO。然后從內(nèi)存的內(nèi)存的doublewritebuffer刷新2m數(shù)據(jù)到磁盤的ibd文件中,這里需要發(fā)生128次io。然后校驗(yàn),如果不一致,就由共享表空間的副本進(jìn)行修復(fù)。這里有個(gè)參數(shù)innodb_flush_method決定了數(shù)據(jù)刷新直接刷新到磁盤,繞后oscache。
6、返回給client。
如果有slave
第4步之后經(jīng)過(guò)slave服務(wù)線程io_thread寫到從庫(kù)的relaylog,再由sqlthread應(yīng)用relaylog到從庫(kù)中。
關(guān)于性能?
寫undoredolog,binlog的過(guò)程中都是順序?qū)?,都?huì)很快的完成,隨機(jī)寫操作,inset_buffer功能。
對(duì)于非聚集類索引的插入和更新操作(5.5版本及以上支持Update/Delete/Purge等操作的buffer功能),不是每一次都直接插入到索引頁(yè)中,而是先插入到內(nèi)存中。具體做法是:如果該索引頁(yè)在緩沖池中,直接插入;否則,先將其放入插入緩沖區(qū)中,再以一定的頻率和索引頁(yè)合并,就可以將同一個(gè)索引頁(yè)中的多個(gè)插入合并到一個(gè)IO操作中,改隨機(jī)寫為順序?qū)?,大大提高寫性能?br />
關(guān)于數(shù)據(jù)安全,這是數(shù)據(jù)庫(kù)寫入的重點(diǎn)?
1,2,3過(guò)程失敗就是事務(wù)失敗,因?yàn)榇藭r(shí)還未寫入磁盤,對(duì)磁盤中的數(shù)據(jù)無(wú)影響,返回事務(wù)失敗給client,從庫(kù)也不會(huì)受到影響。4,5過(guò)程失敗的時(shí)候或者已經(jīng)將寫成功返回給客戶,可以根據(jù)redolog的記錄來(lái)進(jìn)行恢復(fù),如果出現(xiàn)部分寫失效請(qǐng)參考《doublewrite》。
MySQL的寫redolog的第一個(gè)階段會(huì)把所有需要做的操作做完,記錄數(shù)據(jù)變更,第二階段的工作比較簡(jiǎn)單,只做事務(wù)提交確認(rèn)。如果寫入binlog成功,而第二階段失敗,MySQL啟動(dòng)時(shí)也會(huì)將事務(wù)進(jìn)行重做,最終更新到磁盤中。MySQL5.5+的smeisync可以更好的保障主從的事務(wù)一致性。
三、文件訪問(wèn)方式
IO訪問(wèn)的方式分為兩種順序讀寫和隨機(jī)讀寫,在mysql的io過(guò)程中可以以此來(lái)將數(shù)據(jù)庫(kù)文件分類
順序讀寫:
重做日志ib_logfile*,binlogfile。
隨機(jī)讀寫:
innodb表數(shù)據(jù)文件,ibdata文件。
根據(jù)系統(tǒng)的訪問(wèn)類型,對(duì)硬件做如下分類:
讀多SSD+RAID
寫多FIO(flashcache)
容量密集fio+flashcache
由于隨機(jī)io會(huì)嚴(yán)重降低系統(tǒng)的性能,在當(dāng)前的硬件水平下,可以考慮選擇獎(jiǎng)數(shù)據(jù)庫(kù)服務(wù)器配置ssd/fusionio。
四、影響IO的參數(shù)和策略
影響mysqlio的參數(shù)有很多個(gè),這里羅列幾個(gè)重要的參數(shù)。
innodb_buffer_pool_size
該參數(shù)控制innodb緩存大小,用于緩存應(yīng)用訪問(wèn)的數(shù)據(jù),推薦配置為系統(tǒng)可用內(nèi)存的80%。
binlog_cache_size
該參數(shù)控制二進(jìn)制日志緩沖大小,當(dāng)事務(wù)還沒有提交時(shí),事務(wù)日志存放于cache,當(dāng)遇到大事務(wù)cache不夠用的時(shí),mysql會(huì)把uncommitted的部分寫入臨時(shí)文件,等到committed的時(shí)候才會(huì)寫入正式的持久化日志文件。
innodb_max_dirty_pages_pct
該參數(shù)可以直接控制DirtyPage在BP中所占的比率,當(dāng)dirtypage達(dá)到了該參數(shù)的閾值,就會(huì)觸發(fā)MySQL系統(tǒng)刷新數(shù)據(jù)到磁盤。
innodb_flush_log_at_trx_commit
該參數(shù)確定日志文件何時(shí)write、flush。
為0,logbuffer將每秒一次地寫入logfile中,并且logfile的flush(刷到磁盤)操作同時(shí)進(jìn)行.該模式下,在事務(wù)提交的時(shí)候,不會(huì)主動(dòng)觸發(fā)寫入磁盤的操作。
為1,每次事務(wù)提交時(shí)MySQL都會(huì)把logbuffer的數(shù)據(jù)寫入logfile,并且flush(刷到磁盤)中去.
為2,每次事務(wù)提交時(shí)MySQL都會(huì)把logbuffer的數(shù)據(jù)寫入logfile.但是flush(刷到磁盤)操作并不會(huì)同時(shí)進(jìn)行。該模式下,MySQL會(huì)每秒執(zhí)行一次flush(刷到磁盤)操作。
注意:
由于進(jìn)程調(diào)度策略問(wèn)題,這個(gè)“每秒執(zhí)行一次flush(刷到磁盤)操作”并不是保證100%的“每秒”。
sync_binlog
sync_binlog的默認(rèn)值是0,像操作系統(tǒng)刷其他文件的機(jī)制一樣,MySQL不會(huì)同步到磁盤中去而是依賴操作系統(tǒng)來(lái)刷新binarylog。
當(dāng)sync_binlog=N(N>0),MySQL在每寫N次二進(jìn)制日志binarylog時(shí),會(huì)使用fdatasync()函數(shù)將它的寫二進(jìn)制日志binarylog同步到磁盤中去。
innodb_flush_method
該參數(shù)控制日志或數(shù)據(jù)文件如何write、flush??蛇x的值為fsync,o_dsync,o_direct,littlesync,nosync
fdatasync模式:寫數(shù)據(jù)時(shí),write這一步并不需要真正寫到磁盤才算完成(可能寫入到操作系統(tǒng)buffer中就會(huì)返回完成),真正完成是flush操作,buffer交給操作系統(tǒng)去flush,并且文件的元數(shù)據(jù)信息也都需要更新到磁盤。
O_DSYNC模式:寫日志操作是在write這步完成,而數(shù)據(jù)文件的寫入是在flush這步通過(guò)fsync完成。
O_DIRECT模式:數(shù)據(jù)文件的寫入操作是直接從mysqlinnodbbuffer到磁盤的,并不用通過(guò)操作系統(tǒng)的緩沖,而真正的完成也是在flush這步,日志還是要經(jīng)過(guò)OS緩沖。
注意:關(guān)于mysql和io相關(guān)的參數(shù),并不是一成不變的,需要根據(jù)自身業(yè)務(wù)系統(tǒng)和硬件系統(tǒng)做相應(yīng)調(diào)整,系統(tǒng)上線之前,測(cè)試出一個(gè)最佳值。
數(shù)據(jù)庫(kù)的io是一個(gè)很復(fù)雜和細(xì)致的知識(shí)層面,涉及數(shù)據(jù)庫(kù)層和OS層面的IO寫入策略,也和硬件的配置有關(guān),最后想要了解更多關(guān)于大數(shù)據(jù)發(fā)展前景趨勢(shì),請(qǐng)關(guān)注扣丁學(xué)堂官網(wǎng)、微信等平臺(tái),扣丁學(xué)堂IT職業(yè)在線學(xué)習(xí)教育平臺(tái)為您提供權(quán)威的大數(shù)據(jù)視頻教程系統(tǒng),通過(guò)千鋒旗下金牌講師在線錄制的大數(shù)據(jù)培訓(xùn)視頻教程系統(tǒng),讓你快速掌握大數(shù)據(jù)從入門到精通大數(shù)據(jù)開發(fā)實(shí)戰(zhàn)技能??鄱W(xué)堂大數(shù)據(jù)學(xué)習(xí)群:209080834。
【關(guān)注微信公眾號(hào)獲取更多學(xué)習(xí)資料】
查看更多關(guān)于“大數(shù)據(jù)培訓(xùn)資訊”的相關(guān)文章>>
標(biāo)簽:
大數(shù)據(jù)分析
大數(shù)據(jù)培訓(xùn)
大數(shù)據(jù)視頻教程
Hadoop視頻教程
大數(shù)據(jù)開發(fā)工程師
大數(shù)據(jù)在線視頻