標籤:des blog http os 使用 io strong 檔案 for
轉自:http://blog.csdn.net/wyzxg/article/details/7700394
MySQL官網配置說明地址:http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html
其他參考:
《高效能MySQL》 - 8.4.5 InnoDB緩衝池
《MySQL技術內幕InnoDB儲存引擎》(第二版內容有所更新) - 2.3 InnoDB體繫結構
##############################################
書中是先對後台線程進行說明,然後對記憶體部分進行說明,這樣更好理解innoDB引擎記憶體池在使用時的過程。
【後台線程】
InnoDB有多個記憶體塊,可以認為這些記憶體塊組成了一個大的記憶體池,負責如下工作:
維護所有進程/線程需要訪問的多個內部資料結構。
緩衝磁碟上的資料,方便快速的讀取,並且在對磁碟檔案的資料進行修改之前在這裡緩衝。
重做日誌(redo log)緩衝。
後台線程的主要作用是負責重新整理記憶體池中的資料,保證緩衝池中的記憶體緩衝的是最近的資料。此外,將已修改的資料檔案重新整理到磁碟檔案,同時保證在資料庫發生異常情況下InnoDB能恢複到正常運行狀態。
預設情況下,InnoDB儲存引擎的後台線程有7個,4個IO thread,1個master thread,1個鎖(lock)監控線程,1個錯誤監控線程。IO thread的數量由設定檔中的innodb_file_io_threads參數控制,預設為4,可以通過show engine innodb status \G查看IO thread,例如:
mysql> show engine innodb status \G*************************** 1. row *************************** Type: InnoDB Name: Status: =====================================...--------FILE I/O--------I/O thread 0 state: waiting for i/o request (insert buffer thread)I/O thread 1 state: waiting for i/o request (log thread)I/O thread 2 state: waiting for i/o request (read thread)I/O thread 3 state: waiting for i/o request (read thread)I/O thread 4 state: waiting for i/o request (read thread)I/O thread 5 state: waiting for i/o request (read thread)I/O thread 6 state: waiting for i/o request (write thread)I/O thread 7 state: waiting for i/o request (write thread)I/O thread 8 state: waiting for i/o request (write thread)I/O thread 9 state: waiting for i/o request (write thread)
可以看到上面IO線程中的四種分別是insert buffer thread、log thread、read thread、write thread。MySQL 5.5可以對IO thread的read thread、write thread的數量進行配置(下面彩圖Memery-Disk結構圖中Buffer Pool與Table.ibd中間的就是read thread、write thread),預設的read thread、write thread分別增大到4個,預設的insert buffer thread、log thread仍為一個線程,上面也是MySQL 5.5版本的配置,同時不再使用innodb_file_io_threads參數,而是分別使用innodb_read_io_thread和innodb_write_io_thread參數,此參數可根據CPU核心數、磁碟IO效能進行調整,如果將read thread或write thread配置很大但實際伺服器效能不能滿足,會導致線程請求積壓,反而會降低效能。
【記憶體】
InnoDB儲存引擎記憶體由以下幾個部分組成:緩衝池(buffer pool)、重做日誌緩衝池(redo log buffer)以及額外的記憶體池(additional memory pool),分別由設定檔中的參數innodb_buffer_pool_size、innodb_log_buffer_size、innodb_additional_mem_pool_size的大小決定。
緩衝池中緩衝的資料頁類型有:索引頁、資料頁、undo頁、插入緩衝(insert buffer),自適應雜湊索引(adaptive hash index)、InnoDB儲存的鎖資訊(lock info)、資料字典資訊(data dictionary)等,緩衝池不僅有資料頁和索引頁,只是他們占緩衝池的很大部分,InnoDB儲存引擎中記憶體的結構如:
緩衝池是用來存放各種資料的緩衝,因為InnoDB的儲存引擎的工作方式總是將資料庫檔案按頁(每頁16K)讀取到緩衝池,然後按最近最少使用(LRU)的演算法來保留在緩衝池中的快取資料。如果資料庫檔案需要修改,總是首先修改在緩衝池中的頁(發生修改後,該頁即為髒頁),然後再按照一定的頻率將緩衝池的髒頁重新整理(flush)到檔案。
通過show engine innodb status \G查看innodb_buffer_pool的具體使用方式(show engine innodb status查看的並非即時的innodb引擎狀態,只是之前一段時間的平均值):
=====================================Per second averages calculated from the last 17 seconds-----------------...----------------------BUFFER POOL AND MEMORY----------------------Total memory allocated 52747567104; in additional pool allocated 0Dictionary memory allocated 1147940Buffer pool size 3145727Free buffers 3143088Database pages 2630Old database pages 950Modified db pages 0
buffer pool size表明一共有多少個緩衝幀(buffer frame),每個buffer frame為16K。free buffers表示當前閒置緩衝幀,databases pages表示已經使用的緩衝幀,modified db pages表示髒頁的數量。
日誌緩衝將重做日誌資訊先放入這個緩衝區,然後按一定頻率將其重新整理到重做記錄檔,該值一般不需要設定很大,因為一般情況下每一秒就會將重做日誌緩衝重新整理到記錄檔,因此我們只需要保證每秒產生的事務量在innodb_log_buffer_size參數控制的緩衝大小之內即可。
額外的記憶體池通常被忽略,其實該值十分重要,在InnoDB儲存引擎中,對記憶體的管理是通過一種稱為記憶體堆(heap)的方式進行的。在對一些資料結構本身分配記憶體時,需要從額外記憶體池中申請,該地區的記憶體不夠時,會從緩衝池中申請。InnoDB執行個體會申請緩衝池(InnoDB_buffer_pool)的空間,但是每個緩衝池中的幀緩衝(frame buffer)還有對應的緩衝控制對象(buffer control block),而且這些對象記錄了諸如LRU、鎖、等待方面的資訊,而這個對象的記憶體需要從額外記憶體池中申請。因此InnoDB緩衝池比較大時,額外記憶體池也應該增大。
##############################################
網上找到一個XtraDB/InnoDB核心結構圖,XtraDB在某些點上對InnoDB做了最佳化,但是原理基本一樣,原圖是OSCHINA上面的,原圖解析度很低,大致結構和對應參數可以看清楚。
redo和undo,undo先於redo
redo可以理解為需要執行的動作陳述式備份,保證事務完整性,儲存於ib_logfile
undo可以理解為資料受動作陳述式執行前的原始快照備份,用於rollback,儲存於ibdata共用資料表空間
《MySQL技術內幕InnoDB儲存引擎》 - 4.2.1 資料表空間
##############################################
對於啟用了innodb_file_per_table的參數選項,需要注意的是,每張表的資料表空間記憶體放的只是資料、索引和插入緩衝,其他類的資料,如撤銷(Undo)資訊、系統事務資訊、二次寫緩衝(double write buffer)等還是存放在原來的共用資料表空間內。
##############################################
mysql buffer pool裡的三種鏈表和三種page
buffer pool是通過三種list來管理的
1) free list
2) lru list
3) flush list
Buffer pool中的最小單位是page,在innodb中定義三種page
1) free page :此page未被使用,此種類型page位於free鏈表中
2) clean page:此page被使用,對應資料檔案中的一個頁面,但是頁面沒有被修改,此種類型page位於lru鏈表中
3) dirty page:此page被使用,對應資料檔案中的一個頁面,但是頁面被修改過,此種類型page位於lru鏈表和flush鏈表中
Buffer pool flush list的工作原理
dirty page如何存在flush鏈表中?
在flush list中存在的page只能是dirty page,flush list中存在的dirty page是按著oldest_modification時間排序的,當頁面訪問/修改都被封裝為一個mini-transaction,mini-transactin提交的時候,則mini-transaction涉及到的頁面就進入了flush鏈表中,oldest_modification的值越大,說明page越晚被修改過,就排在flush鏈表的頭部,oldest_modification的值越小,說明page越早被修改過,就排在flush鏈表的尾部,這樣當flush鏈表做flush動作時,從flush鏈表的尾部開始scan,寫出一定數量的dirty page到磁碟,推薦checkpoint點,使恢複的時間儘可能的短。除了flush鏈表本身的flush操作可以把dirty page從flush鏈表刪除外,lru鏈表的flush操作也會讓dirty page從flush鏈表刪除。
Buffer pool lru list的工作原理
總的來說每當一個新頁面被讀取buffer pool之後,MySQL資料庫InnoDB儲存引擎都會判斷當前buffer pool的free page是否足夠,若不足,則嘗試flush LRU鏈表。
在MySQL 5.6.2之前,使用者線程在讀入一個page (buf_read_page)、建立一個page(buf_page_create)、預讀page(buf_read_ahead_linear) 等等操作時,都會在操作成功之後,調用buf_flush_free_margin函數,判斷當前buffer pool是否有足夠的free pages,若free pages不足,則進行LRU list flush,釋放出足夠的free pages,保證系統的可用性。
通過判斷當前buf pool中需要flush多少dirty pages,才能夠預留出足夠的可被替換的頁面(free pages or clean pages in LRU list tail)。
說明:
可用pages由以下兩部分組成:
1. buf pool free list中的所有page,都是可以立即使用的。
2. buf pool LRU list尾部(5+2*BUF_READ_AHEAD_AREA)所有的clean pages。
其中:BUF_READ_AHEAD_AREA為64,是一個linear read ahead讀取的大小,1 extent
由於buf_flush_free_margin函數是在使用者線程中調用執行的,若需要flush LRU list,那麼對於使用者的回應時間有較大的影響。因此,在MySQL 5.6.2之後,InnoDB專門開闢了一個page cleaner線程,處理dirty page的flush動作(包括LRU list flush與flush list flush),降低page flush對於使用者的影響。
在MySQL 5.6.2前後的版本中,LRU list flush的不同之處在於是由使用者線程發起,還是有後台page cleaner線程發起。但是,無論是使用者線程,還是後台page cleaner線程,再決定需要進行LRU list flush之後,都會調用buf_flush_LRU函數進行真正的flush操作。
不同之處在於,MySQL 5.6.2之前,使用者線程調用的buf_flush_free_margin函數,在判斷是否真正需要進行LRU list flush時,將LRU list tail部分的clean pages也歸為可以被replace的pages,不需要flush。而在page cleaner線程中,每隔1s,無論如何都會進行一次LRU list flush調用,無論LRU list tail中的page是否clean。這也可以理解,使用者線程,需要盡量降低flush的機率,提高使用者響應;而後台線程,盡量進行flush嘗試,釋放足夠的free pages,保證使用者線程不會堵塞。
Buffer Pool LRU/Flush List flush對比
1).LRU list flush,由使用者線程觸發(MySQL 5.6.2之前);而Flush list flush由MySQL資料庫InnoDB儲存引擎後台srv_master線程處理。(在MySQL 5.6.2之後,都被遷移到page cleaner線程中)
2).LRU list flush,其目的是為了寫出LRU 鏈表尾部的dirty page,釋放足夠的free pages,當buf pool滿的時候,使用者可以立即獲得空閑頁面,而不需要長時間等待;Flush list flush,其目的是推進Checkpoint LSN,使得InnoDB系統崩潰之後能夠快速的恢複。
3).LRU list flush,其寫出的dirty page,需要移動到LRU鏈表的尾部(MySQL 5.6.2之前版本);或者是直接從LRU鏈表中刪除,移動到free list(MySQL 5.6.2之後版本)。Flush list flush,不需要移動page在LRU鏈表中的位置。
4).LRU list flush,由於可能是使用者線程發起,已經持有其他的page latch,因此在LRU list flush中,不允許等待持有新的page latch,導致latch死結;而Flush list flush由後台線程發起,未持有任何其他page latch,因此可以在flush時等待page latch。
5).LRU list flush,每次flush的dirty pages數量較少,基本固定,只要釋放一定的free pages即可;Flush list flush,根據當前系統的更新繁忙程度,動態調整一次flush的dirty pages數量,量很大。
Buffer pool free list工作原理
free鏈表裡存放的是空閑頁面,初始化的時候申請一定數量的page,在使用的過程中,每次成功load頁面到記憶體後,都會判斷free page是否夠用,如果不夠用的話,就flush lru鏈表和flush鏈表來釋放free page,這就可以滿足其他進程在申請頁面,使系統可用。
配置多個Buffer pool的innodb_buffer_pool_instances
官網說明For systems with buffer pools in the multi-gigabyte range, dividing the buffer pool into separate instances can improve concurrency, by reducing contention as different threads read and write to cached pages. This feature is typically intended for systems with a buffer pool size in the multi-gigabyte range. Multiple buffer pool instances are configured using the innodb_buffer_pool_instances configuration option, and you might also adjust the innodb_buffer_pool_size value.When the InnoDB buffer pool is large, many data requests can be satisfied by retrieving from memory. You might encounter bottlenecks from multiple threads trying to access the buffer pool at once. You can enable multiple buffer pools to minimize this contention. Each page that is stored in or read from the buffer pool is assigned to one of the buffer pools randomly, using a hashing function. Each buffer pool manages its own free lists, flush lists, LRUs, and all other data structures connected to a buffer pool, and is protected by its own buffer pool mutex.To enable multiple buffer pool instances, set the innodb_buffer_pool_instances configuration option to a value greater than 1 (the default) up to 64 (the maximum). This option takes effect only when you set the innodb_buffer_pool_size to a size of 1 gigabyte or more. The total size you specify is divided among all the buffer pools. For best efficiency, specify a combination of innodb_buffer_pool_instances and innodb_buffer_pool_size so that each buffer pool instance is at least 1 gigabyte.翻譯:對於使用較大Buffer Pool的執行個體,把Buffer Pool劃分成多個獨立的部分,可以提高並發性,減少不同的線程對緩衝的頁面讀取與寫入的競爭。這個配置通常用於Buffer Pool幾GB或以上的資料量較大的執行個體。將Buffer Pool劃分為多個可使用innodb_buffer_pool_instances配置選項(預設為1),你可能也調整innodb_buffer_pool_size值調整Buffer Pool大小。 當InnoDB的Buffer Pool很大時,查詢的請求可以從記憶體中檢索擷取。您可能會遇到來自多個線程試圖訪問Buffer Pool的瓶頸。您可以啟用多個Buffer Pool以緩解這一情況。儲存或讀取的每個Page是使用一個Hash演算法隨機的分配給多個Buffer Pool的。每個多個Buffer Pool管理它自己的free lists和flush lists還有LRU,其他資料結構串連Buffer Pool,由它自己的Buffer Pool保護互斥。要啟用多個Buffer Pool執行個體,設定innodb_buffer_pool_instances配置選項的值大於1(預設值)到64(最大)。此選項生效,只有當你將innodb_buffer_pool_size調整為1 GB或更大的尺寸才會生效。您所指定的Buffer Pool總大小會劃分。為了獲得最佳的效率,指定innodb_buffer_pool_instances和innodb_buffer_pool_size的結合,使每個緩衝池執行個體至少1千MB。
Log buffer刷盤機制修改的innodb_flush_log_at_trx_commit
If the value of innodb_flush_log_at_trx_commit is 0, the log buffer is written out to the log file once per second and the flush to disk operation is performed on the log file, but nothing is done at a transaction commit. When the value is 1 (the default), the log buffer is written out to the log file at each transaction commit and the flush to disk operation is performed on the log file. When the value is 2, the log buffer is written out to the file at each commit, but the flush to disk operation is not performed on it. However, the flushing on the log file takes place once per second also when the value is 2. Note that the once-per-second flushing is not 100% guaranteed to happen every second, due to process scheduling issues.The default value of 1 is required for full ACID compliance. You can achieve better performance by setting the value different from 1, but then you can lose up to one second worth of transactions in a crash. With a value of 0, any mysqld process crash can erase the last second of transactions. With a value of 2, only an operating system crash or a power outage can erase the last second of transactions. InnoDB‘s crash recovery works regardless of the value.當值為0,log_buffer日誌緩衝區(上面彩圖Memery-Disk結構圖最下面的部分)每秒一次寫出重新整理到磁碟上的記錄檔ib_logfile中,在單個事務提交時什麼都不做。
當值為1(預設值),日誌緩衝區寫入到記錄檔在每個事務提交和重新整理到磁碟操作的記錄檔執行。
當該值是2,日誌緩衝區寫出到檔案在每次提交,但並不在其上執行的重新整理到磁碟的操作。然而,在記錄檔中的潮紅髮生每秒一次也當值為2。注意,一旦每秒沖洗不保證100%的情況發生每一秒,因為要處理的調度問題。 需要完全符合ACID的預設值1。您可以通過設定該值從1不同實現更好的效能,但你可能會失去多達交易的崩潰一秒鐘的。隨著一個0值,任何mysqld進程的崩潰可擦寫的交易最後一秒。為2的值,只有一個作業系統崩潰或斷電時可擦寫交易的最後一秒。 InnoDB的崩潰恢複工程,無論價值。
物理結構
【轉】mysql-innodb-buffer pool 結構分析