轉載請註明出處 陳小跑 http://www.cnblogs.com/chenxianpao/p/5878159.htmlhtml
本文只梳理了大體流程,細節部分還沒搞的太懂,有時間再看,再補充,有錯誤請指正,謝謝。服務器
Ceph 的主要一大特色是強一致性,這裏主要指端到端的一致性。衆所周知,傳統存儲路徑上從應用層到內核的文件系統、通用塊層、SCSI層到最後的HBA和磁盤控制器,每層都有發生錯誤的可能性,所以傳統的端到端解決方案會以數據塊校驗爲主來解決。而在 Ceph 方面,更是加入了 Ceph 本身的客戶端和網絡、存儲邏輯、數據遷移,勢必致使更高的錯誤機率。網絡
由於 Ceph 做爲一個應用層的路徑,它利用了 POSIX 接口進行存儲並支持 Parity Read/Write,這時候若是封裝固定數據塊而且加入校驗數據會致使較嚴重的性能問題,所以 Ceph 在這方面只是引入 Scrub 機制(Read Verify)來保證數據的正確性。併發
簡單來講,Ceph 的 OSD 會定時啓動 Scrub 線程來掃描部分對象,經過與其餘副本進行對比來發現是否一致,若是存在不一致的狀況,Ceph 會拋出這個異常交給用戶去解決。app
2、Scrub 函數流程:從PG::chunky_scrub開始進行scrub的狀態機
NEW_CHUNK狀態_request_scrub_map函數發送new MOSDRepScrub消息給replicas,replicas處理流程:
Primary接收到MOSDSubOp消息後的處理流程:
將收到的replicas的scrubmap寫入到scrubber.received_maps中;
對於全部replicas都返回scrubmap,則調用PG::requeue_scrub()函數從新進入scrub操做
3、Scrub 狀態機
① INACTIVE
開始進行scrub;更新osd的狀態;設置scrubber的狀態信息,好比start、state、epoch_start等,將state設置成NEW_CHUNK
② NEW_CHUNK
初始化scrubber.primary_scrubmap、received_maps;根據osd_scrub_chunk_min和osd_scrub_chunk_max獲取指定數量個object(具體如何獲取,從何獲取?);向全部的actingbackfill副本發送new MOSDRepScrub()消息,獲取scrub_map信息,將狀態設置成WAIT_PUSHES
③ WAIT_PUSHES
等待PUSH(push什麼?)完成,若是active_pushes爲0則把狀態設置成WAIT_LAST_UPDATE
④ WAIT_LAST_UPDATE
等待update(update什麼?)完成,若是last_update_applied大於scrubber.subset_last_update把狀態設置成BUILD_MAP
⑤ BUILD_MAP
創建一個scrub_map,讀取對象的大小和屬性信息,若是是deep模式,根據EC和replicate兩種pool計算不一樣的CRC32校驗碼,repicate類型以omap_header計算CRC值,EC類型的CRC值爲object的hash值;scrubmap包括 object size, attr 和omap attr, 歷史版本信息;把狀態設置成WAIT_REPLICAS
⑥ WAIT_REPLICAS
等待收到replicas返回的信息,把狀態設置成COMPARE_MAPS
⑦ COMPARE_MAPS
根據scrubber.primary_scrubmap建立權威authmap;創建包含全部object的master set;遍歷master set,選擇一個沒發生異常的權威的osd做爲比較對象,比較文件大小、屬性信息以及digest信息(digest and omap_digest);記錄錯誤對象和丟失對象,後續recovery恢復;將狀態設置成WAIT_DIGEST_UPDATES。
⑧ WAIT_DIGEST_UPDATES
ReplicatedPG::_scrub()函數完成(作了什麼);若是還有obj未校驗完,則繼續回到NEW_CHUNK流程,重複以上動做;若是所有校驗完則進去FINISH狀態
⑨ FINISH
Scrub結束
注:
1. OSD 會以 PG 爲粒度觸發 Scrub 流程,觸發的頻率能夠經過選項指定,而一個 PG 的 Scrub 啓動都是由該 PG 的 Master 角色所在 OSD 啓動
2. 一個 PG 在普通的環境下會包含幾千個到數十萬個不等的對象,由於 Scrub 流程須要提取對象的校驗信息而後跟其餘副本的校驗信息對比,這期間被校驗對象的數據是不能被修改的。所以一個 PG 的 Scrub 流程每次會啓動小部分的對象校驗,Ceph 會以每一個對象名的哈希值的部分做爲提取因子,每次啓動對象校驗會找到符合本次哈希值的對象,而後進行比較。這也是 Ceph 稱其爲 Chunky Scrub 的緣由。
3. 在找到待校驗對象集後,發起者須要發出請求來鎖定其餘副本的這部分對象集。由於每一個對象的 master 和 replicate 節點在實際寫入到底層存儲引擎的時間會出現必定的差別。這時候,待校驗對象集的發起者會附帶一個版本發送給其餘副本,直到這些副本節點與主節點同步到相同版本。
4. 在肯定待校驗對象集在不一樣節點都處於相同版本後,發起者會要求全部節點都開始計算這個對象集的校驗信息並反饋給發起者。
5. 該校驗信息包括每一個對象的元信息如大小、擴展屬性的全部鍵和歷史版本信息等等,在 Ceph 中被稱爲 ScrubMap。
6. 發起者會比較多個 ScrubMap並發現不一致的對象,不一致對象會被收集最後發送給 Monitor,最後用戶能夠經過 Monitor 瞭解 Scrub 的結果信息
用戶在發現出現不一致的對象後,能夠經過 「ceph pg repair [pg_id]」 的方式來啓動修復進程,目前的修復僅僅會將主節點的對象全量複製到副本節點,所以目前要求用戶手工確認主節點的對象是」正確副本」。另外,Ceph 容許 Deep Scrub 模式來全量比較對象信息來指望發現 Ceph 自己或者文件系統問題,這一般會帶來較大的 IO 負擔,所以在實際生產環境中很難達到預期效果。
4、Scrub 測試
Scrubbing 是 Ceph 保持數據完整性的一個機制,相似於文件系統中的 fsck,它會發現存在的數據不一致。scrubbing 會影響集羣性能。它分爲兩類:
· 一類是默認天天進行的,稱爲 light scrubbing,其週期由配置項 osd scrub min interval (默認24小時)和 osd scrub max interval (默認7天)決定。它經過檢查對象的大小和屬性來發現數據輕度不一致性問題。
· 另外一種是默認每週進行的,稱爲 deep scrubbing,其週期由配置項 osd deep scrub interval (默認一週)決定。它經過讀取數據並作 checksum 檢查數據來發現數據深度不一致性問題。
下面是默認的 osd scrub 的配置項:
root@ceph2:~# ceph --admin-daemon /var/run/ceph/ceph-osd.5.asok config show | grep scrub"osd_scrub_thread_timeout": "60","osd_scrub_thread_suicide_timeout": "60","osd_scrub_finalize_thread_timeout": "600","osd_scrub_finalize_thread_suicide_timeout": "6000","osd_scrub_invalid_stats": "true","osd_max_scrubs": "1","osd_scrub_load_threshold": "0.5","osd_scrub_min_interval": "86400","osd_scrub_max_interval": "604800","osd_scrub_chunk_min": "5","osd_scrub_chunk_max": "25","osd_scrub_sleep": "0","osd_deep_scrub_interval": "604800","osd_deep_scrub_stride": "524288",
實驗過程:
0:找到對象的 PG acting set
osdmap e334 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([5,3,0], p5) acting ([5,3,0], p5)
1:刪除對象的文件
根據 pg id,osd id 以及 object name,找到 osd.5 上文件路徑爲 /var/lib/ceph/osd/ceph-5/current/9.1e_head/Evernote\u5.8.6.7519.exe__head_6094A41E__9,將它刪除
2:設置 light scrub 週期
爲了避免等一天,將osd_scrub_min_interval 和 osd_scrub_max_interval 都設爲4分鐘:
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config set osd_scrub_max_interval 240
{ "success": "osd_scrub_max_interval = '240' "}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config get osd_scrub_max_interval
{ "osd_scrub_max_interval": "240"}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config set osd_scrub_min_interval 240
{ "success": "osd_scrub_min_interval = '240' "}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config get osd_scrub_min_interval
{ "osd_scrub_min_interval": "240"}
3:嘗試 light scrub,發現問題
能看到 light scrub 按計劃進行了,並且發現了 pg 9.1e 的問題,即有文件丟失了:
2016-06-06 18:15:49.798236 osd.5 [INF] 9.1d scrub ok
2016-06-06 18:15:50.799835 osd.5 [ERR] 9.1e shard 5 missing 6094a41e/Evernote_5.8.6.7519.exe/head//92016-06-06 18:15:50.799863 osd.5 [ERR] 9.1e scrub 1 missing, 0 inconsistent objects2016-06-06 18:15:50.799866 osd.5 [ERR] 9.1e scrub 1 errors2016-06-06 18:15:52.804444 osd.5 [INF] 9.20 scrub ok
pgmap 呈現 inconsistent 狀態:
2016-06-06 18:15:58.439927 mon.0 [INF] pgmap v5752: 64 pgs: 63 active+clean, 1 active+clean+inconsistent; 97071 kB data, 2268 MB used, 18167 MB / 20435 MB avail
此時集羣狀態是 ERROR 狀態:
health HEALTH_ERR 1 pgs inconsistent; 1 scrub errors;
除了定時的清理外,管理員也能夠經過命令啓動清理過程:
root@ceph1:~# ceph pg scrub 9.1einstructing pg 9.1e on osd.5 to scrub
從輸出能看出來,scrubbing 是由 PG 的主 OSD 發起的。
4:嘗試 deep scrub,結果相同。
手工運行命令 ceph pg deep-scrub 9.1e,它會啓動深度清理,結果相同。
5:嘗試 pg repair,成功
運行 ceph pg repair 9.1e,啓動 PG 修復過程,結果修復成功(1 errors, 1 fixed),被刪除的文件回來了,集羣從新回到 OK 狀態。
結論:
· PG scrubbing 能發現文件丟失的問題
· PG scrubbing 對集羣性能有負面影響,能夠適當下降其優先級以及所須要的資源。
注意:PG repair 目前還有很多問題,根據這篇文章,它會將 primary osd 上的數據複製到其它osd上,這可能會致使正確的數據被錯誤的數據覆蓋,所以使用須要謹慎。下面的實驗將驗證這個問題。
0:建立一個對象,其內容是一個含有字符串 1111 的文本文件,其PG分佈在 [2,0,3] 上。
1:修改 osd.2 上文件內容爲 1122
2:啓動 light scrub,9.2e scrub ok,沒法發現問題。這不是蠻奇怪的麼??light scrub 應該會檢查文件屬性和大小,屬性應該包括修改時間吧,應該能檢查出來啊。。
3. 啓動 deep scrub,9.2e deep-scrub ok,沒法發現問題。這不是蠻奇怪的麼??deep scrub 應該會檢查對象數據的啊,數據變了,應該能檢查出來啊。。。
4. 啓動 pg repair,內容不變。對不在 inconsistent 狀態的 PG 看來作repair 不會作什麼。
5. 繼續修改 osd.2 上的文件,增長內容,致其 size 改變。
6. 啓動 light scrub,終於發現 shard 2: soid b2e6cb6e/text/head//9 size 931 != known size 5, 1 inconsistent objects,集羣狀態也變爲 HEALTH_ERR。
7. 啓動 deep scrub,它也一樣地終於發現了問題。
8. 運行 rados get 命令,能正確獲取原始文件。這說明即便集羣處於HEALTH_ERR 狀態,處於 active+clean+inconsistent 狀態的 PG 的 IO 能正常進行。
9. 啓動 pg repari,osd.2 上的文件被覆蓋,回到原始內容。這說明 pg repair 也不是從主osd 向別的 osd 拷貝嘛。。
結論:
· 兩種 scrubbing 只是根據不一樣的方法來發現數據一致性上的不一樣類型的問題,修復的事情它無論;不是全部的問題它們都能發現;通過驗證,size 的變化會被發現,可是在size不變內容改變的時候不能被發現。
· pg repair 也不是像 Re: [ceph-users] Scrub Error / How does ceph pg repair work? 所說的簡單地將 primary osd 上的數據拷貝到其它 osd 上,這種作法很明顯這可能會致使正確的數據被損壞。文章是寫於 2015 年,個人ceph 版本是 0.8.11,也許二者有不一致。
5、Scrub 問題
正如流程所述,目前的 Scrub 有如下問題:
1. 在發現不一致對象後,缺乏策略來自動矯正錯誤,好比若是多數副本達成一致,那麼少數副本對象會被同化
2. Scrub 機制並不能及時解決存儲系統端到端正確的問題,頗有可能上層應用早已經讀到錯誤數據
對於第一個問題,目前 Ceph 已經有 Blueprint 來增強 Scrub 的修復能力,用戶啓動 Repair 時會啓動多數副本一致的策略來替代目前的主副本同步策略。
對於第二個問題,傳統端到端解決方案會更多采用固定數據塊附加校驗數據的「端到端校驗」方案,可是 Ceph 由於並非存儲設備空間實際的管理和分配者,它依賴於文件系統來實現存儲空間的管理,若是採用對象校驗的方式會嚴重損耗性能。所以在從文件系統到設備的校驗須要依賴於文件系統,而 Ceph 包括客戶端和服務器端的對象正確性校驗只能更多的依賴於 Read Verify 機制,在涉及數據遷移時須要同步的比較不一樣副本對象的信息來保證正確性。目前的異步方式會容許期間發生錯誤數據返回的可能性。
參考文檔:
本文的測試參考於劉世民(Sammy Liu) http://www.cnblogs.com/sammyliu/p/5568989.html ,後續有空再結合代碼作個測試