使用 Go 構建併發的 KV 存儲系統

帶你使用 Go 編寫一個簡單的 KV 存儲系統,使用Fiber框架,支持併發操作並實現 TTL 功能。

通過本教程,你可以:

  1. 初始化項目

首先,創建一個新的項目目錄並進行初始化:

go mod init mszluKV
  1. 安裝依賴

//fiber框架
go get github.com/gofiber/fiber/v2
  1. 項目結構

mszluKV/
│── kvstore/
│   └── kvstore.go
│── main.go
│── go.mod
│── go.sum
│── Dockerfile
  1. 具體實現

4.1 定義存儲結構

kvstore/kvstore.go:

package kvstore

import (
    "sync"
    "time"
)

type Data struct {
    value      string
    expiration time.Time
}

type KeyValueStore struct {
    mu   sync.RWMutex
    data map[string]Data
}

func NewKeyValueStore() *KeyValueStore {
    return &KeyValueStore{
        data: make(map[string]Data),
    }
}

4.2 CRUD

func (kv *KeyValueStore) Set(key, val string, ttl time.Duration) {
    // 加鎖以確保獨佔訪問
    kv.mu.Lock()
    defer kv.mu.Unlock()

    kv.data[key] = Data{
        value:      val,
        expiration: time.Now().Add(ttl),
    }
}

func (kv *KeyValueStore) Get(key string) (string, bool) {
    kv.mu.Lock()
    defer kv.mu.Unlock()
    val, ok := kv.data[key]

    // 檢查鍵是否過期。如果過期時間爲零或當前時間早於過期時間,則表示未過期。
    if val.expiration.IsZero() || time.Now().Before(val.expiration) {
        return val.value, ok
    }

    // 如果鍵已過期,則從存儲中刪除該鍵
    delete(kv.data, key)
    return ""false
}

func (kv *KeyValueStore) Delete(key string) bool {
    kv.mu.Lock()
    defer kv.mu.Unlock()

    _, ok := kv.data[key]
    if !ok {
        return false
    }
    delete(kv.data, key)
    return true
}

4.3 http 服務

package main

import (
    "time"
    "mszluKV/kvstore"
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()
    kv := kvstore.NewKeyValueStore()

    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("This is a Simple Key-Value store like Redis in Go.")
    })

    app.Get("/get/:key", func(c *fiber.Ctx) error {
        key := c.Params("key")
        value, ok := kv.Get(key)
        if !ok {
            return c.SendString("The Key " + key + " doesn't exist")
        }
        return c.SendString("The Key " + key + " has Value " + value)
    })

    app.Post("/set/:key/:value", func(c *fiber.Ctx) error {
        key := c.Params("key")
        value := c.Params("value")
        kv.Set(key, value, 10*time.Minute)
        return c.SendString("Key " + key + " Value " + value)
    })

    app.Delete("/delete/:key", func(c *fiber.Ctx) error {
        key := c.Params("key")
        ok := kv.Delete(key)
        if !ok {
            return c.SendString("The Key " + key + " doesn't exist")
        }
        return c.SendString("Successfully Deleted!!")
    })

    app.Listen(":3000")
}

4.4 運行和測試

go run main.go

使用 curl 進行測試:

curl -X POST http://localhost:3000/set/foo/bar
curl -X GET http://localhost:3000/get/foo
curl -X DELETE http://localhost:3000/delete/foo
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/cv3zL3kvEbj6e2FfX8R9DQ