调用es接口等待时间过长
查询es集群状态:curl -XGET http://192.168.0.12:9200/_cluster/health?pretty
发现集群状态为red "status" : "red"
查看每个索引的状态:curl -XGET http://192.168.0.12:9200/_cat/indices?v
发现有许多之前安装X-Pack时候自带的无用索引(X-Pack是kibana开启系统监控必须集成的组件,用了一段时间后面过期了需要证书,就把X-Pack给下了)
删除无用索引(带通配符):curl -XDELETE "http://192.168.0.12:9200/.monitoring-*"
查看所以索引分配方式:curl -s "http://192.168.0.12:9200/_cat/shards"
过滤查看所有未分配索引的方式:curl -s "http://192.168.0.12:9200/_cat/shards" | grep UNASSIGNED
发现有3个索引的状态是UNASSIGNED(每个索引原先4个primary,但是集群仅有3个节点,有一个主分片没有被分配)
自动分配分片(没试成功):curl -XPOST http://192.168.0.12:9200/_cluster/reroute?retry_failed
手动移动分片(没试成功):
curl -XPOST 'http://192.168.0.12:9200/_cluster/reroute?pretty' -d '
{
"commands" : [ {
"allocate_stale_primary" : {
"index" : "imei",
"shard" :0,
"node" : "hadoop2",
"accept_data_loss" : true
}
}]
}'
想尝试动态修改分片数量(痴心妄想,只能动态修改副本数):curl -XPUT 'http://192.168.0.12:9200/users/_settings' -d '{"number_of_shards": 3}'
没法之后尝试重建索引,将分片数量设为3,感觉用命令太麻烦了,直接上java方法比较方便:
/*索引重建迁移大法*/
private static void indexMigration() throws UnknownHostException {
String node = "192.168.0.12";
int port = 9300;
String cn = "my-application";
Settings settings = Settings.builder()
.put("cluster.name", cn)//设置ES实例的名称
.put("client.transport.sniff", true)// 自动嗅探发现集群节点
.build();
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(node), port));
log.info("初始化客户端成功");
List<Map<String, Object>> addList = new ArrayList<>();
//指定一个index和type
SearchRequestBuilder search = client.prepareSearch("users2").setTypes("type");
//使用原生排序优化性能
//search.addSort("_doc", SortOrder.ASC);
search.addSort("_doc", SortOrder.ASC);
//设置每批读取的数据量
search.setSize(100);
//默认是查询所有
search.setQuery(QueryBuilders.queryStringQuery("*:*"));
//设置 search context 维护1分钟的有效期
search.setScroll(TimeValue.timeValueMinutes(1));
//获得首次的查询结果
SearchResponse scrollResp = search.get();
//打印命中数量、
log.info("命中总数量:" + scrollResp.getHits().getTotalHits());
int count = 1;
do {
log.info("第" + count + "次打印数据:");
for (SearchHit hit : scrollResp.getHits().getHits()) {
addList.add(hit.getSource());
}
count++;
//将scorllId循环传递
scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(TimeValue.timeValueMinutes(1)).execute().actionGet();
} while (scrollResp.getHits().
getHits().length != 0);
//当searchHits的数组为空的时候结束循环,至此数据全部读取完毕
BulkRequestBuilder bulkRequest = client.prepareBulk();
for (
int i = 0; i < addList.size(); i++)
{
bulkRequest.add(client.prepareIndex("users", "type").setSource(addList.get(i)));
// 每1000条提交一次
if (i % 1000 == 0) {
bulkRequest.execute().actionGet();
bulkRequest = client.prepareBulk();
}
}
bulkRequest.execute().
actionGet();
}
public static void main(String[] args) throws UnknownHostException {
indexMigration();
}
最后通过新建合适的索引,把原先的数据迁移过来,再重构旧索引,将数据导入回去后,集群状态恢复正常。
测试api的时候发现这样做的话貌似_id被系统设为自动生成(起初将某些字段同样给_id赋值,本来是想省一个字段,但是留个心眼在结构里都把字段写上了),不过还好当时所有有需要的字段都预留下来了,修改一下方法里查询的字段名即可。
重新测试调用api,稳妥的一匹
挺好的shard问题解决方案: