---
title: DB淺談-Transaction Processing and Recovery
tags: DB
description: DB淺談-事務處理與恢復
---
# Transaction Processing and Recovery
## Movitation
```Transction```是指資料庫中一個不可被切分的邏輯工作單元.
允許將多個操作表示為一個步驟. 操作包含了讀取跟寫入修改數據紀錄.
Transction必須遵從ACID這四個原則.
[Haerder, Theo, and Andreas Reuter. 1983. “Principles of transaction-oriented database recovery.” ACM Computing Surveys 15 no. 4 (December):287–317](https://dl.acm.org/doi/10.1145/289.291)
[微服務瞎談(4) 單機ACID事務 & MySQL主從同步](https://ithelp.ithome.com.tw/articles/10235277)
資料庫要完成Transction還需要多個組件一起協同作業, 在節點內部, ```Transaction manager```負責協調、調度與追蹤tx與tx各個步驟.
```Lock manager```保護對資料的訪問, 並防止可能破壞數據完整性的併發存取.
```Page cache```充當了硬碟與存儲引擎中間的媒介.
```Log manager```紀錄了在page cache上的操作.
要完成單機tx操作跑不掉上面組件的協作.
若是分佈式tx, 就需要額外的組件了.
[Optimizing InnoDB Transaction Management](https://dev.mysql.com/doc/refman/8.0/en/optimizing-innodb-transaction-management.html)
[MySQL · 引擎特性 · 8.0 Lock Manager](http://mysql.taobao.org/monthly/2020/04/09/)
[InnoDB Locking](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html)
[MySQL · 性能优化 · PageCache优化管理](http://mysql.taobao.org/monthly/2020/09/01/)
[Redo Log](https://dev.mysql.com/doc/refman/8.0/en/innodb-redo-log.html)
[MySQL字典](https://dev.mysql.com/doc/refman/8.0/en/glossary.htm)
## Buffer Management
大部分的資料庫都採用two-level memory hierarchy :
慢速的持久化存處(disk)與高速的main memory(Ram).
Pages被cached在ram中的話, 直接就能返回其cached copy.
假設沒有其他process修改過數據, 那cached pages就能一直被reuse.
這種作法也能稱為virtual disk
[Organization and maintenance of large ordered indexes](https://link.springer.com/article/10.1007/BF00288683)
當ram中沒有cached page時, .
上面這樣的機制稱為```page cache```或```buffer pool```
[MySQL Buffer Pool](https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html)
[MySQL · 性能优化 · PageCache优化管理](http://mysql.taobao.org/monthly/2020/09/01/)
OS其實也有page cache的概念, OS會利用unused memmory來透明地緩存硬碟上的內容, 提供I/O性能.
把硬碟做加載的過程稱為```Page in```
cached page要是被更改就成為```dirty```, 這些dirty會被```flush```到硬碟上.
但暫存區總是會滿的, 因為容量配置上, 就是比硬碟小, 總是會被填滿的, 這時候就必須把某個page直接換出(evict)buffer.

圖5.1展示了Btree的表示, 以及cache page與disk page之間的關係.
因為page cache是以亂序載入disk page到記憶體中的空白處, 所以硬碟中與記憶體中的page順序併不存在直接的映射.
都是透過buffer pool來對照的.
page cache的主要用途有
- 緩存page到memory中
- 對硬碟上page的修改給緩衝(buffer), 並且修改看到的版本是buffer上的版本
- 被請求的page不再memory中且free space還夠時, page cache機制會將該page給page in, 並返回緩存的版本
- 如果請求的page已經被緩存, 則直接返回緩存的版本
- 如果free space已經不夠來page in新的page, 就會有些page被evict, 被evict的page, 會被flush回disk.
### Cache Eviction
讓memory盡量保持在空間利用度極高的狀態是好事情.
可以讓更多的讀取請求直接從buffer返回.
也能讓同一個page上的修改請求被緩衝再一起, 一起flush寫回disk.
當page cache已經滿了, 為了填充新內容, 就必須要evict舊頁.
如果該cached page跟disk是同步的(表示非dirty), 並且該page沒被pin/referenced, 就可以被立刻evict.
dirty page必須在flush完成後才能被evict.
如果該page正在被存取, 也不能被evict.



每次evict就觸發flush to disk, 性能當下會很差.
所以有些資料庫會使用另一個背景進程, 檢查可能被evict的dirty page來更新進disk.
[MySQL Purge](https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_purge)
刷到disk的重點就是durability(持久性), 如果db crash了, 所有還沒被flush完成的資料將會lost.
所以為了確保都能被完整flush, 會有個checkpoint進程來觸發把WAL跟page cache做flush, 把有log已經flush完成, 才能從WAL中丟棄. 過程都完成了, Dirty page才能被evict出page cache.
[MySQL Checkpoint](https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_checkpoint)
flush strategiec trade-offs
- 推遲(postpone)flushes來減少disk access次數
- 提早(preeptively)fluss page來能快速地eviction
- 挑選pages來被evict, 且用最優的順序做flush
- 保持cache size在memory的限制內
- 避免資料還沒被持久化到disk時, 就被丟失了
### Locking Pages in Cache
併發得讀取可能去請求同一個page, 併發的寫入也是.