高性能本地缓存Ristretto(二)——过期策略
ristretto提供了SetWithTTL()方法,支持创建key的同时,并设置一个过期时间。
ristretto 利用嵌套的map结构,并结合巧妙的存储方式,实现了对每一个key的过期时间的管理。并能在时间到期后,尽快的删除过期的key,以节省资源开销。
过期时间的存储结构
ristretto采用嵌套的map结构记录key以及对应的过期时间,如下所示:
type shardedMap struct {...expiryMap *expirationMap // expirationMap 是全局共享的...
}type expirationMap struct {...buckets map[int64]bucket // buckets的value也是map
}type bucket map[uint64]uint64 // bucket 本质上是一个map结构
对于以上结构buckets的key是时间戳。bucket中的key和 value则 分别存储是keyHash和conflictHash值(对于这两个值如何得到的,请参考上一篇文章高性能本地缓存Ristretto(一)——存储策略)。这么干说可能有点懵逼,举个例子,画个图可能更形象。
假如有 key = “ZHH” value= “ZhaoHaihang”
需要缓存,并且要设置过期时间为5秒。通过keyToHash()对key做hash得到keyHash= “666" 和 conflictHash=“888”,并且现在的时间戳为1000。则最终该结构会以如下图的方式存储:
其中,1005为key = “ZHH” value= “ZhaoHaihang”
这条数据的过期时间戳。1005对应的value为bucket2,因此bucket2中的key、value分别为666,888
过期时间的存储策略
仔细考虑可以发现,上面的存储方式可能还有些可优化的地方。我们真的需要将key按每一秒划分bucket吗?如果按每5秒 划分为一个bucket是不是也行呢?
比如,在10秒钟内,每一秒存了1个key。时间戳分别为1000 - 1010,key分别为A-J,每个key的过期时间为5s,则key与之对应的过期时间戳为:
体现在内存中存储结构就变成了如下图所示:
图中,对每一个时间戳除5取整,得到buckets中的key,然后将keyHash 和conflictHash 分别作为bucket的key和value。
具体流程
对大概的存储方式有一定了解后,再结合代码看具体的流程就非常容易了,同时对于key如何过期的就能了解的更清楚。
接下来将以写缓存为例,详细梳理,key的过期时间的存储方式,和删除过期key的方法。
存储key过期时间的流程
调用SetWithTTL()函数,在写缓存的同时为key设置一个过期时间。以秒为单位。
图中,参数ttl即为过期时间。并在内部调用setInternal()setInternal()函数中,对通过ttl 计算key的过期时间戳,并记录在Item中,最终进入setBuf
3. 另外一个协程执行processItems(),从setBuf中取Item,根据不同的操作类型,执行不同的操作。
Set() 中会在增加一条key的过期时间的数据。
add() 先通过 storeBucket() 计算该时间戳应该是哪个bucket,之后将key 和 confict写入bucket就行了。
storeBucket()中,就是通过将时间戳除5得到一个数值的。
如何删除过期了的key
已经知道了怎么存储过期时间,现在来看看过期的key是怎么被删除的吧。
- 首先回到processItems()函数,里面有个定时器,会定时的执行CleanUp() 函数。
该定时器是在初始化的时候就设置好的:
可以发现,定时周期为 bucketDurationSecs / 2,还记得bucketDurationSecs 是多少吗?没错!是5,因此定时周期为2s,即每2秒就会执行一次清理任务。
- Cleanup() 通过简单的封装,继续执行cleanup().
- 在cleanup() 中,执行最终的删除操作。
cleanupBucket() 返回的是storageBucket() -1 ,即5秒前过期的key,这样就不会误删还没有过期的key。
至此,删除过期key的流程就执行完了。
现在,终于可以明白,为什么要以5秒为一个单位记录key,如果以每一秒,那删除操作的频率会很高,这显然是大可不必的。
链接
高性能本地缓存Ristretto(一)——存储策略
高性能本地缓存Ristretto(二)——过期策略相关推荐
- 高性能本地缓存Ristretto(一)——存储策略
Ristretto是Dgraph基于golang实现的一个高性能的本地缓存库.特点是高命中率,高吞吐量,可自定义存储成本,支持一些自定义回调函数,并提供了较多的统计信息. 本文将主要讲述Ristret ...
- 高性能本地缓存Ristretto(三)——淘汰策略
之前提到过,缓存即 存储 和 淘汰策略.一个好的淘汰策略,对于提升命中率起着至关重要的作用.一般常用的淘汰策略有,LRU.LFU.TinyLFU以及Window-TinyLFU (讲解LRU.LFU. ...
- Java高性能本地缓存框架Caffeine
文章目录 Java高性能本地缓存框架Caffeine 如何使用 缓存加载 手动加载 自动加载 手动异步加载 自动异步加载 过期策略 基于大小 基于时间 基于引用 Caffeine.weakKeys() ...
- 「GoCN酷Go推荐」高性能内存缓存 ristretto
背景 ristretto 是 dgraph 团队开源的一款高性能内存缓存库,旨在解决高并发场景下的缓存性能和吞吐瓶颈.dgraph 专攻的方向是高性能图数据库,ristretto 就是其图数据库和 K ...
- 转:基于AOP实现Ibatis的缓存配置过期策略
一.上篇回顾 自从上次<网站性能优化之应用程序缓存-中篇>得到不少园友的支持和鼓励,并且提出了不错的思路来实现我们中篇中提到的缓存策略,那么我将会结合.NET 本身内置 的AOP的方式来跟 ...
- Java8本地缓存Caffeine
文章目录 一.Caffeine介绍 1.缓存介绍 2.Caffeine介绍 二.Caffeine基础 1.缓存加载策略 1.1 Cache手动创建 1.2 Loading Cache自动创建 1.3 ...
- 本地缓存王者,Caffeine 保姆级教程!给力...
缓存(Cache)在代码世界中无处不在.从底层的CPU多级缓存,到客户端的页面缓存,处处都存在着缓存的身影.缓存从本质上来说,是一种空间换时间的手段,通过对数据进行一定的空间安排,使得下次进行数据访问 ...
- 干掉GuavaCache:Caffeine才是本地缓存的王
点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群",加入新技术 话说,中间件的选择上,Spring(SpringBoot)一直是业 ...
- 干掉 GuavaCache:Caffeine 才是本地缓存的王
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 话说,中间件的选择上,Spring(SpringBoot ...
最新文章
- java的final修饰_java final 修饰符详解
- 使用Levmar的L-M算法拟合曲线
- java mysql 二级缓存_深入理解MyBatis中的一级缓存与二级缓存
- Android开发笔记(四十九)异步任务处理AsyncTask
- iOS 使用iPhone配置实用工具 创建桌面快捷方式
- debain下装memcached
- 自定义linux桌面,教您6个自定义Ubuntu桌面的步骤
- opencv--轮廓拟合函数 boundingRect(),minAreaRect(),minEnclosingCircle(),fitEllipse(),fitLine()
- 惠而浦将斥资30亿美元收购艾默生电气旗下爱适易;高通和格芯签署一项长期制造协议 | 美通企业日报...
- C++蜜蜂的爬行路线
- Vue3使用路由及配置vite.alias简化导入写法
- 极智AI | 一文看懂昇腾达芬奇架构计算单元
- 如何做好基于地图的数据可视化?
- 多投影完美拼接——边缘融合投影技术
- c语言不用strcpy复制字符串,c语言程序(二十三)——字符串复制(不使用strcpy()函数)...
- 微信开发者工具 网络连接失败
- kafka基础入门(4):kafka消费者
- EBS 修改系统名称
- html——标签分类
- android数据库降级_Android 数据库版本降低时的操作