在使用restHighLevelClient连接es时出现这个问题,进行了以下情况排查:
1、先排查配置文件中的es服务器和端口是否没问题
2、排查es连接的账号密码是否正确(在es开了密码校验的情况下),这个可通过直接在浏览器访问es的ip端口,会自动弹出账号密码校验框登陆,在此可校验账号密码是否正确。
3、restHighLevelClient配置文件中,HttpHost的设置是否正确,一般我们使用restHighLevelClient都会在配置文件中初始化restHighLevelClient
package com.elasticsearch.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author mqs
*/
@Configuration
public class RestClientConfig {
@Value("${elasticsearch.clientIps}")
private String clientIps;
@Value("${elasticsearch.httpPort}")
private int httpPort;
@Value("${elasticsearch.username}")
private String username;
@Value("${elasticsearch.password}")
private String password;
private HttpHost[] getHttpHosts(String clientIps, int esHttpPort) {
String[] clientIpList = clientIps.split(",");
HttpHost[] httpHosts = new HttpHost[clientIpList.length];
for (int i = 0; i < clientIpList.length; i++) {
httpHosts[i] = new HttpHost(clientIpList[i], esHttpPort, "http");
}
return httpHosts;
}
/**
* 创建带HTTP Basic Auth认证rest客户端
*/
@Bean
public RestHighLevelClient restHighLevelClient() {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
return new RestHighLevelClient(RestClient.builder(getHttpHosts(clientIps, httpPort)).setHttpClientConfigCallback((HttpAsyncClientBuilder httpAsyncClientBuilder) -> httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)));
}
}
我在httpHosts[i] = new HttpHost(clientIpList[i], esHttpPort, “http”);这一行中指定了协议为’http’,实际上我的es是走https的,因此就给我报了连接不上的错误,在这里把http改为https。
然而改完之后,又有新问题出现了:
Authentication of [elastic] was terminated by realm [reserved]
需要在HttpHost类中将CredentialsProvider和SSLIOSessionStrategy配置参数类封装在自定义的SecuredHttpClientConfigCallback类配置请求连接参数,于是继续改代码:
package com.elasticsearch.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* @author mqs
*/
@Configuration
public class RestClientConfig {
@Value("${elasticsearch.clientIps}")
private String clientIps;
@Value("${elasticsearch.httpPort}")
private int httpPort;
@Value("${elasticsearch.username}")
private String username;
@Value("${elasticsearch.password}")
private String password;
private HttpHost[] getHttpHosts(String clientIps, int esHttpPort) {
String[] clientIpList = clientIps.split(",");
HttpHost[] httpHosts = new HttpHost[clientIpList.length];
for (int i = 0; i < clientIpList.length; i++) {
httpHosts[i] = new HttpHost(clientIpList[i], esHttpPort, "https");
}
return httpHosts;
}
/**
* 创建带HTTP Basic Auth认证rest客户端
*/
@Bean
public RestHighLevelClient restHighLevelClient() {
try{
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
return new RestHighLevelClient(RestClient.builder(getHttpHosts(clientIps, httpPort)).setHttpClientConfigCallback((HttpAsyncClientBuilder httpAsyncClientBuilder) ->{
httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
httpAsyncClientBuilder.disableAuthCaching();
httpAsyncClientBuilder.setSSLStrategy(sessionStrategy);
return httpAsyncClientBuilder;
} ));
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
然后边可以链接成功了。
参考资料:
ElasticSearch安全模式:创建RestHighLevelClient 连接SSL认证的HTTPS ES集群