SolrCloud 分布式请求
当 Solr 节点接收到搜索请求时,该请求会自动路由到正在搜索的集合中某个分片的副本。
所选的副本充当聚合器:它创建对集合中每个分片的随机选择的副本的内部请求,协调响应,根据需要发出任何后续内部请求(例如,细化分面值或请求其他存储的字段),并为客户端构建最终响应。
查询容错
在 SolrCloud 集群中,每个单独的节点都会跨集合中的所有副本进行读取请求的负载平衡。您可能仍然需要在与集群通信的“外部”使用负载均衡器。或者,您需要一个了解如何读取 Solr 在 ZooKeeper 中的元数据并与之交互的客户端,并且只需要请求 ZooKeeper 集群的地址以发现应接收请求的节点。Solr 提供了一个名为 CloudSolrClient 的智能 Java SolrJ 客户端,它能够做到这一点。
即使集群中的某些节点脱机或无法访问,只要 Solr 节点能够与每个分片的至少一个副本通信,或者如果用户通过 shards
或 _route_
参数限制了搜索,则可以与每个相关分片的至少一个副本通信,Solr 节点就能够正确响应搜索请求。每个分片的副本越多,Solr 集群在节点发生故障时越有可能处理搜索结果。
zkConnected 参数
只要 Solr 节点能够与它知道的每个分片的至少一个副本通信,即使它在接收请求时无法与 ZooKeeper 通信,它也会返回搜索请求的结果。从容错的角度来看,这通常是首选行为,但是如果集合结构发生了重大更改,而节点尚未通过 ZooKeeper 获知(即,分片可能已被添加或删除,或拆分为子分片),则可能会导致过时或不正确的结果。
每个搜索响应中都包含一个 zkConnected
标头,指示处理请求的节点当时是否已连接到 ZooKeeper
{
"responseHeader": {
"status": 0,
"zkConnected": true,
"QTime": 20,
"params": {
"q": "*:*"
}
},
"response": {
"numFound": 107,
"start": 0,
"docs": [ "..." ]
}
}
为了防止在请求服务节点无法与 ZooKeeper 通信时出现过时或不正确的结果,请将 shards.tolerant
参数设置为 requireZkConnected
。这将导致请求失败,而不是将 zkConnected
标头设置为 false
。
shards.tolerant 参数
如果查询的一个或多个分片不可用,Solr 的默认行为是使请求失败。但是,在许多用例中,部分结果是可以接受的,因此 Solr 提供了一个布尔值 shards.tolerant
参数(默认为 false
)。除了 true
和 false
之外,shards.tolerant
还可以设置为 requireZkConnected
- 见下文。
如果 shards.tolerant=true
,则可能会返回部分结果。如果返回的响应不包含来自所有适当分片的结果,则响应头将包含一个名为 partialResults
的特殊标志。
如果 shards.tolerant=requireZkConnected
且提供搜索请求的节点无法与 ZooKeeper 通信,则请求将失败,而不是返回可能过时或不正确的结果。当一个或多个查询的分片完全不可用时,这也会导致请求失败,就像 shards.tolerant=false
时一样。
客户端可以指定 shards.info
以及 shards.tolerant
参数来检索更细粒度的详细信息。
设置了 partialResults
标志为 true
的响应示例
{
"responseHeader": {
"status": 0,
"zkConnected": true,
"partialResults": true,
"QTime": 20,
"params": {
"q": "*:*"
}
},
"response": {
"numFound": 77,
"start": 0,
"docs": [ "..." ]
}
}
路由查询
有几种方法可以控制查询的路由方式。
限制查询的分片
虽然使用 SolrCloud 的优点之一是能够查询分布在各个分片上的非常大的集合,但在某些情况下,您可能已经使用特定的 文档路由配置了 Solr。您可以选择搜索所有数据或仅搜索部分数据。
由于 SolrCloud 会自动进行负载均衡查询,因此对集合的所有分片进行查询只是一个不定义 shards
参数的查询
https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*
这与用户管理的集群形成对比,在用户管理的集群中,需要 shards
参数才能分发查询。
要将查询限制为仅一个分片,请使用 shards
参数按其逻辑 ID 指定分片,如下所示:
https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1
如果要搜索一组分片,可以在一个请求中指定每个分片,并用逗号分隔
https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1,shard2
在上面的两个示例中,虽然仅查询了特定的分片,但是该分片的任何随机副本都将收到该请求。
您可以改为指定要使用的副本列表,而不是使用分片 ID,方法是用逗号分隔副本 ID
https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=localhost:7574/solr/gettingstarted,localhost:8983/solr/gettingstarted
或者,您可以通过在不同的副本 ID 之间使用管道符号 (|) 来指定要从单个分片中选择的副本列表(用于负载均衡目的)
https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=localhost:7574/solr/gettingstarted|localhost:7500/solr/gettingstarted
最后,您可以指定一个分片列表(用逗号分隔),每个分片都由一个副本列表(用管道分隔)定义。
在以下示例中,将查询 2 个分片,第一个分片是来自 shard1 的随机副本,第二个分片是来自显式管道分隔列表的随机副本
https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1,localhost:7574/solr/gettingstarted|localhost:7500/solr/gettingstarted
shards.preference 参数
Solr 允许您传递一个名为 shards.preference
的可选字符串参数,以指示分布式查询应按给定优先级顺序对每个分片中的可用副本进行排序。
语法为:shards.preference=property:value
。属性和值的顺序很重要:第一个是主要排序,第二个是次要排序,依此类推。
仅在使用 SolrJ 客户端时,单分片场景才支持 shards.preference 。不使用 SolrJ 客户端的查询不能在单分片集合中使用 shards.preference 。 |
可以指定的属性如下:
replica.type
-
一个或多个首选的副本类型。允许使用
PULL
、TLOG
和NRT
的任意组合。 replica.location
-
一个或多个首选的副本位置。
位置以
http://hostname:port
开头。匹配是针对给定的字符串作为前缀完成的,因此可以例如省略端口。可以使用特殊值
local
来表示与处理查询的 Solr 实例在同一 Solr 实例上运行的任何本地副本。当查询请求返回每个文档的许多字段或大型字段时,这很有用,因为它避免了在本地可用时通过网络移动大量数据。此外,此功能对于最大限度地减少性能下降的有问题的副本的影响也很有用,因为它减少了其他健康副本命中性能下降的副本的可能性。随着集合中(没有本地可用副本的)分片的数量增加,
replica.location:local
的值会减少,因为查询控制器必须将查询定向到大多数分片的非本地副本。换句话说,此功能主要用于优化定向到具有少量分片和许多副本的集合的查询。
此外,仅当您跨所有托管要查询集合的副本的节点进行负载均衡请求时,才应使用此选项,因为 Solr 的
CloudSolrClient
将执行此操作。如果不进行负载均衡,此功能可能会在集群中引入热点,因为查询不会在集群中均匀分布。 replica.base
-
在按固有的副本属性排序后应用,此属性定义在首选项等效副本集之间的回退顺序;如果指定,则此属性只能指定一个值,并且必须最后指定。
random
是默认值,它会为每个请求随机打乱副本。这可以均匀地分配请求,但对于复制因子 > 1 的分片,可能会导致次优的缓存使用。stable:dividend:_paramName_
从与给定参数名称关联的值中解析整数;此整数用作除数(模等效副本计数),以确定(通过列表旋转)等效副本之间的首选项顺序。stable[:hash[:_paramName_]]
与给定参数名称关联的字符串值被哈希为一个除数,该除数用于确定副本首选项顺序(类似于上面的显式dividend
属性);如果未指定,paramName
默认为q
,提供以“主查询”的字符串值为键的稳定路由。请注意,这可能不适合某些用例(例如,利用参数替换的静态主查询) replica.leader
-
根据副本的领导者状态来首选副本,设置为
true
或false
。考虑一个具有两个
TLOG
副本和四个PULL
副本的分片(总共六个副本,其中一个是领导者)。使用shards.preference=replica.leader:false
,将首选 6 个副本中的 5 个。与shards.preference=replica.type:PULL
相比,后者仅首选 6 个副本中的 4 个。请注意,从搜索角度来看,非领导者
TLOG
副本的行为类似于PULL
副本;它像PULL
副本一样从领导者那里提取索引更新,并且不执行软提交。不同之处在于,非领导者TLOG
副本还会在其 TLOG 中捕获更新,因此如果当前领导者丢失,它可以成为替代当前领导者的候选者。 node.sysprop
-
查询将路由到与当前节点具有相同已定义系统属性的节点。例如,如果在不同的机架上启动 Solr 节点,则需要通过 系统属性(例如,
-Drack=rack1
)来标识这些节点。然后,查询可以包含shards.preference=node.sysprop:sysprop.rack
,以确保您始终命中具有相同rack
值的分片。
示例:
-
在其他等效副本中首选稳定路由(以客户端“sessionId”参数为键)
shards.preference=replica.base:stable:hash:sessionId&sessionId=abc123
-
首选 PULL 副本
shards.preference=replica.type:PULL
-
首选 PULL 副本,如果 PULL 副本不可用,则首选 TLOG 副本
shards.preference=replica.type:PULL,replica.type:TLOG
-
首选任何本地副本
shards.preference=replica.location:local
-
首选名为“server1”的主机上的任何副本,以“server2”为辅助选项
shards.preference=replica.location:http://server1,replica.location:http://server2
-
如果可用,则首选 PULL 副本,否则首选 TLOG 副本,以及其中的本地副本
shards.preference=replica.type:PULL,replica.type:TLOG,replica.location:local
-
首选本地副本,并在可用时首选其中的 PULL 副本,否则首选 TLOG 副本
shards.preference=replica.location:local,replica.type:PULL,replica.type:TLOG
-
首选任何不是领导者的副本
shards.preference=replica.leader:false
请注意,如果在查询字符串中提供这些参数,则需要对其进行适当的 URL 编码。
collection 参数
collection
参数允许您指定应执行查询的集合或多个集合。这使您可以一次查询多个集合,并且以分布式方式工作的 Solr 功能将在多个集合中起作用。
https://127.0.0.1:8983/solr/collection1/select?collection=collection1,collection2,collection3
_route_ 参数
_route_
参数可用于指定用于确定相应分片的路由键。例如,如果您有一个唯一的键为“user1!123”的文档,则将路由键指定为“_route_=user1!”(请注意结尾的“!”字符)会将请求路由到托管该用户的分片。您可以指定多个用逗号分隔的路由键。当按用户分片数据时,可以使用此参数。有关更多信息,请参见文档路由
https://127.0.0.1:8983/solr/collection1/select?q=*:*&_route_=user1!
https://127.0.0.1:8983/solr/collection1/select?q=*:*&_route_=user1!,user2!
近实时 (NRT) 用例
近实时 (NRT) 搜索意味着文档在被索引后不久即可用于搜索。NRT 搜索是 SolrCloud 的主要功能之一,在用户管理的集群或单节点安装中很少尝试。
文档的持久性和可搜索性由 commits
控制。“近实时”中的“近”是可配置的,以满足您的应用程序的需求。提交可以是“硬”提交或“软”提交,并且可以由客户端(例如 SolrJ)、通过 REST 调用或配置为在 solrconfig.xml
中自动发生来发出。通常建议在 solrconfig.xml
中配置提交策略(如下所示),并避免在外部发出提交。
通常,在 NRT 应用程序中,硬提交配置为 openSearcher=false
,软提交配置为使文档对搜索可见。
当发生提交时,将启动各种后台任务,例如段合并。这些后台任务不会阻止对索引的额外更新,也不会延迟文档对搜索的可用性。
为 NRT 配置时,请特别注意缓存和自动预热设置,因为它们会对 NRT 性能产生重大影响。对于极短的 autoCommit 间隔,请考虑完全禁用缓存和自动预热。
配置 ShardHandlerFactory
为了进行更细粒度的控制,您可以直接配置和调整 Solr 中分布式搜索中使用的并发和线程池的各个方面。默认配置优先考虑吞吐量而不是延迟。
这是通过在搜索处理程序的配置中定义 shardHandlerFactory
来完成的。
要将 shardHandlerFactory
添加到标准搜索处理程序,请在 solrconfig.xml
中提供配置,如本例所示
<requestHandler name="/select" class="solr.SearchHandler">
<!-- other params go here -->
<shardHandlerFactory class="HttpShardHandlerFactory">
<int name="socketTimeout">1000</int>
<int name="connTimeout">5000</int>
</shardHandlerFactory>
</requestHandler>
HttpShardHandlerFactory
是 Solr 中开箱即用的唯一 ShardHandlerFactory
实现。
- 注意
-
shardHandlerFactory
依赖于solr.xml
中配置的allowUrls
参数,该参数控制哪些节点可以相互通信。这意味着主机配置是全局性的,而不是每个核心或每个集合的。有关详细信息,请参阅allowUrls部分。
HttpShardHandlerFactory
接受以下参数:
socketTimeout
-
可选
默认值:
0
套接字允许等待的时间(以毫秒为单位)。默认值为
0
,将使用操作系统的默认值。 connTimeout
-
可选
默认值:
0
接受绑定/连接套接字的时间(以毫秒为单位)。默认值为
0
,将使用操作系统的默认值。 maxConnectionsPerHost
-
可选
默认值:
100000
在分布式搜索中,与每个单独的分片建立的最大并发连接数。
corePoolSize
-
可选
默认值:
0
用于协调分布式搜索的线程数的保留最低限制。
maximumPoolSize
-
可选
默认值:
Integer.MAX_VALUE
用于协调分布式搜索的最大线程数。
maxThreadIdleTime
-
可选
默认值:
5
在负载减少后,线程缩减之前等待的时间(以秒为单位)。
sizeOfQueue
-
可选
默认值:
-1
如果指定,线程池将使用后备队列而不是直接切换缓冲区。高吞吐量的系统应该将其配置为直接切换(使用
-1
)。希望获得更好延迟的系统应该配置一个合理大小的队列来处理请求的波动。 fairnessPolicy
-
可选
默认值:
false
选择处理公平策略排队的 JVM 特性。如果启用,分布式搜索将以先进先出的方式处理,但这会牺牲吞吐量。如果禁用,则吞吐量优先于延迟。
分布式逆文档频率(IDF)
为了计算相关性,需要文档和词项统计信息。在分布式系统中,这些统计信息可能因节点而异,从而导致评分计算出现偏差或不准确。
Solr 将文档和词项统计信息存储在名为 statsCache
的缓存中。在文档统计信息计算方面,有四种开箱即用的实现:
-
LocalStatsCache
:此方法仅使用本地词项和文档统计信息来计算相关性。在分片之间词项分布均匀的情况下,此方法效果相当好。如果没有配置<statsCache>
,则此选项为默认选项。 -
ExactStatsCache
:此实现使用全局值(跨集合)来表示文档频率。如果跨节点的精确评分对您的实现很重要,建议选择此选项。 -
ExactSharedStatsCache
:此功能类似于ExactStatsCache
,但全局统计信息会为具有相同词项的后续请求重用。 -
LRUStatsCache
:此实现使用最近最少使用的缓存来保存全局统计信息,这些统计信息在请求之间共享。
可以通过在 solrconfig.xml
中设置 <statsCache>
来选择实现。例如,以下行使 Solr 使用 ExactStatsCache
实现:
<statsCache class="org.apache.solr.search.stats.ExactStatsCache"/>