垃圾回收

关于垃圾回收的详细信息

垃圾回收的必要性

  • 当用户删除文档时,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

数字索引上的垃圾回收

数字索引是倒排索引的树,具有特殊的编码格式(文档 ID 增量,值)。这意味着可以将相同的算法应用于它们,只需遍历树中的每个倒排索引对象。

FORK GC

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

自 v1.6 版本以来,FORK GC 是默认的垃圾回收策略,已被证明在清理索引和不降低查询与索引性能方面非常高效,即使对于写操作非常密集的使用场景也是如此。

评价此页面
返回顶部 ↑