刷盤,還是不刷盤,是一個問題 | 架構師之路重啟
前幾個有個朋友留言,問我說最近兩年公號發讀書感悟,職場感悟,AI實踐居多了,發架構思路類的內容少了。
最近準備重啟架構思路類的內容,且會保持一如既往的風格:
- 希望引發大家思考,多討論,多互動;
- 核心原理通俗化描述,目標是讓所有人搞懂;
- 思路,比結論重要;
本篇源自我去年看到的一篇關于ARIES算法的論文,作為重啟后的第一篇,算是一個引子,希望大伙多多支持。
畫外音:去掉了論文里復雜的概念、算法及公式,加入了相關概念的補充解釋說明與架構思考與補充。
讓我們來看數據庫中一個典型的讀寫事務的場景。
事務T1:
- 開始事務
- 讀取記錄A的值(假設A=1)
- 修改記錄A的值(假設修改為2)
- 提交事務
這里面可能涉及哪些技術問題呢?
問題一,數據庫如何讀取記錄A的值?
相關技術點:
- 數據庫使用緩沖池(buffer pool)機制提升讀寫效率;
- 數據庫以數據頁(page)為單位管理緩沖池;
- 如果被讀取的數據在緩沖池中,直接從緩沖池中讀取數據;
- 否則,先將磁盤上的數據復制到緩沖池,再從緩沖池中讀取數據;
此例中,假設記錄存儲在一個單頁上,且事先不在緩沖池中,故數據頁會被復制到緩沖池。
問題二,數據庫如何寫入記錄A的值?
相關技術點:
- 數據庫直接修改緩沖池中的數據;
- 緩沖池中的數據不能實時刷回磁盤,畢竟事務還沒有提交;
此例中,緩沖池中的數據被修改為2,磁盤上的數據仍是1(如上圖)。
那么,問題來了,如果緩沖池滿了,要將哪些數據刷回磁盤呢?
原則上,得做到:
- 如果事務未提交,“臟”數據不會被刷回磁盤;
- 如果事務已提交,數據會被刷回磁盤。
數據庫的故障恢復系統(crash recovery system)也會面臨類似的問題,在數據庫崩潰,內存中數據丟失的時候,未提交的事務和已提交的事務,如何保證ACID特性?
再來看一個并發的事務T1和T2的復雜場景:
T1.1. 開始事務
T1.2. 讀取記錄A的值(假設A=1)
T1.3. 修改記錄A的值(假設修改為2)
T2.1開始事務
T2.2讀取記錄B的值(假設B=3)
T2.3修改記錄B的值(假設修改為7)
T2.4提交事務
T1.4.回滾事務
假設,記錄A和記錄B都在一個數據頁上。
事務T1讀取記錄A的值,會將磁盤上的數據頁復制到緩沖池,再進行讀取(如上圖)。
事務T1修改記錄A的值,會直接修改緩沖池中的數據(如上圖)。
好,這個時候,事務T2啟動了。
事務T2先讀取記錄B的值,緩沖池中已經存在記錄B所在的頁,所以無需進行磁盤訪問。
畫外音:緩沖池的核心作用,提高讀寫性能。
接下來,事務T2修改記錄B的值,會直接修改緩沖池中的數據(如上圖)。
接下來,事務T2提交了。
這個時刻,我們面臨一個巨大的難題:在數據庫返回應用程序事務成功之前,要不要將數據刷回磁盤?
如果不將數據刷回磁盤,就返回應用程序事務成功,那么萬一數據庫故障,緩沖池中的數據丟失,事務T2的ACID特性就會被破壞。
反之,如果將數據刷回磁盤,但此時事務T1還沒有提交/回滾,事務T1的臟數據刷回磁盤,事務T1的ACID特性也會被破壞。
我們似乎陷入了一個兩難的境地。如果是你,你會考慮用什么思路解決這個問題呢?
總結與思考:
- 數據庫使用緩沖池(buffer pool)機制提升讀寫效率;
- 數據庫以數據頁(page)為單位管理緩沖池;
- 數據庫直接讀寫緩沖池中的數據;
- 此情況,刷盤,還是不刷盤?