这是我参与「第五届青训营」伴学笔记创作活动的第 15 天
为评论查询添加本地缓存
本地缓存选型
go语言的本地缓存库有很多种选择,我这里首先找到的是一个缓存的统一管理库eko/gocache,它里面给出了很多本地缓存库的可选项,它们分别为:
其中go-cache虽然简单易用可以直接存储原生的go数据,star也很多但是已经很多年没有维护过了。freecache和bigcache都给出了良好的benchmark数据,其中freecache需要在建立时提前给出缓存的空间大小这对调优有挑战,而bigcache则是可以不提前设置,但是二者都需要使用者自行序列化和反序列化,这对我需要存储的评论数据结构有挑战,因为我希望能在使用时可以对缓存有一定程度的更新,而不是全选择删除。因此,我准备尝试使用ristretto来完成本地缓存。
对于缓存中保存的数据结构我准备使用emirpasic/gods中提供的队列。以便我进行缓存修改的操作。
要存储的内容
首先对于本地缓存,要存储哪部分信息这个要确定。首先对评论的操作只有发布和删除两种操作,因此评论内容与评论ID、用户ID、发布时间是永远一一对应的,而在用户部分的接口可以看到用户的姓名并没有给出修改接口,所以用户名和用户ID永远是一一对应的,这3部分都可以保证不会很频繁地变更,会变更的部分主要是各个用户的关注和粉丝数,还有浏览者和这些评论用户间的关注关系。我们确定了不变的东西,那么这些信息应该以怎样的形式存储在缓存中呢?我决定使用response中的结构体数组作为评论缓存的主要载体,每次输出前更新一下用户关注和粉丝数。但是,光是存评论行信息还是不够的。因为每次要完成评论信息的拼接我们需要访问两个表,分别是评论表和用户表。我们很可能碰到一个用户在多个视频中发表多条言论,因此单独为用户开辟存储是可行的。
先消除连接?
之前我实现获取视频评论的操作时,为了减少复杂度增加数据一致性,我使用的是单条语句使用左连接的方式直接读取所有内容的。但是在阿里的编码规范的数据库部分中提到过尽量不要使用过多的表连接,因为如果未来做了分库分表,这部分内容会会不太好处理,并且表连接可能会影响性能。虽然我这个查询只是两表做连接并且也有索引支持,但是我还是觉得还是将他们分为两部分查询可能会更方便缓存的引入。
接下来先看一下当前程序问题
接下来就是具体进行实施了,这部分我还在进行尝试。但是,在此之前我先使用pprof和自己写的一些压测,分析了一下之前的使用表连接完成的查询和不使用连接分开查询的两种情况,发现分开做增加了网络和内存开销并且也增加了程序的复杂度,pprof分析发现每次gorm都会带来大量的allocs非常不值。因此,虽然前面说使用两次查询拼接成目标评论,并存储评论内容和评论用户信息两部分,但是在具体实现时,我先使用原来的直接查询方法,只缓存拼接好的评论可能在实现成本上比较可以接受。