INNODB整體講解

1 內存結構

  組成部分:
  緩衝池   buffer pool, 由innodb_buffer_pool_size配置
  重做日誌緩衝池 redo log buffer, 由innodb_log_buffer_size配置
  額外內存池  additional memory pool, 由innodb_additional_mem_pool_size配置

1.1 buffer pool

  是佔最大塊內存的部分,用來存放各種數據的緩存;
  innodb將數據庫文件按頁(16K)讀取到緩衝池,然後按最少使用(LRU)算法來保留緩存數據;數據文件修改時,先修改緩存池中的頁(即髒頁),然後按一定頻率將髒頁刷新到文件;

  緩衝池中的數據頁類型有:
  索引頁、數據頁、undo頁、插入緩衝(insert buffer)、自適應哈希索引(adaptive hash index)、鎖信息(lock info)、數據字典信息(data dictionary)

  查看buffer pool的使用情況
  show engine innodb status\G

  結果示例:
=====================================
120610 18:31:49 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 44 seconds
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 53657600; in additional pool allocated 0
Dictionary memory allocated 39802
Buffer pool size   3200
Free buffers       2790
Database pages     409
Old database pages 0
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 409, created 0, written 4
0.09 reads/s, 0.00 creates/s, 0.09 writes/s
Buffer pool hit rate 998 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s
LRU len: 409, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...

  分析
  (1)Per second averages calculated from the last 44 seconds
  show engine innodb status 顯示的過去某個時間段內的使用情況
  (2)Total memory allocated 53657600; in additional pool allocated 0
  當前分配的memory大小和additional pool大小,單位byte
  (3)接下來的pool中各項佔的大小
  Dictionary memory allocated 39802  數據字典內存區大小,單位byte
  Buffer pool size   3200    總頁數, 3200*16/1024=50M
  Free buffers       2790    空閒的頁數, 2790*16/1024=43M
  Database pages     409    已使用的緩衝頁數, 409*16/1024=6.3M
  Old database pages 0    
  Modified db pages  0     表示髒頁數

1.2 log buffer
  作用
  將重做日誌先放入這個區,然後按一定頻率將其刷新至重做日誌文件,一般情況下每1秒就會刷新一次;

  配置
  一般不需配置很大;

1.3 額外內存池
  作用:
  innodb申請緩衝池(buffer pool),但每個緩衝池中的頁緩衝有對應的緩衝控制對象(buffer control block),這些對象記錄LRU、鎖、等待等信息,這些對象的內存需要多額外內存池中申請;因此當buffer pool較大時,也需相應增大該值

====================================
2 innodb的後臺線程

  默認情況下,innodb有以下幾類線程:
  io thread,分爲read thread和write thread;
  master thread,1個
  lock monit thread,1個
  error monit thread,1個

3 io thread
  包括以下幾種:
  read thread
  write thread
  insert buffer thread
  log thread

  配置設置:
  read thread和write thread分別由innodb_read_io_threads和innodb_write_io_threads來配置;
  log thread和insert buffer thread一般是1個;

  查看
  show variables like '%threads%';
  show engine innodb status\G

4 master thread
  完成的工作
  主循環 loop
  後臺循環 background loop
  刷新循環 flush loop
  暫停循環 suspend loop

4.1 主循環 loop
  該循環中完成的有兩種操作,每秒一次的操作和每10秒一次的操作

  每秒一次的操作:
  a)日誌緩衝刷新到磁盤,即使這個事務未提交(總是);
  b)合併插入緩衝(可能),會根據前一秒內的io次數判斷,如果小於5次,可以執行合併插入緩衝;
  c)至多刷新100個髒頁至磁盤(可能),通過判斷髒頁比例是否超過了innodb_max_dirty_pages_pct這個設置值來進行,未超過則不執行;
  d)無用戶活動,切換到background loop(可能);

 

  每10秒一次的操作:
  a)刷新100個髒頁到磁盤(可能),如果過去10秒磁盤io操作小於200次,則執行本操作;
  b)合併至多5個插入緩衝(總是);
  c)日誌緩衝刷新到磁盤(總是);
  d)刪除無用的undo頁(總是);
  e)刷新100個或10個髒頁到磁盤(總是),判斷緩衝池髒頁比例,超過70%則刷新100個髒頁,比例小於10%則刷新10個髒頁;
  f)產生一個檢查點checkpoint(總是),注意此時並不是把所有髒頁都刷新到了磁盤,只是將最老日誌序列號的頁寫入磁盤;

4.2 後臺循環 background loop
  當沒有用戶活動或數據庫關閉時,會切換到這個循環;

  完成的操作
  a)刪除無用的undo頁(總是);
  b)合併20個插入緩衝(總是);
  c)跳回到主循環(總是);
  d)不斷刷新100個頁,直到符合條件(可能,跳轉到flush loop中完成);

4.3 flush loop
  由background loop跳轉到此loop中完成刷新髒頁的工作;
  當flush loop中無事可做時會切換到suspend loop;

4.4 suspend loop
  該loop將master thread掛起,等待事件發生;在啓用了innodb引擎,但未使用innodb表時,master thread總是處於掛起狀態;

4.5 查看示例
  show engine innodb status\G

-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 4 1_second, 4 sleeps, 0 10_second, 6 background, 6 flush
srv_master_thread log flush and writes: 4

  說明
  (1)主循環,每秒一次的操作有4次,每10秒一次的操作有0次;一般這兩個比例在1:10時較合理;
  (2)background loop,執行了6次,flush loop執行了6次
  (3)其中的sleeps指循環中的每秒sleep的操作,一般壓力較小情況下此值和每秒一次的操作數相同,壓力大時會小於每秒一次的操作數;

4.6 新版本優化了上邊的判斷配置值
  innodb_io_capacity=200
  合併插入緩衝時,合併插入緩衝的數量爲innodb_io_capacity數值的5%;
  緩衝區刷新到磁盤時,刷新髒頁數量爲innodb_io_capacity;

  使用情況
  在使用了ssd磁盤,或做了raid後,可將此值設置較大,直到符合磁盤io的吞吐量;

4.7 其它配置值注意情況
  innodb_max_dirty_pages_pct=90
  每秒的主loop和flush loop中,會判斷此值,如果大於才刷新100個髒頁,在數據庫壓力很大時,這時刷新速度反而會降低;google的測試表明75是個合理值;

  innodb_adaptive_flushing=on
  該值影響每秒刷新髒頁的操作,開啓此配置後,刷新髒頁會通過判斷產生重做日誌的速度來判斷最合適的刷新髒頁的數量;

===============================
5 innodb的插入緩衝
  是innodb引擎的關鍵特性之一;
  插入緩衝,insert buffer,是從緩衝池中分配的;用來對插入的性能進行優化和提升;
  具體講,即是對有非唯一的非聚集索引的索引頁的插入進行了緩衝,之後合併再插入;

  工作原理
  當表只有一個聚集索引時,插入順序是按照該主鍵的順序進行插入的,不需要磁盤的隨機讀取;
  當表有一個甚或多個非聚集索引時,且該索引不是表的唯一索引時,插入時數據而按主鍵順序存放,但葉子節點需要離散地訪問非聚集索引頁,插入性能會降低;此時,插入緩衝生效,先判斷非聚集索引頁是否在緩衝池中,如在則直接插入;如不在,則先放入一個插入緩衝區,然後再以一定的頻率執行插入緩衝和非聚集索引頁子節點的合併操作;

  插入緩衝生效的條件
  存在非聚集索引,且索引不是表的唯一索引;

  插入緩衝的分析
  show engine innodb status\G

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 2366, seg size 2368, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 103867, node heap has 1 buffer(s)
0.00 hash searches/s, 0.20 non-hash searches/s

  說明
  (1)seg size表示當前插入緩衝的大小 2368*16K,free list len表示空閒列表的長度,size表示已經合併記錄頁的數量,merges表示合併的數量;
  (2)merged operations是合併的情況,此處是我們最關注的部分;inserts表示插入的記錄數;

====================================
6 innodb的doublewrite
  是innodb引擎的關鍵特性之一;
  兩次寫保證的是innodb的可靠性;插入緩衝保證的是性能;

  數據文件的邏輯結構:
  頁 page 16K, 區 extent 1M, 段 seg 2M

  主要作用:
  針對寫磁盤文件失敗(由於各種原因)時,通過頁的副本還原該頁,再進行redo恢復,保證數據的完整性;

  工作原理:
  由兩部分組成,一部分是內存中的doublewrite buffer,大小爲2M,另一部分是磁盤上共享表空間中連續的兩個區extend, 2M;
  刷新髒頁時,先後做三步工作:
  一先將髒頁拷貝到內存的doublewrite buffer,
  二是通過該buffer兩次寫入(每次寫入1M)到共享表空間,然後馬上調用fsync函數同步磁盤;這個過程是順序寫的,開銷不大;
  三是再將該buffer中的頁寫入各個表空間文件中,此過程中的寫入是離散的;

  查看doublewrite的運行情況
  show global status like 'innodb_dblwr%'\G
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Innodb_dblwr_pages_written | 4     |
| Innodb_dblwr_writes        | 2     |
+----------------------------+-------+

  結果分析
  pages_written爲寫的頁數,writes爲寫的次數,一般兩者的比例小於64:1;
  如果比例較高,說明寫入壓力較大;

  寫入磁盤失效時的恢復原理
  從共享表空間中的doublewrite中找到該頁的一個副本,拷貝到表空間文件,再應用重做日誌進行恢復;

  配置建議
  innodb_doublewrite=ON
  #skip_innodb_doublewrite 或 innodb_doublewrite=OFF
  需要提供較快的性能時,可禁用雙寫;但在主服務器上,任何時間都應確保開啓雙寫功能;
  有些文件系統本身提供了部分寫失效的機制,如zfs文件系統,此時可以關閉雙寫;

=================================
7 自適應哈希索引
  工作機制
  innodb會自動監控表上索引的查找,如果發現建立哈希索引可以帶來速度的提升,則建立哈希索引;
  建立的依據是根據訪問的頻率和模式自動進行的;據官方文檔說明,對讀取和寫入可以提高2倍,對輔助索引的連接操作性能可提高5倍;

  適用條件
  只能用來搜索等值的查詢,如select * from table where index_col='xxx';
  對其他類型是不會被使用的;

  查看運行情況
  show engine innodb status\G
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 2366, seg size 2368, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 103867, node heap has 1 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s

  結果說明
  hash searches顯示了hash查找的次數
  non-hash searches顯示了不能利用hash查找的次數;

  配置:
  innodb_adaptive_hash_index=ON

=================================
8 innodb啓動關閉和恢複相關

  innodb_fast_shutdown=1
  可取值0, 1, 2,默認爲1
  0 關閉mysql時,完成所有的full purge和merge insert buffer操作,這個可能會花費很長時間,不次啓動可不用做重做日誌恢復;
    在做plugin升級時通常需要調整這個值爲0
  1 關閉mysql時,不完成上述的full purge和merge insert buffer操作,只是刷新緩衝池中的一些數據髒頁;
  2 關閉mysql時,既不完成上述的full purge和merge insert buffer操作,也不刷新緩衝池中的一些數據髒頁;只是將日誌寫入日誌文件,下次啓動時進行恢復;

  innodb_force_recovery=0..6
  0 默認值,表示當需要恢復時執行所有的恢復操作;
  1-6 用於恢復不能啓動的或崩潰的數據文件,此時只能進行select/create/drop等操作,不以進行update/delete/insert操作;
  1 忽略檢查到的corrupt頁
  2 阻止主線程的運行,如主線程需要執行full purge會導致crash
  3 不執行事務回滾
  4 不執行插入緩衝的合併操作
  5 不查看撤銷日誌undo log,視未提交的事務爲已提交;
  6 不執行前滾操作
  數據庫出現問題時,可利用此配置嘗試進行備份數據,結合error log觀察操作過程;

==============================
9 redo日誌,重做日誌
  作用:
  用於保證事務已提交時發生故障,數據庫的數據如果如果和日誌不一致,則將日誌中的數據重寫到數據庫中;
  redo存放在重做日誌文件中;

  過程:
  一個事務開始時,redo會記錄該事務的一個lsn(log sequence number,日誌序列號),事務執行時會往日誌緩衝裏插入事務日誌,事務提交時,將日誌緩衝寫入磁盤;

  觀察日誌情況:
  show engine innodb status\G
  ...
---
LOG
---
Log sequence number 1995757275
Log flushed up to   1995757275
Last checkpoint at  1995757275
0 pending log writes, 0 pending chkp writes
1220353 log i/o's done, 0.27 log i/o's/second

  說明:
  log sequence number 爲當前的lsn(log sequence number,日誌序列號);
  log flushed up to  爲刷新到redo的lsn;
  Last checkpoint at 爲刷新到磁盤的lsn;

===========================
10 undo日誌,撤消日誌
  作用:
  用於保證事務未提交時發生故障後,數據庫的數據如果和日誌不一致,則將日誌中的數據寫回到數據庫中;
  undo存放在數據庫內部的一個特殊段segment中,稱爲undo段,位於共享表空間內;

  過程
  undo並不是物理地恢復,而是邏輯地恢復;這個不難理解,因爲同一個頁,可能有多個事務在進行操作,不可能進行物理地恢復;
  回滾時,實際是做一個與先前相反的工作;對於insert,undo會完成一個delete;對於delete,會執行一個delete;對於update, 會執行一個相反的update;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章