垃圾回收
有关垃圾回收的详细信息
垃圾回收的需求
- 当用户删除文档时,Redis 只会在全局文档表中将其标记为已删除,而不会直接删除它们。这样做是为了提高效率。根据文档的长度,删除可能是一个漫长的作。
- 这意味着不再为已删除的文档分配内部数字 ID。遍历索引时,将检查是否删除。
- 属于已删除文档 ID 的所有倒排索引条目都是垃圾。
- 更新文档与删除文档,然后使用新的增量内部 ID 再次添加文档基本相同。不执行比较,并且会附加索引,因此 ID 保持增量,并且更新速度很快。
以上所有意味着,如果有大量的更新和删除,我们的倒排索引的很大一部分将变成垃圾,既会减慢速度,又会消耗不必要的内存。
您想要优化索引,但也不想打扰正常作。这意味着优化或垃圾回收应该是非侵入性的后台进程。它只需要在足够长的时间内比删除率更快,这样您就不会创建超出可以收集的垃圾。
垃圾回收单项索引
单项倒排索引是一个块数组,每个块都包含一个编码的记录列表;例如,文档 ID 增量加上其他数据,具体取决于索引编码方案。当其中一些记录引用已删除的文档时,这称为垃圾。
算法很简单:
- 为每个数据块创建一个读取器和写入器。
- 逐个读取每个块的记录。
- 如果没有记录无效,则不执行任何作。
- 找到垃圾记录时,读取器是高级的,但不是写入器。
- 当找到至少一条垃圾记录时,下一条记录将被编码到写入器,重新计算增量。
伪代码:
foreach index_block as block:
reader = new_reader(block)
writer = new_write(block)
garbage = 0
while not reader.end():
record = reader.decode_next()
if record.is_valid():
if garbage != 0:
# Write the record at the writer's tip with a newly calculated delta
writer.write_record(record)
else:
writer.advance(record.length)
else:
garbage += record.length
数值索引上的 GC
数字索引是一棵倒排索引树,其特殊编码为 (docId delta, value)。这意味着可以对它们应用相同的算法,只遍历树中的每个倒排索引对象。
分叉 GC
有关 FORK GC 的信息,请参阅此博客。
从 v1.6 开始,FORK GC 是默认的 GC 策略,并且被证明在清理索引和不降低查询和索引性能方面都非常有效,即使对于非常密集的写入用例也是如此。