DreameMo:开箱即用的高标准性,模块化设计分布式缓存
#网络开发人员 #开源 #go #distributedsystems

介绍

如标题所示,DREAMEMO是一个分布式缓存,具有开箱即用,高尺度性,模块化设计功能。引用了groupcache实现,重新结构,特定的模块差异化如下:如下:

arch

主模块将在设计模块中详细介绍。

快速开始

安装

执行以下命令以安装DreameMo:

go get github.com/B1NARY-GR0UP/dreamemo

使用独立模式运行

DreameMo提供了函数dream.StandAlone使用的默认配置,以帮助用户迅速以独立模式启动。您需要做的就是配置相应数据源的source.Getter

package main

import (
    "context"
    "fmt"
    "net/http"

    "github.com/B1NARY-GR0UP/dreamemo/common/constant"
    "github.com/B1NARY-GR0UP/dreamemo/dream"
    "github.com/B1NARY-GR0UP/dreamemo/guidance"
    "github.com/B1NARY-GR0UP/dreamemo/source"
    log "github.com/B1NARY-GR0UP/inquisitor/core"
    "github.com/B1NARY-GR0UP/piano/core"
    "github.com/B1NARY-GR0UP/piano/core/bin"
)

var db = map[string]string{
    "binary": "dreamemo",
    "hello":  "world",
    "ping":   "pong",
}

func getFromDB(_ context.Context, key string) ([]byte, error) {
    log.Info("Get from DB")
    if v, ok := db[key]; ok {
        return []byte(v), nil
    }
    return nil, fmt.Errorf("key %v is not exist", key)
}

// go run .
// curl localhost:8080/hello?key=ping
func main() {
    dream.StandAlone(source.GetterFunc(getFromDB))
    p := bin.Default(core.WithHostAddr(":8080"))
    p.GET("/hello", func(ctx context.Context, pk *core.PianoKey) {
        key := pk.Query("key")
        g := guidance.GetGroup(constant.DefaultGroupName)
        value, _ := g.Get(ctx, key)
        pk.JSON(http.StatusOK, core.M{
            key: value.String(),
        })
    })
    p.Play()
}

map仿真数据源数据库的形式,并使用PIANO HTTP Framework作为前端服务器,而不是使用其他HTTP框架,例如Hertz,Gin等。检索钥匙的URL。

go run .
curl localhost:8080/hello?key=ping

使用集群模式运行

DreameMo还提供了使用默认配置在群集模式下运行的dream.Cluster函数。您需要做的就是配置相应的群集节点和数据源的地址。

package main

import (
    "context"
    "fmt"
    "net/http"

    "github.com/B1NARY-GR0UP/dreamemo/common/constant"
    "github.com/B1NARY-GR0UP/dreamemo/common/util"
    "github.com/B1NARY-GR0UP/dreamemo/dream"
    "github.com/B1NARY-GR0UP/dreamemo/guidance"
    "github.com/B1NARY-GR0UP/dreamemo/source"
    log "github.com/B1NARY-GR0UP/inquisitor/core"
    "github.com/B1NARY-GR0UP/piano/core"
    "github.com/B1NARY-GR0UP/piano/core/bin"
)

var db = map[string]string{
    "binary": "dreamemo",
    "hello":  "world",
    "ping":   "pong",
}

func getFromDB(_ context.Context, key string) ([]byte, error) {
    log.Info("Get from DB")
    if v, ok := db[key]; ok {
        return []byte(v), nil
    }
    return nil, fmt.Errorf("key %v is not exist", key)
}

// go run . --addrs=http://localhost:7246,http://localhost:7247,http://localhost:7248 --api
// go run . --addrs=http://localhost:7247,http://localhost:7248,http://localhost:7246
// go run . --addrs=http://localhost:7248,http://localhost:7246,http://localhost:7247
// curl localhost:8080/hello?key=ping
func main() {
    addrs, api := util.ParseFlags()
    e := dream.Cluster(source.GetterFunc(getFromDB), addrs...)
    if api {
        go func() {
            p := bin.Default(core.WithHostAddr(":8080"))
            p.GET("/hello", func(ctx context.Context, pk *core.PianoKey) {
                key := pk.Query("key")
                g := guidance.GetGroup(constant.DefaultGroupName)
                value, _ := g.Get(ctx, key)
                pk.JSON(http.StatusOK, core.M{
                    key: value.String(),
                })
            })
            p.Play()
        }()
    }
    e.Run()
}

再次将数据库数据源模拟为map,并在localhost:7246localhost:7247localhost:7248上配置了三个缓存节点,前端服务器在port 8080上配置。要检索键的值,请运行以下命令并访问URL:

go run . --addrs=http://localhost:7246,http://localhost:7247,http://localhost:7248 --api
go run . --addrs=http://localhost:7247,http://localhost:7248,http://localhost:7246
go run . --addrs=http://localhost:7248,http://localhost:7246,http://localhost:7247
curl localhost:8080/hello?key=ping

定制组装

dream.StandAlonedream.Cluster功能由DreameMo配置为较早使用,在这里我们将查看一种更自定义的运行汇编的方式。

  • 配置引擎

在这里,我们配置了引擎,util.ParseFlags是提供用于解析标志参数的实用程序方法。我们使用app.WithHostAddr来配置引擎以聆听和app.WithThrift0用作thrift作为序列化协议并注册其他节点。

  addrs, api := util.ParseFlags()
  e := server.NewEngine(app.WithHostAddr(addrs[0]), app.WithThrift0())
  e.RegisterInstances(addrs...)
  • 配置缓存消除策略

配置LFU

  l := lfu.NewLFUCore()
  m := memo.NewMemo(l)
  • 配置缓存组

我们将CACHE组名称配置为guidance.WithGroupName,将节俭配置为具有guidance.WithThrift1的序列化协议,与引擎保持一致,并使用source.Getter
配置数据源

  guidance.NewGroup(m, e, guidance.WithGroupName("hello"), guidance.WithThrift1(), guidance.WithGetter(source.GetterFunc(getFromDB)))

完整的代码如下:

package main

import (
    "context"
    "fmt"
    "net/http"

    "github.com/B1NARY-GR0UP/dreamemo/app"
    "github.com/B1NARY-GR0UP/dreamemo/app/server"
    "github.com/B1NARY-GR0UP/dreamemo/common/util"
    "github.com/B1NARY-GR0UP/dreamemo/guidance"
    "github.com/B1NARY-GR0UP/dreamemo/memo"
    "github.com/B1NARY-GR0UP/dreamemo/source"
    "github.com/B1NARY-GR0UP/dreamemo/strategy/eliminate/lfu"
    log "github.com/B1NARY-GR0UP/inquisitor/core"
    "github.com/B1NARY-GR0UP/piano/core"
    "github.com/B1NARY-GR0UP/piano/core/bin"
)

var db = map[string]string{
    "binary": "dreamemo",
    "hello":  "world",
    "ping":   "pong",
}

func getFromDB(_ context.Context, key string) ([]byte, error) {
    log.Info("Get from DB")
    if v, ok := db[key]; ok {
        return []byte(v), nil
    }
    return nil, fmt.Errorf("key %v is not exist", key)
}

// go run . --addrs=http://localhost:7246,http://localhost:7247,http://localhost:7248 --api
// go run . --addrs=http://localhost:7247,http://localhost:7248,http://localhost:7246
// go run . --addrs=http://localhost:7248,http://localhost:7246,http://localhost:7247
// curl localhost:8080/hello?key=ping
func main() {
    addrs, api := util.ParseFlags()
    e := server.NewEngine(app.WithHostAddr(addrs[0]), app.WithThrift0())
    e.RegisterInstances(addrs...)
    l := lfu.NewLFUCore()
    m := memo.NewMemo(l)
    guidance.NewGroup(m, e, guidance.WithGroupName("hello"), guidance.WithThrift1(), guidance.WithGetter(source.GetterFunc(getFromDB)))
    if api {
        go func() {
            p := bin.Default(core.WithHostAddr(":8080"))
            p.GET("/hello", func(ctx context.Context, pk *core.PianoKey) {
                key := pk.Query("key")
                g := guidance.GetGroup("hello")
                value, _ := g.Get(ctx, key)
                pk.JSON(http.StatusOK, core.M{
                    key: value.String(),
                })
            })
            p.Play()
        }()
    }
    e.Run()
}

运行并使用以下命令获取缓存值:

go run . --addrs=http://localhost:7246,http://localhost:7247,http://localhost:7248 --api
go run . --addrs=http://localhost:7247,http://localhost:7248,http://localhost:7246
go run . --addrs=http://localhost:7248,http://localhost:7246,http://localhost:7247
curl localhost:8080/hello?key=ping

设计

消除策略

在缓存策略方面,DreameMo支持LRU和LFU缓存消除算法,用户可以自己选择和组装它们:

  • lru
  c := lru.NewLRUCore()
  • lfu
  c := lfu.NewLFUCore()

DreameMo还提供了用于扩展其他消除策略的界面。只需实现界面并将对象传递到memo.NewMemo如下:

type ICore interface {
    Add(Key, Value)
    Get(Key) (Value, bool)
    Remove(Key)
    Clear()
    Name() string
}

序列化

dreamemo支持节俭和Protobuf序列化协议。默认值是Protobuf,要使用thrift,您需要在配置引擎和高速缓存组中启用节俭:

e := server.NewEngine(app.WithThrift0()) // engine
guidance.NewGroup(m, e, guidance.WithThrift1()) // group

数据源

DreameMo提供了使用Redis作为数据源的默认配置:

s := redis.NewSource()

DreameMo还提供了一个接口来配置您自己的更多数据源:

type Getter interface {
    Get(ctx context.Context, key string) ([]byte, error)
}

一致的哈希

DreameMo,例如GroupCache,使用一致的散布进行分布式节点选择,同时还提供了一个配置更多策略的接口。

全部

DreameMo还很年轻,可以做出许多变化。将来,将提供更多节点选择算法和快速配置工具。

概括

这就是本文的全部。希望这可以帮到你。如果您可以给DREAMEMO成为明星,我会很感激。

如果您有任何疑问,请将其留在评论或问题中。感谢您的阅读。

参考文献列表