最近把单机版solr改成了solrcloud,原本单机版的solr查询代码执行批量保存失败了一部分
原本的单机solr代码如下:
// 添加对象
try {
**client.addBeans(“zgcbCollection”, list);**
} catch (SolrServerException e) {
logger.error("SolrSaveClient saveAll Exception error : " + e.toString());
} catch (Exception e) {
logger.error("SolrSaveClient saveAll Exception error : " + e.toString());
}
try {
client.commit(getCollection());
} catch (SolrServerException e) {
logger.error("SolrSaveClient commit SolrServerException error:" + e.toString());
} catch (IOException e) {
logger.error("SolrSaveClient commit IOException error:" + e.toString());
}
此代码在单机solr下一直没遇到什么问题,但在solrcloud模式下,批量保存成功了一部分,失败了一部分,某些情况下某个solr节点会挂掉!并且报出如下错误(为了隐私,部分包名做了隐藏):
ERROR[20181025-15:51:01] [org.apache.solr.client.solrj.impl.CloudSolrClient:919] Request to collection [zgcbCollection] failed due to (0) java.net.SocketTimeoutException: Read timed out, retry? 0
ERROR[20181025-15:51:01] [包名.solr.client.SolrSaveClient:54] SolrSaveClient saveAll Exception error : org.apache.solr.client.solrj.SolrServerException: Timeout occured while waiting response from server at: http://192.168.1.97:8001/solr/zgcbCollection
Timeout——超时,很明显。但我在client创建的时候,确实设置了超时参数,代码如下:
private SolrClient getCloudSolrClient(List<String> zkHosts, Optional<String> zkChroot) {
return new CloudSolrClient.Builder(zkHosts, zkChroot)
.withConnectionTimeout(**connectionTimeout**)
.withSocketTimeout(**socketTimeout**)
.build();
}
网上其他文章的解决办法也是设置connectionTimeout和socketTimeout,但都没有效果,于是再看官方代码:
发现我使用的addBeans接口里面调用了另一个接口,接口里面默认了一个参数“-1”,这个参数很特殊
源码如下:
public UpdateResponse addBeans(String collection, Collection<?> beans) throws SolrServerException, IOException {
return addBeans(collection, beans, -1);
}
于是找到这个接口,如图
查看接口参数名,叫做“commitWithinMs”!
@param commitWithinMs max time (in ms) before a commit will happen
翻译如下:提交发生前的最大时间(以ms为单位)
超时vs提交,判断是我批量保存的数据很大,因此受到影响。果断
把
client.addBeans(“zgcbCollection”, list);
改成:
client.addBeans(“zgcbCollection”, list,300);
再次junit测试,报错完全消失,问题解决!!!
但仍然不明觉厉,明明我在solr配置文件也设置了自动提交,而且也在后面调用了”client.commit(getCollection());“,但为什么还会报错呢?
这次目的很明确,找到如下文章:三种solr提交(commit)索引的方式
摘抄如下内容:
soft commit做的事情
1、把内存文件fsync到磁盘,但不创建index descriptor。
也就是说原索引和现在的索引还互不感知,所以如果jvm崩溃,那这部分索引就没了。
2、可以重新打开searcher,使得新的索引可以被查找到。
服务挂掉了,然后自然数据就丢了。
所以commit、AutoCommit(包括autoSoftCommit)、CommitWithin,这几种提交方式需要结合使用,互补长短!