首页 > 数据库 >Redis、Memcached、Guava、Ehcache中的算法

Redis、Memcached、Guava、Ehcache中的算法

时间:2023-04-23 10:00:51浏览次数:50  
标签:Ehcache 检查 过期 Cache Redis LRU 内存 Guava Memcached


1. LRU

简单粗暴的Redis

今天看 Redis3.0的发行通告里说,LRU算法大幅提升了,就翻开源码来八卦一下,结果哭笑不得,这旧版的"近似LRU"算法,实在太简单,太偷懒,太Redis了。

在 Github的Redis项目里搜索lru,找到代码在redis.c的freeMemoryIfNeeded()函数里。

先看 2.6版的代码: 竟然就是随机找三条记录出来,比较哪条空闲时间最长就删哪条,然后再随机三条出来,一直删到内存足够放下新记录为止.......可怜我看 配置文档后的想象,一直以为它会帮我在整个Redis里找空闲时间最长的,哪想到我有一百万条记录的时候,它随便找三条就开始删了。

好,收拾心情再看 3.0版的改进:现在每次随机五条记录出来,插入到一个长度为十六的按空闲时间排序的队列里,然后把排头的那条删掉,然后再找五条出来,继续尝试插入队列.........嗯,好了一点点吧,起码每次随机多了两条,起码不只在一次随机的五条里面找最久那条,会连同之前的一起做比较......

中规中矩的Memcached

相比之下,Memcached实现的是再标准不过的LRU算法,专门使用了一个教科书式的双向链表来存储slab内的LRU关系,代码在 item.c里,详见 memcached源码分析-----LRU队列与item结构体,元素插入时把自己放到列头,删除时把自己的前后两个元素对接起来,更新时先做删除再做插入。

分配内存超限时,很自然就会从LRU的队尾开始清理。

同样中规中矩的Guava Cache

Guava Cache同样做了一个双向的Queue,见 LocalCache中的AccessQueue类,也会在超限时从Queue的队尾清理,见 evictEntries()函数

和Redis一样懒的Ehcache

看 文档,居然和Redis2.6一样,直接随机8条记录,找出最旧那条,刷到磁盘里,再看代码, Eviction类 和  OnHeapStore的evict()函数,的确如此。

小结

不过后来再想想,也许Redis本来就不是主打做Cache的,这种内存爆了需要通过LRU删掉一些元素不是它的主要功能,默认设置都是noeviction——内存不够直接报错的,所以就懒得建个双向链表,而且每次访问时都要更新它了,看Google Group里长长的讨论,新版算法也是社区智慧的结晶。但Ehache是专门做Cache的呀,也这么懒。

 

2. 过期键删除

如果能为每一个设置了过期的元素启动一个Timer,一到时间就触发把它删掉,那无疑是能最快删除过期键最省空间的,在Java里用一条 DeplayQueue存着,开条线程不断的读取就能做到。但因为该线程消耗CPU较多,在内存不紧张时有点浪费,似乎大家都不用这个方法。

所以有了惰性检查,就是每次元素被访问时,才去检查它是否已经超时了,这个各家都一样。但如果那个元素后来都没再被访问呢,会永远占着位子吗?所以各家都再提供了一个定期主动删除的方式。

Redis

代码在 redis.c的activeExpireCycle()里,看过文档的人都知道,它会在主线程里,每100毫秒执行一次,每次随机抽20条Key检查,如果有1/4的键过期了,证明此时过期的键可能比较多,就不等100毫秒,立刻开始下一轮的检查。不过为免把CPU时间都占了,又限定每轮的总执行时间不超过1毫秒。

Memcached

Memcached里有个文不对题的 LRU爬虫线程,利用了之前那条LRU的队列,可以设置多久跑一次(默认也是100毫秒),沿着列尾一直检查过去,每次检查LRU队列中的N条数据。虽然每条Key设置的过期时间可能不一样,但怎么说命中率也比Redis的随机选择N条数据好一点,但它没有Redis那种过期的多了立马展开下一轮检查的功能,所以每秒最多只能检查10N条数据,需要自己自己权衡N的设置。

Guava Cache

在Guava Cache里,同一个Cache里所有元素的过期时间是一样的,所以它比Memached更方便,顺着之前那条LRU的Queue检查超时,不限定个数,直到不超时为止。而且它这个检查的调用时机并不是100毫秒什么的,而是每次各种写入数据时的 preWriteCleanup()方法中都会调用。

吐槽一句,Guava的Localcache类里面已经4872行了,一点都不轻量了。

Ehcache

Ehcache更乱,首先它的内存存储中只有惰性检查,没有主动检查过期的,只会在内存超限时不断用近似LRU算法(见上)把内存中的元素刷到磁盘中,在文件存储中才有超时检查的线程, FAQ里专门解释了原因。

然后磁盘存储那有一条8小时左右跑一次的线程,每次遍历所有元素.....见 DiskStorageFactory里的DiskExpiryTask。 一圈看下来,Ehcache的实现最弱。

 

标签:Ehcache,检查,过期,Cache,Redis,LRU,内存,Guava,Memcached
From: https://blog.51cto.com/u_6186189/6216310

相关文章

  • memcached命令行参数说明
    评:1、启动Memcache常用参数-p<num>设置TCP端口号(默认不设置为:11211)-U<num>UDP监听端口(默认:11211,0时关闭)[u][b]-l<ip_addr>绑定地址(默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)[/b][/u]-d以daemon方式运行......
  • FastCGI server uwsgi server SCGI server memcached server
     NGINXReverseProxy|NGINXPlushttps://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/fastcgi_pass passesarequesttoaFastCGIserveruwsg......
  • memcached的slab钙化问题
    memcached的slab钙化问题现象:服务某些接口成功率波动,经研发查看是数据在memcached查询的偶尔失败。因为前一晚升级的时候,改了存储在memcahed的数据(图片base64)的大小,改成......
  • Spring 3.2.1.RELEASE MVC 基于注解ehcache.xml 配置方式
    载的关联包里的ehcache-spring-annotations.jar之外,还需要spring-context-support.jar,cblib-2.2.jar.<dependency><groupId>com.googlecod......
  • 本地缓存 GuavaCache & Caffeine
    1.GuavaCacheGuavaCache是一個全内存的本地缓存实现,提供了线程安全实现机制1.1GuavaCache数据结构底层类似ConcurrentlHashMap,所以是线程安全的(分段锁)  1.2Gu......
  • 【Retry】消息重试框架 Spring-Retry 和 Guava-Retry
    消息重试框架背景1、调用第三方的方法或接口等,并不保证一次性就能调用成功2、消息推送,MQ消费后才进行处理时,尝试几次不成功,就再放回数据库再做补偿措施等等,这些都是需......
  • Google Guava Cache
    JAVA8guava31.1-jre--- 序章Guavaisasuiteofcoreandexpandedlibrariesthatincludeutilityclasses,Google'scollections,I/Oclasses,andmuchmor......
  • Guava EventBus介绍
     介绍GuavaEventBus是GoogleGuava提供的一种发布-订阅式的事件总线,基于观察者模式的思想,用于处理应用程序内部的消息通信。导入依赖<dependency><groupId>co......
  • Ehcache初体验
    前言读张开涛写的《亿级流量网站架构核心技术》里面讲到使用Java缓存:堆内缓存,堆外缓存,磁盘缓存,分布式缓存。介绍了几种缓存工具:GauvaCache,Ehcache和MapDB。其中Gauva......
  • 接口限流常见算法方案原理 及其 实现(Guava RateLimiter,Redis+AOP+Lua)
    (目录)什么是限流?为什么要限流?限流,这个词其实并不陌生,在我们生活中也随处可见。做核酸时,工作人员会在核酸检测点的空地上摆放着弯弯曲曲的围栏,人们排着队左拐右拐的往前......