ceph bluefs 日誌壓縮解析

2021-09-11 07:14:24 字數 3898 閱讀 6497

bluefs的操作大量增加時,日誌也會增加,從而增加占用空間,由於檔案系統的元資料在記憶體中都有記錄,且記憶體中的元資料都是非重複的,因此可以通過遍歷元資料,將元資料重新寫到日誌檔案當中,即可實現日誌的壓縮,具體是_compact_log_async函式來實現的,其實現如下:

old_log_jump_to = log_file->fnode.get_allocated();  //獲取已經分配的空間,這些空間最後要釋放

_allocate(log_file->fnode.prefer_bdev, cct->_conf->bluefs_max_log_runway, &log_file->fnode); //重新在快速裝置中開闢一段新的空間

log_t.op_file_update(log_file->fnode);

log_t.op_jump(log_seq, old_log_jump_to);

_flush_and_sync_log(l, 0, old_log_jump_to);

_compact_log_dump_metadata(&t); //壓縮日誌

new_log_jump_to = round_up_to(t.op_bl.length() + super.block_size * 2, cct->_conf->bluefs_alloc_size)

t.op_jump(log_seq, new_log_jump_to);

_allocate(bluefs::bdev_db, new_log_jump_to, &new_log->fnode);

new_log_writer = _create_writer(new_log);

_flush(new_log_writer, true);

_flush_bdev_safely(new_log_writer); //此時,原來的日誌已經寫在新空間裡了

while (discarded < old_log_jump_to)

bluefs_extent_t& e = log_file->fnode.extents.front();

bluefs_extent_t temp = e;

if (discarded + e.length <= old_log_jump_to) //這個pextent可以完全釋放

discarded += e.length;

log_file->fnode.pop_front_extent(); //將這個pextent出棧

else //該pextent只能釋放前一部分

uint64_t drop = old_log_jump_to - discarded;

temp.length = drop; //將長度變小,就相當於擷取pextent的前一部分了

e.offset += drop;

e.length -= drop; //e代表原來的pextent,這裡更新原來的pextent的元資料

old_extents.push_back(temp);

//經過上述的while迴圈後,old_extents中儲存了舊日誌檔案中old_log_jump_to位置之前的日誌,舊日誌檔案中儲存了old_log_jump_to位置之後的pextent

auto from = log_file->fnode.extents.begin();

auto to = log_file->fnode.extents.end();

while (from != to)

++from;

log_file->fnode.clear_extents();

new_log->fnode.swap_extents(log_file->fnode); //交換新老日誌檔案的pextent,

log_writer->pos = log_writer->file->fnode.size = log_writer->pos - old_log_jump_to + new_log_jump_to; //更新日誌檔案的寫偏移,即日誌的最後一項

super.log_fnode = log_file->fnode;

++super.version;

_write_super(); //將super寫的super block中

encode(super, bl);

encode(crc, bl);

bdev[bdev_db]->write(get_super_offset(), bl, false);

for (auto& r : old_extents) //釋放老日誌檔案中,old_log_jump_to位置之前的空間

pending_release[r.bdev].insert(r.offset, r.length);

(1)計算log_file目前已經分配磁碟空間大小,利用old_log_jump_to標記,這部分空間在壓縮後可以釋放。同時在塊裝置block.wal中申請新的空間用於以後的日誌儲存。

(2)呼叫_compact_log_dump_metadata函式來壓縮日誌,並設定下乙個日誌項的位址new_log_jump_to,注意new_log_jump_to是根據bluefs_alloc_size(1m)對齊的,因此很多時候新的日誌檔案中有一些空間是為了對齊沒有使用的,向裝置block.db申請new_log_jump_to大小的空間存放這些壓縮後的日誌。

(3)呼叫_flush和_flush_bdev_safely將壓縮後的日誌重新整理到磁碟裝置中。

(4)經過一系列的swap等操作後,log_file就只儲存了壓縮後的日誌和op_jump(log_seq, new_log_jump_to)日誌,然後把log_file的fnode寫入到super中。

(5)最後將log_file中原來的處於old_extents的老日誌所占用的空間釋放。

關於磁碟壓縮過程中磁碟空間的變化如下圖所示

原來日誌是存放在block.wal裝置中,將壓縮後的日誌放在block.db裝置中,並且最後一條日誌為op_jump,所跳到位置就是new_log_jump_to,而在op_jump和new_log_jump_to之間是為了對齊而多出的空間,因此日誌回放過程中遇到op_jump就會跳到new_log_jump_to,從new_log_jump_to開始讀取block.wal裝置中新增加的日誌。因此壓縮的日誌是存放在block.db裝置中的,未壓縮的日誌是存放在block.wal裝置中的。

最後關於日誌的壓縮函式_compact_log_dump_metadata,其實現如下:

t->op_init();

for (unsigned bdev = 0; bdev < max_bdev; ++bdev)

interval_set& p = block_all[bdev];

for (interval_set::iterator q = p.begin(); q != p.end(); ++q)

t->op_alloc_add(bdev, q.get_start(), q.get_len());

for (auto& p : file_map)

if (p.first == 1)

continue;

t->op_file_update(p.second->fnode);

for (auto& p : dir_map)

t->op_dir_create(p.first);

for (auto& q : p.second->file_map)

t->op_dir_link(p.first, q.first, q.second->fnode.ino);

可以看到日誌壓縮就是主要是記錄bluefs的總空間、目錄、檔案、目錄和檔案的聯絡,在日誌回放的時候就可以僅根據這些資訊來還原出bluefs檔案組織結構,這樣可以把不需要的重複日誌刪除。

日誌打包壓縮

這幾天,伺服器日誌漲的很快。因為沒有日誌伺服器,都是寫在本地。要保留三個月,打包,壓縮能節省些空間。做個記錄。顯示當前系統前兩個的日期 date d 2 days ago y m d bin sh 會員服務的日誌 路徑 opt logs member ma logs 保留三天的日誌。打包壓縮存在當前...

壓縮mysql binlog日誌

伺服器硬碟太貴了 mysql的binlog日誌增長太快了 需要定時壓縮一下 然後清除 清除步驟 建立清除shell vim bzbinlog.sh bin sh tar jcvpf date mysqlbinlogdir mysql bin.000108.tar.bz2 usr local mysq...

SQL 壓縮日誌

backup log 資料庫名稱 with no log go dump transaction 資料庫名稱 with no log go dbcc shrinkdatabase 資料庫名稱 gouse 資料庫名稱 goalter database 資料庫名稱 set recovery 設定簡單恢復...