
Security News
Open VSX Begins Implementing Pre-Publish Security Checks After Repeated Supply Chain Incidents
Following multiple malicious extension incidents, Open VSX outlines new safeguards designed to catch risky uploads earlier.
springautum.work/orca-zhang/ecache
Advanced tools
一款极简设计、高性能、并发安全、支持分布式一致性的轻量级内存缓存
👁️🗨️点我看用例 👁️🗨️点我看结果 (除了缓存命中率数值越低越好)
gc pause测试结果 代码由
bigcache提供(数值越低越好)
已验证]公众号后台(几百QPS):用户信息、订单信息、配置信息验证中]推送系统(几万QPS):可调整系统配置、信息去重、固定信息缓存待上线]评论系统(几万QPS):用户信息、分布式一致性组件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")
非go modules模式:
sh>go get -u github.com/orca-zhang/ecache
go modules模式:
sh>go mod tidy && go mod download
🎉 完美搞定 🚀 性能直接提升X倍!
sh>go run <你的main.go文件>
NewLRUCache
ecache会找一个合适的数字便于后面掩码计算ecache全部写满的情况下,应该有第一个参数 X 第二个参数个item,最多能支持存储42亿个item可选]第三个参数是每个item的过期时间
ecache使用内部计时器提升性能,默认100ms精度,每秒校准0,代表永久有效Put/PutInt64/PutBytes三种方法,适应不同场景,需要与Get/GetInt64/GetBytes配对使用(后两种方法GC开销较小)LRU-2模式,可能有很少的损耗(💬 什么是LRU-2)
LRU2和LRU的大小设置分别为1/4和3/4效果较好256、1024个桶,甚至更多Inspector监听驱逐事件Walk将数据刷到存储// 整型键
c.Put(strconv.FormatInt(d, 10), o) // d为`int64`类型
// 整型值
c.PutInt64("uid1", int64(1))
if d, ok := c.GetInt64("uid1"); ok {
// d为`int64`类型的1
}
// 字节数组
c.PutBytes("uid1", b)// b为`[]byte`类型
if b, ok := c.GetBytes("uid1"); ok {
// b为`[]byte`类型
}
直接在
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 - 可以用来做统计或者缓冲队列等
// `action`:PUT, `status`: evicted=-1, updated=0, added=1
// `action`:GET, `status`: miss=0, hit=1
// `action`:DEL, `status`: miss=0, hit=1
// `iface`/`bytes`只有在`status`不为0或者`action`为PUT时才不为nil
type inspector func(action int, key string, iface *interface{}, bytes []byte, status int)
cache.Inspect(func(action int, key string, iface *interface{}, bytes []byte, status int) {
// TODO: 实现你想做的事情
// 监听器会根据注入顺序依次执行
// 注意⚠️如果有耗时操作,尽量另开channel保证不阻塞当前协程
// - 如何获取正确的值 -
// - `Put`: `*iface`
// - `PutBytes`: `bytes`
// - `PutInt64`: `ecache.ToInt64(bytes)`
})
// 只会遍历缓存中存在且未过期的项
cache.Walk(func(key string, iface *interface{}, bytes []byte, expireAt int64) bool {
// `key`是值,`iface`/`bytes`是值,`expireAt`是过期时间
// - 如何获取正确的值 -
// - `Put`: `*iface`
// - `PutBytes`: `bytes`
// - `PutInt64`: `ecache.ToInt64(bytes)`
return true // 是否继续遍历
})
实现超级简单,注入inspector后,每个操作只多了一次原子操作,具体看代码
import (
"github.com/orca-zhang/ecache/stats"
)
名称为自定义的池子名称,内部会按名称聚合
注意⚠️绑定可以放在全局
var _ = stats.Bind("user", c)
var _ = stats.Bind("user", c0, c1, c2)
var _ = stats.Bind("token", caches...)
stats.Stats().Range(func(k, v interface{}) bool {
fmt.Printf("stats: %s %+v\n", k, v) // k是池子名称,v是(*stats.StatsNode)类型
// 其中统计了各种事件的次数,使用`HitRate`方法可以获得缓存命中率
return true
})
import (
"github.com/orca-zhang/ecache/dist"
)
名称为自定义的池子名称,内部会按名称聚合
注意⚠️绑定可以放在全局,不依赖初始化
var _ = dist.Bind("user", c)
var _ = dist.Bind("user", c0, 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") // user是池子名称,uid1是要删除的key
lrucache的老用户升级指导github.com/orca-zhang/lrucache 改为 github.com/orca-zhang/ecachelrucache.NewSyncCache 改为 ecache.NewLRUCache*time.SecondDelete方法改为Delecache做了啥,以及为什么要这么做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库的升级版本
LRU(最久未访问)
LRU-2能力,代码不超过20行,直接看源码(搜关键词LRU-2)LRU-K是少于K次访问的用单独的LRU队列存放,超过K次的另外存放LRU-2,也就是第2次访问就放到热队列里,并不记录访问次数WORM(Write-Once-Read-Many)的场景
canary发布,或者发布过程中)的情况下,比如
ecache但首次添加此插件string类型(可扩展性强;语言内建支持引用,更省内存)LRU-2实现LRU-K(实现简单,近乎没有额外损耗)[]byte那优势大大降低)bigcache节省内存50%以上)string改为reflect.StringHeader,结果:负优化time.Timer实现内部计时器,结果:触发不稳定,后直接用time.Sleep实现计时器[]byte的值存储,意味着可能需要序列化、拷贝(虽不在库的性能指标里,人家用还是要算,包括:GC、内存、CPU)ZeroCopy,那也无可厚非,而ecache存储指针直接省了额外的部分KISS才是王道ecache一共只有不到300行,千行bug率一定的情况下,它的bug不会多问:一个实例可以存储多种对象吗?
问:如何给不同item设置不同过期时间?
问:如果有热热热热key问题怎么解决?
LRU-2不让类似遍历的请求把热数据刷掉,二是除了增加bucket,可以用多实例(同时写入相同的item)+读访问某一个(比如按访问用户uid hash)的方式,让热key有多个副本,不过删除(反写)的时候要注意多实例全部删除,适用于“写少读多WORM(Write-Once-Read-Many)”的场景,或者“写多读多”的场景可以把有变化的diff部分单独摘出来转化为“写少读多WORM(Write-Once-Read-Many)”的场景。问:为什么不用虚表头方式处理双链表?太弱了吧!
感谢在开发过程中进行code review、勘误 & 提出宝贵建议的各位!(排名不分先后)
|
askuy [ego] |
Leon Ding [打码匠] |
黄振 |
Ice |
水不要鱼 [cachego] |
FAQs
Unknown package
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Following multiple malicious extension incidents, Open VSX outlines new safeguards designed to catch risky uploads earlier.

Research
/Security News
Threat actors compromised four oorzc Open VSX extensions with more than 22,000 downloads, pushing malicious versions that install a staged loader, evade Russian-locale systems, pull C2 from Solana memos, and steal macOS credentials and wallets.

Security News
Lodash 4.17.23 marks a security reset, with maintainers rebuilding governance and infrastructure to support long-term, sustainable maintenance.