【mysql】關於checkpoint機制

来源:http://www.cnblogs.com/chenpingzhao/archive/2016/01/08/5107480.html
-Advertisement-
Play Games

一、簡介思考一下這個場景:如果重做日誌可以無限地增大,同時緩衝池也足夠大,那麼是不需要將緩衝池中頁的新版本刷新回磁碟。因為當發生宕機時,完全可以通過重做日誌來恢復整個資料庫系統中的數據到宕機發生的時刻。但是這需要兩個前提條件:1、緩衝池可以緩存資料庫中所有的數據;2、重做日誌可以無限增大因此Chec...


一、簡介

思考一下這個場景:如果重做日誌可以無限地增大,同時緩衝池也足夠大,那麼是不需要將緩衝池中頁的新版本刷新回磁碟。因為當發生宕機時,完全可以通過重做日誌來恢復整個資料庫系統中的數據到宕機發生的時刻。

但是這需要兩個前提條件:1、緩衝池可以緩存資料庫中所有的數據;2、重做日誌可以無限增大

因此Checkpoint(檢查點)技術就誕生了,目的是解決以下幾個問題:1、縮短資料庫的恢復時間;2、緩衝池不夠用時,將臟頁刷新到磁碟;3、重做日誌不可用時,刷新臟頁。

  • 當資料庫發生宕機時,資料庫不需要重做所有的日誌,因為Checkpoint之前的頁都已經刷新回磁碟。資料庫只需對Checkpoint後的重做日誌進行恢復,這樣就大大縮短了恢復的時間。

  • 當緩衝池不夠用時,根據LRU演算法會溢出最近最少使用的頁,若此頁為臟頁,那麼需要強制執行Checkpoint,將臟頁也就是頁的新版本刷回磁碟。

  • 當重做日誌出現不可用時,因為當前事務資料庫系統對重做日誌的設計都是迴圈使用的,並不是讓其無限增大的,重做日誌可以被重用的部分是指這些重做日誌已經不再需要,當資料庫發生宕機時,資料庫恢復操作不需要這部分的重做日誌,因此這部分就可以被覆蓋重用。如果重做日誌還需要使用,那麼必須強制Checkpoint,將緩衝池中的頁至少刷新到當前重做日誌的位置。

對於InnoDB存儲引擎而言,是通過LSN(Log Sequence Number)來標記版本的。

LSN是8位元組的數字,每個頁有LSN,重做日誌中也有LSN,Checkpoint也有LSN。可以通過命令SHOW ENGINE INNODB STATUS來觀察:

mysql> show engine innodb status \G

---
LOG
---
Log sequence number 34778380870
Log flushed up to   34778380870
Last checkpoint at  34778380870
0 pending log writes, 0 pending chkp writes
54020151 log i/o's done, 0.92 log i/o's/second

Checkpoint發生的時間、條件及臟頁的選擇等都非常複雜。而Checkpoint所做的事情無外乎是將緩衝池中的臟頁刷回到磁碟,不同之處在於每次刷新多少頁到磁碟,每次從哪裡取臟頁,以及什麼時間觸發Checkpoint。

二、Checkpoint分類

在InnoDB存儲引擎內部,有兩種Checkpoint,分別為:Sharp Checkpoint、Fuzzy Checkpoint

Sharp Checkpoint 發生在資料庫關閉時將所有的臟頁都刷新回磁碟,這是預設的工作方式,即參數innodb_fast_shutdown=1。但是若資料庫在運行時也使用Sharp Checkpoint,那麼資料庫的可用性就會受到很大的影響。故在InnoDB存儲引擎內部使用Fuzzy Checkpoint進行頁的刷新,即只刷新一部分臟頁,而不是刷新所有的臟頁回磁碟。

Fuzzy Checkpoint:1、Master Thread Checkpoint;2、FLUSH_LRU_LIST Checkpoint;3、Async/Sync Flush Checkpoint;4、Dirty Page too much Checkpoint

1、Master Thread Checkpoint 

以每秒或每十秒的速度從緩衝池的臟頁列表中刷新一定比例的頁回磁碟,這個過程是非同步的,此時InnoDB存儲引擎可以進行其他的操作,用戶查詢線程不會阻塞。

2、FLUSH_LRU_LIST Checkpoint

因為InnoDB存儲引擎需要保證LRU列表中需要有差不多100個空閑頁可供使用。在InnoDB1.1.x版本之前,需要檢查LRU列表中是否有足夠的可用空間操作發生在用戶查詢線程中,顯然這會阻塞用戶的查詢操作。倘若沒有100個可用空閑頁,那麼InnoDB存儲引擎會將LRU列表尾端的頁移除。如果這些頁中有臟頁,那麼需要進行Checkpoint,而這些頁是來自LRU列表的,因此稱為FLUSH_LRU_LIST Checkpoint。

而從MySQL 5.6版本,也就是InnoDB1.2.x版本開始,這個檢查被放在了一個單獨的Page Cleaner線程中進行,並且用戶可以通過參數innodb_lru_scan_depth控制LRU列表中可用頁的數量,該值預設為1024,如:

mysql>  SHOW GLOBAL VARIABLES LIKE 'innodb_lru_scan_depth';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 1024  |
+-----------------------+-------+

3、Async/Sync Flush Checkpoint

指的是重做日誌文件不可用的情況,這時需要強制將一些頁刷新回磁碟,而此時臟頁是從臟頁列表中選取的。若將已經寫入到重做日誌的LSN記為redo_lsn,將已經刷新回磁碟最新頁的LSN記為checkpoint_lsn,則可定義:

checkpoint_age = redo_lsn - checkpoint_lsn

再定義以下的變數:

async_water_mark = 75% * total_redo_log_file_size

sync_water_mark = 90% * total_redo_log_file_size

若每個重做日誌文件的大小為1GB,並且定義了兩個重做日誌文件,則重做日誌文件的總大小為2GB。那麼async_water_mark=1.5GB,sync_water_mark=1.8GB。則:

當checkpoint_age<async_water_mark時,不需要刷新任何臟頁到磁碟;

當async_water_mark<checkpoint_age<sync_water_mark時觸發Async Flush,從Flush列表中刷新足夠的臟頁回磁碟,使得刷新後滿足checkpoint_age<async_water_mark;

checkpoint_age>sync_water_mark這種情況一般很少發生,除非設置的重做日誌文件太小,並且在進行類似LOAD DATA的BULK INSERT操作。此時觸發Sync Flush操作,從Flush列表中刷新足夠的臟頁回磁碟,使得刷新後滿足checkpoint_age<async_water_mark。

可見,Async/Sync Flush Checkpoint是為了保證重做日誌的迴圈使用的可用性。在InnoDB 1.2.x版本之前,Async Flush Checkpoint會阻塞發現問題的用戶查詢線程,而Sync Flush Checkpoint會阻塞所有的用戶查詢線程,並且等待臟頁刷新完成。從InnoDB 1.2.x版本開始——也就是MySQL 5.6版本,這部分的刷新操作同樣放入到了單獨的Page Cleaner Thread中,故不會阻塞用戶查詢線程。

MySQL官方版本並不能查看刷新頁是從Flush列表中還是從LRU列表中進行Checkpoint的,也不知道因為重做日誌而產生的Async/Sync Flush的次數。但是InnoSQL版本提供了方法,可以通過命令SHOW ENGINE INNODB STATUS來觀察,如:

mysql> show engine innodb status \G

BUFFER POOL AND MEMORY
----------------------
Total memory allocated 2058485760; in additional pool allocated 0
Dictionary memory allocated 913470
Buffer pool size   122879
Free buffers       79668
Database pages     41957
Old database pages 15468
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 15032929, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 15075936, created 366872, written 36656423
0.00 reads/s, 0.00 creates/s, 0.90 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 41957, unzip_LRU len: 0
I/O sum[39]:cur[0], unzip sum[0]:cur[0]

4、Dirty Page too much

即臟頁的數量太多,導致InnoDB存儲引擎強制進行Checkpoint。其目的總的來說還是為了保證緩衝池中有足夠可用的頁。其可由參數innodb_max_dirty_pages_pct控制:

mysql> SHOW GLOBAL VARIABLES LIKE 'innodb_max_dirty_pages_pct' ;
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_max_dirty_pages_pct | 75    |
+----------------------------+-------+

innodb_max_dirty_pages_pct值為75表示,當緩衝池中臟頁的數量占據75%時,強制進行Checkpoint,刷新一部分的臟頁到磁碟。在InnoDB 1.0.x版本之前,該參數預設值為90,之後的版本都為75。

三、Checkpoint機制

在Innodb事務日誌中,採用了Fuzzy Checkpoint,Innodb每次取最老的modified page(last checkpoint)對應的LSN,再將此臟頁的LSN作為Checkpoint點記錄到日誌文件,意思就是“此LSN之前的LSN對應的日誌和數據都已經flush到redo log

當mysql crash的時候,Innodb掃描redo log,從last checkpoint開始apply redo log到buffer pool,直到last checkpoint對應的LSN等於Log flushed up to對應的LSN,則恢復完成

那麼具體是怎麼恢復的呢?

 

如上圖所示,Innodb的一條事務日誌共經歷4個階段:

  • 創建階段:事務創建一條日誌;

  • 日誌刷盤:日誌寫入到磁碟上的日誌文件;

  • 數據刷盤:日誌對應的臟頁數據寫入到磁碟上的數據文件;

  • 寫CKP:日誌被當作Checkpoint寫入日誌文件;

對應這4個階段,系統記錄了4個日誌相關的信息,用於其它各種處理使用:

  • Log sequence number(LSN1):當前系統LSN最大值,新的事務日誌LSN將在此基礎上生成(LSN1+新日誌的大小);

  • Log flushed up to(LSN2):當前已經寫入日誌文件的LSN;

  • Oldest modified data log(LSN3):當前最舊的臟頁數據對應的LSN,寫Checkpoint的時候直接將此LSN寫入到日誌文件;

  • Last checkpoint at(LSN4):當前已經寫入Checkpoint的LSN;

對於系統來說,以上4個LSN是遞減的,即: LSN1>=LSN2>=LSN3>=LSN4.

具體的樣例如下(使用show innodb status \G命令查看,Oldest modified data log沒有顯示):

LOG
---
Log sequence number 34822137537
Log flushed up to   34822137537
Last checkpoint at  34822133028
0 pending log writes, 0 pending chkp writes
54189288 log i/o's done, 3.00 log i/o's/second 

四、日誌保護機制

mysql crash的時候,Innodb有日誌刷盤機制,可以通過innodb_flush_log_at_trx_commit參數進行控制,這裡說的是如何防止日誌覆蓋導致日誌丟失

Innodb的checkpoint和redo log有哪些緊密關係?有幾上名詞需要解釋一下:

  • Ckp age(動態移動): 最老的dirty page還沒有flush到數據文件,即沒有做last checkpoint的範圍

  • Buf age(動態移動): modified page information沒有寫到log中,但已在log buffer

  • Buf async(固定點): 日誌空間大小的7/8,當buf age移動到Buf async點時,強制把沒有寫到log中的modified page information開始寫入到log中,不阻塞事務

  • Buf sync(固定點): 日誌空間大小的15/16,當寫入很大的,buf age移動非常快,一下子到buf sync的點,阻塞事務,強制把modified page information開始寫入到log中。如果不阻塞事務,未做last checkpoint的redo log存在覆蓋危險

  • Ckp async(固定點): 日誌空間大小的31/32,當ckp age到達ckp async,強製做last checkpoint,不阻塞事務

  • Ckp sync(固定點):日誌空間大小,當ckp age到達ckp sync,強製做last checkpoint,阻塞事務,存在redo log覆蓋的危險

接下分析4種情況

  • 如果buf age在buf async和buf sync之間

  • 如果buf age在buf sync之後(當然這種情況是不存在,mysql有保護機制)

  • 如果ckp age在ckp async和ckp sync之間(這種情況是不存在)

  • 如果ckp age在ckp sync之後(這種情況是不存在)

第一種情況:

當寫入量巨大時,buf age移動到buf async和buf sync之間,觸發寫出到log中,mysql把儘量多的log寫出,如果寫入量減慢,buf age又移回到“圖一”狀態。如果寫入量大於flush log的速度,buf age最終會和buf sync重疊,這時所有的事務都被阻塞,強制將2*(Buf age-Buf async)的臟頁刷盤,這時IO會比較繁忙。

第二種情況:

當然這種情況是不可能出現,因為如果出現,redo log存在覆蓋的可能,數據就會丟失。buf age會越過log size,buf age的大小可能就超過log size,如果要刷buf age,那麼整個log size都不夠容納所有的buf age。

第三種和第四種情況不存在分析:

ckp age始終位於buf age的後面(左邊),因為ckp age是last checkpoint點,總是追趕buf age(將儘可能多的modified page flush到磁碟),所以buf age肯定是先到達到buf sync。

ckp async及ckp sync存在意義?

mysql中page cache也存在high water及low water,當dirty page觸到low water時,os是開始flush dirty page到磁碟,到high water時,會阻塞一切動作,os會瘋狂的flush dirty page,磁碟會很忙,存在IO Storm,

 

本文參考:

http://blog.csdn.net/yah99_wolf/article/category/539408

http://www.cnblogs.com/bamboos/p/3532150.html

http://tech.uc.cn/?p=716

http://www.mysqlperformanceblog.com/2011/04/04/innodb-flushing-theory-and-solutions/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、簡介 使用linux系統的過程中,有時發現系統根目錄(/)的空間不足,導致系統運行很慢,針對該現象,本文詳細介紹根目錄(/)的空間擴展方法。 二、操作步驟 1)查看根目錄大小 df 2)查找系統有無可用空間,發現系統存在未使用硬碟/dev/sdb fdisk -l 3)依次執行如下指令,對該磁碟...
  • 在我自己的伺服器上面搭建了郵件伺服器,為的是接下來寫shell腳本進行報警監控。當伺服器發生意外,可以及時發送郵件伺服器到郵箱。看了兩個教程,按照兩個教程來搭建的,感謝原作。Linux 下搭建Postfix郵件伺服器詳解:1、首先關閉sendmail服務service sendmail stop2、...
  • Linux安裝jdk。
  • 概述 LVM的產生是因為傳統的分區一旦分區好後就無法線上擴充空間,也存在一些工具能實現線上擴充空間但是還是會面臨數據損壞的風險;傳統的分區當分區空間不足時,一般的解決辦法是再創建一個更大的分區將原分區卸載然後將數據拷貝到新分區,但是在企業的生產系統往往不允許停機或者允許停機的時間很短,LVM就能.....
  • Ubuntu 15.10 (似乎從14.04開始) 的小坑,使用自帶遠程桌面連接出錯,弄得我很不爽,偶爾從 上看到一視頻,解決了。聊以記之。 順便說一下,這個自帶的桌面共用的名字是:vino 原本使用 vnc4server 也挺好,無奈 `lubuntu ubuntu unity` 就是灰屏,...
  • Linux 系統 網路配置配置Linux系統網路的方法有幾種,這裡介紹本人常用的兩種。第一種:使用命令ifconfig配置,具體用法:Ipconfig ethx x.x.x.x netmask x.x.x.x效果如下圖:通常,此種配置法只是用來測試用,因為重啟機器後,該配置的內容將會失效。第二種方....
  • 最近準備做一個公司物品申領系統,資料庫的表已經設計好,目前正在搭建開發和運行環境。計劃使用ASP.Net + SQL Server完成此次的設計。以下為會員註冊的存儲過程,預計把註冊頁面中的兩個Text框中的數值作為參數傳入資料庫中,最後返回1或0表示成功/失敗: 1 ALTER procedure...
  • 昨天在做一個sql代碼查詢的問題,發現了一些可優化的東西,藉此記錄一下。1,善用with as之前在寫sql 分頁查詢的時候,就只是用嵌套查詢,然後一個普通的關聯幾個表查詢,例如:SELECT * FROM( SELECT TOP 100 lr.SKU,lr.ItemPrice,lr.La...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...