Link Search Menu Expand Document Documentation Menu

搜索分片路由

为了确保冗余并提升搜索性能,OpenSearch 将索引数据分布到多个主分片上,每个主分片带有一个或多个副本分片。当执行搜索查询时,OpenSearch 会将请求路由到包含主索引分片或副本索引分片的节点。这种技术被称为搜索分片路由

自适应副本选择

为了改善延迟,搜索请求使用自适应副本选择进行路由,它根据以下因素选择节点:

  • 特定节点运行先前请求所花费的时间量。
  • 协调节点与所选节点之间的延迟。
  • 节点搜索线程池的队列大小。

如果您有权限调用 OpenSearch REST API,您可以关闭搜索分片路由。有关 REST API 用户访问的更多信息,请参阅REST 管理 API 设置。要禁用搜索分片路由,请按如下方式更新集群设置:

PUT /_cluster/settings
{
  "persistent": {
    "cluster.routing.use_adaptive_replica_selection": false
  }
}

如果您关闭搜索分片路由,OpenSearch 将使用轮询路由,这可能会对搜索延迟产生负面影响。

搜索期间的节点和分片选择

OpenSearch 使用所有节点来为搜索请求选择最佳路由。然而,在某些情况下,您可能希望手动选择发送搜索请求的节点或分片,包括以下情况:

  • 使用缓存的先前搜索。
  • 将特定硬件专用于搜索。
  • 仅使用本地节点进行搜索。

您可以使用搜索查询中的 preference 参数来指示搜索目的地。以下是可用选项的完整列表:

  1. _primary: 强制搜索仅在主分片上执行。

     GET /my-index/_search?preference=_primary
    

  2. _primary_first: 优先使用主分片,但如果主分片不可用,则会使用副本分片。

     GET /my-index/_search?preference=_primary_first
    

  3. _replica: 强制搜索仅在副本分片上执行。

     GET /my-index/_search?preference=_replica
    

  4. _replica_first: 优先使用副本分片,但如果没有可用的副本分片,则会使用主分片。

     GET /my-index/_search?preference=_replica_first
    

  5. _only_nodes:<node-id>,<node-id>: 限制搜索仅在指定 ID 的节点上执行。

     GET /my-index/_search?preference=_only_nodes:node-1,node-2
    

  6. _prefer_nodes:<node-id>,<node-id>: 优先在特定节点上执行搜索,但如果首选节点不可用,则会使用其他节点。

     GET /my-index/_search?preference=_prefer_nodes:node-1,node-2
    

  7. _shards:<shard-id>,<shard-id>: 限制搜索到特定分片。

     GET /my-index/_search?preference=_shards:0,1
    

  8. _local: 如果可能,在本地节点上执行搜索,这可以减少延迟。

     GET /my-index/_search?preference=_local
    

  9. 自定义字符串:您可以使用任何自定义字符串作为首选项值。此自定义字符串可确保包含相同字符串的请求始终路由到相同的分片,这对于缓存非常有用。

     GET /my-index/_search?preference=custom_string
    

您可以在索引和搜索操作期间指定路由。

索引期间的路由

当您索引文档时,OpenSearch 会计算路由值的哈希,并使用此哈希来确定文档将存储在哪个分片上。如果您未指定路由值,OpenSearch 会使用文档 ID 来计算哈希。

以下是一个带有路由值的索引操作示例:

POST /index1/_doc/1?routing=user1
{
  "name": "John Doe",
  "age": 20
}

在此示例中,ID 为 1 的文档使用路由值 user1 进行索引。所有具有相同路由值的文档都将存储在同一个分片上。

搜索期间的路由

当您搜索文档时,指定相同的路由值可确保搜索请求路由到适当的分片。这可以通过减少需要查询的分片数量来显著提高性能。

以下示例请求使用特定的路由值进行搜索:

GET /index1/_search?routing=user1
{
  "query": {
    "match": {
      "name": "John Doe"
    }
  }
}

在此示例中,搜索查询被路由到包含使用路由值 user1 索引的文档的分片。

使用自定义路由时需要谨慎,以防止热点和数据倾斜。

  • 当不成比例的文档数量路由到单个分片时,就会出现热点。这可能导致该分片成为瓶颈,因为它将比其他分片处理更多的读写操作。因此,该分片可能会出现更高的 CPU、内存和 I/O 使用率,从而导致性能下降。

  • 数据倾斜是指数据在分片之间分布不均匀。如果路由值分布不均匀,某些分片最终可能会存储比其他分片多得多的数据。这可能导致存储使用不平衡,其中某些节点的磁盘利用率远高于其他节点。

并发分片请求

在搜索期间同时命中大量分片可能会显著影响 CPU 和内存消耗。默认情况下,OpenSearch 不会拒绝这些请求。但是,您可以使用多种方法来降低此风险。以下各节描述了这些方法。

限制可以并发查询的分片数量

您可以在搜索请求中使用 max_concurrent_shard_requests 参数来限制可以并发查询的分片数量。例如,以下请求将并发分片请求的数量限制为 12

GET /index1/_search?max_concurrent_shard_requests=12
{
  "query": {
    "match_all": {}
  }
}

定义搜索分片计数限制

您可以在 opensearch.yml 文件中或使用 REST API 定义动态的 action.search.shard_count.limit 设置。任何超出此限制的搜索请求都将被拒绝并抛出错误。这有助于防止单个搜索请求消耗过多资源,从而可能降低整个集群的性能。以下示例请求使用 API 更新此集群设置:

PUT /_cluster/settings
{
  "transient": {
    "action.search.shard_count.limit": 1000
  }
}

搜索线程池

OpenSearch 使用线程池来管理各种任务的执行,包括搜索操作。搜索线程池专门用于搜索请求。您可以通过将以下设置添加到 opensearch.yml 来调整搜索线程池的大小和队列容量:

thread_pool.search.size: 100
thread_pool.search.queue_size: 1000

此设置是静态的。有关如何配置动态和静态设置的更多信息,请参阅配置 OpenSearch

线程池状态

以下三种状态描述了线程池操作:

  • 线程分配:如果搜索线程池中有可用线程,则请求会立即分配给一个线程并开始处理。

  • 排队:如果搜索线程池中的所有线程都忙碌,则请求会被放入队列。

  • 拒绝:如果队列已满(例如,排队请求的数量达到队列大小限制),则额外的传入搜索请求将被拒绝,直到队列中有可用空间为止。

您可以通过运行以下请求来检查搜索线程池的当前配置:

GET /_cat/thread_pool/search?v&h=id,name,active,rejected,completed,size,queue_size