MySQL的crash-safe的原理
組件分為
- 連接器
- 分析器
- 優化器
- 執行器
- 存儲引擎(插件的形式)
前面的四個分別是Server層的組件,后面存儲引擎層是插件,如InnoDB,MyISAM,Memory等
連接器
連接器的作用主要是維持和客戶端之間的通信功能。同時還負責同客戶端的認證和授權的功能。
每個連接在完成認證和授權后就會一直維持一個長連接,創建完連接的后的所有通信都不需要進行再次進行認證,但每次SQL請求操作都會有權限的認證
在連接完成后,如果連接長時間沒有SQL請求通信,該連接會處於Sleep狀態,直到超過MySQL實例配置的wait_timeout
參數的時間后,連接器會主動斷開該長連接。MySQL實例默認的wait_timeout
的的時間是8小時
分析器
分析器的執行分為兩個過程,一個是詞法分析,另一個是語法分析
我們發送的SQL語句是一個字符串,里面可能存在空格和字符串。詞法分析器的作用就是把這個字符串代表的意思進行數據的格式化,比如SELECT
子串標識這是一個讀請求,FROM t_table
表示要操作t_table這張表
語法分析的作用是要對這個語法的正確性做一個檢查,如果當前的SQL語法不符合MySQL的語法,那么就直接報錯了,不進行下一步的執行
優化器
優化器的作用是根據分析器得出的結果再結合當前表數據的儲存情況來的出一個查詢效率最高的執行計划。常見的情況有“:
- 同一個SQL語句中存在多個索引列條件,那么應該先選擇哪個索引先進行查詢
- 多表join操作的時候,如何選擇哪個表作為驅動表等
上面兩種情況都是優化器等工作職責
執行器
執行器的作用就是負責調用底層存儲引擎實現的抽象接口,按照優化器輸出的執行計划進行執行。執行器才是真正負責執行SQL操作的組件
存儲引擎
存儲引擎的作用就是當初MySQL實現的時候留下的可擴展的點,不同的存儲引擎的實現可以有着不同的應用場景。MySQL為存儲引擎定一個統一的抽象接口,只要不同的存儲引擎實現該抽象接口就能被上層的執行器比如OLTP的場景下需要數據庫事務的支持,那么InnoDB就是好的選擇。而在需要大量讀請求而寫請求少,並且不需要事物的情況下MyISAM是一個好的選擇
一條SQL的執行就是上面的組件從上到下的執行順序,下面就用MySQL默認的InnoDB引擎進行展開看看InnoDB的執行原理
redo-log
InnoDB有一個重要的模塊: redo-log
,它是InnoDB支持事物的重要模塊。redo-log是物理日志,它記錄了哪一個數據頁上做了什么修改。可以說如果沒有redo-log,InnoDB就不具有crash-safe的能力
redo-log是由一組分別為4個固定大小文件組成。可以通過MySQL的參數來指定文件的大小。作為日志文件,redo-log是順序寫的,所以寫對磁盤來說是非常高效的。數據的結構可以看成是下面的圖
Check-point是當前的數據擦除指針,標識了當前redo-log的擦除文件位置。write-point是寫指針,標識了當前的數據寫文件位置。InnoDB要保證的是write-point不能超過check-point。check-point要一直保持在write-point之前的一段距離。
bin-log
bin-log是MySQL的server層實現的邏輯日志,相當於記錄的SQL語句的操作邏輯。
兩階段提交
InnoDB是如何實現crash-safe的呢?一個需要知道的理論就是兩階段提交
兩階段提交用簡單點的話講就是:
- 先讀取數據,並更新然后將新行數據保存在內存中
- 將物理更新記錄寫入redo-log,並標記這條記錄為prepare狀態(第一步)
- InnoDB將操作提交到執行器,執行器再將邏輯更新記錄寫入bin-log,同時調用引擎的寫入和更新接口將磁盤文件更新
- 上一步操作完成后再提交事物,將redo-log中對應的記錄狀態改為commit狀態(第二步)
- 返回更新結果
崩潰后的數據恢復階段
如果在更新或寫入數據的過程中,機器出現崩潰。那么在機器在重啟后,MySQL會首先去驗證redolog的完整性,如果redolog中沒有prepare狀態的記錄,則記錄是完整的,就日記提交。如果redolog中存在prepare記錄,那么就去驗證這條redolog對應的binlog記錄,如果這條binlog是完整的,那么完整提交redolog,否則執行回滾邏輯