使用 Go 構建併發的 KV 存儲系統
帶你使用 Go 編寫一個簡單的 KV 存儲系統,使用Fiber
框架,支持併發操作並實現 TTL 功能。
通過本教程,你可以:
-
瞭解 KV 存儲的底層工作原理
-
瞭解 CRUD 如何實現
-
瞭解併發處理,比如鎖的使用
-
瞭解 TTL 功能如何實現
- 初始化項目
首先,創建一個新的項目目錄並進行初始化:
go mod init mszluKV
- 安裝依賴
//fiber框架
go get github.com/gofiber/fiber/v2
- 項目結構
mszluKV/
│── kvstore/
│ └── kvstore.go
│── main.go
│── go.mod
│── go.sum
│── Dockerfile
- 具體實現
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),
}
}
-
使用 map 來存儲實際的鍵值對
-
使用 sync.RWMutex 來確保安全的併發訪問
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
}
-
Set
方法用於存儲鍵值對並設置過期時間。 -
Get
方法用於檢索鍵值,並檢查鍵是否已過期。如果過期,會自動從存儲中刪除。 -
Delete
方法用於手動刪除鍵值對。
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")
}
-
/get/:key
: 如果給定的鍵存在,則獲取其值;否則,返回一條消息,指示該鍵不存在。 -
/set/:key/:value
: 存儲一個鍵值對,默認 TTL 爲 10 分鐘。 -
/delete/:key
: 如果存在,則從存儲中刪除一個鍵。
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