GolangNote

Golang笔记

Golang 数据库 Bolt 碎片整理

Permalink

Bolt 是一个优秀、纯 Go 实现、支持 ACID 事务的嵌入式 Key/Value 数据库。但在使用过程中会有很多空间碎片。一般数据库占用的空间是元数据空间的 1.5~4 倍。Bolt 没有内置的压缩功能,需要手动压缩。

ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。

产生碎片原因

当插入键/值对时,Bolt 需要找到一组连续的空闲页面,或者需要在文件末尾添加更多页面。 当值很小(小于 4KB)时,很容易找到连续的页面,因为 Bolt 只需要找到一个空闲页面。 随着键值的值变大,很难找到“完美”大小的空闲页面集,因此它会追加到末尾。键值对越大,越容易出现严重的碎片,当不断对数据库做删除时,碎片会更多。

碎片整理过程

假设当前数据库是 a.db,压缩后的数据库是 b.db

  1. 打开数据库文件 a.dbb.db
  2. a.db 数据库读取每个对象,并将其写入 b.db
  3. 关闭两个文件。
  4. 重命名。 把 b.db 重命名为 a.db 。操作系统,重命名是原子的。
  5. 重新打开新压缩的 a.db 文件

这过程用到 Bolt 两个有用的遍历函数: tx.ForEachbucket.ForEach

第一个是遍历所有的 Bucket

Go: 遍历 Bucket
1
2
3
4
5
6
7
8
9
10
11
// ForEach executes a function for each bucket in the root.
// If the provided function returns an error then the iteration is stopped and
// the error is returned to the caller.
func (tx *Tx) ForEach(fn func(name []byte, b *Bucket) error) error {
	return tx.root.ForEach(func(k, v []byte) error {
		if err := fn(k, tx.root.Bucket(k)); err != nil {
			return err
		}
		return nil
	})
}

第二个是遍历某个 Bucket 里所有的 Key/Value

Go: 遍历 KV
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ForEach executes a function for each key/value pair in a bucket.
// If the provided function returns an error then the iteration is stopped and
// the error is returned to the caller. The provided function must not modify
// the bucket; this will result in undefined behavior.
func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
	if b.tx.db == nil {
		return ErrTxClosed
	}
	c := b.Cursor()
	for k, v := c.First(); k != nil; k, v = c.Next() {
		if err := fn(k, v); err != nil {
			return err
		}
	}
	return nil
}

如果在数据库里使用嵌套 Bucket,还需处理一下

Bolt 嵌套 Bucket

参考

本文网址: https://golangnote.com/topic/311.html 转摘请注明来源

Related articles

bolt 数据库的事务

Bolt 类似于 LMDB,这个被认为是在现代 kye/value 存储中最好的。但是又不同于 LevelDB,BoltDB 支持完全可序列化的ACID事务...

Golang http client 处理重定向网页

假设一个网址有多个重定向,A-B-C-D,使用 http.Client.Get 最后取得的内容是网址D的内容,我们该手动处理包含重定向的网址。...

golang共享数据用Mutex 或 Channel

在go 里,多线程对共享数据的操作一般要使用Mutex 或 Channel 来加锁或隔离通信。下面是一个使用Mutex 和 Channel 比较的例子。...

Write a Comment to "Golang 数据库 Bolt 碎片整理"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.22.3 Processed in 0ms