欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang實現(xiàn)事務(wù)型內(nèi)存數(shù)據(jù)庫的方法詳解

 更新時間:2023年03月03日 11:44:29   作者:qingwave  
內(nèi)存數(shù)據(jù)庫經(jīng)我們經(jīng)常用到,例如Redis,那么如何從零實現(xiàn)一個內(nèi)存數(shù)據(jù)庫呢,本文旨在介紹如何使用Golang編寫一個KV內(nèi)存數(shù)據(jù)庫MossDB

內(nèi)存數(shù)據(jù)庫經(jīng)我們經(jīng)常用到,例如Redis,那么如何從零實現(xiàn)一個內(nèi)存數(shù)據(jù)庫呢,本文旨在介紹如何使用Golang編寫一個KV內(nèi)存數(shù)據(jù)庫MossDB。

特性

MossDB是一個純Golang編寫、可嵌入的、鍵值型內(nèi)存數(shù)據(jù)庫,包含以下特性

  • 可持久化,類似Redis AOF(Append only Log)
  • 支持事務(wù)
  • 支持近實時的TTL(Time to Live), 可以實現(xiàn)毫秒級的過期刪除
  • 前綴搜索
  • Watch接口,可以監(jiān)聽某個鍵值的內(nèi)容變化,類似etcd的Watch
  • 多后端存儲,目前支持HashMap和RadixTree

命名由來

Moss有苔、苔花的含義,MossDB的名字來源于清代袁牧的一句詩:

苔花如米小,也學(xué)牡丹開

MossDB雖小,但五臟俱全,也支持了很多重要功能。另外,巧合的是《流浪地球2》中的超級計算機(jī)550W名字就是Moss。

架構(gòu)

內(nèi)存數(shù)據(jù)庫雖然使用簡單,實現(xiàn)起來卻有很多細(xì)節(jié),Golang目前也存在不少優(yōu)秀的開源內(nèi)存數(shù)據(jù)庫,比如buntdb、go-memdb,在編寫MossDB過程中也借鑒了一些它們的特性。

MossDB的架構(gòu)如圖:

自上往下分為:

  • 接口層,提供API接受用戶請求
  • 核心層,實現(xiàn)事務(wù)、過期刪除、Watch等功能
  • 存儲層,提供KV的后端存儲以及增刪改查
  • 持久化層,使用AOL持久化即每次修改操作都會持久化到磁盤Log中

快速開始

MossDB可嵌入到Go程序中,可以通過go get獲取

go get github.com/qingwave/mossdb

MossDB提供了易用的API,可以方便地進(jìn)行數(shù)據(jù)處理,下面的示例代碼展示了如何使用MossDB:

package main

import (
	"log"

	"github.com/qingwave/mossdb"
)

func main() {
    // create db instance
	db, err := mossdb.New(&mossdb.Config{})
	if err != nil {
		log.Fatal(err)
	}

    // set, get data
	db.Set("key1", []byte("val1"))
    log.Printf("get key1: %s", db.Get("key1"))

    // transaction
    db.Tx(func(tx *mossdb.Tx) error {
        val1 := tx.Get("key1")

        tx.Set("key2", val1)

        return nil
    })
}

更多示例見源碼

具體實現(xiàn)

從下往上分別介紹下MossDB如何設(shè)計與實現(xiàn),以及相關(guān)的細(xì)節(jié)。

AOF持久化

AOF源于Redis提供兩種持久化技術(shù),另外一種是RDB,AOF是指在每次寫操作后,將該操作序列化后追加到文件中,重啟時重放文件中的對應(yīng)操作,從而達(dá)到持久化的目的。其實現(xiàn)簡單,用在MossDB是一個不錯的選擇,但需要注意的是AOF缺點同樣明顯,如果文件較大,每次重啟會花費較多時間。

Redis的AOF是一種后寫式日志,先寫內(nèi)存直接返回給用戶,再寫磁盤文件持久化,可以保證其高性能,但如果中途宕機(jī)會丟失數(shù)據(jù)。MossDB中的AOF采用了WAL(預(yù)寫式日志)實現(xiàn),先寫Log再寫內(nèi)存,用來保證數(shù)據(jù)不會丟失,從而可以進(jìn)一步實現(xiàn)事務(wù)。

那么采用WAL會不會影響其性能?每次必須等到落盤后才進(jìn)行其他操作,WAL的每次寫入會先寫到內(nèi)核緩沖區(qū),這個調(diào)用很快就返回了,內(nèi)核再將數(shù)據(jù)落盤。我們也可以使用fsync調(diào)用強(qiáng)制內(nèi)核執(zhí)行直接將數(shù)據(jù)寫入磁盤。在MossDB中普通寫操作之會不會直接調(diào)用fsync,事務(wù)寫中強(qiáng)制開啟fsync,從而平衡數(shù)據(jù)一致性與性能。

WAL的實現(xiàn)引用了tiwall/wal,其中封裝了對Log文件的操作,可以支持批量寫入。由于WAL是二進(jìn)制的,必須將數(shù)據(jù)進(jìn)行編碼,通過varint編碼實現(xiàn),將數(shù)據(jù)長度插入到數(shù)據(jù)本體之前,讀取時可以讀取定長的數(shù)據(jù)長度,然后按長度讀取數(shù)據(jù)本體。MossDB中數(shù)據(jù)格式如下:

type Record struct {
	Op        uint16
	KeySize   uint32
	ValSize   uint32
	Timestamp uint64
	TTL       uint64
	Key       []byte
	Val       []byte
}

對應(yīng)編碼后的二進(jìn)制格式為:

|------------------------------------------------------------|
| Op | KeySize | ValSize | Timestamp | TTL | Key    | Val    |
|------------------------------------------------------------|
| 2  | 4       | 4       | 8         | 8   | []byte | []byte |
|------------------------------------------------------------|

使用binary.BigEndian.PutUint16進(jìn)行編碼,解碼時通過binary.BigEndian.Uint16,從而依次取得生成完整的數(shù)據(jù)。

存儲引擎

MossDB提供了存儲接口,只要實現(xiàn)了此接口都可以作為其后端存儲

type Store interface {
	Get(key string) ([]byte, bool)
	Set(key string, val []byte)
	Delete(key string)
	Prefix(key string) map[string][]byte
	Dump() map[string][]byte

	Len() int
}

內(nèi)置提供了HashMap與RadixTree兩種方式,HashMap實現(xiàn)簡單通過簡單封裝map可以快速進(jìn)行查詢與插入,但范圍搜索性能差。RadixTree即前綴樹,查詢插入的時間復(fù)雜度只與Key的長度相關(guān),而且支持范圍搜索,MossDB采用Adaptive Radix Tree可以避免原生的前準(zhǔn)樹空間浪費。

由于RadixTree的特性,MossDB可以方便的進(jìn)行前綴搜索,目前支持ListWatch操作。

事務(wù)實現(xiàn)

要實現(xiàn)事務(wù)必須要保證其ACID特性,MossDB的事務(wù)定義如下:

type Tx struct {
	db      *DB // DB實例
	commits []*Record // 對于寫操作生成 Record, 用來做持久化
	undos   []*Record // 對于寫操作生成 Undo Record,用于回滾
}

MossDB中一次事務(wù)的流程主要包含以下幾個步驟:

  • 首先加鎖,保證其數(shù)據(jù)一致性
  • 對于寫操作,生成Commits和Undo Records,然后寫入內(nèi)存;讀操作則直接執(zhí)行
  • 提交階段,將Commits持久化到WAL中;若寫入失敗,則刪除已寫入數(shù)據(jù);成功則設(shè)置數(shù)據(jù)的其他屬性(TTL, Watch等)
  • 若中間發(fā)生錯誤,執(zhí)行回滾操作,將Undo Records的記錄執(zhí)行
  • 事務(wù)完成,釋放鎖

Watch

由于工作中經(jīng)常使用Kubernetes,對于其Watch接口印象深刻,通過Watch來充當(dāng)其事件總線,保證其聲明式對象的管理。Kubernetes的Watch底層由etcd實現(xiàn),MossDB也實現(xiàn)了類似的功能。

Watch的定義如下:

type Watcher struct {
	mu       sync.RWMutex // 鎖
	watchers map[string]*SubWatcher // watchId與具體Watcher直接的映射
	keys     map[string]containerx.Set[string] // Watch單個key
	ranges   *art.Tree // 前綴Watch
	queue    workqueue.WorkQueue // 工作隊列,存放所有事件
	stop     chan struct{} // 是否中止
}

通過工作隊列模式,任何寫操作都會同步追加到隊列中,如果存在單個key的監(jiān)聽者,則通過watchers map獲取到對應(yīng)列表,依次發(fā)送事件。對于前綴Watch,我們不可能記錄此前綴的所有Key,這里借鑒了etcd,通過RadixTree保存前綴Key,當(dāng)有新事件時,匹配Key所在的路徑,如果有監(jiān)聽者,則進(jìn)行事件通知。

調(diào)用Watch會返回一個Channel,用戶只需要監(jiān)聽Channel即可

func Watch(db *mossdb.DB) {
	key := "watch-key"

	ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Millisecond)
	defer cancel()

	// start watch key
	ch := db.Watch(ctx, key)
	log.Printf("start watch key %s", key)

	go func() { // 模擬發(fā)送event
		db.Set(key, mossdb.Val("val1"))
		db.Set(key, mossdb.Val("val2"))
		db.Delete(key)

		time.Sleep(100 * time.Second)

		db.Set(key, mossdb.Val("val3"))
	}()

	for {
		select {
		case <-ctx.Done():
			log.Printf("context done")
			return
		case resp, ok := <-ch:
			if !ok {
				log.Printf("watch done")
				return
			}
			log.Printf("receive event: %s, key: %s, new val: %s", resp.Event.Op, resp.Event.Key, resp.Event.Val)
		}
	}

    // Output
    // 2023/02/23 09:48:50 start watch key watch-key
	// 2023/02/23 09:34:19 receive event: MODIFY, key: watch-key, new val: val1
	// 2023/02/23 09:34:19 receive event: MODIFY, key: watch-key, new val: val2
	// 2023/02/23 09:34:19 receive event: DELETE, key: watch-key, new val:
	// 2023/02/23 09:34:19 context done
}

TTL

過期刪除再很多場景很有用,比如驗證碼過期、訂單未支付關(guān)閉等。MossDB采用時間堆來實現(xiàn)精確的Key過期策略,具體原理可以參考之前的文章Golang分布式應(yīng)用之定時任務(wù),在查詢操作時也會檢查Key是否過期,如果過期則直接返回空數(shù)據(jù)。配合Watch操作可以精確管理數(shù)據(jù)的生命周期。

總結(jié)

至此,MossDB的實現(xiàn)細(xì)節(jié)已經(jīng)分析完成,支持了事務(wù)、持久化、Watch與過期刪除等特性,后續(xù)可能會支持HTTP API、存儲快照等功能。

所有代碼見https://github.com/qingwave/mossdb,歡迎批評指正以及Star。

以上就是Golang實現(xiàn)事務(wù)型內(nèi)存數(shù)據(jù)庫的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Golang事務(wù)型內(nèi)存數(shù)據(jù)庫的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語言實戰(zhàn)之實現(xiàn)比特幣地址校驗步驟

    go語言實戰(zhàn)之實現(xiàn)比特幣地址校驗步驟

    這篇文章主要介紹了go語言實戰(zhàn)之實現(xiàn)比特幣地址校驗步驟,利用生產(chǎn)的隨機(jī)數(shù)采用橢圓加密算法生成公鑰,具體步驟實例代碼請參考下本文
    2021-05-05
  • 基于Go語言實現(xiàn)分金幣游戲

    基于Go語言實現(xiàn)分金幣游戲

    這篇文章主要為大家詳細(xì)介紹了如何利用Go語言實現(xiàn)分金幣游戲,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Golang 之協(xié)程的用法講解

    Golang 之協(xié)程的用法講解

    這篇文章主要介紹了Golang 之協(xié)程的用法講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang如何實現(xiàn)proxy代理簡單方法

    golang如何實現(xiàn)proxy代理簡單方法

    這篇文章主要給大家介紹了關(guān)于golang如何實現(xiàn)proxy代理簡單方法的相關(guān)資料,Proxy是golang實現(xiàn)的高性能http,https,websocket,tcp,udp,socks5,ss代理服務(wù)器,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • GoFrame框架使用避坑指南和實踐干貨

    GoFrame框架使用避坑指南和實踐干貨

    這篇文章主要為大家介紹了GoFrame框架使用避坑指南和實踐干貨,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go結(jié)合MQTT實現(xiàn)通信的示例代碼

    Go結(jié)合MQTT實現(xiàn)通信的示例代碼

    本文主要介紹了Go結(jié)合MQTT實現(xiàn)通信的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • golang1.21新特性全面講解

    golang1.21新特性全面講解

    經(jīng)過了半年左右的開發(fā),golang?1.21?最近正式發(fā)布了,這個版本中有不少重要的新特性和變更,尤其是在泛型相關(guān)的代碼上,下面小編就來和大家好好嘮嘮吧
    2023-08-08
  • Go語言遍歷map實現(xiàn)(訪問map中的每一個鍵值對)

    Go語言遍歷map實現(xiàn)(訪問map中的每一個鍵值對)

    這篇文章主要介紹了Go語言遍歷map實現(xiàn)(訪問map中的每一個鍵值對),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的步驟

    利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的步驟

    目前,OpenCV逐步成為一個通用的基礎(chǔ)研究和產(chǎn)品開發(fā)平臺,下面這篇文章主要給大家介紹了關(guān)于利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-09-09
  • 基于Go語言實現(xiàn)簡單的計算器

    基于Go語言實現(xiàn)簡單的計算器

    這篇文章主要為大家詳細(xì)介紹了如何基于Go語言實現(xiàn)簡單的計算器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-10-10

最新評論