用 Go 语言造了一个全新的 kv 存储引擎

简介: 经历了大概 4 个月的打磨,LotusDB 的第一个 release 版本终于发布了,我看了下,有 200 多次 commit(接近 rosedb 一年多的 commit 次数了)。

经历了大概 4 个月的打磨,LotusDB 的第一个 release 版本终于发布了,我看了下,有 200 多次 commit(接近 rosedb 一年多的 commit 次数了)。

RVW1$B~GCYW9}VMQKN3C}{X.png

项目地址:https://github.com/flower-cor...

有了 rosedb 在 bitcask 模型上的实践之后,以及自己在存储这方面的一些经验积累,去年底的时候,在上班路上突然想到的一个 idea,让我有了做一个新的 kv 存储引擎的想法。


有了想法之后便是验证,因为其实心里还是没谱,我又在 Github 上翻了翻,并没有同类型的实现。后来又找一些大佬沟通了下,证明我的想法是可行的。


这期间还发现了 Usenix Fast 上的一篇关于优化 LSM 的论文,发现论文的内容跟我的 idea 非常类似,这算是又多了一个理论依据,于是便决定开干了。

感兴趣的可以参考下论文,叫做 SLM-DB,地址: https://www.usenix.org/confer...


众所周知,数据存储引擎,目前最主流的两种模型是 B+ 树和 LSM 树,B+ 树在关系型数据库例如 Mysql 中应用比较广泛,而 LSM 的典型代表 rocksdb 也是大多数分布式系统数据落盘的首选。


B+ 树读性能稳定,而 LSM 写吞吐高,LotusDB 在这基础上做了一个巨大的改动,就是完全舍弃掉 LSM 中的 SST 文件,改由 B+ 树来存储索引,而 value 存放则参考了 Wisckey 和 bitcask 模型的设计,存储到单独的 value log 文件中。


LotusDB 是对 LSM 和 B+ 树的优势结合,目前并没有同类型的实现,我们应该是第一个吃螃蟹的人。

LotusDB 的架构图如下:

T7OZ)N]{(9]%60]X5DGHU_A.png

前台的写入和 LSM 完全一致,先写 wal 再写 memtable。


而读取则会从 memtable 开始,如果 memtable 找到了,直接返回;没找到的话则从 B+ 树中查询索引,然后根据索引信息到 value log 中获取 value。


大家可以先了解个大概,后续我会出一个完整的《LotusDB 设计与实现》系列文章,全面解析 LotusDB 的架构细节以及代码实现,目前已经写了几篇待发布,欢迎关注公众号的后续更新:

_R`N~[HNNQIY~)B[@8F4H~D.png

再来看看 LotusDB 提供的一些基本接口,目前实现了基础的 Put、Get、Delete 接口,并且支持 Column Family(借鉴于 rocksdb),以及 value log 的自动 GC 回收。

简单的使用方法如下:

package main
import (
    "github.com/flower-corp/lotusdb"
    "io/ioutil"
    "time"
)
// basic operations for LotusDB:
// put
// put with options
// get
// delete
// delete with options
func main() {
    path, _ := ioutil.TempDir("", "lotusdb")
    opts := lotusdb.DefaultOptions(path)
    db, err := lotusdb.Open(opts)
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 1.----put----
    key1 := []byte("name")
    err = db.Put(key1, []byte("lotusdb"))
    if err != nil {
        // ...
    }
    key2 := []byte("feature")
    // 2.----put with options----
    writeOpts := &lotusdb.WriteOptions{
        Sync:      true,
        ExpiredAt: time.Now().Add(time.Second * 100).Unix(),
    }
    err = db.PutWithOptions(key2, []byte("store data"), writeOpts)
    if err != nil {
        // ...
    }
    // 3.----get----
    val, err := db.Get(key1)
    if err != nil {
        // ...
    }
    if len(val) > 0 {
        // ...
    }
    // 4.----delete----
    err = db.Delete(key1)
    if err != nil {
        // ...
    }
    // 5.----delete with options----
    deleteOpts := &lotusdb.WriteOptions{
        Sync:       false,
        DisableWal: true,
    }
    err = db.DeleteWithOptions([]byte("dummy key"), deleteOpts)
    if err != nil {
        // ...
    }
}

目前自认为 LotusDB 的代码质量比之前的 RoseDB 好多了,单元测试更加完备,注释清晰,代码也更加简洁规范,如果你是 Go 新手,或者准备学习 Go,也能够把项目当做练习素材,自己对照着来学习。


当然我们的愿景还是打造一个能够在生产环境中实际落地的存储引擎,目前的版本只是一个开始,后续还会有非常多的工作,包括但不限于:

  • batch 操作,保证原子性
  • 多个 Column Family 保证原子性
  • 基于 SSI 的事务
  • Iterator 迭代器
  • 数据压缩
  • 数据备份
  • index 的分裂
相关文章
|
2月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
188 1
|
4月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
295 1
|
4月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
391 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
256 0
|
4月前
|
Cloud Native Java Go
Go:云原生时代的效率引擎
Go:云原生时代的效率引擎
172 0
|
4月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
225 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
325 0
|
4月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
4月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
5月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。

热门文章

最新文章