最近在工作中,我的任务是向我们的一个 Golang 服务添加缓存。这个服务需要传入请求以提供用于身份验证的 API key。因此,对于每个请求,该服务都会额外查询数据库以验证 API key,尽管它通常是相同的 key。这很不好。实现缓存最终比我想象的要难得多。

经过调研和工程师之间详尽讨论之后,我们认为 BigCache[1] 最适合我们的需求。

Set(key string, entry []byte) errorSet(key, entry interface{})
encoding/gob
register()interface{}
// 大多数示例中注册的类型
type foo struct {
    bar string
}

gob.register(foo{})

// 我想要注册的类型
var type interface{} // 可以是任何结构

gob.register(type)

把它们组合在一起

解决了将任意 struct 存储为 bytes 的问题后,我将向您展示如何将它们组合在一起。首先,我们需要一个缓存 interface,以便系统的其余部分能够与之交互。对于一个简单的缓存,我们只需要 get 和 set 方法。

type Cache interface {
    Set(key, value interface{}) error
    Get(key interface{}) (interface{}, error)
}

现在,让我们定义实现上述接口的 BigCache 实现。首先,我们需要一个结构来保存缓存并可以向其中添加方法。您还可以在此结构中添加其他字段,例如 metrics。

type bigCache struct {
    cache *bigcache.BigCache
}

接下来是 get 和 set 方法的实现。两种方法都断言 key 是 string。由此开始,get 和 set 的实现就彼此独立了。一个序列化一个值并存储它。另一个获取值并将其反序列化。

func (c *bigCache) Set(key, value interface{}) error {
    // 断言 key 为 string 类型
    keyString, ok := key.(string)
    if !ok {
        return errors.New("a cache key must be a string")
    }

    // 将 value 序列化为 bytes
    valueBytes, err := serialize(value)
    if err != nil {
        return err
    }

    return c.cache.Set(keyString, valueBytes)
}

func (c *bigCache) Get(key interface{}) (interface{}, error) {
    // 断言 key 为 string 类型
    keyString, ok := key.(string)
    if !ok {
        return nil, errors.New("a cache key must be a string")
    }

    // 获取以 bytes 格式存储的 value
    valueBytes, err := c.cache.Get(keyString)
    if err != nil {
        return nil, err
    }

    // 反序列化 valueBytes
    value, err := deserialize(valueBytes)
    if err != nil {
        return nil, err
    }

    return value, nil
}
encoding/gobregister()
func serialize(value interface{}) ([]byte, error) {
    buf := bytes.Buffer{}
    enc := gob.NewEncoder(&buf)
    gob.Register(value)

    err := enc.Encode(&value)
    if err != nil {
        return nil, err
    }

    return buf.Bytes(), nil
}

func deserialize(valueBytes []byte) (interface{}, error) {
    var value interface{}
    buf := bytes.NewBuffer(valueBytes)
    dec := gob.NewDecoder(buf)

    err := dec.Decode(&value)
    if err != nil {
        return nil, err
    }

    return value, nil
}
interface{}

如果您喜欢这篇文章,请查看我的 博客[5] 以获取类似内容。

via: https://dev.to/calebschoepp/storing-empty-interfaces-in-bigcache-1b33

作者:calebschoepp[6]译者:alandtsang[7]校对:polaris1119[8]

本文由 GCTT[9] 原创编译,Go 中文网[10] 荣誉推出,发布在 Go语言中文网公众号,转载请联系我们授权。

参考资料

[1]

BigCache: https://github.com/allegro/bigcache

[2]

博客文章: https://blog.golang.org/gob

[3]

register funtion: https://golang.org/pkg/encoding/gob/#Register

[4]

gist: https://gist.github.com/calebschoepp/0165d92de412e288aa7441e792d0aa3a

[5]

博客: https://calebschoepp.com/blog

[6]

calebschoepp: https://dev.to/calebschoepp

[7]

alandtsang: https://github.com/alandtsang

[8]

polaris1119: https://github.com/polaris1119

[9]

GCTT: https://github.com/studygolang/GCTT

[10]

Go 中文网: https://studygolang.com/