Ceph的os模塊,也就是ObjectStore模式,是Ceph對象存儲的底層的存儲機制。它是單機版的存儲。基本功能如下:
1) 提供底層對象的隨機讀寫
2) 保證讀寫數據的一致性
其功能主要包括以下幾個模塊:
FileStore
ObjectStore是對象存儲的接口,主要包括對象讀寫,對象屬性的get和set操作。JournalingObjectStore 繼承了ObjectStore,提供了日誌提交管理相關的接口。FileStore實現了一個基於文件系統 的對象存儲。FilestoreBackend提供了不同文件系統的實現的一個公共的接口。
Journl定義了日誌的接口,FileJournal實現了基於文件系統的日誌實現。
Omap
Omap 也就是objectMap,其用來存儲對象的屬性kv值的。 Omap可以保持在文件系統的擴展屬性中,也可以保存在單獨的kv存儲系統中。如上圖所示,是保存在keyvalue存儲中。
ObjectMap類是一個對象的omap的接口。GenericObjectMap是所有對象保存omap的接口,可以遍歷訪問所有Object的omap值。GenericObjectMap也是一個抽象類,其用了KeyValueDB的接口。
KeyValueDB是所有外部kv存儲系統的抽象接口,其實現目前有三種kv存儲系統,Kinetic,LevelDB,RocksDB三種。默認採用LevelDB,都是開源的系統,可以自己網上搜索相關的資料。
CollectionIndex
CollectionIndex是對象在文件系統的組織方式。一個對象,在文件系統就對應一個文件,當有很多文件時,如何組織這些文件,比如幾層目錄,每層目錄多少個文件,如何檢索,這些組織不好都會影響性能。
讀寫流程分析
根據日誌的不同,FileStore有三種寫的方式:
1)Writeahead方式:一般XFS都採用這種日誌,在這種情況下,數據先寫入日誌,並等待日誌同步到日誌磁盤上,然後再寫到對象對應的日誌文件中。
2)Parallel方式:Btrfs和ZFS採用這種方式,日誌和數據是同時(並行)寫入。由於BTRFS和ZFS支持checkpoint操作,如果數據在寫入過程中出錯,可以rollback,保證數據的一致性。
3)無日誌的方式,在這種情況下,數據之間寫入並同步的磁盤中。這種模式下只支持append模式的寫入。不支持隨機寫。
主要寫流程分析:
1)int FileStore::queue_transactions(Sequencer *posr, list<Transaction*> &tls,
TrackedOpRef osd_op,
ThreadPool::TPHandle *handle)
FileStore的寫的入口,寫都是以事務的形式提交。
2)_op_journal_transactions(tbl, data_align, o->op, new C_JournaledAhead(this, osr, o, ondisk),
osd_op);
journal->submit_entry(op, tbl, data_align, onjournal, osd_op);
本函數調用 journal->submit_entry 接口,提交日誌,也就是把日誌寫入日誌盤。參數onjournal回調函數,當日志完成後就調用該回調函數。
3)當日志提交完成後,Contex類C_JournaledAhead調用函數FileStore::_journaled_ahead,該函數調用queue_op函數,把該請求加入的op_wq隊列中。
4)op_wq的處理線程調用FileStore::_do_op 函數,最終調用_do_transactions 實現數據真正寫入對象對應的文件中。需要注意的是,這個函數直接調用文件系統的write函數,數據寫緩存中就直接返回。因爲此時,數據已經persistent到了日誌盤中,這時候保證數據可讀即可。
日誌的寫入流程
日誌寫入的入口函數爲:journal的submit_entry函數
1)通過加writeq_lock和completions_lock首先把請求加入的到writeq和completions兩個隊列中。
2)FileJournal的內部線程write_thread,對應的run函數write_thread_entry從writeq隊列中獲取請求,通過aio 寫入日誌磁盤
3)write_finish_thread(這裏分析aio的情況)檢查是否有aio請求完成 ,如果完成,則把該請求從completions隊列刪除,並添加到Finisher隊列裏。
4)Finisher隊列調用日誌的回調函數完成。
日誌的同步
在FileStore::mount方法中,會創建sync線程 sync_thread.create();
該線程的入口函數爲:void FileStore::sync_entry()
該函數定期執行同步操作,當同步時,調用tp.pause, 是FileStore的 op_wq的線程池停止,等待正在應用的日誌完成。然後調用fsycn同步內存中的數據到數據盤,當同步完成後,就可以丟棄相應的日誌,釋放相應的日誌空間。