-
Notifications
You must be signed in to change notification settings - Fork 575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support eviction #176
base: master
Are you sure you want to change the base?
support eviction #176
Conversation
db.updateEvictionMark(read) | ||
defer func() { | ||
db.RWUnLocks(write, read) | ||
db.Eviction() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eviction 只用定时任务调用就行了,放在主流程里太拖性能了
defer mem.Lock.Unlock() | ||
var memFreed uint64 = 0 | ||
var memToFree uint64 | ||
mem.GetMaxMemoryState(memToFree) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
直接让 GetMaxMemoryState 返回 memToFree 就好了, 不需要模仿 C/C++ 这种传指针进去赋值的风格,
@@ -294,3 +307,88 @@ func (db *DB) ForEach(cb func(key string, data *database.DataEntity, expiration | |||
return cb(key, entity, expiration) | |||
}) | |||
} | |||
|
|||
//eviction | |||
func (db *DB) Eviction() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eviction 这边有几个问题:
- runtime.ReadMemStats 需要 StopTheWorld, 成本极高
- 对象可能已经不再使用但仍未 GC
- 不确定需要逐出多少对象
我后来考虑了一下可以这样解决:
- 首先使用 gopsutil 从操作系统中获取当前进程内存占用。它的成本很低不会影响正常运行。
- 若 gopsutil 发现内存超限手动调用 runtime.GC 优先进行垃圾回收
- 垃圾回收后使用 runtime.ReadMemStats 再次检查内存,若仍超限再进行逐出
- 设置一个逐出的 batch size,再逐出一批对象后再次调用 runtime.GC 和 runtime.ReadMemStats 直到内存符合要求:
伪代码
func eviction() {
if gopsutil.RSS < maxMemory {
return
}
for i:=0; i < loopLimit; i++ { // go 的 gc 不一定立即完成,还是设个上限
runtime.GC()
if runtime.ReadMemStats < maxMemory {
return
}
const batchSize = 1024
evict(batchSize)
}
}
Eviction 这边有几个问题:
我后来考虑了一下可以这样解决:
伪代码 func eviction() {
if gopsutil.RSS < maxMemory {
return
}
for i:=0; i < loopLimit; i++ { // go 的 gc 不一定立即完成,还是设个上限
runtime.GC()
if runtime.ReadMemStats < maxMemory {
return
}
const batchSize = 1024
evict(batchSize)
}
} 另外 :
|
info中
info中,有数据的属性只用rss和vms似乎都不符合 |
RSS 是物理内存大小, VMS 是虚拟内存空间大小,这里当然使用 RSS. GC 后内存读数未减少的原因很复杂,比如 runtime.GC 不一定立即完成清理、回收的内存不一定立即还给操作系统。 runtime.GC() 后再次检查内存使用 runtime.ReadMemStat 而不用系统的 RSS 就是为了拿到尽可能实时的内存占用量。 我做了一些实验,总的来说由于 GC 和操作系统内存管理的各种机制存在很难拿到准确的内存使用量, eviction 只能尽力而为吧 |
放到定时任务里是为了保证线上快速响应命令,每次执行命令都要查一下RSS会导致命令执行非常非常慢,定时任务不会影响命令执行速度。 |
support lfu and lru