ecache 是一款极简设计、高性能、并发安全、支持分布式一致性的内存缓存。
非go modules模式:
sh>go get -u github.com/orca-zhang/ecache
go modules模式:
sh>go mod tidy && go mod download
import ( "time" "github.com/orca-zhang/ecache" )
可以放置在任意位置(全局也可以),建议就近定义
var c = ecache.NewLRUCache(16, 200, 10 * time.Second)
c.Put("uid1", o) // o可以是任意变量,一般是对象指针,存放固定的信息,比如*UserInfo
if v, ok := c.Get("uid1"); ok { return v.(*UserInfo) // 不用类型断言,咱们自己控制类型 } // 如果内存缓存没有查询到,下面再回源查redis/db
在信息发生变化的地方
c.Del("uid1")
�� 完美搞定 �� 性能直接提升X倍!
sh>go run <你的main.go文件>
NewLRUCache
ecache
会找一个等于或者略大于输入大小的2的幂次的数字,后面便于掩码计算ecache
全部写满的情况下,应该有第一个参数✖️第二个参数
个itemecache
使用内部定时器提升性能,默认100ms精度,每秒校准LRU-2
模式,虽然可能有很少的损耗(�� 什么是LRU-2)256
、1024
个桶,甚至更多直接在
NewLRUCache()
后面跟.LRU2(<num>)
就好,参数<num>
代表LRU-2
热队列的item上限个数(每个桶)
var c = ecache.NewLRUCache(16, 200, 10 * time.Second).LRU2(1024)
// 设置的时候直接给`nil`就好 c.Put("uid1", nil)
// 读取的时候,也和正常差不多 if v, ok := c.Get("uid1"); ok { if v == nil { // 注意⚠️这里需要判断是不是空缓存哨兵 return nil // 是空缓存哨兵,那就返回没有信息或者也可以让`uid1`不出现在待回源列表里 } return v.(*UserInfo) } // 如果内存缓存没有查询到,下面再回源查redis/db
比如,我们从
ecache
中获取了*UserInfo
类型的用户信息缓存v,需要修改其状态字段
import ( "github.com/jinzhu/copier" )
o := &UserInfo{} copier.Copy(o, v) // 从v复制到o o.Status = 1 // 修改副本的数据
实现超级简单,注入inspector后,每个操作只多了一次原子操作,具体看代码
引入stats包
import ( "github.com/orca-zhang/ecache/stats" )
var _ = stats.Bind("user", c) var _ = stats.Bind("user", c, c1, c2) var _ = stats.Bind("room", caches...)
stats.Stats().Range(func(k, v interface{}) bool { fmt.Printf("stats: %s %+v\n", k, v) return true })
import ( "github.com/orca-zhang/ecache/dist" )
名称为自定义的池子名称,内部会按名称聚合
注意⚠️绑定可以放在全局,不依赖初始化
var _ = dist.Bind("user", c) var _ = dist.Bind("user", c, c1, c2) var _ = dist.Bind("token", caches...)
目前支持redigo和goredis,其他库可以自行实现dist.RedisCli接口,或者提issue给我
import ( "github.com/orca-zhang/ecache/dist/goredis/v7" ) dist.Init(goredis.Take(redisCli)) // redisCli是*redis.RedisClient类型 dist.Init(goredis.Take(redisCli, 100000)) // 第二个参数是channel缓冲区大小,不传默认100
import ( "github.com/orca-zhang/ecache/dist/goredis" ) dist.Init(goredis.Take(redisCli)) // redisCli是*redis.RedisClient类型 dist.Init(goredis.Take(redisCli, 100000)) // 第二个参数是channel缓冲区大小,不传默认100
注意⚠️
github.com/gomodule/redigo
要求最低版本go 1.14
import ( "github.com/orca-zhang/ecache/dist/redigo" ) dist.Init(redigo.Take(pool)) // pool是*redis.Pool类型
当db的数据发生变化或者删除时调用
发生错误时会降级成只处理本机所有实例(比如未初始化或者网络错误)
dist.OnDel("user", "uid1")
ecache
做了啥,以及为什么要这么做L1 缓存引用 .................... 0.5 ns
分支错误预测 ...................... 5 ns
L2 缓存引用 ...................... 7 ns
互斥锁/解锁 ...................... 25 ns
主存储器引用 .................... 100 ns
使用 Zippy 压缩 1K 字节 ........3,000 ns = 3 µs
通过 1 Gbps 网络发送 2K 字节... 20,000 ns = 20 µs
从内存中顺序读取 1 MB ........ 250,000 ns = 250 µs
同一数据中心内的往返........... 500,000 ns = 0.5 ms
发送数据包 加州<->荷兰 .... 150,000,000 ns = 150 ms
ecache
是lrucache
库的升级版本
node
实现的最基础LRU
(最久未访问)
LRU-2
能力,代码不超过20行,直接看源码(搜关键词LRU-2
)LRU-K
是少于K次访问的用单独的LRU
队列存放,超过K次的另外存放LRU-2
,也就是第2次访问就放到热队列里,并不记录访问次数WORM(Write-Once-Read-Many)
的场景
canary
发布,或者发布过程中)的情况下,比如
ecache
但首次添加此插件高性能
还用defer的,直接pass吧)LRU-2
实现LRU-K
(实现简单,近乎没有额外损耗)[]byte
那优势大大降低)[]byte
的值存储,意味着必须序列化、拷贝(虽不在库的性能指标里,人家用还是要算,包括:GC、内存、CPU)ZeroCopy
,那也无可厚非,而ecache
存储指针直接省了额外的部分KISS
才是王道ecache
一共只有不到300行,千行bug率一定的情况下,它的bug不会多问:一个实例可以存储多种对象吗?
问:如何给不同item设置不同过期时间?
问:如果有热热热热key问题怎么解决?
LRU-2
不让类似遍历的请求把热数据刷掉,二是除了增加bucket,可以用多实例(同时写入相同的item)+读随机访问某一个的方式,让热key有多个副本,不过删除(反写)的时候要注意多实例全部删除,适用于“写少读多WORM(Write-Once-Read-Many)
”的场景,或者“写多读多”的场景可以把有变化的diff部分单独摘出来转化为“写少读多WORM(Write-Once-Read-Many)
”的场景。问:为什么不用虚表头方式处理双链表?太弱了吧!
问:为什么不提供int类型的key的接口?
ecache缓存机制,web项目启动时自动加载相应字典,配置文档等内容,提供性能。 主要功能:初始化缓存,或者响应缓存内容,获取缓存列表,清除缓存等功能。 集成springMVC,具体配置及后台代码实现,请点击下面连接,下载使用:本人已经实践过,没问题。 ecache配置使用说明文档
ecache-core包版本不对引起的错误,将2.5.3换成2.4.5就好了 来源 WARN [RMI TCP Connection(3)-127.0.0.1] - Exception encountered during context initialization - cancelling refresh attempt org.springframework.beans.fact
applicationxml <!-- 启用缓存注解功能 --> <cache:annotation-driven cache-manager="ehcacheManager"/> <bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <proper
最近在写自己框架的时候研究了下ecache缓存技术,我在纠结使用ecache还是使用redis呢,因为redis是基于内存的缓存技术,当然他们的应用场景不同。我更加倾向于redis,所以,自己写了基于spring aop的redis注解,本来想用ecache的注解方式实现redis注解,发现工作量庞大,所以,就实现了一个最初版: 注解 package com.nise.common.framewo
Java Ecache缓存工具类源代码复制到编译器,调用即可: public class EcacheUtil { public static CacheManager manager = CacheManager.getInstance();//找到ehcache.xml的路径 public static Cache cache = manager.getCache("cache");//cac
前言 EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。具体详情参考官网:ehcache官网 Ehcache2和Ehcache3之间的差异比较大, 最大差异在:Ehcache2包名为:net.sf.ehcache,而Ehcache3包名为:org.ehcache。Ehcache有xml配置和代码配置两种方式,本文只讲代码
1、配置ecache.xml文件内容如下: 注释:<diskStore path="java.io.tmpdir"/>代表默认临时文件路径 user.home 代表用户主目录 user.dir 代表当前工作目录 <?xml version="1.0" encoding="UTF-8"?> <ehcache name="es"> <diskStore path="java.
问题内容: 题 我正在寻找Java内存对象缓存API。有什么建议吗?您过去使用过什么解决方案? 当前 现在,我只是在使用地图: 要求 我需要扩展缓存以包括以下基本功能: 最大尺寸 生存时间 但是,我不需要更复杂的功能,例如: 来自多个进程的访问(缓存服务器) 持久性(到磁盘) 意见建议 内存中缓存: Guava CacheBuilder-活动开发。请参阅此演示文稿。 LRUMap-通过API配置。
本文向大家介绍Android图片三级缓存策略(网络、本地、内存缓存),包括了Android图片三级缓存策略(网络、本地、内存缓存)的使用技巧和注意事项,需要的朋友参考一下 一、简介 现在的Android应用程序中,不可避免的都会使用到图片,如果每次加载图片的时候都要从网络重新拉取,这样不但很耗费用户的流量,而且图片加载的也会很慢,用户体验很不好。所以一个应用的图片缓存策略是很重要的。通常情况下,A
Serenity 提供一些缓存抽象和实用功能让你更容易地使用本地缓存。 术语 本地(local) 的意思是指在本地内存中缓存项目(因此没有涉及到序列化)。 当你的应用程序在网站群(web farm) 中部署时,本地缓存可能还不够或者有时合适。我们将在 分布式缓存 章节中讨论该场景。
我们可以通过下面的简单算法实现该目的: 检查本地缓存的键(key); 如果本地缓存存在该键,则返回它的值; 如果本地缓存不存在该键,则尝试在分布式缓存中找; 如果分布式缓存存在该键,则返回它的值并把它添加到本地缓存; 如果分布式缓存不存在该键,则从数据库中获取,并添加到本地和分布式缓存,最后返回该值。 当在本地缓存服务器中缓存一些信息时,使用这种方式,它还将信息缓存到分布式缓存,但这一次,如果其他
本文向大家介绍浅谈Android轻量级的数据缓存框架RxCache,包括了浅谈Android轻量级的数据缓存框架RxCache的使用技巧和注意事项,需要的朋友参考一下 请求网络数据是在安卓开发中使用最频繁的一个功能,网络请求的体验决定了用户对整个APP的感觉,因此合理地使用缓存对网络请求的数据进行处理极为重要。合理的进行缓存和网络请求,可以为APP带来更优秀的体验。图片的缓存有Picasso、Gl
当你使用本地(在内存中)缓存时,服务器可以缓存一些信息并快速地检索它,但是其他服务器不能访问这个缓存数据,他们需要到数据库中查询同样的信息。 如果你喜欢使用分布式缓存让其他服务器访问缓存的数据,由于它有一些序列化/反序列化和网络延迟开销,则需要注意:在某些情况下,它可能会降低性能。 缓存需要处理的另一个问题:缓存失效。 There are only two hard things in Compu
1、一级缓存:指的是mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入sqlSession中,再次查询的时候,先去sqlSession中查询,有的话直接拿出,当sqlSession消失时,mybatis的一级缓存也就消失了,当调用sqlSession的修改、添加、删除、commit()、close()等方法时,会清空一级缓存。 2、二级缓存:指的是mybati