All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.client.solrj.impl.LBHttpSolrClient Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.client.solrj.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.apache.http.client.HttpClient;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.URLUtil;

/**
 * LBHttpSolrClient or "LoadBalanced HttpSolrClient" is a load balancing wrapper around {@link
 * HttpSolrClient}. This is useful when you have multiple Solr servers and the requests need to be
 * Load Balanced among them.
 *
 * 

Do NOT use this class for indexing in leader/follower scenarios since documents must be * sent to the correct leader; no inter-node routing is done. * *

In SolrCloud (leader/replica) scenarios, it is usually better to use {@link CloudSolrClient}, * but this class may be used for updates because the server will forward them to the appropriate * leader. * *

It offers automatic failover when a server goes down, and it detects when the server comes * back up. * *

Load balancing is done using a simple round-robin on the list of servers. * *

If a request to a server fails by an IOException due to a connection timeout or read timeout * then the host is taken off the list of live servers and moved to a 'dead server list' and the * request is resent to the next live server. This process is continued till it tries all the live * servers. If at least one server is alive, the request succeeds, and if not it fails. * *

* *
 * SolrClient lbHttpSolrClient = new LBHttpSolrClient("http://host1:8080/solr/", "http://host2:8080/solr", "http://host2:8080/solr");
 * //or if you wish to pass the HttpClient do as follows
 * httpClient httpClient = new HttpClient();
 * SolrClient lbHttpSolrClient = new LBHttpSolrClient(httpClient, "http://host1:8080/solr/", "http://host2:8080/solr", "http://host2:8080/solr");
 * 
* *
* * This detects if a dead server comes alive automatically. The check is done in fixed intervals in * a dedicated thread. This interval can be set using {@link * LBHttpSolrClient.Builder#setAliveCheckInterval(int)} , the default is set to one minute. * *

When to use this?
* This can be used as a software load balancer when you do not wish to set up an external load * balancer. Alternatives to this code are to use a dedicated hardware load balancer or using Apache * httpd with mod_proxy_balancer as a load balancer. See Load balancing on Wikipedia * * @since solr 1.4 * @deprecated Please use {@link LBHttp2SolrClient} */ @Deprecated(since = "9.0") public class LBHttpSolrClient extends LBSolrClient { private final HttpClient httpClient; private final boolean clientIsInternal; private final ConcurrentHashMap urlToClient = new ConcurrentHashMap<>(); private final HttpSolrClient.Builder httpSolrClientBuilder; private volatile Set urlParamNames = new HashSet<>(); final int connectionTimeoutMillis; final int soTimeoutMillis; /** The provided httpClient should use a multi-threaded connection manager */ protected LBHttpSolrClient(Builder builder) { super(builder.baseSolrUrls); this.clientIsInternal = builder.httpClient == null; this.httpSolrClientBuilder = builder.httpSolrClientBuilder; this.httpClient = builder.httpClient == null ? constructClient(builder.baseSolrUrls.toArray(new String[0])) : builder.httpClient; this.defaultCollection = builder.defaultCollection; if (httpSolrClientBuilder != null && this.defaultCollection != null) { httpSolrClientBuilder.defaultCollection = this.defaultCollection; } this.connectionTimeoutMillis = builder.connectionTimeoutMillis; this.soTimeoutMillis = builder.socketTimeoutMillis; this.parser = builder.responseParser; this.aliveCheckIntervalMillis = builder.aliveCheckInterval; for (String baseUrl : builder.baseSolrUrls) { urlToClient.put(baseUrl, makeSolrClient(baseUrl)); } } private HttpClient constructClient(String[] solrServerUrl) { ModifiableSolrParams params = new ModifiableSolrParams(); if (solrServerUrl != null && solrServerUrl.length > 1) { // we prefer retrying another server params.set(HttpClientUtil.PROP_USE_RETRY, false); } else { params.set(HttpClientUtil.PROP_USE_RETRY, true); } return HttpClientUtil.createClient(params); } protected HttpSolrClient makeSolrClient(Endpoint endpoint) { return makeSolrClient(endpoint.getUrl()); } /** * @deprecated use {@link #makeSolrClient(Endpoint)} instead */ @Deprecated protected HttpSolrClient makeSolrClient(String server) { HttpSolrClient client; if (httpSolrClientBuilder != null) { synchronized (this) { httpSolrClientBuilder .withBaseSolrUrl(server) .withHttpClient(httpClient) .withConnectionTimeout(connectionTimeoutMillis, TimeUnit.MILLISECONDS) .withSocketTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS); if (defaultCollection != null) { httpSolrClientBuilder.withDefaultCollection(defaultCollection); } if (requestWriter != null) { httpSolrClientBuilder.withRequestWriter(requestWriter); } if (urlParamNames != null) { httpSolrClientBuilder.withTheseParamNamesInTheUrl(urlParamNames); } client = httpSolrClientBuilder.build(); } } else { final var clientBuilder = new HttpSolrClient.Builder(server) .withHttpClient(httpClient) .withResponseParser(parser) .withConnectionTimeout(connectionTimeoutMillis, TimeUnit.MILLISECONDS) .withSocketTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS); if (defaultCollection != null) { clientBuilder.withDefaultCollection(defaultCollection); } if (requestWriter != null) { clientBuilder.withRequestWriter(requestWriter); } if (urlParamNames != null) { clientBuilder.withTheseParamNamesInTheUrl(urlParamNames); } client = clientBuilder.build(); } return client; } /** * @deprecated use {@link #getClient(Endpoint)} instead */ @Deprecated @Override protected SolrClient getClient(String baseUrl) { SolrClient client = urlToClient.get(baseUrl); if (client == null) { return makeSolrClient(baseUrl); } else { return client; } } @Override protected SolrClient getClient(Endpoint endpoint) { return getClient(endpoint.getUrl()); } /** * @deprecated use {@link #removeSolrEndpoint(Endpoint)} instead */ @Deprecated @Override public String removeSolrServer(String server) { urlToClient.remove(server); return super.removeSolrServer(server); } @Override public String removeSolrEndpoint(Endpoint endpoint) { return removeSolrServer(endpoint.getUrl()); } @Override public void close() { super.close(); if (clientIsInternal) { HttpClientUtil.close(httpClient); } } /** Return the HttpClient this instance uses. */ public HttpClient getHttpClient() { return httpClient; } @Deprecated public Set getQueryParams() { return urlParamNames; } /** * Expert Method. * * @param urlParamNames set of param keys to only send via the query string */ @Deprecated public void setQueryParams(Set urlParamNames) { this.urlParamNames = urlParamNames; } @Deprecated public void addQueryParams(String urlParamNames) { this.urlParamNames.add(urlParamNames); } /** Constructs {@link LBHttpSolrClient} instances from provided configuration. */ public static class Builder extends SolrClientBuilder { public static final int CHECK_INTERVAL = 60 * 1000; // 1 minute between checks protected final List baseSolrUrls; protected HttpSolrClient.Builder httpSolrClientBuilder; private int aliveCheckInterval = CHECK_INTERVAL; public Builder() { this.baseSolrUrls = new ArrayList<>(); this.responseParser = new BinaryResponseParser(); } public HttpSolrClient.Builder getHttpSolrClientBuilder() { return httpSolrClientBuilder; } /** * Provide a Solr endpoint to be used when configuring {@link LBHttpSolrClient} instances. * *

Method may be called multiple times. All provided values will be used. * *

Two different paths can be specified as a part of the URL: * *

1) A path pointing directly at a particular core * *

     *   SolrClient client = builder.withBaseSolrUrl("http://my-solr-server:8983/solr/core1").build();
     *   QueryResponse resp = client.query(new SolrQuery("*:*"));
     * 
* * Note that when a core is provided in the base URL, queries and other requests can be made * without mentioning the core explicitly. However, the client can only send requests to that * core. Attempts to make core-agnostic requests, or requests for other cores will fail. * *

Use of these core-based URLs is deprecated and will not be supported in Solr 10.0 Users * should instead provide base URLs as described below, and provide a "default collection" as * desired using {@link #withDefaultCollection(String)} * *

2) The path of the root Solr path ("/solr") * *

     *   SolrClient client = builder.withBaseSolrUrl("http://my-solr-server:8983/solr").build();
     *   QueryResponse resp = client.query("core1", new SolrQuery("*:*"));
     * 
* * In this case the client is more flexible and can be used to send requests to any cores. This * flexibility though requires that the core is specified on all requests. * * @deprecated use {@link #withBaseEndpoint(String)} or {@link #withCollectionEndpoint(String, * String)} instead, based on the type of URL string currently being supplied */ @Deprecated public Builder withBaseSolrUrl(String baseSolrUrl) { this.baseSolrUrls.add(baseSolrUrl); return this; } /** * Provide a "base" Solr URL to be used when configuring {@link LBHttpSolrClient} instances. * *

Method may be called multiple times. All provided values will be used. However, all * endpoints must be of the same type: providing a mix of "base" endpoints via this method and * core/collection endpoints via {@link #withCollectionEndpoint(String, String)} is prohibited. * *

Users who use this method to provide base Solr URLs may specify a "default collection" for * their requests using {@link #withDefaultCollection(String)} if they wish to avoid needing to * specify a collection or core on relevant requests. * * @param rootUrl the base URL for a Solr node, in the form "http[s]://hostname:port/solr" */ public Builder withBaseEndpoint(String rootUrl) { this.baseSolrUrls.add(rootUrl); return this; } /** * Provide multiple "base" Solr URLs to be used when configuring {@link LBHttpSolrClient} * instances. * *

Method may be called multiple times. All provided values will be used. However, all * endpoints must be of the same type: providing a mix of"base" endpoints via this method and * core/collection endpoints via {@link #withCollectionEndpoint(String, String)} is prohibited. * *

Users who use this method to provide base Solr URLs may specify a "default collection" for * their requests using {@link #withDefaultCollection(String)} if they wish to avoid needing to * specify a collection or core on relevant requests. * * @param baseSolrUrls Solr base URLs, in the form "http[s]://hostname:port/solr" */ public Builder withBaseEndpoints(String... baseSolrUrls) { for (String baseSolrUrl : baseSolrUrls) { this.baseSolrUrls.add(baseSolrUrl); } return this; } /** * Provide a core/collection Solr endpoint to be used when configuring {@link LBHttpSolrClient} * instances. * *

Method may be called multiple times. All provided values will be used. However, all * endpoints must be of the same type: providing a mix of "core" endpoints via this method and * base endpoints via {@link #withBaseEndpoint(String)} is prohibited. * * @param rootUrl the base URL for a Solr node, in the form "http[s]://hostname:port/solr" * @param collection the Solr core or collection to target */ public Builder withCollectionEndpoint(String rootUrl, String collection) { this.baseSolrUrls.add(URLUtil.buildCoreUrl(rootUrl, collection)); return this; } /** * Provide multiple core/collection endpoints to be used when configuring {@link * LBHttpSolrClient} instances. * *

Method may be called multiple times. All provided values will be used. However, all * endpoints must be of the same type: providing a mix of "core" endpoints via this method and * base endpoints via {@link #withBaseEndpoint(String)} is prohibited. * * @param endpoints endpoint instances pointing to distinct cores/collections */ public Builder withCollectionEndpoints(Endpoint... endpoints) { if (endpoints != null) { for (Endpoint e : endpoints) { this.baseSolrUrls.add(URLUtil.buildCoreUrl(e.getBaseUrl(), e.getCore())); } } return this; } /** * Provide Solr endpoints to be used when configuring {@link LBHttpSolrClient} instances. * *

Method may be called multiple times. All provided values will be used. * *

Two different paths can be specified as a part of each URL: * *

1) A path pointing directly at a particular core * *

     *   SolrClient client = builder.withBaseSolrUrls("http://my-solr-server:8983/solr/core1").build();
     *   QueryResponse resp = client.query(new SolrQuery("*:*"));
     * 
* * Note that when a core is provided in the base URL, queries and other requests can be made * without mentioning the core explicitly. However, the client can only send requests to that * core. Attempts to make core-agnostic requests, or requests for other cores will fail. * *

Use of these core-based URLs is deprecated and will not be supported in Solr 10.0 Users * should instead provide base URLs as described below, and provide a "default collection" as * desired using {@link #withDefaultCollection(String)} * *

2) The path of the root Solr path ("/solr") * *

     *   SolrClient client = builder.withBaseSolrUrls("http://my-solr-server:8983/solr").build();
     *   QueryResponse resp = client.query("core1", new SolrQuery("*:*"));
     * 
* * In this case the client is more flexible and can be used to send requests to any cores. Users * can still provide a "default" collection if desired through use of {@link * #withDefaultCollection(String)}. * * @deprecated use either {@link #withBaseEndpoints(String...)} or {@link * #withCollectionEndpoints(Endpoint...)}, based on the type of URL strings currently used. */ @Deprecated public Builder withBaseSolrUrls(String... solrUrls) { for (String baseSolrUrl : solrUrls) { this.baseSolrUrls.add(baseSolrUrl); } return this; } /** * LBHttpSolrServer keeps pinging the dead servers at fixed interval to find if it is alive. Use * this to set that interval * * @param aliveCheckInterval time in milliseconds */ public Builder setAliveCheckInterval(int aliveCheckInterval) { if (aliveCheckInterval <= 0) { throw new IllegalArgumentException( "Alive check interval must be " + "positive, specified value = " + aliveCheckInterval); } this.aliveCheckInterval = aliveCheckInterval; return this; } /** * Provides a {@link HttpSolrClient.Builder} to be used for building the internally used * clients. */ public Builder withHttpSolrClientBuilder(HttpSolrClient.Builder builder) { this.httpSolrClientBuilder = builder; return this; } /** Create a {@link HttpSolrClient} based on provided configuration. */ public LBHttpSolrClient build() { return new LBHttpSolrClient(this); } @Override public Builder getThis() { return this; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy