solr1.4 中SearchHandler使用的httpclient在高并发可能出现的问题

2019-03-27 01:18|来源: 网路

solr 1.4 中使用的分布式搜索,是基于httpclient发出分布结点的请求,主要实现在SearchHandler类,该类里有个内部类

HttpCommComponent

里面有一个httpclient ,是一个静态实例,也就是说在同一个jvm里只有一个实例,可以重复使用,主要代码:


static HttpClientclient;


static {

MultiThreadedHttpConnectionManagermgr =new MultiThreadedHttpConnectionManager();

mgr.getParams().setDefaultMaxConnectionsPerHost(20);

mgr.getParams().setMaxTotalConnections(10000);

mgr.getParams().setConnectionTimeout(SearchHandler.connectionTimeout);

mgr.getParams().setSoTimeout(SearchHandler.soTimeout);

// mgr.getParams().setStaleCheckingEnabled(false);

client = new HttpClient(mgr);

}



其中有两个参数设置死了。。这两个参数是作用于线程池,管理于http连接


httpclient在处理请求连接方面使用了连接池,它内部实际上有两种连接池,一种是全局的ConnectionPool,一种是每主机(per-host)HostConnectionPool。参数maxHostConnections就HostConnectionPool中表示每主机可保持连接的连接数,maxTotalConnections是ConnectionPool中可最多保持的连接数。每主机的配置类是HostConfiguration,HttpClient有个int executeMethod(final HostConfiguration hostConfiguration, final HttpMethod method)方法可以指定使用哪个HostConfiguration,不过多数情况都是不显示指定HostConfiguration,这样httpclient就用了默认的HostConfiguration=null,也就是说所有的请求可以认为指自同一个主机。如果不设置这两个参数,httpclient自然会用默认的配置,也就是MultiThreadedHttpConnectionManager中的:

 /** The default maximum number of connections allowed per host */
    public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2;   // Per RFC 2616 sec 8.1.4
 
    /** The default maximum number of connections allowed overall */
    public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;



设置于对应请求的目标主机线程数最多为20条

mgr.getParams().setDefaultMaxConnectionsPerHost(20);

总共的线程数为10000。

mgr.getParams().setMaxTotalConnections(10000);


具体如何分配可以看MultiThreadedHttpConnectionManagermgr的实现代码,在不大于总线程的情况下,最多分配给某个目标主机最多20条线程。


这里有个问题,如果 主要请求两台机器 ,那么最终分配的线程数为20*2=40条,在高并发情况下就会出现阻塞情况。所以对于高并发的线上服务来说,20是比较吝啬的。。


这里是一段httclient请求调用的方法,应该就是在高并发中,阻塞在getConnectionWithTimeout()这个方法中。。具体可能追综下源代码 .。



这里为了测试这个参数引起的问题,简单实现了一个小程序,代码如下:


package org.yzy.jetty;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;

public class HttpClientTest {

	static HttpClient client;

	static {
		MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
		mgr.getParams().setDefaultMaxConnectionsPerHost(2);
		mgr.getParams().setMaxTotalConnections(10);
		mgr.getParams().setConnectionTimeout(2000);
		mgr.getParams().setSoTimeout(1000);
		client = new HttpClient(mgr);
	}

	public static void main(String[] args) {
		
		Thread t[]=new Thread[3];

		for (int i = 0; i < t.length; i++) {
			t[i]=new Thread(new Send());
		}
		
		for (int i = 0; i < t.length; i++) {
			t[i].start();
		}
	
	}

	public static class Send implements Runnable {
		@Override
		public void run() {
			try{
				HttpMethod method = new GetMethod("http://localhost:8080/solr");
				System.out.println(Thread.currentThread().getName()+"-" +Thread.currentThread().getId() +":send");
				int result = client.executeMethod(method);
				System.out.println(Thread.currentThread().getName()+"-" +Thread.currentThread().getId() +":back" +result);
			}catch(Exception e){
				e.printStackTrace();
			}

		}

	}

}



运行结果如下:

Thread-2-11:send

Thread-1-10:send

Thread-3-12:send

Thread-3-12:back200

Thread-2-11:back200


可以看到有一条没有执行成功,一直阻塞中。。。




将Send类修改一下,代码再改下:


public static class Send implements Runnable {
		@Override
		public void run() {
			HttpMethod method = new GetMethod("http://localhost:8080/solr");
			try{
				System.out.println(Thread.currentThread().getName()+"-" +Thread.currentThread().getId() +":send");
				int result = client.executeMethod(method);
				System.out.println(Thread.currentThread().getName()+"-" +Thread.currentThread().getId() +":back" +result);
				Thread.sleep(1000);
			}catch(Exception e){
				e.printStackTrace();
			}finally{
				method.releaseConnection();
				System.out.println("relase..");
			}

		}

	}


再运行:


Thread-3-12:send

Thread-1-10:send

Thread-2-11:send

Thread-2-11:back200

Thread-3-12:back200

relase..

relase..

Thread-1-10:back200

relase..


当有连接断掉的时候,阻塞的线程可用。。完成请求。。


还有个问题,就是用户请求solr时,分发为三个请求,分别请求,主索引,小索引,专辑索引,最后发现,总是主索引抛出socke超时异常,又作何解释呢:


首先,分发的三个请求是在多线程的情况下处理的,当主索引搜索时间过长,而小索引,专辑索引搜索时间较短,比较快地 releaseConnection,

所以相对大索引来说,其它两上在同一时间内可用的连接比较多,相反大索引由于响应过慢,导致同一时间内占握的连接超过了默认设置的20条连接。

所以才会在大索引上产生请求阻塞。


至于为什么抛出socket超时异常,因为solr的服务运行在tomcat上,tomcat 设置了连接超时等待,比如3000ms,这个时候,由于阻塞的连接没完成,所以这个时候,tomcat主动抛弃了连接,最后看到的就是socket超时异常。。


因为socket异常主要发生在等待读取数据造成的。。。这就是我的分析。。。



当然solr的最新版本已解决了这个问题,连接池已改为可以配置的形式。。


新版本的solr可配置方式,请看wiki..  http://wiki.apache.org/solr/SolrConfigXml/


<requestHandler name="standard" class="solr.SearchHandler" default="true">
    <!-- other params go here -->
     <shardHandlerFactory class="HttpShardHandlerFactory">
        <int name="socketTimeOut">1000</int>
        <int name="connTimeOut">5000</int>
      </shardHandler>
  </requestHandler>

The parameters that can be specified are as follows:

socketTimeout. default: 0 (use OS default) - The amount of time in ms that a socket is allowed to wait for
connTimeout. default: 0 (use OS default) - The amount of time in ms that is accepted for binding / connection a socket
maxConnectionsPerHost. default: 20 - The maximum number of connections that is made to each individual shard in a distributed search
corePoolSize. default: 0 - The retained lowest limit on the number of threads used in coordinating distributed search
maximumPoolSize. default: Integer.MAX_VALUE - The maximum number of threads used for coordinating distributed search
maxThreadIdleTime. default: 5 seconds - The amount of time to wait for before threads are scaled back in response to a reduction in load
sizeOfQueue. default: -1 - If specified the thread pool will use a backing queue instead of a direct handoff buffer. This may seem difficult to grasp, essentially high throughput systems will want to configure this to be a direct hand off (with -1). Systems that desire better latency will want to configure a reasonable size of queue to handle variations in requests.
fairnessPolicy. default: false - Chooses in the JVM specifics dealing with fair policy queuing, if enabled distributed searches will be handled in a First in First out fashion at a cost to throughput. If disabled throughput will be favoured over latency.





 








http://blog.csdn.net/duck_genuine/article/details/7839479










转自:http://blog.csdn.net/duck_genuine/article/details/7839479

相关问答

更多
  • 解决高并发访问,或者说改善,提高一点思路: 1.使用Squid或者Varnish做缓存代理,将经常访问的图片等静态内容缓存起来,提高访问速度; 2.使用CDN内容分发网络,减少主服务器的压力(附CDN相关内容:CDN通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近); 3.使用LVS服务器负载均衡,LVS服务器结合Keepalived做高可用; 4.LVS下 ...
  • 解决高并发访问,或者说改善,提高一点思路: 1.使用Squid或者Varnish做缓存代理,将经常访问的图片等静态内容缓存起来,提高访问速度; 2.使用CDN内容分发网络,减少主服务器的压力(附CDN相关内容:CDN通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近); 3.使用LVS服务器负载均衡,LVS服务器结合Keepalived做高可用; 4.LVS下 ...
  • 根据JIRA( https://issues.apache.org/jira/browse/SOLR-5532 ),这个错误出现在Solr 4.6中 我建议您至少更新Solr 4.6到4.6.1,或者如果可能的话,更新到4.7或甚至更新到4.10。 According to JIRA (https://issues.apache.org/jira/browse/SOLR-5532) this bug was here in Solr 4.6 I will recommend you to update So ...
  • 首先:1.4是Solr的一个非常老的版本。 我不确定当时是否支持每个字段值(突出显示本身是在Solr 1.3中引入的)。 默认的荧光笔在3.1中已更改。 但是,您应该能够通过为hl.maxAnalyzedChars提供一个较大的值来突出显示字段中的所有hl.maxAnalyzedChars (不确定-1是否会执行您想要的操作)。 尝试的另一个选择应该是具有大的hl.maxAnalyzedChars值和大的hl.fragsize值(对两个字段使用相同的值而不是0)。 如果您仍然无法使其工作,请在更新版本的So ...
  • 您可以使用构面查询而不是构面范围来完成所要求的内容。 尝试这样的事情: facet.query=myDateField:[NOW-11MONTH/MONTH TO NOW-10MONTH/MONTH] facet.query=myDateField:[NOW-10MONTH/MONTH TO NOW-9MONTH/MONTH] facet.query=myDateField:[NOW-9MONTH/MONTH TO NOW-8MONTH/MONTH] ... 等等。 现在你可以完全控制任何一个方面, ...
  • 不。 Solr不允许更新特定字段。 您需要使用所有现有值和更改的值再次更新文档。 更新基本上是删除和添加文档。 更新 Solr允许部分更新4.0 @ http://solr.pl/en/2012/07/09/solr-4-0-partial-documents-update/ Nope. Solr doesn't allow updating a specific field. You would need to update the document again with all the existing ...
  • 您可以安装插件,不包括其中的Solr库版本,然后明确包含更新版本。 此处的详细信息将在另一个插件的上下文中进行描述。 假设您已经拥有一个插件开发者帐户,那么下载插件源代码,升级库和发布新版本可能会更容易。 仅供参考,任何人都可以发布新的插件版本,而不仅仅是原始的插件作者。 你的Solr插件用户会为此感谢你。 You could install the plugin, excluding the version of the Solr library therein, then explicitly incl ...
  • 为什么使用真的非常老的Nutch版本? 但是,你面临的问题是这一行开头的空间: _+^http://([a-z0-9]*\.)*nutch.apache.org/ (我用空格标出了空格)每行以空格开头, \n , #被配置解析器忽略,请看: https : //github.com/apache/nutch/blob/master /src/plugin/lib-regex-filter/src/java/org/apache/nutch/urlfilter/api/RegexURLFilterBase ...
  • 在两个不同版本的Solr中使用完全相同的配置文件将为架构属性(如multiValued生成相同的默认行为。 如果你看到不同的行为,那么你在某个地方有一种堕落...... 1) 声明上属性的默认行为首先取决于相应上的属性。 由于您的问题没有指定两个schema.xml文件中string的声明是什么,因此它们可能在您的两个配置之间有所不同。 2)如果定义中没有定义multiValued属性,则默认行为来自< ...
  • 正如这个问题的答案所表明的那样,这是由于PDF格式本身的性质。 有可能OCR选项在这个问题上比PDFBox做得更好,有一些免费的OCR选项,如Tesseract和Ocropus,但我不知道它们的工作情况如何,或者它们是否可以轻松地与Solr集成。 As the answer to this SO question indicates, this is due to the nature of the PDF format itself. It's possible that OCR options do b ...