MySQL的InnoDBIO子系統(tǒng)知識(shí)點(diǎn)有哪些

本篇內(nèi)容介紹了“MySQL的InnoDB IO子系統(tǒng)知識(shí)點(diǎn)有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

成都創(chuàng)新互聯(lián)公司成立十年來(lái),這條路我們正越走越好,積累了技術(shù)與客戶資源,形成了良好的口碑。為客戶提供網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)頁(yè)設(shè)計(jì)、域名與空間、網(wǎng)絡(luò)營(yíng)銷(xiāo)、VI設(shè)計(jì)、網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。網(wǎng)站是否美觀、功能強(qiáng)大、用戶體驗(yàn)好、性價(jià)比高、打開(kāi)快等等,這些對(duì)于網(wǎng)站建設(shè)都非常重要,成都創(chuàng)新互聯(lián)公司通過(guò)對(duì)建站技術(shù)性的掌握、對(duì)創(chuàng)意設(shè)計(jì)的研究為客戶提供一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶,共同發(fā)展進(jìn)步。

基礎(chǔ)知識(shí)

WAL技術(shù) : 日志先行技術(shù),基本所有的數(shù)據(jù)庫(kù),都使用了這個(gè)技術(shù)。簡(jiǎn)單的說(shuō),就是需要寫(xiě)數(shù)據(jù)塊的時(shí)候,數(shù)據(jù)庫(kù)前臺(tái)線程把對(duì)應(yīng)的日志先寫(xiě)(批量順序?qū)懀┑酱疟P(pán)上,然后就告訴客戶端操作成功,至于真正寫(xiě)數(shù)據(jù)塊的操作(離散隨機(jī)寫(xiě))則放到后臺(tái)IO線程中。使用了這個(gè)技術(shù),雖然多了一個(gè)磁盤(pán)寫(xiě)入操作,但是由于日志是批量順序?qū)?,效率很高,所以客戶端很快就能得到相?yīng)。此外,如果在真正的數(shù)據(jù)塊落盤(pán)之前,數(shù)據(jù)庫(kù)奔潰,重啟時(shí)候,數(shù)據(jù)庫(kù)可以使用日志來(lái)做崩潰恢復(fù),不會(huì)導(dǎo)致數(shù)據(jù)丟失。

數(shù)據(jù)預(yù)讀 : 與數(shù)據(jù)塊A“相鄰”的數(shù)據(jù)塊B和C在A被讀取的時(shí)候,B和C也會(huì)有很大的概率被讀取,所以可以在讀取B的時(shí)候,提前把他們讀到內(nèi)存中,這就是數(shù)據(jù)預(yù)讀技術(shù)。這里說(shuō)的相鄰有兩種含義,一種是物理上的相鄰,一種是邏輯上的相鄰。底層數(shù)據(jù)文件中相鄰,叫做物理上相鄰。如果數(shù)據(jù)文件中不相鄰,但是邏輯上相鄰(id=1的數(shù)據(jù)和id=2的數(shù)據(jù),邏輯上相鄰,但是物理上不一定相鄰,可能存在同一個(gè)文件中不同的位置),則叫邏輯相鄰。

文件打開(kāi)模式 : Open系統(tǒng)調(diào)用常見(jiàn)的模式主要三種:O_DIRECT,O_SYNC以及default模式。O_DIRECT模式表示后續(xù)對(duì)文件的操作不使用文件系統(tǒng)的緩存,用戶態(tài)直接操作設(shè)備文件,繞過(guò)了內(nèi)核的緩存和優(yōu)化,從另外一個(gè)角度來(lái)說(shuō),使用O_DIRECT模式進(jìn)行寫(xiě)文件,如果返回成功,數(shù)據(jù)就真的落盤(pán)了(不考慮磁盤(pán)自帶的緩存),使用O_DIRECT模式進(jìn)行讀文件,每次讀操作是真的從磁盤(pán)中讀取,不會(huì)從文件系統(tǒng)的緩存中讀取。O_SYNC表示使用操作系統(tǒng)緩存,對(duì)文件的讀寫(xiě)都經(jīng)過(guò)內(nèi)核,但是這個(gè)模式還保證每次寫(xiě)數(shù)據(jù)后,數(shù)據(jù)一定落盤(pán)。default模式與O_SYNC模式類(lèi)似,只是寫(xiě)數(shù)據(jù)后不保證數(shù)據(jù)一定落盤(pán),數(shù)據(jù)有可能還在文件系統(tǒng)中,當(dāng)主機(jī)宕機(jī),數(shù)據(jù)有可能丟失。

此外,寫(xiě)操作不僅需要修改或者增加的數(shù)據(jù)落盤(pán),而且還需要文件元信息落盤(pán),只有兩部分都落盤(pán)了,才能保證數(shù)據(jù)不丟。O_DIRECT模式不保證文件元信息落盤(pán)(但大部分文件系統(tǒng)都保證,Bug #45892),因此如果不做其他操作,用O_DIRECT寫(xiě)文件后,也存在丟失的風(fēng)險(xiǎn)。O_SYNC則保證數(shù)據(jù)和元信息都落盤(pán)。default模式兩種數(shù)據(jù)都不保證。

調(diào)用函數(shù)fsync后,能保證數(shù)據(jù)和日志都落盤(pán),因此使用O_DIRECT和default模式打開(kāi)的文件,寫(xiě)完數(shù)據(jù),需要調(diào)用fsync函數(shù)。

同步IO : 我們常用的read/write函數(shù)(Linux上)就是這類(lèi)IO,特點(diǎn)是,在函數(shù)執(zhí)行的時(shí)候,調(diào)用者會(huì)等待函數(shù)執(zhí)行完成,而且沒(méi)有消息通知機(jī)制,因?yàn)楹瘮?shù)返回了,就表示操作完成了,后續(xù)直接檢查返回值就可知道操作是否成功。這類(lèi)IO操作,編程比較簡(jiǎn)單,在同一個(gè)線程中就能完成所有操作,但是需要調(diào)用者等待,在數(shù)據(jù)庫(kù)系統(tǒng)中,比較適合急需某些數(shù)據(jù)的時(shí)候調(diào)用,例如WAL中日志必須在返回客戶端前落盤(pán),則進(jìn)行一次同步IO操作。

異步IO : 在數(shù)據(jù)庫(kù)中,后臺(tái)刷數(shù)據(jù)塊的IO線程,基本都使用了異步IO。數(shù)據(jù)庫(kù)前臺(tái)線程只需要把刷塊請(qǐng)求提交到異步IO的隊(duì)列中即可返回做其他事情,而后臺(tái)線程IO線程,則定期檢查這些提交的請(qǐng)求是否已經(jīng)完成,如果完成再做一些后續(xù)處理工作。同時(shí)異步IO由于常常是一批一批的請(qǐng)求提交,如果不同請(qǐng)求訪問(wèn)同一個(gè)文件且偏移量連續(xù),則可以合并成一個(gè)IO請(qǐng)求。例如,***個(gè)請(qǐng)求讀取文件1,偏移量100開(kāi)始的200字節(jié)數(shù)據(jù),第二個(gè)請(qǐng)求讀取文件1,偏移量300開(kāi)始的100字節(jié)數(shù)據(jù),則這兩個(gè)請(qǐng)求可以合并為讀取文件1,偏移量100開(kāi)始的300字節(jié)數(shù)據(jù)。數(shù)據(jù)預(yù)讀中的邏輯預(yù)讀也常常使用異步IO技術(shù)。

目前Linux上的異步IO庫(kù),需要文件使用O_DIRECT模式打開(kāi),且數(shù)據(jù)塊存放的內(nèi)存地址、文件讀寫(xiě)的偏移量和讀寫(xiě)的數(shù)據(jù)量必須是文件系統(tǒng)邏輯塊大小的整數(shù)倍,文件系統(tǒng)邏輯塊大小可以使用類(lèi)似sudo blockdev --getss /dev/sda5的語(yǔ)句查詢。如果上述三者不是文件系統(tǒng)邏輯塊大小的整數(shù)倍,則在調(diào)用讀寫(xiě)函數(shù)時(shí)候會(huì)報(bào)錯(cuò)EINVAL,但是如果文件不使用O_DIRECT打開(kāi),則程序依然可以運(yùn)行,只是退化成同步IO,阻塞在io_submit函數(shù)調(diào)用上。

InnoDB常規(guī)IO操作以及同步IO

在InnoDB中,如果系統(tǒng)有pread/pwrite函數(shù)(os_file_read_func和os_file_write_func),則使用它們進(jìn)行讀寫(xiě),否則使用lseek+read/write方案。這個(gè)就是InnoDB同步IO。查看pread/pwrite文檔可知,這兩個(gè)函數(shù)不會(huì)改變文件句柄的偏移量且線程安全,所以多線程環(huán)境下推薦使用,而lseek+read/write方案則需要自己使用互斥鎖保護(hù),在高并發(fā)情況下,頻繁的陷入內(nèi)核態(tài),對(duì)性能有一定影響。

在InnoDB中,使用open系統(tǒng)調(diào)用打開(kāi)文件(os_file_create_func),模式方面除了O_RDONLY(只讀),O_RDWR(讀寫(xiě)),O_CREAT(創(chuàng)建文件)外,還使用了O_EXCL(保證是這個(gè)線程創(chuàng)建此文件)和O_TRUNC(清空文件)。默認(rèn)情況下(數(shù)據(jù)庫(kù)不設(shè)置為只讀模式),所有文件都以O(shè)_RDWR模式打開(kāi)。innodb_flush_method這個(gè)參數(shù)比較重要,重點(diǎn)介紹一下:

  • 如果innodb_flush_method設(shè)置了O_DSYNC,日志文件(ib_logfileXXX)使用O_SYNC打開(kāi),因此寫(xiě)完數(shù)據(jù)不需要調(diào)用函數(shù)fsync刷盤(pán),數(shù)據(jù)文件(ibd)使用default模式打開(kāi),因此寫(xiě)完數(shù)據(jù)需要調(diào)用fsync刷盤(pán)。

  • 如果innodb_flush_method設(shè)置了O_DIRECT,日志文件(ib_logfileXXX)使用default模式打開(kāi),寫(xiě)完數(shù)據(jù)需要調(diào)用fsync函數(shù)刷盤(pán),數(shù)據(jù)文件(ibd)使用O_DIRECT模式打開(kāi),寫(xiě)完數(shù)據(jù)需要調(diào)用fsync函數(shù)刷盤(pán)。

  • 如果innodb_flush_method設(shè)置了fsync或者不設(shè)置,數(shù)據(jù)文件和日志文件都使用default模式打開(kāi),寫(xiě)完數(shù)據(jù)都需要使用fsync來(lái)刷盤(pán)。

  • 如果innodb_flush_method設(shè)置為O_DIRECT_NO_FSYNC,文件打開(kāi)方式與O_DIRECT模式類(lèi)似,區(qū)別是,數(shù)據(jù)文件寫(xiě)完后,不調(diào)用fsync函數(shù)來(lái)刷盤(pán),主要針對(duì)O_DIRECT能保證文件的元數(shù)據(jù)也落盤(pán)的文件系統(tǒng)。

InnoDB目前還不支持使用O_DIRECT模式打開(kāi)日志文件,也不支持使用O_SYNC模式打開(kāi)數(shù)據(jù)文件。

注意,如果使用linux native aio(詳見(jiàn)下一節(jié)),innodb_flush_method一定要配置成O_DIRECT,否則會(huì)退化成同步IO(錯(cuò)誤日志中不會(huì)有任務(wù)提示)。

InnoDB使用了文件系統(tǒng)的文件鎖來(lái)保證只有一個(gè)進(jìn)程對(duì)某個(gè)文件進(jìn)行讀寫(xiě)操作(os_file_lock),使用了建議鎖(Advisory locking),而不是強(qiáng)制鎖(Mandatory locking),因?yàn)閺?qiáng)制鎖在不少系統(tǒng)上有bug,包括linux。在非只讀模式下,所有文件打開(kāi)后,都用文件鎖鎖住。

InnoDB中目錄的創(chuàng)建使用遞歸的方式(os_file_create_subdirs_if_needed和os_file_create_directory)。例如,需要?jiǎng)?chuàng)建/a/b/c/這個(gè)目錄,先創(chuàng)建c,然后b,然后a,創(chuàng)建目錄調(diào)用mkdir函數(shù)。此外,創(chuàng)建目錄上層需要調(diào)用os_file_create_simple_func函數(shù),而不是os_file_create_func,需要注意一下。

InnoDB也需要臨時(shí)文件,臨時(shí)文件的創(chuàng)建邏輯比較簡(jiǎn)單(os_file_create_tmpfile),就是在tmp目錄下成功創(chuàng)建一個(gè)文件后直接使用unlink函數(shù)釋放掉句柄,這樣當(dāng)進(jìn)程結(jié)束后(不管是正常結(jié)束還是異常結(jié)束),這個(gè)文件都會(huì)自動(dòng)釋放。InnoDB創(chuàng)建臨時(shí)文件,首先復(fù)用了server層函數(shù)mysql_tmpfile的邏輯,后續(xù)由于需要調(diào)用server層的函數(shù)來(lái)釋放資源,其又調(diào)用dup函數(shù)拷貝了一份句柄。

如果需要獲取某個(gè)文件的大小,InnoDB并不是去查文件的元數(shù)據(jù)(stat函數(shù)),而是使用lseek(file, 0, SEEK_END)的方式獲取文件大小,這樣做的原因是防止元信息更新延遲導(dǎo)致獲取的文件大小有誤。

InnoDB會(huì)預(yù)分配一個(gè)大小給所有新建的文件(包括數(shù)據(jù)和日志文件),預(yù)分配的文件內(nèi)容全部置為零(os_file_set_size),當(dāng)前文件被寫(xiě)滿時(shí),再進(jìn)行擴(kuò)展。此外,在日志文件創(chuàng)建時(shí),即install_db階段,會(huì)以100MB的間隔在錯(cuò)誤日志中輸出分配進(jìn)度。

總體來(lái)說(shuō),常規(guī)IO操作和同步IO相對(duì)比較簡(jiǎn)單,但是在InnoDB中,數(shù)據(jù)文件的寫(xiě)入基本都用了異步IO。

InnoDB異步IO

由于MySQL誕生在Linux native aio之前,所以在MySQL異步IO的代碼中,有兩種實(shí)現(xiàn)異步IO的方案。

***種是原始的Simulated aio,InnoDB在Linux native air被import進(jìn)來(lái)之前以及某些不支持air的系統(tǒng)上,自己模擬了一條aio的機(jī)制。異步讀寫(xiě)請(qǐng)求提交時(shí),僅僅把它放入一個(gè)隊(duì)列中,然后就返回,程序可以去做其他事情。后臺(tái)有若干異步io處理線程(innobase_read_io_threads和innobase_write_io_threads這兩個(gè)參數(shù)控制)不斷從這個(gè)隊(duì)列中取出請(qǐng)求,然后使用同步IO的方式完成讀寫(xiě)請(qǐng)求以及讀寫(xiě)完成后的工作。

另外一種就是Native aio。目前在linux上使用io_submit,io_getevents等函數(shù)完成(不使用glibc aio,這個(gè)也是模擬的)。提交請(qǐng)求使用io_submit, 等待請(qǐng)求使用io_getevents。另外,window平臺(tái)上也有自己對(duì)應(yīng)的aio,這里就不介紹了,如果使用了window的技術(shù)棧,數(shù)據(jù)庫(kù)應(yīng)該會(huì)選用sqlserver。目前,其他平臺(tái)(Linux和window之外)都只能使用Simulate aio。

首先介紹一下一些通用的函數(shù)和結(jié)構(gòu),接下來(lái)分別詳細(xì)介紹一下Simulate alo和Linux上的Native aio。

在os0file.cc中定義了全局?jǐn)?shù)組,類(lèi)型為os_aio_array_t,這些數(shù)組就是Simulate aio用來(lái)緩存讀寫(xiě)請(qǐng)求的隊(duì)列,數(shù)組的每一個(gè)元素是os_aio_slot_t類(lèi)型,里面記錄了每個(gè)IO請(qǐng)求的類(lèi)型,文件的fd,偏移量,需要讀取的數(shù)據(jù)量,IO請(qǐng)求發(fā)起的時(shí)間,IO請(qǐng)求是否已經(jīng)完成等。另外,Linux native io中的struct iocb也在os_aio_slot_t中。數(shù)組結(jié)構(gòu)os_aio_slot_t中,記錄了一些統(tǒng)計(jì)信息,例如有多少數(shù)據(jù)元素(os_aio_slot_t)已經(jīng)被使用了,是否為空,是否為滿等。這樣的全局?jǐn)?shù)組一共有5個(gè),分別用來(lái)保存數(shù)據(jù)文件讀異步請(qǐng)求(os_aio_read_array),數(shù)據(jù)文件寫(xiě)異步請(qǐng)求(os_aio_write_array),日志文件寫(xiě)異步請(qǐng)求(os_aio_log_array),insert buffer寫(xiě)異步請(qǐng)求(os_aio_ibuf_array),數(shù)據(jù)文件同步讀寫(xiě)請(qǐng)求(os_aio_sync_array)。日志文件的數(shù)據(jù)塊寫(xiě)入是同步IO,但是這里為什么還要給日志寫(xiě)分配一個(gè)異步請(qǐng)求隊(duì)列(os_aio_log_array)呢?原因是,InnoDB日志文件的日志頭中,需要記錄checkpoint的信息,目前checkpoint信息的讀寫(xiě)還是用異步IO來(lái)實(shí)現(xiàn)的,因?yàn)椴皇呛芫o急。在window平臺(tái)中,如果對(duì)特定文件使用了異步IO,就這個(gè)文件就不能使用同步IO了,所以引入了數(shù)據(jù)文件同步讀寫(xiě)請(qǐng)求隊(duì)列(os_aio_sync_array)。日志文件不需要讀異步請(qǐng)求隊(duì)列,因?yàn)橹挥性谧霰紳⒒謴?fù)的時(shí)候日志才需要被讀取,而做崩潰恢復(fù)的時(shí)候,數(shù)據(jù)庫(kù)還不可用,因此完全沒(méi)必要搞成異步讀取模式。這里有一點(diǎn)需要注意,不管變量innobase_read_io_threads和innobase_write_io_threads兩個(gè)參數(shù)是多少,os_aio_read_array和os_aio_write_array都只有一個(gè),只不過(guò)數(shù)據(jù)中的os_aio_slot_t元素會(huì)相應(yīng)增加,在linux中,變量加1,元素?cái)?shù)量增加256。例如,innobase_read_io_threads=4,則os_aio_read_array數(shù)組被分成了四部分,每一個(gè)部分256個(gè)元素,每個(gè)部分都有自己獨(dú)立的鎖、信號(hào)量以及統(tǒng)計(jì)變量,用來(lái)模擬4個(gè)線程,innobase_write_io_threads類(lèi)似。從這里我們也可以看出,每個(gè)異步read/write線程能緩存的讀寫(xiě)請(qǐng)求是有上限的,即為256,如果超過(guò)這個(gè)數(shù),后續(xù)的異步請(qǐng)求需要等待。256可以理解為InnoDB層對(duì)異步IO并發(fā)數(shù)的控制,而在文件系統(tǒng)層和磁盤(pán)層面也有長(zhǎng)度限制,分別使用cat /sys/block/sda/queue/nr_requests和cat /sys/block/sdb/queue/nr_requests查詢。

os_aio_init在InnoDB啟動(dòng)的時(shí)候調(diào)用,用來(lái)初始化各種結(jié)構(gòu),包括上述的全局?jǐn)?shù)組,還有Simulate aio中用的鎖和互斥量。os_aio_free則釋放相應(yīng)的結(jié)構(gòu)。os_aio_print_XXX系列的函數(shù)用來(lái)輸出aio子系統(tǒng)的狀態(tài),主要用在show engine innodb status語(yǔ)句中。

Simulate aio

Simulate aio相對(duì)Native aio來(lái)說(shuō),由于InnoDB自己實(shí)現(xiàn)了一套模擬機(jī)制,相對(duì)比較復(fù)雜。

  • 入口函數(shù)為os_aio_func,在debug模式下,會(huì)校驗(yàn)一下參數(shù),例如數(shù)據(jù)塊存放的內(nèi)存地址、文件讀寫(xiě)的偏移量和讀寫(xiě)的數(shù)據(jù)量是否是OS_FILE_LOG_BLOCK_SIZE的整數(shù)倍,但是沒(méi)有檢驗(yàn)文件打開(kāi)模式是否用了O_DIRECT,因?yàn)镾imulate aio最終都是使用同步IO,沒(méi)有必要一定要用O_DIRECT打開(kāi)文件。

  • 校驗(yàn)通過(guò)后,就調(diào)用os_aio_array_reserve_slot,作用是把這個(gè)IO請(qǐng)求分配到某一個(gè)后臺(tái)io處理線程(innobase_xxxx_io_threads分配的,但其實(shí)是在同一個(gè)全局?jǐn)?shù)組中)中,并把io請(qǐng)求的相關(guān)信息記錄下來(lái),方便后臺(tái)io線程處理。如果IO請(qǐng)求類(lèi)型相同,請(qǐng)求同一個(gè)文件且偏移量比較接近(默認(rèn)情況下,偏移量差別在1M內(nèi)),則InnoDB會(huì)把這兩個(gè)請(qǐng)求分配到同一個(gè)io線程中,方便在后續(xù)步驟中IO合并。

  • 提交IO請(qǐng)求后,需要喚醒后臺(tái)io處理線程,因?yàn)槿绻笈_(tái)線程檢測(cè)到?jīng)]有IO請(qǐng)求,會(huì)進(jìn)入等待狀態(tài)(os_event_wait)。

  • 至此,函數(shù)返回,程序可以去干其他事情了,后續(xù)的IO處理交給后臺(tái)線程了。

  • 介紹一下后臺(tái)IO線程怎么處理的。

  • InnoDB啟動(dòng)時(shí),后臺(tái)IO線程會(huì)被啟動(dòng)(io_handler_thread)。其會(huì)調(diào)用os_aio_simulated_handle從全局?jǐn)?shù)組中取出IO請(qǐng)求,然后用同步IO處理,結(jié)束后,需要做收尾工作,例如,如果是寫(xiě)請(qǐng)求的話,則需要在buffer pool中把對(duì)應(yīng)的數(shù)據(jù)頁(yè)從臟頁(yè)列表中移除。

  • os_aio_simulated_handle首先需要從數(shù)組中挑選出某個(gè)IO請(qǐng)求來(lái)執(zhí)行,挑選算法并不是簡(jiǎn)單的先進(jìn)先出,其挑選所有請(qǐng)求中offset最小的請(qǐng)求先處理,這樣做是為了后續(xù)的IO合并比較方便計(jì)算。但是這也容易導(dǎo)致某些offset特別大的孤立請(qǐng)求長(zhǎng)時(shí)間沒(méi)有被執(zhí)行到,也就是餓死,為了解決這個(gè)問(wèn)題,在挑選IO請(qǐng)求之前,InnoDB會(huì)先做一次遍歷,如果發(fā)現(xiàn)有請(qǐng)求是2s前推送過(guò)來(lái)的(也就是等待了2s),但是還沒(méi)有被執(zhí)行,就優(yōu)先執(zhí)行最老的請(qǐng)求,防止這些請(qǐng)求被餓死,如果有兩個(gè)請(qǐng)求等待時(shí)間相同,則選擇offset小的請(qǐng)求。

  • os_aio_simulated_handle接下來(lái)要做的工作就是進(jìn)行IO合并,例如,讀請(qǐng)求1請(qǐng)求的是file1,offset100開(kāi)始的200字節(jié),讀請(qǐng)求2請(qǐng)求的是file1,offset300開(kāi)始的100字節(jié),則這兩個(gè)請(qǐng)求可以合并為一個(gè)請(qǐng)求:file1,offset100開(kāi)始的300字節(jié),IO返回后,再把數(shù)據(jù)拷貝到原始請(qǐng)求的buffer中就可以了。寫(xiě)請(qǐng)求也類(lèi)似,在寫(xiě)操作之前先把需要寫(xiě)的數(shù)據(jù)拷貝到一個(gè)臨時(shí)空間,然后一次寫(xiě)完。注意,只有在offset連續(xù)的情況下IO才會(huì)合并,有間斷或者重疊都不會(huì)合并,一模一樣的IO請(qǐng)求也不會(huì)合并,所以這里可以算是一個(gè)可優(yōu)化的點(diǎn)。

  • os_aio_simulated_handle如果發(fā)現(xiàn)現(xiàn)在沒(méi)有IO請(qǐng)求,就會(huì)進(jìn)入等待狀態(tài),等待被喚醒

綜上所述,可以看出IO請(qǐng)求是一個(gè)一個(gè)的push的對(duì)立面,每push進(jìn)一個(gè)后臺(tái)線程就拿去處理,如果后臺(tái)線程優(yōu)先級(jí)比較高的話,IO合并效果可能比較差,為了解決這個(gè)問(wèn)題,Simulate aio提供類(lèi)似組提交的功能,即一組IO請(qǐng)求提交后,才喚醒后臺(tái)線程,讓其統(tǒng)一進(jìn)行處理,這樣IO合并的效果會(huì)比較好。但這個(gè)依然有點(diǎn)小問(wèn)題,如果后臺(tái)線程比較繁忙的話,其就不會(huì)進(jìn)入等待狀態(tài),也就是說(shuō)只要請(qǐng)求進(jìn)入了隊(duì)列,就會(huì)被處理。這個(gè)問(wèn)題在下面的Native aio中可以解決。

總體來(lái)說(shuō),InnoDB實(shí)現(xiàn)的這一套模擬機(jī)制還是比較安全可靠的,如果平臺(tái)不支持Native aio則使用這套機(jī)制來(lái)讀寫(xiě)數(shù)據(jù)文件。

Linux native aio

如果系統(tǒng)安裝了libaio庫(kù)且在配置文件里面設(shè)置了innodb_use_native_aio=on則啟動(dòng)時(shí)候會(huì)使用Native aio。

  • 入口函數(shù)依然為os_aio_func,在debug模式下,依然會(huì)檢查傳入的參數(shù),同樣不會(huì)檢查文件是否以O(shè)_DIRECT模式打開(kāi),這算是一個(gè)有點(diǎn)風(fēng)險(xiǎn)的點(diǎn),如果用戶不知道linux native aio需要使用O_DIRECT模式打開(kāi)文件才能發(fā)揮出aio的優(yōu)勢(shì),那么性能就不會(huì)達(dá)到預(yù)期。建議在此處做一下檢查,有問(wèn)題輸出到錯(cuò)誤日志。

  • 檢查通過(guò)之后,與Simulated aio一樣,調(diào)用os_aio_array_reserve_slot,把IO請(qǐng)求分配給后臺(tái)線程,分配算法也考慮了后續(xù)的IO合并,與Simulated aio一樣。不同之處,主要是需要用IO請(qǐng)求的參數(shù)初始化iocb這個(gè)結(jié)構(gòu)。IO請(qǐng)求的相關(guān)信息除了需要初始化iocb外,也需要在全局?jǐn)?shù)組的slot中記錄一份,主要是為了在os_aio_print_XXX系列函數(shù)中統(tǒng)計(jì)方便。

  • 調(diào)用io_submit提交請(qǐng)求。

  • 至此,函數(shù)返回,程序可以去干其他事情了,后續(xù)的IO處理交給后臺(tái)線程了。

接下來(lái)是后臺(tái)IO線程。

  • 與Simulate aio類(lèi)似,后臺(tái)IO線程也是在InnoDB啟動(dòng)時(shí)候啟動(dòng)。如果是Linux native aio,后續(xù)會(huì)調(diào)用os_aio_linux_handle這個(gè)函數(shù)。這個(gè)函數(shù)的作用與os_aio_simulated_handle類(lèi)似,但是底層實(shí)現(xiàn)相對(duì)比較簡(jiǎn)單,其僅僅調(diào)用io_getevents函數(shù)等待IO請(qǐng)求完成。超時(shí)時(shí)間為0.5s,也就是說(shuō)如果即使0.5內(nèi)沒(méi)有IO請(qǐng)求完成,函數(shù)也會(huì)返回,繼續(xù)調(diào)用io_getevents等待,當(dāng)然在等待前會(huì)判斷一下服務(wù)器是否處于關(guān)閉狀態(tài),如果是則退出。

在分發(fā)IO線程時(shí),盡量把相鄰的IO放在一個(gè)線程內(nèi),這個(gè)與Simulate aio類(lèi)似,但是后續(xù)的IO合并操作,Simulate aio是自己實(shí)現(xiàn),Native aio則交給內(nèi)核完成了,因此代碼比較簡(jiǎn)單。

還要一個(gè)區(qū)別是,當(dāng)沒(méi)有IO請(qǐng)求的時(shí)候,Simulate aio會(huì)進(jìn)入等待狀態(tài),而Native aio則會(huì)每0.5秒醒來(lái)一次,做一些檢查工作,然后繼續(xù)等待。因此,當(dāng)有新的請(qǐng)求來(lái)時(shí),Simulated aio需要用戶線程喚醒,而Native aio不需要。此外,在服務(wù)器關(guān)閉時(shí),Simulate aio也需要喚醒,Native aio則不需要。

可以發(fā)現(xiàn),Native aio與Simulate aio類(lèi)似,請(qǐng)求也是一個(gè)一個(gè)提交,然后一個(gè)一個(gè)處理,這樣會(huì)導(dǎo)致IO合并效果比較差。Facebook團(tuán)隊(duì)提交了一個(gè)Native aio的組提交優(yōu)化:把IO請(qǐng)求首先緩存,等IO請(qǐng)求都到了之后,再調(diào)用io_submit函數(shù),一口氣提交先前的所有請(qǐng)求(io_submit可以一次提交多個(gè)請(qǐng)求),這樣內(nèi)核就比較方便做IO優(yōu)化。Simulate aio在IO線程壓力大的情況下,組提交優(yōu)化會(huì)失效,而Native aio則不會(huì)。注意,組提交優(yōu)化,不能一口氣提交太多,如果超過(guò)了aio等待隊(duì)列長(zhǎng)度,會(huì)強(qiáng)制發(fā)起一次io_submit。

“MySQL的InnoDB IO子系統(tǒng)知識(shí)點(diǎn)有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

分享題目:MySQL的InnoDBIO子系統(tǒng)知識(shí)點(diǎn)有哪些
文章位置:http://muchs.cn/article24/ihidje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站內(nèi)鏈網(wǎng)站策劃、用戶體驗(yàn)、定制開(kāi)發(fā)、面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

綿陽(yáng)服務(wù)器托管