许多 Solr 用户需要处理多租户数据。有不同的技术可以处理这种情况:一些很好,一些不太好。使用路由来处理此类数据是解决方案之一,它允许有效地划分客户端并将它们放入专用分片,同时仍然使用 SolrCloud 的所有优点。在这篇博文中,我将向您展示如何处理此解决方案带来的一些问题:分片中的文档数量不同和负载不均匀。
想象一下,您的 Solr 实例索引了您客户的数据。可以肯定的是,并非每个客户端都拥有相同数量的数据,因为有越来越小的客户端。因此,要找到适合所有人的完美解决方案并不容易。但是,我可以告诉你一件事:通常最好避免创建每个/租户集合。在单个 SolrCloud 集群中拥有数百或数千个集合很可能会导致维护问题,并且会给协同工作的 SolrCloud 和 ZooKeeper 节点带来压力。假设我们宁愿走到围栏的另一边,并使用一个包含许多分片的大型集合来存储我们拥有的所有数据。
完全没有路由
我们可以寻求的最简单的解决方案是根本没有路由。在这种情况下,我们索引的数据可能会在所有分片中结束,因此索引负载将均匀分布在集群中:
但是,当有大量分片时,查询最终会访问所有分片:
这可能会有问题,尤其是在同时处理大量查询和大量分片时。在这种情况下,Solr 将不得不聚合来自大量分片的结果,这可能需要时间并且性能昂贵。在这些情况下,路由可能是最好的解决方案,所以让我们看看它能给我们带来什么。
使用路由
使用路由时,我们告诉 Solr 数据应该放在哪个分片中。Solr 会自动执行此操作,因此我们只需要在文档的标识符前加上路由值和 !特点。例如,如果我们想使用用户名作为我们的路由值,我们可以使用 user1!12345 的路由值,其中 user1 是用户标识符, 12345 是文档的标识符。索引看起来像这样:
当然,在查询时,我们可以使用 _route_ 请求参数并提供路由值来告诉 Solr 查询哪个分片:
然而,这不是一个完美的解决方案。非常大的租户数据最终将位于单个分片中。这意味着某些分片可能会变得非常大,并且对此类租户的查询会变慢,即使 Solr 不必聚合来自多个分片的数据。对于此类用例——当您知道租户的规模时——您可以在 Solr 中使用一种经过修改的路由方法,该方法会将此类租户的数据放置在多个分片中。
复合哈希路由
Solr 允许我们稍微修改路由值,并提供有关要使用路由密钥的多少位的信息(这对于默认的 compositeId 路由器是可能的)。例如,我们可以使用 user1/2! 12345 而不是提供 user1!12345 的路由值。 /2 部分指示在复合哈希中使用多少位。在这种情况下,我们将使用 2 位,这意味着数据将进入 1/4 的分片。如果我们将其设置为 /3, 则数据将转到 1/8 的分片,依此类推。
鉴于上述情况,索引看起来如下(假设我们有 12 个分片):
现在我们可以使用多个分片来处理索引负载,并且非常大的分片问题不太明显——或者根本不可见(取决于用例和数据)。
当然,查询时间也会发生变化。因此,与其提供 _route_ 请求参数并将其设置为 user1! ,我们将提供复合哈希,这意味着 _route_ 参数值应该是 user1/2! .在这种情况下,查询时间路由将如下所示:
同样,这是对基本路由的改进。我们现在可以查询多个分片,并在多个分片之间分配处理查询的负载——至少对于大租户来说是这样。
概括
所提供的路由解决方案的好处在于它们可以组合在一起工作。对于小分片,您可以只提供等于用户标识符的路由值;对于中型租户,您可以将数据发送到多个分片;并且,对于大租户,您可以将它们发送到多个分片。这些策略最好的一点是它们是自动完成的,只需要在索引和查询期间关心路由值。