Golang的缓存选型:go-cache vs. bigcache
初步看一下,目前人气比较高的以go-cache和bigcache为主,其他还有挺多选择的。
go-cache vs. bigcache 有相关对比吗?求推荐。或者别的更好的golang的缓存也行。
jerkzhang
我推荐goleveldb作为缓存。如果纯粹要一个正统的内存缓存,bigcache比较推荐。(看使用场景,最近一个工程中没有使用goleveldb,选择了bigcache,因为本身需要的就是纯粹的内存型缓存,对缓存的数据量并不没有追求,go-cache已经停止更新了,处理的比较简单,不推荐,但中国人重写的go-cache可以考虑与考察;其实主流的这几个大同小异,随便选一个来用都可以;其实我觉得把 json-iterator 和 bigtable 放在一起做个封装,会挺爽的)
DB's methods may be called concurrently from multiple goroutine.
leveldb是可以在多个goroutine中并发读写的。goleveldb应该是处理了线程安全问题,但是处理到什么程度我不确定。leveldb本身就有LRU内存缓存机制,你可以设置最大缓存容量,超过这个内存空间,就基于LRU进行抛弃,再读的时候就去硬盘里读。
等于是把硬盘也当作缓存的一部分,这个时代的硬盘的随机读写能力已经爆高无比了,完全具有作为缓存的潜质,虽然比内存还是差很多,但是能利用更大的硬盘空间,等于是多级缓存。
如果你觉得有必要限制最大可用的硬盘空间,就是限制leveldb占用的硬盘空间,你可以自己基于LRU原则或者别的原则,定时的有选择的去抛弃多余的数据,从而把硬盘空间控制在一个大约指定的范围内。这个可以自己单独开一个goroutine来定时去整理硬盘数据。不难的。不过我觉得没必要。硬盘本身就便宜,没必要废这个事,而且你本身就是需要对数据作为备份。不如就把leveldb中的数据作为一种备份数据库。(其实这样,你后端的数据存储看起来更像是备份。)
但是,为何直接leveldb作为缓存+数据库的方式,看似很完美,但是并没有那么流行起来,在底层服务商可能会这样,但是对于普通的应用者而言,并没有那么流行,相反直接的缓存go-cache/bigcache反而受到更多关注度?
因为,云计算平台的对象存储的价格远超过直接提供云硬盘。所以更多的人会选择直接基于对象存储,无限扩容,而不是采用leveldb本地存储。内存型缓存配合对象存储,更加方便高效,关键,便宜很多很多。
回到正题,leveldb是否可以作为缓存,我认为是可以的,不过得在参数上自行设置一下,因为默认的leveldb是8MB的内存作为缓存,这个你可以设置的更大。
使用leveldb作为缓存,主要是那种场景,因为云硬盘一般的价格会远昂贵于对象存储,所以,leveldb虽然是持久化存储,但当把leveldb视作单机缓存来用的则是,有大量数据,又不想花钱去买内存,这时候就可以用leveldb来把硬盘空间也用上去,其实有点类似虚拟内存的概念了。
但是leveldb的缓存,不是把具体的那个数据放在内存,而是把数据块放内存中,根据近期哪些数据块被用到最多的原则,来把常用的放在leveldb中。
所以,leveldb作为缓存,用硬盘扩充了内存,这时候因为命中率的原因,整体来说缓存的效率就没有那么那么高,这个比较适合偏随机性请求。不适合对那种很确定就是要高频访问的指定数据。
所以凡事有利必有弊,关键是选择最适合自己的。
leveldb作为缓存,主要是通过硬盘来扩充量的问题,用更少的成本来满足更多数据的缓存。
东方不败
如果是考虑程序自用,不考虑作为分布式缓存对外提供服务,其实golang自身就提供了一个不错的选择sync.Map。所以用golang + sync.Map + 分片 + 网络库,很容易就可以写成一个对外服务的分布式缓存。
其实嘛,golang使用bigcache这类缓存,主要就是图的是:
1、别人把线程安全都做好了,不需要你自己去上锁解锁了;
2、为了提高并发能力,别人帮你把sharding分片都搞定了;
3、别人把过期、LRU删除机制或 别的方法,总之别人把生命周期问题都解决好了。
golang不同协程之间有一些数据是共享的,有些场景适合使用channel,有些场景直接使用这类缓存是便捷的,因为有使用需求,所以golang的高性能高并发的单机内存缓存的库很多。
选主流的几个用即可。
喷火的尾巴
go-cache 和 bigcache 都是很好的选择;两者有一些差异,关键还是看你的需求与使用场景。
go-cache比较简单一些,容易上手;bigcache的配置相对复杂一点。
bigcache更适合对于大数据的缓存,专为处理大量数据而设计。它采用了一种称为"分块索引"的策略,将数据分成多个块并存储在不同的内存区域中。这种方式允许bigcache在处理大量数据时更好地管理内存,并支持更高的并发访问。bigcache还提供了多种数据类型和可选的压缩功能,以进一步减少内存使用和提高性能。
对于非大数据的场景,go-cache与bigcache在性能上应该是同一个水平的,可能对于小数据上go-cache的性能更好一些。
所以,如果你是小数据或者中等水平的数据,我还是推荐使用go-cache,如果你是大数据的缓存,我定然是推荐bigcache。主要还是看你的需求场景。
补充:go-cache可以存的go对象类型比较多,bigcache只能存[]byte类型。bigcache之所以能更高并发,因为用锁粒度更细的sharding们避免冲突,go-cache虽然不支持,但是可以自己去分片。我记得有中国人的gocache的重写的项目,性能提高三倍,且可以支持锁粒度更细的分片。
go-cache和bigcache都不支持持久化,但是都留出了自己将对象持久化的可能性。防止关闭进程,失去内存数据。但是用硬盘来扩充缓存,这个思路仍然需要进一步去自行设计,可以考虑去结合leveldb。
go-cache与bigcache 中小数据的读写性能我认为是一个水平的,但是并发能力,我认为bigcache更优越,如果追求并发,我推荐bigcache吧。