BlueStore checksum機制

BlueStore checksum機制
1.checksum的計算
2.checksum的驗證算法

BlueStore 磁盤靜默數據損壞分析數據庫

  1. fsck過程當中發現磁盤數據靜默錯誤
  2. clone操做
  3. read操做
  4. write操做
  5. Gc操做

實際場景
1.騰訊場景問題確認
2.rbd mirror
3.rbd export import
4.集羣擴容數組

BlueStore checksum機制

Bluestore的checksum算法默認採用的是crc32, 算法的邏輯很簡單,即以固定大小的數據塊爲單位進行計算checksum,數據塊的大小通常爲4K,同設備的塊大小。
Checksum的結果做爲bluestore_blob_t結構體序列化的一部分存放在數據庫中,假設一個blob的長度爲64KB,進行checksum的數據塊大小爲4KB, 則初始化該blob時,對於crc32,每一個數據塊的checksum用4字節描述,將分配(64KB/4KB)* 4 = 64字節用於存儲該blob數據的checksum。 ide

1.checksum的計算

寫數據會進行checksum的計算,對於對齊寫和非對齊寫,都會以數據所在的4KB對齊的數據塊爲單位進行計算。好比0-256區間的數據更新,會將257-4095區間的數據讀出來,而後以4KB爲單位進行計算,若是257-4095原來不存在數據,則用0進行填充後進行計算,計算完將checksum值存儲在該blob中。 測試

2.checksum的驗證

讀數據時,bluestore中會首先查找所讀取數據區間所對應的checksum數組,而後用讀取的數據計算checksum,判斷二者是否一致。舉例以下:假設blob的大小爲64KB,
本次讀取的數據區間爲8192~16383, 則分別計算8192~12287和12288-16383兩個數據塊的checksum,而後讀取blob中以前寫數據時計算的checksum,這兩塊數據對應的checksum值爲checksum數組偏移爲2和3的兩個4字節變量。日誌

BlueStore 磁盤靜默數據損壞分析

BlueStore中以下五種操做會讀取對象數據,其中目前只有對象數據read操做能主動觸發對象修復操做,且對上層用戶不感知。code

結論:讀數據的時候依靠checksum機制能夠發現數據不一致的狀況,其中read能夠自動修復,其餘的讀取操做若是發現存在靜默錯誤,會及時報錯,因此能夠取消按期deep-scrub操做。對象

1. fsck過程當中發現磁盤數據靜默錯誤

==>> int BlueStore::_mount(bool kv_only, bool open_db)
====>> fsck(cct->_conf->bluestore_fsck_on_mount_deep)
若是bluestore_fsck_on_mount_deep爲真,bluestore的fsck過程當中將會讀取整個文件,以此將會檢查該文件對應的磁盤塊是否存在數據損壞現象,若是文件損壞,會致使mount失敗,從而致使該osd啓動失敗。進程

//bluestore_fsck_on_mount_deep 默認爲true
    Option("bluestore_fsck_on_mount_deep", Option::TYPE_BOOL, Option::LEVEL_DEV)
    .set_default(true)
    .set_description("Run deep fsck at mount"),
2. clone操做

Clone操做是否從磁盤讀數據取決於bluestore_clone_cow配置,若是bluestore_clone_cow爲真,則直接進行extent的共享,不會有實際的數據讀寫操做。若是爲假,讀取被clone對象的數據,寫入新的對象,若是此時讀取過程當中,發生磁盤靜默錯誤,則直接assert,osd進程down掉。事務

//bluestore_clone_cow 默認爲true
     Option("bluestore_clone_cow", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
    .set_default(true)
    .set_safe()
    .set_description("Use copy-on-write when cloning objects (versus reading and rewriting them at clone time)"),
3. read操做

讀操做過程當中,若是發現磁盤靜默數據錯誤,是會主動對該對象進行修復的,代碼調用流程以下:

==>> do_osd_ops
====>> do_read
======>> objects_read_sync
======>> rep_repair_primary_object

將對象加入待修復列表,進行修復,讀操做 會從新發起,用戶不感知。

4. write操做

Write操做的rmw寫,須要首先從磁盤讀取數據進行覆蓋寫,若是此時發生磁盤靜默錯誤,代碼中直接assert,代碼調用流程以下:
==>> _do_write_small
====>> _do_read 觸發( assert(r >= 0 && r <= (int)tail_read);)

一般ext4類的本地文件系統會直接abort事務,將文件系統掛載爲只讀,所以此處直接assert osd,致使osd進程down也能夠理解。

5. Gc操做

==>> _do_write
====>> _do_gc
======>> _do_read 觸發assert(r == (int)it->length);
此處也會致使osd down,策略我理解同write操做。

實際場景

1.騰訊場景問題確認

1.1 cache?1.2 no crc? 1.3 migration?
ceph社區郵件」Copying without crc check when peering may lack reliability」提到的磁盤靜默數據損壞沒有及時發現的問題,根據發件人的測試步驟沒有復現,數據都能自動修復,目前正在請求發件人提供完整復現腳本。現階段調查結果以下:
1, ceph-objectstore-tool修改對象數據時,若是checksum使能,會同步用新的數據計算checksum,若是修改對象主副本,則新數據遷移到新的crush root下,此處是合理的,由於checksum檢查經過,osd會認爲數據是正確的,若是修改對象的從副本,因爲遷移是根據主副本的數據,新的crush root下的數據仍然是主副本數據。
若是對該osd作deep-scrub, 若是對象所屬的pg在該osd上是主pg,是能檢測到數據變更的,由於會和從pg上的副本作對比,若是對象所屬的pg在該osd上爲從pg, deep-scrub將不會針對該pg作檢查的。
2,若是對象數據的主副本存在cache,即便對應的底層硬件存在靜默錯誤,正常的讀操做和deep-scrub都不會檢測到磁盤靜默錯誤(我已經發送patch讓deep-scrub能檢測出此種損壞,patch已經被merge)。
3,數據遷移在ceph master分支上驗證,在三副本測試中,破壞一個副本的數據,而後讓數據遷移到另外一個crush root下,ceph會自動進行數據修復的,用戶不感知。

2.rbd mirror

測試步驟:
破壞journal對象的主副本數據,而後進行replay,待replay完成後檢查兩個rbd設備的數據是否一致。
測試結果:
暫時沒有找到測試方法來控制上述流程,但理論分析是能夠修復的,用戶不感知道。Rbd-mirror回放日誌數據,也就是讀取日誌對象主副本數據,具體流程同」3. read操做」。

3.rbd export import

測試步驟:
建立一個rbd設備,向其偏移0處寫入4MB隨機數據,而後經過dd破壞其中一段數據,注意破壞是主副本的數據。破壞完成後,將主副本所在的osd重啓以消除cache的影響,而後進行rbd的export 和import測試,讀取兩個rbd設備的前4MB數據MD5值與初始的寫入rbd設備的隨機數據文件md5值是否一致。

測試結果:
損壞的rbd對象數據會自動進行修復,用戶不感知,具體原理參見」3. read操做」。

4.集羣擴容

測試步驟:
建立3 osd集羣,用rados建立一個對象,損壞對象主副本數據,注意一樣須要重啓osd以清除bluestore層cache,加入3個新的osd,待集羣穩定後,用rados讀取對象數據,驗證數據md5值是否一致。

測試結果: 集羣rebalance成功,損壞的數據會自動進行修復,用戶不感知,具體原理參見」3. read操做」。

相關文章
相關標籤/搜索