• 实时表的结构

一个普通表可以通过一个名为 indexer 的特殊工具从外部源创建,该工具从配置中读取“食谱”,连接到数据源,提取文档并构建表文件。这是一个耗时的过程。如果您的数据发生变化,表就会变得过时,您需要从刷新后的源重新构建它。如果您的数据是增量变化的,比如一个博客或新闻源,其中旧文档不会改变,只会添加新文档,重建将需要越来越多的时间,因为您需要在每次处理时重复处理存档源。

解决这个问题的一种方法是使用多个表,而不是一个大型表。例如,您可以处理前几年生成的源并保存表。然后,仅处理当前年份的源,并将其放入单独的表中,按照需要频繁重建。然后,您可以将这两个表作为分布式表的一部分,并用于查询。这里的关键是,每次重建时,您最多只处理过去12个月的数据,而包含旧数据的表保持不变,无需重建。您可以进一步将最近的12个月表按月、按周或按天分开,依此类推。

这种方法是可行的,但您需要手动维护您的分布式表。也就是说,添加新块、删除旧块,并保持部分表的总数不过多(如果表过多,搜索可能会变慢,操作系统通常会限制同时打开的文件数量)。为了解决这个问题,您可以通过运行 indexer --merge 手动将多个表合并在一起。然而,这只是解决了表数量过多的问题,使维护变得更加复杂。即使是每小时的重新索引,您也很可能会在新数据到达源和重建表(以填充这些数据进行搜索)之间有明显的时间差。

实时表旨在解决此问题。它由两部分组成:

  1. 一个基于 RAM 的特殊表(称为 RAM 块),包含当前到达的数据部分。

  2. 一组过去构建的普通表,称为磁盘块。

这与标准的 分布式表 非常相似,由几个本地表组成。

您不需要通过运行 indexer 来构建这样的表,indexer 从配置和表数据源读取“食谱”。相反,实时表提供了“插入”新文档和“替换”现有文档的能力。当执行“插入”命令时,您将新文档推送到服务器。然后,它从添加的文档构建一个小表,并立即将其上线。因此,在“插入”命令完成后,您可以在所有表部分中执行搜索,包括刚添加的文档。

搜索服务器自动维护该表,因此您不必担心。然而,您可能会对“它是如何维护的”感兴趣。

首先,既然索引数据存储在 RAM 中,紧急断电怎么办? 那么我会失去我的表吗?在完成之前,服务器会将新数据保存到一个特殊的“binlog”中。这由一个或多个文件组成,存储在您的持久存储上,随着您添加更多更改而逐渐增长。您可以调整关于新查询(或事务)存储在 binlog 中的频率,以及在 binlog 文件上执行“sync”命令以强制操作系统实际将数据保存到安全存储中的行为。最极端的做法是在每个事务后进行刷新和同步。这是最慢的,但也是最安全的方法。最便宜的方法是完全关闭 binlog。这是最快的方法,但您面临着失去已索引数据的风险。中间变体,如每秒刷新/同步,也可以使用。

binlog 专门用于顺序保存新到达的事务;它不是表,不能进行搜索。它仅仅是一个保险政策,以确保服务器不会丢失您的数据。如果发生突发故障,因软件或硬件问题导致崩溃,服务器将加载 RAM 块的最新可用转储,然后重放 binlog,重复存储的事务。最终,它将达到与上一次更改时相同的状态。

第二,限制呢? 如果我想处理,比如说,10TB 的数据,但它根本不适合 RAM!实时表的 RAM 是有限的,可以进行配置。当索引到达某一数据量时,服务器通过合并小事务来管理表的 RAM 部分,保持其数量和整体大小较小。然而,这个过程有时会在插入期间导致延迟。当合并不再有效,且新的插入达到 RAM 限制 时,服务器会将基于 RAM 的表转换为存储在磁盘上的普通表(称为磁盘块)。这个表会添加到实时表的第二部分的表集合中,并可以在线访问。然后,RAM 被刷新,空间被释放。

当来自 RAM 的数据安全保存到磁盘时,会发生以下情况:

  • 服务器将收集到的数据保存为磁盘表

  • 或者在干净关机期间或通过 手动刷新 转储 RAM 部分

该表的 binlog 将不再需要。因此,它被丢弃。如果所有表都被保存,binlog 将被删除。

第三,磁盘集合呢? 如果有很多磁盘部分会使搜索变慢,那么如果我以分布式表的方式手动创建它们或作为 RT 表产生的磁盘部分(或“块”)有什么区别?在这两种情况下,您都可以将多个表合并为一个。例如,您可以合并昨天的每小时表,并保留一个“每日”表。通过手动维护,您必须自己考虑模式和命令。在 RT 表中,服务器提供了 OPTIMIZE 命令,它执行相同的操作,但让您远离不必要的内部细节。

第四,如果我的“文档”构成一个“迷你表”,而我不再需要它,我可以直接丢弃它。但是如果它被“优化”,即与其他大量文档混合在一起,我该如何撤销或删除它呢? 是的,已索引的文档是“混合”在一起的,没有简单的方法可以在不重建整个表的情况下删除一个。如果对于普通表来说,重建或合并只是正常的维护方式,对于实时表,它保持了操作的简单性,但没有“实时性”。为了解决这个问题,Manticore 使用了一个技巧:当您删除一个由文档 ID 标识的文档时,服务器仅跟踪该编号。与其他已删除文档一起,它们的 ID 被保存在一个所谓的 kill-list 中。当您在表中搜索时,服务器首先检索所有匹配的文档,然后将找到的文档从 kill-list 中剔除(这只是最基本的描述;实际上,内部会更复杂)。关键是——为了“立即”删除,文档实际上并没有被删除,而只是标记为“已删除”。它们仍然占据不同表结构中的空间,本质上是垃圾。单词统计,影响排名,也不会受到影响,这意味着它的工作方式与声明的完全一致:我们在所有文档中搜索,然后仅从最终结果中隐藏标记为已删除的文档。当文档被 替换 时,这意味着它在表的旧部分被“杀死”,并在最新部分重新插入。所有“通过 killlist 隐藏”的后果在这种情况下也适用。

当表的某个部分重建时,例如,当 RAM 块的某些事务(段)合并,或当 RAM 块转换为磁盘块,或当两个磁盘块合并在一起时,服务器会对受影响的部分进行全面迭代,并从所有部分中物理排除已删除的文档。也就是说,如果它们在某些单词的文档列表中——它们会被清除。如果这是一个唯一的单词——它会被完全移除。

总结一下:删除分为两个阶段:

  1. 首先,我们在实时表中将文档标记为“已删除”,并在搜索结果中抑制它们。

  2. 在与 RT 表块的某些操作中,我们最终会彻底物理清除已删除的文档。

第五,如果 RT 表包含其集合中的普通磁盘表,我能否直接将我的旧磁盘表添加到其中? 不可以。为了避免不必要的复杂性和防止意外损坏,这是不可能的。然而,如果您的 RT 表刚创建并且不包含数据,那么您可以 ATTACH TABLE 将您的磁盘表附加到其中。您的旧表将被移动到 RT 表内,成为其一部分。

关于 RT 表结构的总结:它是一个巧妙组织的普通磁盘表的集合,具有快速的内存表,旨在进行实时插入和半实时删除文档。RT 表具有共同的模式、共同的设置,并且可以在不深入细节的情况下轻松维护。

最后更新于