垃圾回收

有关垃圾回收的详细信息

垃圾回收的必要性

  • 当用户删除文档时,Redis 仅将它们标记为在全局文档表中删除,而不是直接删除它们。这是为了提高效率。根据文档的长度,删除可能是一个漫长的操作。
  • 这意味着不再为已删除的文档分配内部数字 ID。遍历索引时,会检查是否已删除。
  • 属于已删除文档 ID 的所有倒排索引条目都是垃圾。
  • 更新文档基本上与删除它然后使用新的增量内部 ID 再次添加它相同。不执行差异,并且追加索引,因此 ID 保持增量,更新速度很快。

以上所有内容意味着,如果存在大量更新和删除操作,我们倒排索引的很大一部分将变成垃圾,这不仅会降低速度,还会占用不必要的内存。

您想要优化索引,但又不想影响正常运行。这意味着优化或垃圾回收应该是一个非侵入性的后台进程。它只需要比删除率更快,才能在足够长的时间内避免创建比收集更多的垃圾。

单项索引的垃圾回收

单项倒排索引是一个由块组成的数组,每个块都包含一个编码的记录列表;例如,一个文档 ID 增量加上其他数据,具体取决于索引编码方案。当其中一些记录引用已删除的文档时,这被称为垃圾。

算法很简单

  1. 为每个块创建一个读取器和写入器。
  2. 逐个读取每个块的记录。
  3. 如果没有任何记录无效,则不做任何操作。
  4. 当找到垃圾记录时,读取器会向前移动,但写入器不会移动。
  5. 当至少找到一条垃圾记录时,将对写入器编码下一条记录,并重新计算增量。

伪代码

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 增量,值) 的倒排索引树。这意味着相同的算法可以应用于它们,只需遍历树中的每个倒排索引对象即可。

FORK GC

有关 FORK GC 的信息可以在此博客中找到。

从 v1.6 开始,FORK GC 是默认的 GC 策略,已被证明在清理索引方面非常有效,并且不会降低查询和索引性能,即使对于非常写入密集型的用例也是如此。

RATE THIS PAGE
Back to top ↑