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.8.1
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.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.http.client.HttpClient;
import org.apache.solr.client.solrj.ResponseParser;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.params.ModifiableSolrParams;

/**
 * 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 master/slave scenarios since documents must be sent to the
 * correct master; 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 #setAliveCheckInterval} , 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 setup 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 */ 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 Integer connectionTimeout; private volatile Integer soTimeout; /** * @deprecated use {@link LBSolrClient.Req} instead */ @Deprecated public static class Req extends LBSolrClient.Req { public Req(SolrRequest request, List servers) { super(request, servers); } public Req(SolrRequest request, List servers, Integer numServersToTry) { super(request, servers, numServersToTry); } } /** * @deprecated use {@link LBSolrClient.Rsp} instead */ @Deprecated public static class Rsp extends LBSolrClient.Rsp { } /** * The provided httpClient should use a multi-threaded connection manager * * @deprecated use {@link LBHttpSolrClient#LBHttpSolrClient(Builder)} instead, as it is a more extension/subclassing-friendly alternative */ @Deprecated protected LBHttpSolrClient(HttpSolrClient.Builder httpSolrClientBuilder, HttpClient httpClient, String... solrServerUrl) { this(new Builder() .withHttpSolrClientBuilder(httpSolrClientBuilder) .withHttpClient(httpClient) .withBaseSolrUrls(solrServerUrl)); } /** * The provided httpClient should use a multi-threaded connection manager * * @deprecated use {@link LBHttpSolrClient#LBHttpSolrClient(Builder)} instead, as it is a more extension/subclassing-friendly alternative */ @Deprecated protected LBHttpSolrClient(HttpClient httpClient, ResponseParser parser, String... solrServerUrl) { this(new Builder() .withBaseSolrUrls(solrServerUrl) .withResponseParser(parser) .withHttpClient(httpClient)); } 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[builder.baseSolrUrls.size()])) : builder.httpClient; this.connectionTimeout = builder.connectionTimeoutMillis; this.soTimeout = builder.socketTimeoutMillis; this.parser = builder.responseParser; 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(String server) { HttpSolrClient client; if (httpSolrClientBuilder != null) { synchronized (this) { httpSolrClientBuilder .withBaseSolrUrl(server) .withHttpClient(httpClient); if (connectionTimeout != null) { httpSolrClientBuilder.withConnectionTimeout(connectionTimeout); } if (soTimeout != null) { httpSolrClientBuilder.withSocketTimeout(soTimeout); } client = httpSolrClientBuilder.build(); } } else { final HttpSolrClient.Builder clientBuilder = new HttpSolrClient.Builder(server) .withHttpClient(httpClient) .withResponseParser(parser); if (connectionTimeout != null) { clientBuilder.withConnectionTimeout(connectionTimeout); } if (soTimeout != null) { clientBuilder.withSocketTimeout(soTimeout); } client = clientBuilder.build(); } if (requestWriter != null) { client.setRequestWriter(requestWriter); } if (queryParams != null) { client.setQueryParams(queryParams); } return client; } /** * @deprecated since 7.0 Use {@link Builder} methods instead. */ @Deprecated public void setConnectionTimeout(int timeout) { this.connectionTimeout = timeout; this.urlToClient.values().forEach(client -> client.setConnectionTimeout(timeout)); } /** * set soTimeout (read timeout) on the underlying HttpConnectionManager. This is desirable for queries, but probably * not for indexing. * * @deprecated since 7.0 Use {@link Builder} methods instead. */ @Deprecated public void setSoTimeout(int timeout) { this.soTimeout = timeout; this.urlToClient.values().forEach(client -> client.setSoTimeout(timeout)); } /** * @deprecated use {@link LBSolrClient#request(LBSolrClient.Req)} instead */ @Deprecated public Rsp request(Req req) throws SolrServerException, IOException { LBSolrClient.Rsp rsp = super.request(req); // for backward-compatibility support Rsp result = new Rsp(); result.rsp = rsp.rsp; result.server = rsp.server; return result; } @Override protected SolrClient getClient(String baseUrl) { HttpSolrClient client = urlToClient.get(baseUrl); if (client == null) { return makeSolrClient(baseUrl); } else { return client; } } @Override public String removeSolrServer(String server) { urlToClient.remove(server); return super.removeSolrServer(server); } @Override public void close() { super.close(); if(clientIsInternal) { HttpClientUtil.close(httpClient); } } /** * Return the HttpClient this instance uses. */ public HttpClient getHttpClient() { return httpClient; } /** * Constructs {@link LBHttpSolrClient} instances from provided configuration. */ public static class Builder extends SolrClientBuilder { protected final List baseSolrUrls; protected HttpSolrClient.Builder httpSolrClientBuilder; 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. * * 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. */ public Builder withBaseSolrUrl(String baseSolrUrl) { this.baseSolrUrls.add(baseSolrUrl); 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. * * 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. This flexibility though * requires that the core is specified on all requests. */ public Builder withBaseSolrUrls(String... solrUrls) { for (String baseSolrUrl : solrUrls) { this.baseSolrUrls.add(baseSolrUrl); } 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