一个 Gin 缓存中间件的设计与实现 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
cyhone
V2EX    Go 编程语言

一个 Gin 缓存中间件的设计与实现

  •  
  •   cyhone 2021-06-18 16:17:05 +08:00 2536 次点击
    这是一个创建于 1583 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我们在开发 HTTP Server 的时候,经常有对接口内容做缓存的需求。例如,对于某些热点内容,我们希望做 1 分钟内的缓存。短期内缓存相同内容不会对业务造成实质影响,同时也会降低系统的整体负载。

    有时我们需要把缓存逻辑放在 Server 内部,而非网关侧如 Nginx 等,是因为这样我们可以根据需要便捷地清除缓存,或者可以使用 Redis 等其他存储介质作为缓存后端。

    这样的缓存场景无非是有缓存时从缓存取,无缓存时从下游服务取,并将数据放入缓存中。这其实是个非常通用的逻辑,应该可以将其抽象出来。从而缓存逻辑无需进侵入业务代码。

    cache

    我常用的 HTTP 框架是 golang 的 gin 。gin 官方就有一个 cache 组件:github.com/gin-contrib/cache,但这个 cache 组件无论在性能还是接口设计上,都有一些不足之处。

    因此,我重新设计了一套 cache 中间件: gin-cache。 从压测结果来看,其性能相比于 gin-contrib/cache 明显提升。

    点击查看原文>>

    11 条回复    2022-05-20 00:17:58 +08:00
    meshell
        1
    meshell  
       2021-06-18 16:21:02 +08:00
    没看代码。问个问题,比如说如果根据用户不同缓存是怎么做,或者其它的不同?在中间件中取唯一码,生成不同的缓存 key?
    cyhone
        2
    cyhone  
    OP
       2021-06-18 16:30:22 +08:00
    @meshell 好问题。gin-cache 提供了两个快捷函数,CacheByPath 和 CacheByUri,如果用户的信息(比如 uid)就在 url 中,直接使用这两个函数就行。

    如果需要从其他地方获取用户的唯一信息(例如 header 、body ),gin-cache 也支持用户自定义 KeyGenerator,这样可以自行写函数,根据不同请求,生成不同的 cache key
    xkeyideal
        3
    xkeyideal  
       2021-06-18 16:40:40 +08:00
    inmemory cache 以为是自己写的,没想到居然用的是”大名鼎鼎“的 https://github.com/patrickmn/go-cache fork 而来的库,在此呢,想劝你改掉,要么自己写一个,要么换个别的,换之前呢,类似 cache 这种代码量没多少,先阅读一下源码,看看有没有 bug 或性能问题。

    看到此贴的人,在 inmemory 没有换底层库之前,不要使用此缓存中间件,否则线上 P0 随时等着你
    meshell
        4
    meshell  
       2021-06-18 16:41:09 +08:00
    @cyhone 针对当前用户标识,一般我们都在 logic server 里面拿 uid 。还有就是我是不是要告诉中间件,我这个请求需要缓存,需要根据啥规则缓存,时间等。这些是直接写在 cache middleware 里面?
    xkeyideal
        5
    xkeyideal  
       2021-06-18 16:45:40 +08:00
    @meshell 再修复问题之前,先把在各个论坛上推广的帖子给屏蔽一下吧,inmemory 不能在较大数据量场景下使用,这是在给使用者制造故障,会把别人饭碗砸掉的
    xkeyideal
        6
    xkeyideal  
       2021-06-18 16:46:17 +08:00
    @cyhone @错人了 []
    cyhone
        7
    cyhone  
    OP
       2021-06-18 16:54:04 +08:00
    @xkeyideal 感谢反馈此库的问题。但需要说明的两点是:
    1. 并不是 fork 了此库。而是使用了该库作为内置的 inmemory 实现,是属于依赖而非 fork 关系。
    2. 如果觉得内置方案有问题,是可以替换为其他的自己的方案的。只要实现 persist.CacheStore 就可以

    此外,感谢反馈,我先研究下这个库的问题。同时已将该贴下沉了一天~
    cyhone
        8
    cyhone  
    OP
       2021-06-18 17:20:09 +08:00
    @meshell 是的,这些信息需要提供给 cache middleware 。但目前自定义 cache 策略中,暂时只支持生成 cache key, 以及是否要进行 cache 。缓存时间目前沿用了 api 默认的缓存时间,暂不支持每个请求自定义,不过这个 case 感觉可以加一下~
    xkeyideal
        9
    xkeyideal  
       2021-06-18 17:23:01 +08:00   1
    @cyhone 有问题反馈给作者是应该的,面向接口编程是好的设计,提供的实现方案也不应该有严重的潜在问题,这个库的问题之前有位线上出故障了,最终找到是此库的原因,还拿出来秀了一遍故障复盘。

    如果找不到问题可以找我

    inmemory cache 的实现无非需注意以下几点:
    1 、考虑到大数据量时的查询性能与并发安全,直接解决方案就是分片存储与加锁
    2 、此类 cache 一般都会涉及过期自动删除问题,如何最少化遍历或尽可能少的遍历,解决方案主流就是空间换时间,链表或堆
    3 、结合实际项目需求做相应的需求封装,建议不要使用或少使用第三方开源的 cache (因为并不难写)

    再提供一个可能存在问题的 cache 库,`muesli/cache2go` 三年前有位同事使用该库出现过 bug,原因好像是死锁,如今有无修复不清楚。
    cyhone
        10
    cyhone  
    OP
       2021-06-18 17:44:18 +08:00
    @xkeyideal 明白了~ 我研究下这里,之后应该会一个更好的方案替代这个库。
    2liuqi
        11
    2liuqi  
       2022-05-20 00:17:58 +08:00
    @xkeyideal 那只能我们重新造轮子了吗?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2547 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 02:19 PVG 10:19 LAX 19:19 JFK 22:19
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86