Hi (๑╹◡╹)ノ”,各位
Gopher
自己最近又用Go
造了一个轮子,一个超级轻量级KV
存储引擎,欢送👏🏻各位Gopher
进行评测。
主页介绍:https://bottle.ibyte.me (PC成果更加😋)
我的项目地址:https://github.com/auula/bottle
特 性
- 嵌入的存储引擎
- 数据能够加密存储
- 能够自定义实现存储加密器
- 即便数据文件被拷贝,也保障存储数据的平安
- 将来索引数据结构也能够反对自定义实现
简 介
首先要阐明的是Bottle
是一款KV
嵌入式存储引擎,并非是一款KV
数据库,我晓得很多人看到了KV
认为是数据库,当然不是了,很多人会把这些搞混同掉,KV
存储能够用来存储很多货色,而并非是数据库这一畛域。能够这么了解数据库是一台汽车,那么Bottle
是一台车的发动机。能够简略了解Bottle
是一个对操作系统文件系统的KV
抽象化封装,能够基于Bottle
做为存储层,在Bottle
层之上封装一些数据结构和对外服务的协定就能够实现一个数据库。
本我的项目性能实现齐全基于 bitcask
论文所实现,另外本我的项目所用到一些常识和卡内基梅隆大学
的CMU 15-445: Database Systems
课程内容很靠近,这门课由数据库畛域的大牛Andy Pavlo
讲授,有感兴趣的敌人能够去看看这套课,如果感觉不错你能够给我按一颗小星⭐
谢谢。
装置Bottle
你只须要在你的我的项目中装置Bottle
模块即可应用:
go get -u github.com/auula/bottle
根本API
如何操作一个Bottle
实例代码:
package main
import (
"fmt"
"github.com/auula/bottle"
)
func init() {
// 通过默认配置关上一个存储实例
err := bottle.Open(bottle.DefaultOption)
// 并且解决一下可能产生的谬误
if err != nil {
panic(err)
}
}
// Userinfo 测试数据结构
type Userinfo struct {
Name string
Age uint8
Skill []string
}
func main() {
// PUT Data
bottle.Put([]byte("foo"), []byte("66.6"))
// 如果转成string那么就是字符串
fmt.Println(bottle.Get([]byte("foo")).String())
// 如果不存在默认值就是0
fmt.Println(bottle.Get([]byte("foo")).Int())
// 如果不胜利就是false
fmt.Println(bottle.Get([]byte("foo")).Bool())
// 如果不胜利就是0.0
fmt.Println(bottle.Get([]byte("foo")).Float())
user := Userinfo{
Name: "Leon Ding",
Age: 22,
Skill: []string{"Java", "Go", "Rust"},
}
var u Userinfo
// 通过Bson保留数据对象,并且设置超时工夫为5秒,TTL超时能够不设置看需要
bottle.Put([]byte("user"), bottle.Bson(&user), bottle.TTL(5))
// 通过Unwrap解析出构造体
bottle.Get([]byte("user")).Unwrap(&u)
// 打印取值
fmt.Println(u)
// 删除一个key
bottle.Remove([]byte("foo"))
// 敞开解决一下可能产生的谬误
if err := bottle.Close(); err != nil {
fmt.Println(err)
}
}
加密器
数据加密器是针对数据的value
记录的,也就是针对字段级别的区块加密,并非是把整个文件加密一遍,那样设计会带来性能耗费,所以采纳区块数据段形式加密的形式。
上面例子是通过bottle.SetEncryptor(Encryptor,[]byte)
函数去设置数据加密器并且配置16
位的数据加密秘钥。
func init() {
bottle.SetEncryptor(bottle.AES(), []byte("1234567890123456"))
}
你也能够自定义去实现数据加密器的接口:
// SourceData for encryption and decryption
type SourceData struct {
Data []byte
Secret []byte
}
// Encryptor used for data encryption and decryption operation
type Encryptor interface {
Encode(sd *SourceData) error
Decode(sd *SourceData) error
}
上面代码就是内置AES
加密器的实现代码,实现bottle.Encryptor
接口即可,数据源为bottle.SourceData
构造体字段:
// AESEncryptor Implement the Encryptor interface
type AESEncryptor struct{}
// Encode source data encode
func (AESEncryptor) Encode(sd *SourceData) error {
sd.Data = aesEncrypt(sd.Data, sd.Secret)
return nil
}
// Decode source data decode
func (AESEncryptor) Decode(sd *SourceData) error {
sd.Data = aesDecrypt(sd.Data, sd.Secret)
return nil
}
具体的加密器实现代码能够查看encrypted.go
散列函数
如果你须要自定义实现散列函数,实现bottle.Hashed
接口即可:
type Hashed interface {
Sum64([]byte) uint64
}
而后通过内置的bottle.SetHashFunc(hash Hashed)
设置即可实现你的散列函数配置。
索引大小
索引预设置的大小很大水平上会影响你的程序存取和读取数据的速度,如果在初始化的时候可能预计出程序运行时须要的索引大小,并且在初始化的时候配置好,能够减小程序在运行过程中带来的运行数据迁徙和扩容带来的性能问题。
func init() {
// 设置索引大小
bottle.SetIndexSize(1000)
}
配置信息
你也能够不应用默认配置,你能够应用内置的bottle.Option
的构造体初始化你存储引擎,配置实例如下:
func init() {
// 自定义配置信息
option := bottle.Option{
// 工作目录
Directory: "./data",
// 算法开启加密
Enable: true,
// 自定义秘钥,能够应用内置的秘钥
Secret: bottle.Secret,
// 自定义数据大小,存储单位是kb
DataFileMaxSize: 1048576,
}
// 通过自定义配置信息
bottle.Open(option)
}
当然也能够应用内置的bottle.Load(path string)
函数加载配置文件启动Bottle
,配置文件格式为yaml
,可配置项如下:
# Bottle config options
Enable: TRUE
Secret: "1234567890123456"
Directory: "./testdata"
DataFileMaxSize: 536870912
须要留神的是内置的加密器实现的秘钥必须是16
位,如果你是自定义实现的加密器可通过bottle.SetEncryptor(Encryptor,[]byte)
设置你自定义的加密器,那这个秘钥位数将不受限制。
数据目录
因为bottle
设计就是基于但过程的程序,所以每个存储实例对应是一个数据目录,data
为日志合并构造数据目录,index
为索引数据版本。
日志合并构造数据目前版本是每次数据启动时候进行合并,默认是data
数据文件夹下的所有数据文件占用总和超过1GB
就会触发一次合并,合并之后没有用的数据被抛弃。
当然如果未达到脏数据合并要求,数据文件会以启动时候配置的大小进行归档,每个数据有版本号,并且被设置为只读挂载,过程工作目录构造如下:
./testdata
├── data
│ └── 1.data
└── index
├── 1646378326.index
└── 1646378328.index
2 directories, 3 files
当存储引擎开始工作的时候,这个目录下的所以文件夹和文件只能被这个过程操作,保障数据安全。
后续保护
Bottle
目前不反对多数据存储分区,后续版本会引入一个Bucket
概念,将来能够把指定的数据存储到指定的分区中,来升高并发的时候索引锁的颗粒度。- 后续将引入
零拷贝技术
,以后文件操作很大水平上依赖于操作系统,以后文件必须sync
能力保证数据一致性。 - 脏数据合并能够在运行中进行合并整顿,基于
信号量
的形式告诉垃圾回收工作线程。
其余信息
如果你发现了bug
欢送提issue
或者发动pull request
,我收到了音讯会尽快回复你,另外欢送各位Gopher
提出本人意见,或者奉献做本人的代码也是能够的,另外咱们也十分欢送大家进行存储相干技术交换,不错的话别忘去Github
点一个⭐
Thanks♪(・ω・)ノ。
更具体的问题能够查看:https://github.com/auula/bottle
发表回复