日前接到一个任务,就是在搜索服务器中使用solr replication功能, 这个功能是solr 3.1新加的,只需要在solrconfig.xml进行配置就可以进行replication,而我们原来的搜索服务器使用的是solr1.4, 它的replication功能是通过编写linux脚本来实现的。
按照replication的要求进行配置(这个可以在网上查到),重启两台服务器后,却发现slave怎么也不能从master取得索引数据,于是就找了份solr3.1的源码,进行debug, 发现原因如下:
1. Solr 进行replication功能使用的是solr 自身创建的solrcore, 它会使用这个solrcore来获得master的indexversion, 然后与slave的indexversion相比,从而判断需不需要进行replication,如果相同,则不需要进行replication
2. 我们索引服务器新增索引使用是的EmbeddedSolrServer,它并没有使用solr自身创建的solrcore,而是自己会利用配置文件来创建一个新的solrcore.
3. 这样问题就出现了,索引服务器新增了索引,它的indexversion改变了,但是solr自身创建的solrcore的indexversion并没有改变,所以Solr进行replication时判断indexversion相等,不需要进行replication。 这就像两个线程一样,互不相干。
知道了原因,就可以想出解决方案,最后选择包装solr进行replication时使用的http请求,让这些请求走EmbeddedSolrServer创建的solrcore,这样就可以保证replication和EmbeddedSolrServer使用的同一个solrcore. 这个可以参照solrServelet调用的代码,大概的代码如下:
public class ReplicationHandlerImpl implements RequestHandler {
protected Logger log = LogFactory.getLog(getClass());
private static final String REPLICATION = "/replication";
// The replication request parameters in prototype Solr server.
private static final String[] paramterKeys = { "command", "indexversion", "file", "wt", "compression", "cf","details",
"checksum", "offset" };
public void handle(Request request) throws IOException, SolrServerException {
EmbeddedSolrServerImpl solrServerInterface = (EmbeddedSolrServerImpl)AppProperties.getSpringContext().getBean("EmbeddedSolrServer");
SolrCore solrCore = solrServerInterface.getSolrCore();
Map<String, String> namedMap = new HashMap<String, String>();
StringBuffer sb = new StringBuffer();
for (String key : paramterKeys) {
String value = request.getHttpParameter(key);
if (null != value && !StringUtils.isEmpty(value)) {
namedMap.put(key, value);
sb.append(String.format("%s=%s&", key, value));
}
}
if (log.isDebugEnabled()) {
log.debug(String.format("Replication with url %s?%s", request.getHttpRequest().getRequestURI(), sb.toString()));
}
// There should be a command for replication request
String command = request.getHttpParameter(AppConstants.HTTP_PARAM_COMMAND);
if (StringUtils.isEmpty(command) || namedMap.isEmpty()) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Command is empty");
}
// Forward and invoke Solr replication request, then response a binary file.
SolrQueryResponse solrRsp = new SolrQueryResponse();
SolrQueryRequest solrReq = replication(namedMap, solrRsp, solrCore);
QueryResponseWriter responseWriter = solrCore.getQueryResponseWriter(solrReq);
if (responseWriter instanceof BinaryQueryResponseWriter) {
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
binWriter.write(request.getHttpResponse().getOutputStream(), solrReq, solrRsp);
} else if (responseWriter instanceof XMLResponseWriter) {
XMLResponseWriter xmlWriter = (XMLResponseWriter) responseWriter;
xmlWriter.write(request.getHttpResponse().getWriter(), solrReq, solrRsp);
} else{
log.warn("No response will be wrote! Expect BinaryQueryResponseWriter.");
return;
}
}
private SolrQueryRequest replication(Map<String, String> namedMap, SolrQueryResponse solrRsp, SolrCore solrCore) {
SolrQueryRequest solrReq = null;
StringBuffer sb = new StringBuffer();
try {
SolrParams params = buildSolrParams(namedMap, sb);
QueryRequest request = new QueryRequest(params);
SolrRequestParsers parser = new SolrRequestParsers(null);
solrReq = parser.buildRequestFrom(solrCore, params, request.getContentStreams());
SolrRequestHandler handler = solrCore.getRequestHandler(request.getPath());
solrCore.execute(handler, solrReq, solrRsp);
if (log.isInfoEnabled()) {
log.info(String.format("Replication with parameters %s success", sb.toString()));
}
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
}
return solrReq;
}
private SolrParams buildSolrParams(Map<String, String> namedMap, StringBuffer sb) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(AppConstants.QS_TYPE, REPLICATION);
for (Map.Entry<String, String> entry : namedMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
params.set(key, value);
sb.append(String.format("%s=%s&", key, value));
}
return params;
}
}