Golang实现多存储驱动设计SDK案例
本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《Golang实现多存储驱动设计SDK案例》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~
前言:
Gocache是一个基于Go语言编写的多存储驱动的缓存扩展组件。它为您带来了许多缓存数据的功能。
支持功能
多个缓存驱动存储:支持内存、redis或您自定义存储驱动。
支持如下功能:
- 链式缓存:使用具有优先级顺序的多个缓存(例如,内存然后回退到redis共享缓存)。
- 可加载缓存:允许您调用回调函数将数据放回缓存中。
- 指标缓存,可让您存储有关缓存使用情况的指标(命中、未命中、设置成功、设置错误……)。
- 自动编组/解组缓存值作为结构的编组器。
- 在存储中定义默认值并在设置数据时覆盖它们。
- 通过过期时间和/或使用标签缓存失效。
- 泛型的使用。
默认情况下,Gocache支持如下几种缓存驱动:
- 内存 (bigcache) (allegro/bigcache)。
- 内存 (ristretto) (dgraph-io/ristretto)。
- 内存 (go-cache) (patrickmn/go-cache)。
- 内存缓存(bradfitz/memcache)。
- Redis (go-redis/redis)。
- 空闲缓存(coocood/freecache)。
- Pegasus ( apache/incubator-pegasus )基准测试。
开发缘由
在作者的官网博客中提到这样的几句话:
当我开始在 GraphQL Go 项目上实现缓存时,它已经有一个内存缓存,它使用了一个具有简单 API 的小库,但也使用了另一个内存缓存库来使用具有不同库和 API 的批处理模式加载数据,做同样的事情:缓存项目。后来,我们还有一个需求:除了这个内存缓存之外,我们还想使用 Redis 添加一层分布式缓存,主要是为了避免我们的新 Kubernetes pod 在将新版本的应用程序投入生产时出现空缓存。
因此,作者想到是时候拥有一个统一的API来管理多个缓存存储:内存、redis、memcache 或任何你想要的。
如何使用
安装
要开始使用最新版本的 go-cache,您可以使用以下命令:
go get github.com/eko/gocache/v3
为避免尝试导入库时出现任何错误,请使用以下导入语句:
import ( "github.com/eko/gocache/v3/cache" "github.com/eko/gocache/v3/store" )
如果您遇到任何错误,请务必运行go mod tidy以清理您的 go.mod 文件。
存储适配器
首先,当您要缓存项目时,您必须选择要缓存项目的位置:在内存中?在共享的 redis 或 memcache 中?或者可能在另一个存储中。
目前,Gocache 实现了以下存储:
- BigCache:内存中的存储。
- Ristretto : DGraph 提供的另一个内存存储。
- Memcache:基于 bradfitz/gomemcache 客户端库的 memcache 存储。
- Redis:基于 go-redis/redis 客户端库的 redis 存储。
所有这些商店都实现了一个非常简单的 API,它遵循以下接口:
type StoreInterface interface {
Get(key interface{}) (interface{}, error)
Set(key interface{}, value interface{}, options *Options) error
Delete(key interface{}) error
Invalidate(options InvalidateOptions) error
Clear() error
GetType() string
}
此接口代表您可以在商店中执行的所有操作,并且每个操作都调用客户端库中的必要方法。所有这些存储都有不同的配置,具体取决于您要使用的客户端库,
例如,初始化 Memcache 存储:
store := store.NewMemcache(
memcache.New("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212"),
&store.Options{
Expiration: 10*time.Second,
},
)
然后,必须将初始化的存储传递给缓存对象构造函数。
缓存适配器
一个缓存接口来统治它们。
缓存接口与存储接口完全相同,因为基本上,缓存将对存储执行操作:
type CacheInterface interface {
Get(key interface{}) (interface{}, error)
Set(key, object interface{}, options *store.Options) error
Delete(key interface{}) error
Invalidate(options store.InvalidateOptions) error
Clear() error
GetType() string
}
使用这个界面,我可以对缓存项执行所有必要的操作:设置、获取、删除、无效数据、清除所有缓存和另一个方法 (GetType),它可以让我知道当前缓存项是什么,很有用在某些情况下。
从这个接口开始,实现的缓存类型如下:
Cache:允许操作来自给定存储的数据的基本缓存。Chain:一个特殊的缓存适配器,允许链接多个缓存(可能是因为你有一个内存缓存,一个redis缓存等......)。Loadable:一个特殊的缓存适配器,允许指定一种回调函数,如果过期或失效,自动将数据重新加载到缓存中。Metric:一个特殊的缓存适配器,允许存储有关缓存数据的指标:设置、获取、失效、成功与否的项目数。 当所有这些缓存都实现相同的接口并且可以相互包装时,美妙之处就出现了:一个指标缓存可以采用一个可加载的缓存,该缓存可以采用一个可以采用多个缓存的链式缓存。
下面是一个简单的 Memcache 示例:
memcacheStore := store.NewMemcache(
memcache.New("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212"),
&store.Options{
Expiration: 10*time.Second,
},
)
cacheManager := cache.New(memcacheStore)
err := cacheManager.Set("my-key", []byte("my-value"), &cache.Options{
Expiration: 15*time.Second, // Override default value of 10 seconds defined in the store
})
if err != nil {
panic(err)
}
value := cacheManager.Get("my-key")
cacheManager.Delete("my-key")
cacheManager.Clear()
// Clears the entire cache, in case you want to flush all cache
现在,假设您想要一个链式缓存,其中包含一个内存 Ristretto 存储和一个分布式 Redis 存储作为后备,
并带有一个 marshaller 和指标作为结果:
// Initialize Ristretto cache and Redis client
ristrettoCache, err := ristretto.NewCache(&ristretto.Config{NumCounters: 1000, MaxCost: 100, BufferItems: 64})
if err != nil {
panic(err)
}
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
// Initialize stores
ristrettoStore := store.NewRistretto(ristrettoCache, nil)
redisStore := store.NewRedis(redisClient, &cache.Options{Expiration: 5*time.Second})
// Initialize Prometheus metrics
promMetrics := metrics.NewPrometheus("my-amazing-app")
// Initialize chained cache
cacheManager := cache.NewMetric(promMetrics, cache.NewChain(
cache.New(ristrettoStore),
cache.New(redisStore),
))
// Initializes a marshaler
marshal := marshaler.New(cacheManager)
key := BookQuery{Slug: "my-test-amazing-book"}
value := Book{ID: 1, Name: "My test amazing book", Slug: "my-test-amazing-book"}
// Set the value in cache using given key
err = marshal.Set(key, value)
if err != nil {
panic(err)
}
returnedValue, err := marshal.Get(key, new(Book))
if err != nil {
panic(err)
}
// Then, do what you want with the value
我们还没有谈到 Marshaler,但它是 Gocache 的另一个功能:我们提供了一项服务来帮助您自动编组/解组您的对象从/到您的存储。
这在使用 struct 对象作为键而不是内存存储时很有用,因为您必须将对象转换为字节。
所有这些功能:带有内存和 redis 的链式缓存、Prometheus 指标和封送处理程序只需大约 20 行代码即可完成。
编写自己的缓存或存储
如果您想实现自己的专有缓存,也很容易做到。
这是一个简单的示例,以防您想要记录在缓存中完成的每个操作(这不是一个好主意,但很好,这是一个简单的 todo 示例):
package customcache
import (
"log"
"github.com/eko/gocache/cache"
"github.com/eko/gocache/store"
)
const LoggableType = "loggable"
type LoggableCache struct {
cache cache.CacheInterface
}
func NewLoggable(cache cache.CacheInterface) *LoggableCache {
return &LoggableCache{
cache: cache,
}
}
func (c *LoggableCache) Get(key interface{}) (interface{}, error) {
log.Print("Get some data...")
return c.cache.Get(key)
}
func (c *LoggableCache) Set(key, object interface{}, options *store.Options) error {
log.Print("Set some data...")
return c.cache.Set(key, object, options)
}
func (c *LoggableCache) Delete(key interface{}) error {
log.Print("Delete some data...")
return c.cache.Delete(key)
}
func (c *LoggableCache) Invalidate(options store.InvalidateOptions) error {
log.Print("Invalidate some data...")
return c.cache.Invalidate(options)
}
func (c *LoggableCache) Clear() error {
log.Print("Clear some data...")
return c.cache.Clear()
}
func (c *LoggableCache) GetType() string {
return LoggableType
}
同样,您也可以实现自定义存储。如果您认为其他人可以使您的缓存或存储实现受益,请不要犹豫,打开拉取请求并直接为项目做出贡献,以便我们一起讨论您的想法并带来更强大的缓存库。
压缩
生成模拟测试数据:
go get github.com/golang/mock/mockgen make mocks
测试套件可以运行:
make test # run unit test make benchmark-store # run benchmark test

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
一文搞懂Golang中的内存逃逸
- 上一篇
- 一文搞懂Golang中的内存逃逸
- 下一篇
- Go 语言简单实现Vigenere加密算法
-
- Golang · Go教程 | 6小时前 | 格式化输出 printf fmt库 格式化动词 Stringer接口
- Golangfmt库用法与格式化技巧解析
- 140浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang配置Protobuf安装教程
- 147浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang中介者模式实现与通信解耦技巧
- 378浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang多协程通信技巧分享
- 255浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang如何判断变量类型?
- 393浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang云原生微服务实战教程
- 310浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang迭代器与懒加载结合应用
- 110浏览 收藏
-
- Golang · Go教程 | 8小时前 | 性能优化 并发安全 Golangslicemap 预设容量 指针拷贝
- Golangslicemap优化技巧分享
- 412浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang代理模式与访问控制实现解析
- 423浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang事件管理模块实现教程
- 274浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3166次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3379次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3408次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4512次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3788次使用
-
- OpenTelemetry-go的SDK使用方法详解
- 2022-12-30 302浏览
-
- 聊聊QT添加MySQL驱动依赖的问题
- 2022-12-30 204浏览
-
- 关于Mysql-connector-java驱动版本问题总结
- 2022-12-31 174浏览
-
- Datagrip2020下载MySQL驱动失败的问题
- 2022-12-31 248浏览

