ceph-kvstore-tool
生活随笔
收集整理的這篇文章主要介紹了
ceph-kvstore-tool
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
ceph-kvstore-tool 使用說明
參考鏈接:
https://github.com/ceph/ceph/blob/master/doc/man/8/ceph-kvstore-tool.rst
http://www.idcat.cn/ceph-kvstore-tool%E5%B7%A5%E5%85%B7%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8D.html
https://blog.csdn.net/Z_Stand/article/details/98967671
1. 簡介
ceph-kvstore-tool 是一個(gè) kvstore 操作工具。它允許用戶離線操作 leveldb/rocksdb 的數(shù)據(jù)(就像 OSD 的 omap)。
[root@node-1 ceph-objectstore-tool-test]# ceph-kvstore-tool -h Usage: ceph-kvstore-tool <leveldb|rocksdb|bluestore-kv> <store path> command [args...]Commands:list [prefix]list-crc [prefix]dump [prefix]exists <prefix> [key]get <prefix> <key> [out <file>]crc <prefix> <key>get-size [<prefix> <key>]set <prefix> <key> [ver <N>|in <file>]rm <prefix> <key>rm-prefix <prefix>store-copy <path> [num-keys-per-tx] [leveldb|rocksdb|...] store-crc <path>compactcompact-prefix <prefix>compact-range <prefix> <start> <end>destructive-repair (use only as last resort! may corrupt healthy data)stats使用前,關(guān)閉 mon 服務(wù) 或者 osd 服務(wù)
systemctl stop <ceph-mon@node-1>|<ceph-mon@0>使用完,記得重啟服務(wù)
systemctl restart <ceph-mon@node-1>|<ceph-mon@0>2. 示例
查詢數(shù)據(jù)庫表項(xiàng)(prefix,前綴)
# cat /var/lib/ceph/mon/ceph-node-1/kv_backend 查詢 mon 使用何種 db ceph-kvstore-tool <rocksdb|leveldb> /var/lib/ceph/mon/ceph-node-1/store.db/ listceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 list# 查看 mon 數(shù)據(jù)庫中都有哪些表項(xiàng) ceph-kvstore-tool rocksdb /var/lib/ceph/mon/ceph-node-1/store.db/ list|awk '{print $1}'|uniq# bluestore 表項(xiàng)前綴 # const string PREFIX_SUPER = "S"; // field -> value # const string PREFIX_STAT = "T"; // field -> value(int64 array) # const string PREFIX_COLL = "C"; // collection name -> cnode_t # const string PREFIX_OBJ = "O"; // object name -> onode_t # const string PREFIX_OMAP = "M"; // u64 + keyname -> value # const string PREFIX_PGMETA_OMAP = "P"; // u64 + keyname -> value(for meta coll) # const string PREFIX_PERPOOL_OMAP = "m"; // s64 + u64 + keyname -> value # const string PREFIX_PERPG_OMAP = "p"; // u64(pool) + u32(hash) + u64(id) + keyname -> value # const string PREFIX_DEFERRED = "L"; // id -> deferred_transaction_t # const string PREFIX_ALLOC = "B"; // u64 offset -> u64 length (freelist) # const string PREFIX_ALLOC_BITMAP = "b";// (see BitmapFreelistManager) # const string PREFIX_SHARED_BLOB = "X"; // u64 offset -> shared_blob_t # const string PREFIX_ZONED_FM_META = "Z"; // (see ZonedFreelistManager) # const string PREFIX_ZONED_FM_INFO = "z"; // (see ZonedFreelistManager) # const string PREFIX_ZONED_CL_INFO = "G"; // (per-zone cleaner metadata) ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0/ list | awk '{print $1}'| uniq打印數(shù)據(jù)庫中(kv鍵值對)的crc校驗(yàn)碼
ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0/ list-crc | grep osdmap | head -10# 查詢 kv 數(shù)量 ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0/ list-crc | wc -l# 查詢 crc 校驗(yàn)碼數(shù)量 ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0/ list-crc | awk '{print $3}'| uniq | wc -l打印 Key-Value 鍵值對
ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 dump [prefix]查詢表項(xiàng)是否存在(可指定 key)
ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0/ exists <pfefix> [key]查詢指定 value(可選是否指定輸出文件)
ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0/ get <prefix> <key> [out <file>]# 通過 ceph-dencoder 工具反序列化解析 ceph-kvstore-tool rocksdb /var/lib/ceph/mon/ceph-node1/store.db/ get osdmap full_999 out ./osdmap.full ceph-dencoder import osdmap.full type OSDMap decode dump_json查詢對象大小,若不指定前綴+key,則返回整個(gè) db 大小
ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 /var/lib/ceph/osd/ceph-0/ get-size [<prefix> <key>]更改 key 或 value
# 這條命令含義是:把指定【前綴+key】的 key 替換為 N,或者把該指定【前綴+key】的內(nèi)容替換為 file ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 set <prefix> <key> [ver <N>lin <file>]壓縮數(shù)據(jù)庫(緩解 rocksdb 寫放大)
# rocksdb 數(shù)據(jù)分為多層,并且每層都可能有重復(fù)數(shù)據(jù),啟用 compact 可以把數(shù)據(jù)層層壓縮到最底層,并且刪除重復(fù)數(shù)據(jù),起到壓縮空間的作用 # 壓縮整個(gè)數(shù)據(jù)庫 ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 compact# 壓縮指定前綴的數(shù)據(jù) ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 compact-prefix <prefix># 壓縮指定前綴的 key=[start~end] 范圍的數(shù)據(jù) ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 compact-range <prefix> <start> <end>刪除
ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 rm <prefix> <key># 刪除整個(gè)前綴下的數(shù)據(jù) ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 rm-prefix <prefix>備份
# path:備份到指定路徑,num-keys-per-tx:每次事務(wù)中進(jìn)行備份的 kv 數(shù)量 ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 store-copy <path> [num-keys-per-tx] [leveldb|rocksdb|...] # 備份所有 kv 的 crc ceph-kvstore-tool bluestore-kv /var/lib/ceph/osd/ceph-0 store-crc <path>3. 源碼分析
main
int main(int argc, const char *argv[]) {// 參數(shù)解析vector<const char*> args;argv_to_vec(argc, argv, args);// global 初始化auto cct = global_init(&defaults, args,CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);common_init_finish(g_ceph_context);// 根據(jù) store-type 初始化 storetoolStoreTool st(type, path, to_repair, need_stats);// 根據(jù)命令行 cmd 參數(shù),執(zhí)行對應(yīng)的函數(shù)if (cmd == "destructive-repair") {... }else if(cmd == "rm")... }StoreTool
StoreTool::StoreTool(const string& type,const string& path,bool to_repair,bool need_stats): store_path(path) {// 根據(jù) type,創(chuàng)建 kv 句柄,其中 bluestore-kv,需要調(diào)用 bluestore->open_db_environmentif (type == "bluestore-kv") {if (load_bluestore(path, to_repair) != 0)exit(1);} else {// 創(chuàng)建 kv 句柄 auto db_ptr = KeyValueDB::create(g_ceph_context, type, path);} }int StoreTool::load_bluestore(const string& path, bool to_repair) {// 創(chuàng)建 bluestoreauto bluestore = new BlueStore(g_ceph_context, path);KeyValueDB *db_ptr;// 通過 bluestore 獲取 kvdbint r = bluestore->open_db_environment(&db_ptr, to_repair);db = decltype(db){db_ptr, Deleter(bluestore)};return 0; }destructive-repair
數(shù)據(jù)因?yàn)殄礄C(jī)發(fā)生遺失時(shí),可以嘗試通過 repair 修復(fù),注意:沒有寫入日志文件的數(shù)據(jù)無法恢復(fù)。
int StoreTool::destructive_repair() {return db->repair(std::cout); } /*目前 ceph 后端的 kvdb 一般使用 rocksdb,其修復(fù)過程分為以下4步驟:查找文件把日志轉(zhuǎn)化為表導(dǎo)出metadata寫描述符 */list/list-crc
void StoreTool::list(const string& prefix, const bool do_crc,const bool do_value_dump) {traverse(prefix, do_crc, do_value_dump,& std::cout); }uint32_t StoreTool::traverse(const string& prefix,const bool do_crc,const bool do_value_dump,ostream *out) {// 獲取數(shù)據(jù)庫迭代器KeyValueDB::WholeSpaceIterator iter = db->get_wholespace_iterator();// 如果設(shè)置了 prefix,則把迭代器調(diào)到第一次出現(xiàn) prefix 的位置 if (prefix.empty())iter->seek_to_first();elseiter->seek_to_first(prefix);uint32_t crc = -1;// 循環(huán)查詢,直到迭代器為 invalidwhile (iter->valid()) {pair<string,string> rk = iter->raw_key();// 設(shè)置跳出循環(huán)條件if (!prefix.empty() && (rk.first != prefix))break;if (out)*out << url_escape(rk.first) << "\t" << url_escape(rk.second);if (do_crc) {bufferlist bl;bl.append(rk.first);bl.append(rk.second);bl.append(iter->value());// 計(jì)算 crc 值crc = bl.crc32c(crc);if (out) {*out << "\t" << bl.crc32c(0);}}if (out)*out << std::endl;iter->next();}return crc; }exist
bool StoreTool::exists(const string& prefix, const string& key) {// 未指定 key,調(diào)用 StoreTool::exists(const string& prefix)if (key.empty()) {return exists(prefix);}bool exists = false;// 在指定 key,則調(diào)用 get(),下文介紹該方法get(prefix, key, exists);return exists; }bool StoreTool::exists(const string& prefix) {KeyValueDB::WholeSpaceIterator iter = db->get_wholespace_iterator();// 通過迭代器去查詢第一次出現(xiàn) prefix 位置,查不到則為 invaliditer->seek_to_first(prefix);return (iter->valid() && (iter->raw_key().first == prefix)); }get
bufferlist StoreTool::get(const string& prefix,const string& key,bool& exists) {map<string,bufferlist> result;std::set<std::string> keys;keys.insert(key);// 獲取指定 prefix、key 的 value,結(jié)果保存在 resultdb->get(prefix, keys, &result);// result 中的鍵值對數(shù)量大于0,則表示存在該 key if (result.count(key) > 0) {exists = true;return result[key];} else {exists = false;return bufferlist();} }// rocksdb get 查詢使用方法如下 int RocksDBStore::get(const string &prefix,const std::set <string> &keys,std::map <string, bufferlist> *out) {rocksdb::PinnableSlice value;if (cf_handles.count(prefix) > 0) {for (auto &key : keys) {// 若指定 prefix,則需要?jiǎng)?chuàng)建 cf(columfamily)列族句柄auto cf_handle = get_cf_handle(prefix, key);// 調(diào)用 Get 方法查詢auto status = db->Get(rocksdb::ReadOptions(),cf_handle,rocksdb::Slice(key),&value);if (status.ok()) {(*out)[key].append(value.data(), value.size());} else if (status.IsIOError()) {ceph_abort_msg(status.getState());}value.Reset();}} else {for (auto &key : keys) {string k = combine_strings(prefix, key);// 未指定 prefix,使用默認(rèn)句柄:rocksdb::ColumnFamilyHandle *default_cf = nullptr;auto status = db->Get(rocksdb::ReadOptions(),default_cf,rocksdb::Slice(k),&value);if (status.ok()) {(*out)[key].append(value.data(), value.size());} else if (status.IsIOError()) {ceph_abort_msg(status.getState());}value.Reset();}}return 0; }get-size
// 返回 bl 大小 bufferlist bl = st.get(prefix, key, exists); std::cout << "(" << url_escape(prefix) << "," << url_escape(key)<< ") size " << byte_u_t(bl.length()) << std::endl;set
// 解析命令行參數(shù) if (subcmd == "ver") {version_t v = (version_t) strict_strtoll(argv[7], 10, &errstr);encode(v, val);} else if (subcmd == "in") {int ret = val.read_file(argv[7], &errstr);} // 調(diào)用 StoreTool::set 方法bool ret = st.set(prefix, key, val);bool StoreTool::set(const string &prefix, const string &key, bufferlist &val) {// rocksdb 支持事務(wù)提交,步驟如下:/* rocksdb::WriteBatch bat;* rocksdb::WriteOptions woptions;* woptions.sync = !disableWAL;* auto cf = db->get_cf_handle(prefix, k);* put_bat(bat, cf, k, to_set_bl);* int result = submit_common(woptions, t);*/KeyValueDB::Transaction tx = db->get_transaction();tx->set(prefix, key, val);int ret = db->submit_transaction_sync(tx);return (ret == 0); }store-copy
int StoreTool::copy_store_to(const string &type, const string &other_path,const int num_keys_per_tx,const string &other_type) {// 在參數(shù)路徑位置新建或者打開 kvdb// open or create a leveldb store at @p other_pathboost::scoped_ptr <KeyValueDB> other;KeyValueDB *other_ptr = KeyValueDB::create(g_ceph_context,other_type,other_path);if (int err = other_ptr->create_and_open(std::cerr); err < 0) {return err;}other.reset(other_ptr);// 獲取舊 db 的迭代器KeyValueDB::WholeSpaceIterator it = db->get_wholespace_iterator();// 調(diào)整迭代器位置it->seek_to_first();// 循環(huán)提交事務(wù),直到舊 db 的迭代器遍歷完數(shù)據(jù)庫do {int num_keys = 0;// 創(chuàng)建新 db 事務(wù)KeyValueDB::Transaction tx = other->get_transaction();// 通過舊迭代器查詢,向新 db 的單次事務(wù)中寫入 num-keys-per-tx 數(shù)量的寫操作while (it->valid() && num_keys < num_keys_per_tx) {auto[prefix, key] = it->raw_key();bufferlist v = it->value();tx->set(prefix, key, v);num_keys++;total_size += v.length();it->next();}// 提交事務(wù)if (num_keys > 0)other->submit_transaction_sync(tx);} while (it->valid());print_summary(total_keys, total_size, total_txs, store_path, other_path,duration());return 0; }compact
void RocksDBStore::compact() {logger->inc(l_rocksdb_compact);rocksdb::CompactRangeOptions options;// 壓縮db->CompactRange(options, default_cf, nullptr, nullptr);for (auto cf : cf_handles) {for (auto shard_cf : cf.second.handles) {db->CompactRange(options,shard_cf,nullptr, nullptr);}} }總結(jié)
以上是生活随笔為你收集整理的ceph-kvstore-tool的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于java的人力资源管理系统_基于Ja
- 下一篇: 广州 电信DNS