http://localhost:8983/solr/admin/cores?action=CREATE&name=coreX&instanceDir=path_to_instance_directory
/**
* 实际的重新加载solr核动作
*
@param
coreName
*/
private
void doReloadSolrCore(String coreName) {
boolean isLoadOk =
false;
HttpClient client =
new HttpClient();
String createCMD = "http://" + Constants.LOCAL_ADDRESS + ":" + jbossPort + "/admin/cores?action=RELOAD&core=" + coreName;
HttpMethod method =
new GetMethod(createCMD);
method.getParams().setContentCharset("GBK");
method.getParams().setHttpElementCharset("GBK");
method.getParams().setCredentialCharset("GBK");
logger.error("重新加载核命令: " + createCMD);
//
execute the method.
try {
client.executeMethod(method);
}
catch (Exception e) {
logger.error("重新加载solr核失败, 核名称: " + coreName, e);
throw
new RuntimeException("重新加载solr核失败, 核名称: " + coreName, e);
}
}
/**
* 启动一个线程重新加载solr核
*
@param
groupName
*
@param
coreName
*/
private
void reloadSolrCore(
final String coreName) {
//
http://localhost
:8983/solr/admin/cores?action=RELOAD&core=core0
new Thread() {
@Override
public
void run() {
try {
doReloadSolrCore(coreName);
}
catch (Exception e) {
logger.error("重新加载solr核失败, 核名称: " + coreName, e);
throw
new RuntimeException("重新加载solr核失败, 核名称: " + coreName, e);
}
}
}.start();
}
/**
* 本机从slave成为master,修改对应的配置文件
*
@param
solrConfigPath solr配置文件路径
*/
private
void changeConfigAsMaster(String solrConfigPath) {
SAXReader reader =
new SAXReader();
File file =
new File(solrConfigPath);
try {
Document doc = reader.read(file);
//
首先移除以前slave的配置片段
Node node = doc.selectSingleNode("/config/requestHandler[@name=\"/replication\"]");
node.detach();
//
然后加入master的配置片段
Element rootElement = doc.getRootElement();
//
拿到<config/>元素
Element oneLevelElement = rootElement.addElement("requestHandler").addAttribute("name", "/replication").addAttribute("class", "solr.ReplicationHandler");
Element twoLevelElement = oneLevelElement.addElement("lst").addAttribute("name", "master");
twoLevelElement.addElement("str").addAttribute("name", "replicateAfter").addText("startup");
twoLevelElement.addElement("str").addAttribute("name", "replicateAfter").addText("commit");
twoLevelElement.addElement("str").addAttribute("name", "commitReserveDuration").addText("00:00:10");
XMLWriter writer =
new XMLWriter(
new FileWriter(solrConfigPath));
writer.write(doc);
writer.close();
}
catch (DocumentException e) {
logger.error("写入master节点配置片段失败, 配置文件路径: " + solrConfigPath);
throw
new RuntimeException("写入master节点配置片段失败, 配置文件路径: " + solrConfigPath, e);
}
catch (IOException e) {
logger.error("写入master节点配置片段失败, 配置文件路径: " + solrConfigPath);
throw
new RuntimeException("写入master节点配置片段失败, 配置文件路径: " + solrConfigPath, e);
}
}
/**
* 修改slave配置片段,指向新的mater节点,如果我原先是master,那么先去掉master的配置,因为我身份将转为slave,若原先是slave,只需要简单修改masterUrl即可
*
@param
solrConfigPath solr配置文件路径
*/
private
void changeConfigForSlave(String solrConfigPath, String coreName, String newMasterHost) {
SAXReader reader =
new SAXReader();
File file =
new File(solrConfigPath);
String masterUrl = "";
if (StringUtils.isNotBlank(newMasterHost)) {
masterUrl = "http://" + newMasterHost + ":" + jbossPort + "/" + coreName + "/replication";
try {
Document doc = reader.read(file);
Node node = doc.selectSingleNode("/config/requestHandler[@name=\"/replication\"]");
if (
null != node) {
//
如果我原先是master,那么先去掉master的配置,
node.detach();
}
Element rootElement = doc.getRootElement();
//
拿到<config/>元素
Element oneLevelElement = rootElement.addElement("requestHandler").addAttribute("name", "/replication").addAttribute("class", "solr.ReplicationHandler");
Element twoLevelElement = oneLevelElement.addElement("lst").addAttribute("name", "slave");
twoLevelElement.addElement("str").addAttribute("name", "masterUrl").addText(masterUrl);
twoLevelElement.addElement("str").addAttribute("name", "pollInterval").addText("00:02:00");
twoLevelElement.addElement("str").addAttribute("name", "compression").addText("internal");
twoLevelElement.addElement("str").addAttribute("name", "httpConnTimeout").addText("5000");
twoLevelElement.addElement("str").addAttribute("name", "httpReadTimeout").addText("10000");
XMLWriter writer =
new XMLWriter(
new FileWriter(solrConfigPath));
writer.write(doc);
writer.close();
}
catch (DocumentException e) {
logger.error("写入slave节点配置片段失败, 配置文件路径: " + solrConfigPath);
throw
new RuntimeException("写入master节点配置片段失败, 配置文件路径: " + solrConfigPath, e);
}
catch (IOException e) {
logger.error("写入slave节点配置片段失败, 配置文件路径: " + solrConfigPath);
throw
new RuntimeException("写入master节点配置片段失败, 配置文件路径: " + solrConfigPath, e);
}
}
}
/**
* 本机新身份是master,是从slave转来的,调整指定核的配置文件,重新reload
*
@param
coreName
*/
private
void adjustSolrCoreAsMaster(String coreName) {
if (
this.mapCoreConfigInfo.containsKey(coreName)) {
String configFilePath =
this.mapCoreConfigInfo.get(coreName);
//
目标配置文件路径
if (StringUtils.isNotBlank(configFilePath)) {
//
修改配置文件replication判断为master的片段
this.changeConfigAsMaster(configFilePath);
this.reloadSolrCore(coreName);
}
}
}
/**
* 本机新的身份是slave,可能是master转来的,或者原先还是slave,无论哪种,都需要调整指定核的配置文件,指向新的master节点, 重新reload
*
@param
coreName solr核名称
*/
private
void adjustSolrCoreAsSlave(String coreName, String newMasterHost) {
if (
this.mapCoreConfigInfo.containsKey(coreName)) {
String configFilePath =
this.mapCoreConfigInfo.get(coreName);
//
目标配置文件路径
if (StringUtils.isNotBlank(configFilePath)) {
//
修改配置文件replication, 指向新的master地址
this.changeConfigForSlave(configFilePath, coreName, newMasterHost);
this.reloadSolrCore(coreName);
}
}
}
/**
* 为了m/s同步,master节点强制性commit一下
*/
private
void commitMasterIndex(String masterHost, String port, String coreName) {
String targerUrl = "http://" + masterHost + ":" + port + "/" + coreName;
logger.error("master节点强制性commit一下,url: " + targerUrl);
CommonsHttpSolrServer httpSolrServer =
null;
try {
httpSolrServer =
new CommonsHttpSolrServer(targerUrl);
}
catch (MalformedURLException e1) {
throw
new RuntimeException("连接solr服务器失败, targetURL: " + targerUrl, e1);
}
httpSolrServer.setSoTimeout(Constants.soTimeOut);
httpSolrServer.setConnectionTimeout(Constants.connectionTimeOut);
httpSolrServer.setDefaultMaxConnectionsPerHost(Constants.maxConnectionsPerHost);
httpSolrServer.setMaxTotalConnections(Constants.maxTotalConnections);
httpSolrServer.setFollowRedirects(
false);
httpSolrServer.setAllowCompression(
true);
httpSolrServer.setMaxRetries(Constants.maxRetries);
try {
httpSolrServer.commit();
}
catch (Exception e) {
}
}
/**
* 指定核下指定组的节点发生变化
*
@param
coreName solr核名称
*
@param
groupName 机器分组名称
*
@param
newNodeNameList 最新的组内各个节点
*/
private
void masterSlaveNodeChanged(String coreName, String groupName, List<String> newNodeHostList) {
logger.error("===========masterSlaveNodeChanged============, solr核名称: " + coreName + ", 组节点名称: " + groupName + ", node节点IP列表: " + newNodeHostList);
logger.error("此时全局数据信息: " + mapGroupNodeStatus);
String newMasterHost = getNewestMasterHost(newNodeHostList);
//
当前最新的master节点IP
String oldMasterHost =
this.getOldMasterHost(coreName, groupName);
//
老的master节点地址
if (StringUtils.isBlank(oldMasterHost)) {
//
若本地缓存中记录的master节点没有,则说明是第一次取master节点,
if (StringUtils.isNotBlank(newMasterHost)) {
logger.error("maser节点地址: " + newMasterHost);
this.setMasterNode(coreName, groupName, newMasterHost);
}
if (newMasterHost.equalsIgnoreCase(Constants.LOCAL_ADDRESS) && MineNotifyProducer.isAuctionEntityGroup(coreName)) {
this.commitMasterIndex(Constants.LOCAL_ADDRESS, jbossPort, coreName);
//若这一次是本机重新夺回master节点,强制性commit一下,避免出现replication过程没有启动
logger.error("本机是master节点,可以启动相应的消费者线程");
}
}
else
if (!oldMasterHost.equalsIgnoreCase(newMasterHost)) {
//
若本地缓存有记录,却与最新的master节点不一致,则说明原来的master挂了,取最新的master节点
if (StringUtils.isNotBlank(newMasterHost)) {
this.setMasterNode(coreName, groupName, newMasterHost);
if (oldMasterHost.equalsIgnoreCase(Constants.LOCAL_ADDRESS)) {
//
本机是老的master,集群却又有了新的master,说明是本机提前窃取了master身份,现在需要归还出master身份,自己重新成为slave
//
结束掉相应的处理线程
logger.error("本机是老的master,集群却又有了新的master: " + newMasterHost + ", 说明是发布启动阶段, 本机提前窃取了master身份,结束掉相应的处理线程");
this.adjustSolrCoreAsSlave(coreName, newMasterHost);
//身份成为slave,
写入slave的配置,指向当前最新的master地址,并reload对应的solr核
}
else {
if (newMasterHost.equalsIgnoreCase(Constants.LOCAL_ADDRESS)) {
//
若本机是新的mater节点,则需要转换身份,从slave转为maser,
修改replciation配置,重载solr核,
this.adjustSolrCoreAsMaster(coreName);
}
else {
//
本机原本就是slave节点,需要修改replication配置,指向新的master,重载solr核
this.adjustSolrCoreAsSlave(coreName, newMasterHost);
}
}
}
}
//
首先从节点列表中去掉master节点
newNodeHostList.remove(newMasterHost);
//
设置新的slave列表
if (newNodeHostList.size() > 0) {
this.setSlaveNodeList(coreName, groupName, newNodeHostList);
}
else {
//
slave节点全都挂了,只剩下master节点了,
this.clearSlaveNodeList(coreName, groupName);
}
}
<
dependency
>
<groupId>com.taobao.hsf</groupId>
<artifactId>hsfunit</artifactId>
<version>1.0.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>