承接上文,使用Java客戶端操作elasticsearch,本文主要介紹 常見的配置 和Sniffer(集群探測) 的使用。
常見的配置
前面已介紹過,RestClientBuilder支持同時提供一個RequestConfigCallback和一個HttpClientConfigCallback,你可以定制 the Apache Async Http Client 公開的配置。這兩個回調函數可以修改某些特定的行為,而不會覆蓋RestClient初始化的所有其他默認配置。 本節介紹一些需要為客戶端進行額外配置的常見場景。
Timeouts
啥都不說了,直接上代碼。該例子演示了連接超時(默認為1秒)和套接字超時(默認為30秒)。 也相應地調整最大重試超時時間(默認為30秒)。
RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200)) .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { //該方法接收一個RequestConfig.Builder對象,對該對象進行修改后然后返回。 @Override public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { return requestConfigBuilder.setConnectTimeout(5000) //連接超時(默認為1秒) .setSocketTimeout(60000);//套接字超時(默認為30秒) } }) .setMaxRetryTimeoutMillis(60000);//調整最大重試超時時間(默認為30秒)
線程數
The Apache Http Async Client默認啟動一個dispatcher線程和供連接管理器使用的多個worker線程,與本地檢測到的處理器數量一樣多(取決於Runtime.getRuntime().availableProcessors()的返回值)。 修改線程數可以如下操作:
RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200)) .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { return httpClientBuilder.setDefaultIOReactorConfig( IOReactorConfig.custom().setIoThreadCount(1).build()); } });
基本認證
同樣直接上代碼
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user", "password")); RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200)) .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { // 該方法接收HttpAsyncClientBuilder的實例作為參數,對其修改后進行返回 @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);//提供一個默認憑據 } });
搶占式認證可以被禁用,這意味着每個請求都將被發送,不用去看授權請求頭,在收到HTTP 401響應后,會再次發送相同的請求,這次會帶上基本的身份認證頭,如果你想這樣做,那么你可以通過HttpAsyncClientBuilder來禁用它:
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user", "password")); RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200)) .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { httpClientBuilder.disableAuthCaching(); //禁用搶占式身份驗證 return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); } });
加密通信
加密通信也可以通過HttpClientConfigCallback進行配置。 參數HttpAsyncClientBuilder公開了配置加密通信的多種方法:
setSSLContext,setSSLSessionStrategy和setConnectionManager,重要性依次增加。 以下是一個例子: KeyStore truststore = KeyStore.getInstance("jks"); try (InputStream is = Files.newInputStream(keyStorePath)) { truststore.load(is, keyStorePass.toCharArray()); } SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null); final SSLContext sslContext = sslBuilder.build(); RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200, "https")) .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { return httpClientBuilder.setSSLContext(sslContext); } });
如果未提供明確的配置,則將使用系統默認配置。
其他
如果對其他配置需要修改,可以參考Apache HttpAsyncClient文檔:https://hc.apache.org/httpcomponents-asyncclient-4.1.x/
如果您的應用程序在安全管理器下運行,可能會采用JVM默認緩存策略:
- A. 域名能夠正確解析的IP地址將會永久緩存;
- B. 域名解析出錯的IP地址會默認緩存10S;
如果客戶端連接到的主機的地址隨時間變化,那么可能你想修改默認的JVM行為。這些可以通過添加 networkaddress.cache.ttl=<timeout> 和 networkaddress.cache.negative.ttl=<timeout> 到您的Java安全策略進行修改。
嗅探器
從運行的Elasticsearch集群中自動發現節點,並將其設置到現有的RestClient實例。 默認情況下,它將使用Nodes Info api來檢索屬於集群的節點,並使用jackson解析響應的json數據。看完之后還是不清除說的個啥?那就仔細說說吧。之前我們都是像下面這樣創建客戶端實例的。
RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200, "http"), new HttpHost("localhost", 9201, "http")).build();
假設一個集群有100個節點,如果手動 new HttpHost("localhost", 9200, "http") 這樣創建100個HttpHost也可以,但是可能會寫到手軟,出錯概率極大。所以就出現了sniffer,它來幫你做這件事。
the REST client sniffer 兼容Elasticsearch 2.x及以上版本。可以在這里找到它的javadoc。
Maven倉庫
The REST client sniffer 與Elasticsearch的發布周期相同。 發布的第一版為5.0.0-alpha4。同樣,你也可以自由替換成你想要的版本。 它和通訊的Elasticsearch版本之間沒有關聯。sniffer 支持從Elasticsearch 2.x及其以后的版本獲取節點列表。
Maven配置
以下是使用maven作為依賴管理器。 將以下內容添加到您的pom.xml文件中:
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client-sniffer</artifactId> <version>6.2.3</version> </dependency>
Gradle配置
以下是使用gradle作為依賴管理器。 將以下內容添加到您的build.gradle文件中:
dependencies {
compile 'org.elasticsearch.client:elasticsearch-rest-client-sniffer:6.2.3'
}
用法
RestClient實例創建后,就可以將一個Sniffer關聯到它。Sniffer使用RestClient定期(默認每5分鍾)從集群中獲取當前所有節點的列表,並通過調用RestClient的setHosts方法來更新。
RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200, "http")) .build(); Sniffer sniffer = Sniffer.builder(restClient).build();
關閉Sniffer是非常重要的,這樣它的后台線程才能正常關閉並釋放所有資源。 Sniffer對象的生命周期應與RestClient相同,並在客戶端之前關閉:
sniffer.close();
restClient.close();
Sniffer默認每5分鍾更新一次節點。 該時間間隔也可以自定義(以毫秒為單位),如下所示:
RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200, "http")) .build(); Sniffer sniffer = Sniffer.builder(restClient) .setSniffIntervalMillis(60000).build();
也可以在失敗時啟用嗅探,這意味着在每次失敗后,節點列表將被直接更新。 此種方式需要首先創建SniffOnFailureListener,並在創建RestClient時提供。 同樣,一旦Sniffer被創建,它需要與同一個SniffOnFailureListener實例相關聯,SniffOnFailureListener實例將在每次失敗時通知,並且會使用該Sniffer再執行一輪嗅探。
Elasticsearch Nodes Info api在連接到節點時不會返回使用的協議,而只會返回它們的host:port鍵對,因此默認情況下使用http。 如果想使用https,則必須手動創建ElasticsearchHostsSniffer實例,可按如下方式:
RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200, "http")) .build(); HostsSniffer hostsSniffer = new ElasticsearchHostsSniffer( restClient, ElasticsearchHostsSniffer.DEFAULT_SNIFF_REQUEST_TIMEOUT, ElasticsearchHostsSniffer.Scheme.HTTPS); Sniffer sniffer = Sniffer.builder(restClient) .setHostsSniffer(hostsSniffer).build();
同樣也可以自定義sniffRequestTimeout,默認為1秒。 在調用the Nodes Info api時timeout參數使用querystring方式傳遞,以便當服務器端的超時時,仍然會返回有效的響應,盡管它可能只包含群集一部分的節點 。
RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200, "http")) .build(); HostsSniffer hostsSniffer = new ElasticsearchHostsSniffer( restClient, TimeUnit.SECONDS.toMillis(5), ElasticsearchHostsSniffer.Scheme.HTTP); Sniffer sniffer = Sniffer.builder(restClient) .setHostsSniffer(hostsSniffer).build();
此外,我們可能需要從外部源獲取主機,而不是從Elasticsearch獲取主機。則可以自定義實現HostsSniffer。
RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200, "http")) .build(); HostsSniffer hostsSniffer = new HostsSniffer() { @Override public List<HttpHost> sniffHosts() throws IOException { return null;//從外部獲取主機 } }; Sniffer sniffer = Sniffer.builder(restClient) .setHostsSniffer(hostsSniffer).build();
官方文檔:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/_common_configuration.html