Java Rest High Level Client访问带SSL的Elasticsearch负载均衡器报错求助
问题分析与解决方案
你的问题很典型:启用SSL的负载均衡器后,Java Rest High Level Client无法建立连接,报错“连接被远程主机强制关闭”,核心原因是客户端完全没配置SSL相关参数,无法和启用HTTPS的负载均衡器完成SSL握手。
下面是具体的解决步骤和修改后的代码:
1. 核心问题点
你原来的代码只指定了负载均衡器的hostname,但缺少两个关键配置:
- 没有指定
https协议(默认是http,和负载均衡器的SSL配置不匹配) - 没有配置SSL上下文,让客户端信任负载均衡器的证书(不管是CA签发还是自签名证书)
这两个缺失直接导致SSL握手失败,负载均衡器会强制关闭连接,也就是你看到的错误。
2. 修改后的代码(测试环境快速验证)
如果是测试环境,可以暂时忽略证书验证(生产环境绝对不要这么做),快速验证连接是否正常:
import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.ssl.SSLContexts; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import javax.net.ssl.SSLContext; import java.io.IOException; public class ESClientTest { public static void main(String[] args) { try { // 1. 创建忽略证书的SSL上下文(仅测试环境使用) SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial((chain, authType) -> true) .build(); // 2. 配置HttpClient的SSL参数 RestClient.Builder.HttpClientConfigCallback httpClientConfig = builder -> builder.setSSLContext(sslContext) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE); // 3. 构建客户端:必须指定https协议和正确端口(默认443,自定义端口请修改) RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("hostname", 443, "https")) .setHttpClientConfigCallback(httpClientConfig) ); // 你的搜索逻辑保持不变 SearchRequest searchRequest = new SearchRequest("testCollection"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.queryStringQuery("test")); searchRequest.source(sourceBuilder); SearchResponse searchResponse = client.search(searchRequest); System.out.println("search response :" + searchResponse.toString()); client.close(); } catch (IOException e) { e.printStackTrace(); } } }
3. 生产环境安全配置
生产环境必须信任合法的证书,不能忽略验证。假设你有负载均衡器的CA证书文件(比如lb-cert.crt),可以这样配置:
import org.apache.http.ssl.SSLContexts; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import javax.net.ssl.SSLContext; import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; // ... 其他导入省略 public class ESClientProd { public static void main(String[] args) throws Exception { // 加载负载均衡器的证书到信任库 CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (InputStream certIn = new FileInputStream("/path/to/lb-cert.crt")) { X509Certificate cert = (X509Certificate) cf.generateCertificate(certIn); KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); trustStore.setCertificateEntry("lb-cert", cert); // 创建信任该证书的SSL上下文 SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(trustStore, null) .build(); // 配置HttpClient RestClient.Builder.HttpClientConfigCallback httpClientConfig = builder -> builder.setSSLContext(sslContext); // 构建客户端 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("hostname", 443, "https")) .setHttpClientConfigCallback(httpClientConfig) ); // ... 后续搜索逻辑同上 client.close(); } } }
4. 额外检查项
如果配置后还是报错,可以排查:
- 负载均衡器的端口是否正确(比如是不是用了非443的HTTPS端口)
- 客户端服务器的防火墙是否允许访问负载均衡器的HTTPS端口
- 负载均衡器是否正确转发请求到后端ES节点
- 负载均衡器的证书是否过期或配置错误
内容的提问来源于stack exchange,提问作者User1203
相关产品推荐
相关产品推荐

