在 Solr 中处理多租户数据

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

许多 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! .在这种情况下,查询时间路由将如下所示:

同样,这是对基本路由的改进。我们现在可以查询多个分片,并在多个分片之间分配处理查询的负载——至少对于大租户来说是这样。

概括

所提供的路由解决方案的好处在于它们可以组合在一起工作。对于小分片,您可以只提供等于用户标识符的路由值;对于中型租户,您可以将数据发送到多个分片;并且,对于大租户,您可以将它们发送到多个分片。这些策略最好的一点是它们是自动完成的,只需要在索引和查询期间关心路由值。

相关文章