Elasticsearch Java REST 客户端 6.2(一)Java Low Level REST 客户端官方文档

提示!本文是我翻译自Elasticsearch官方说明文档,这里是原文地址,文章结构与原文对应,对翻译内容如有疑问可自行翻阅,也欢迎私信评论纠正错误。

概述

Java REST客户端有两种风格:

  • Java Low Level REST Client:官方提供的低级客户端。该客户端通过http来连接Elasticsearch集群。用户在使用该客户端时需要将请求数据手动拼接成Elasticsearch所需JSON格式进行发送,收到响应时同样也需要将返回的JSON数据手动封装成对象。虽然麻烦,不过该客户端兼容所有的Elasticsearch版本。

  • Java High Level REST Client:官方提供的高级客户端。该客户端基于低级客户端实现,它提供了很多便捷的API来解决低级客户端需要手动转换数据格式的问题。(也就是说,使用高级客户端我们不再需要去关注如何将请求数据拼接成Elasticsearch所需JSON格式,也不需要关注如何将响应返回数据封装成对象。—-译者加)

Java REST低级客户端

低级客户端包含如下特性:

  • 极少的依赖包
  • 负载均衡访问所有可用节点
  • 故障转移。当发生节点故障时会返回特定的状态码
  • 连接失败处罚策略。(客户端是否会去重连一个连接失败的节点取决于该节点连续连接失败的次数,连接该节点失败次数越多,客户端下次重连它的时间就越长)
  • 持久连接
  • 跟踪记录请求和响应日志
  • 可选的集群节点自动发现

入门

本节描述如何从低级REST客户端开始,获取客户端API并将它们应用到应用程序中。

Javadoc

如下链接是低级REST客户端的Java API文档:
https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-client/6.2.2/index.html

Maven Repository

低级REST客户端的jar包可以在Maven中心仓库找到。所需Java的最低版本为1.7。低级REST客户端的发行版本跟Elasticsearch是一样的。你可以替换成你想要的版本,从5.0.0-alpha4开始。客户端版本和Elasticsearch版本之间没有任何联系,
任何版本的客户端都可以连接任何版本Elasticsearch。

Maven依赖配置

如下是使用Maven依赖管理器配置依赖的方式。添加如下配置到你的pom.xml文件中:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>6.2.2</version>
</dependency>
Gradle依赖配置

如下是使用Gradle依赖管理器配置依赖的方式。添加如下配置到你的build.gradle文件中:

dependencies {
    compile 'org.elasticsearch.client:elasticsearch-rest-client:6.2.2'
}

Dependencies

低级Java REST客户端底层使用Apache Http Async Client发送Http请求。它依赖如下的类库,即async http client和它本身传递的依赖:

  • org.apache.httpcomponents:httpasyncclient
  • org.apache.httpcomponents:httpcore-nio
  • org.apache.httpcomponents:httpclient
  • org.apache.httpcomponents:httpcore
  • commons-codec:commons-codec
  • commons-logging:commons-logging

Shading

为了避免版本冲突,依赖的包可以被遮盖,并且打包客户端jar包到一个单独的jar文件里(通常叫做“uber jar”或者“fat jar”)。遮盖一个依赖(Shading a dependency)意思就是把这个jar包中的resources文件和class文件拿出来并重命名它们的包名,然后把它们放入相同jar文件里作为Java REST客户端。遮盖一个jar包可以通过第三方Maven或Gradle插件完成。

注意,遮盖一个jar也会牵连很多东西。例如遮盖Commons Logging层,意味着它下面依赖的第三方的日志包也需要被遮盖。

Maven配置

这里使用Maven Shade插件进行配置。添加如下配置到你的pom.xml文件中:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals><goal>shade</goal></goals>
                    <configuration>
                        <relocations>
                            <relocation>
                                <pattern>org.apache.http</pattern>
                                <shadedPattern>hidden.org.apache.http</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>org.apache.logging</pattern>
                                <shadedPattern>hidden.org.apache.logging</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>org.apache.commons.codec</pattern>
                                <shadedPattern>hidden.org.apache.commons.codec</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>org.apache.commons.logging</pattern>
                                <shadedPattern>hidden.org.apache.commons.logging</shadedPattern>
                            </relocation>
                        </relocations>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Gradle配置

这里使用Gradle Shadowjar插件进行配置。添加如下配置到你的build.gradle文件中:

shadowJar {
    relocate 'org.apache.http', 'hidden.org.apache.http'
    relocate 'org.apache.logging', 'hidden.org.apache.logging'
    relocate 'org.apache.commons.codec', 'hidden.org.apache.commons.codec'
    relocate 'org.apache.commons.logging', 'hidden.org.apache.commons.logging'
}

初始化客户端

通过RestClientBuilder类来构建一个RestClient实例对象,调用RestClient#builder(HttpHost…)静态方法创建(构建器模式)。该方法需要一个或多个HttpPost对象当做参数,一个HttpHost对象代表一个需要连接的主机地址:

RestClient restClient = RestClient.builder(
        new HttpHost("localhost", 9200, "http"),
        new HttpHost("localhost", 9201, "http")).build();

RestClient对象是线程安全的,并且理论上跟使用它的应用程序有相同的生命周期。所以很重要的一点是,当我们不再需要它的时候要将它关闭,以便所有它占用的资源会被适当的释放,以及它底层的http client实例和它的线程:

restClient.close();

当构建RestClient对象时,RestClientBuilder也允许我们设置一些其它的可选配置参数:

RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
Header[] defaultHeaders = new Header[]{new BasicHeader("header", "value")};
builder.setDefaultHeaders(defaultHeaders); // (1)

(1) 设置默认的请求头,以免在每次请求时都指定。设置后每次请求都会带有该请求头

RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
builder.setMaxRetryTimeoutMillis(10000); // (2)

(2) 最好设置一个超时时间以免对同一个请求尝试重试多次。默认的值是30秒,和socket默认的超时时间是一样的。万一socket的超时时间被自定义了,最大重试超时应相应调整。

RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
builder.setFailureListener(new RestClient.FailureListener() {
    @Override
    public void onFailure(HttpHost host) {
        // (3)
    }
});

(3) 设置一个监听器,当每次节点出现问题时得到提醒,执行方法做一些必要的处理。需要开启失败探测功能。

RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
    @Override
    public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
        return requestConfigBuilder.setSocketTimeout(10000); // (4)
    }
});

(4) 设置一个callback来修改默认的请求配置(例如:请求超时时间,身份认证信息,或者任何可以在org.apache.http.client.config.RequestConfig.Builder中设置的项)

RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
    @Override
    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
        return httpClientBuilder.setProxy(new HttpHost("proxy", 9000, "http")); // (5)
    }
});

(5) 设置一个callback来修改http client配置(例如:基于SSL的加密通信,或者任何org.apache.http.impl.nio.client.HttpAsyncClientBuilder运行设置的项)

执行请求

一旦RestClient对象被创建,我们就可以发送请求了。我们可以调用两个方法来发送请求,一个是performRequest,另一个是performRequestAsync。performRequest方法是同步方法,它会直接返回Response,这意味着client将会在方法调用后阻塞,直到响应返回。performRequestAsync方法返回void,并且它需要接收一个额外的ResponseListener参数,这意味着它会异步执行,不会阻塞当前线程。当请求成功返回或者是失败时会触发ResponseListener:

Response response = restClient.performRequest("GET", "/"); // (1)

(1) 发送一个请求,仅仅提供了请求方式和请求路径端点,这是最基础的请求参数。

Map<String, String> params = Collections.singletonMap("pretty", "true");
Response response = restClient.performRequest("GET", "/", params); // (2)

(2) 发送一个请求,提供请求方式,请求路径端点,还有一些URL请求参数。

Map<String, String> params = Collections.emptyMap();
String jsonString = "{" +
            "\"user\":\"kimchy\"," +
            "\"postDate\":\"2013-01-30\"," +
            "\"message\":\"trying out Elasticsearch\"" +
        "}";
HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
Response response = restClient.performRequest("PUT", "/posts/doc/1", params, entity); // (3)

(3) 发送一个请求,提供请求方式,请求路径端点,可选的URL请求参数和封装成org.apache.http.HttpEntity对象的请求体。

注意!为HttpEntity指定ContentType是很重要的,因为它会被使用去设置Content-Type请求头以便Elasticsearch能正确的转换内容。

Map<String, String> params = Collections.emptyMap();
HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory consumerFactory =
        new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(30 * 1024 * 1024);
Response response = restClient.performRequest("GET", "/posts/_search", params, null, consumerFactory); // (4)

(4) 发送一个请求,提供请求方式,请求路径端点,可选的URL请求参数,可选的请求体和可选的工厂类,这个工厂类被用来为每个请求创建一个org.apache.http.nio.protocol.HttpAsyncResponseConsumer回调实例。控制客户端如何从一个非阻塞的HTTP连接中拿到响应体的流。当没有提供时,会使用一个默认的实现,默认的实现会将响应体缓存在堆内存中,最多占用100MB堆内存空间。

ResponseListener responseListener = new ResponseListener() {
    @Override
    public void onSuccess(Response response) {
        // (5)
    }

    @Override
    public void onFailure(Exception exception) {
        // (6)
    }
};
restClient.performRequestAsync("GET", "/", responseListener); // (7)

(5) 当请求成功时执行onSuccess方法

(6) 当请求失败时执行onFailure方法。不管是当连接失败时,还是响应一个错误码都会调用

(7) 发送一个异步请求,仅仅提供请求方法,请求路径端点和响应监听器。异步请求最基础的参数设置。

Map<String, String> params = Collections.singletonMap("pretty", "true");
restClient.performRequestAsync("GET", "/", params, responseListener); // (8)

(8) 发送一个异步请求,提供请求方式,请求路径端点,一些URL请求参数和响应监听器。

String jsonString = "{" +
        "\"user\":\"kimchy\"," +
        "\"postDate\":\"2013-01-30\"," +
        "\"message\":\"trying out Elasticsearch\"" +
        "}";
HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
restClient.performRequestAsync("PUT", "/posts/doc/1", params, entity, responseListener); // (9)

(9) 发送一个异步请求,提供请求方式,请求路径端点,可选的URL请求参数,封装成org.apache.http.HttpEntity的请求体和响应监听器。

HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory consumerFactory =
        new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(30 * 1024 * 1024);
restClient.performRequestAsync("GET", "/posts/_search", params, null, consumerFactory, responseListener); // (10)

(10) 发送一个异步请求,提供请求方式,请求路径端点,可选的URL查询参数,可选的请求体和可选的工厂类,这个工厂类被用来为每个请求创建一个org.apache.http.nio.protocol.HttpAsyncResponseConsumer回调实例。控制客户端如何从一个非阻塞的HTTP连接中拿到响应体的流。当没有提供时,会使用一个默认的实现,默认的实现会将响应体缓存在堆内存中,最多占用100MB堆内存空间。

如下的基础示例演示异步请求时如何被发送的:

final CountDownLatch latch = new CountDownLatch(documents.length);
for (int i = 0; i < documents.length; i++) {
    restClient.performRequestAsync(
            "PUT",
            "/posts/doc/" + i,
            Collections.<String, String>emptyMap(),
            //let's assume that the documents are stored in an HttpEntity array
            documents[i],
            new ResponseListener() {
                @Override
                public void onSuccess(Response response) {
                    // (11)
                    latch.countDown();
                }

                @Override
                public void onFailure(Exception exception) {
                    // (12)
                    latch.countDown();
                }
            }
    );
}
latch.await();

(11) 处理返回的响应内容
(12) 捕获返回异常,可能是由于连接错误,或者是返回特定的错误状态码

以上列举的每个方法都支持发送自定义请求头,通过Header对象参数设置:

Response response = restClient.performRequest("GET", "/", new BasicHeader("header", "value"));
------------------------------------
Header[] headers = {
        new BasicHeader("header1", "value1"),
        new BasicHeader("header2", "value2")
};
restClient.performRequestAsync("GET", "/", responseListener, headers);

读取响应

读取响应的一个关键对象是Response,它可以通过同步方法performRequest返回,或者通过ResponseListener#onSuccess(Response)方法参数接收,它是对http client的返回对象的一个封装,暴露了很多附加信息。

Response response = restClient.performRequest("GET", "/");
RequestLine requestLine = response.getRequestLine(); (1) 
HttpHost host = response.getHost(); // (2) 
int statusCode = response.getStatusLine().getStatusCode(); // (3)
Header[] headers = response.getHeaders(); // (4)
String responseBody = EntityUtils.toString(response.getEntity()); // (5)

(1) 请求的信息
(2) 响应的主机信息
(3) 响应状态行,例如你可以从中获取响应状态码
(4) 响应头信息,也可以使用getHeader(String)通过名称获取具体的响应头
(5) 响应体信息,在org.apache.http.HttpEntity对象中。

当执行请求抛出异常时(或者被ResponseListener#onFailure(Exception)参数接收时)会有如下的几种情况:

IOException:连接问题(例如:SocketTimeoutException)

ResponseException:响应返回,但是它的状态码表示错误(不是200)。一个ResponseException产生于一个有效的http响应,因此它暴露的对应的Response对象来访问返回响应。

注意! 一个ResponseException不会因为404响应码而抛出异常,因为404是一个很常见且我们希望得到的HEAD响应,它其实并不是错误,它简单的表示请求的资源没有找到。如果你非要想让所有其他的HTTP方法(例如:GET)因为404抛出ResponseException的话,可以设置ignore参数,让它包含404。ignore是一个特殊的客户端参数,它不会被发送给Elasticsearch,它包含一个以逗号分隔的错误状态码列表,它允许控制是否将一些错误状态码当做正常的响应还是抛出一个异常。这个特性非常实用,例如我们的 get api就可以返回404表示文档不存在,在这种情况下,响应体将不会包含一个错误,相反它是一个正常的get api响应,表示文档找不到的情况。

注意低级客户端不会为json的转换提供任何帮助,用户可以自由的使用他们想用的类库来实现这个目的。

底层的Apache Async Http Client提供了不同的org.apache.http.HttpEntity实现,允许使用不同的格式(stream, byte array, string等等)的请求体。至于读取响应体,HttpEntity#getContent方法能派上用场,它返回一个InputStream,从之前缓存的响应体中读取。作为替代,我们也可以提供一个org.apache.http.nio.protocol.HttpAsyncResponseConsumer的自定义实现来控制读取和缓存多少字节。

日志

Java REST Client使用跟Apache Async Http Client相同的日志库:Apache Commons Logging,它支持很多流行的日志实现。开启日志的java包,客户端本身是org.elasticsearch.client,sniffer组件是org.elasticsearch.client.sniffer

请求跟踪日志也可以被开启记录用curl发送的每一个请求和对应响应。这个特性在进行Debug时很有用,例如,万一有一个请求需要手动执行去检查是否还是会产生与之前相同的响应。导入tracer包来开启追踪日志记录功能,会打印出大量的详细的日志信息。一定注意这种类型的日志开销很大,不应该在生产环境中开启。并且当不用时最好暂停它。

公共配置

正如初始化客户端中所解释的那样,RestClientBuilder支持并提供一个RequestConfigCallback和一个HttpClientConfigCallback来允许我们自定义任何Apache Async Http Client暴露的配置。这些回调使我们可以在不覆盖RestClient初始化时指定的默认配置的情况下对特定的配置进行修改。这一节描述了一些常见的场景下Java REST Client需要做的额外配置。

超时时间

为客户端设置超时时间可以通过调用RestClientBuilder#setRequestConfigCallback方法实现,该方法需要一个RequestConfigCallback实例对象。RequestConfigCallback是一个接口,它有一个方法叫做customizeRequestConfig,接收一个org.apache.http.client.config.RequestConfig.Builder实例参数,并且返回同样的类型。请求配置构建器会被修改并返回。在下面的例子中,我们增加了连接的超时时间(默认1秒)和socket的超时时间(默认30秒)。当然我们也要相应的调整最大重试超时时间来跟socket超时时间相同。

RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200))
        .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
            @Override
            public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
                return requestConfigBuilder.setConnectTimeout(5000)
                        .setSocketTimeout(60000);
            }
        })
        .setMaxRetryTimeoutMillis(60000);

线程数量

Apache Http Async Client启动时,默认一个调度线程和一些工作线程,这些工作线程用来进行连接管理,工作线程的数量和本地处理器的数量相同(使用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());
            }
        });

基础身份验证

我们可以通过提供一个HttpClientConfigCallback来实现基础身份验证。通过构建RestClient的builder进行设置。HttpClientConfigCallback是一个接口,这个接口有一个方法,该方法接收一个org.apache.http.impl.nio.client.HttpAsyncClientBuilder实例作为参数,并且返回值是也是这个实例类型。http client builder可以被修改并返回。在下面的例子中我们设置了一个默认的凭证提供者(credentials provider)来提供基础的身份认证。

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) {
                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        });

抢先认证机制可以被禁用,这意味着每个请求发送时都不带授权头信息,然后看会不会被接受,当返回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(); // (1)
                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        });

(1) 禁用抢先认证

加密通信

加密通信也可以通过HttpClientConfigCallback进行配置。该接口有一个方法接收org.apache.http.impl.nio.client.HttpAsyncClientBuilder作为参数,暴露多个方法去配置加密通信:setSSLContextsetSSLSessionStrategysetConnectionManager,从最不重要的开始排序。如下是一个例子:

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/

嗅探器(Sniffer)

最小的客户端库允许在一个运行中的Elasticsearch集群中自动发现节点,并且设置它们到一个存在的RestClient实例中。它默认使用Nodes Info API从集群获取节点信息,并且使用Jackson转换获取到的json响应。

从Elasticsearch 2.x开始支持。

Javadoc

客户端Sniffer的javadoc可以在这里找到:https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-client-sniffer/6.2.2/index.html

Maven仓库

客户端嗅探器类库版本跟Elasticsearch保持一致。你只需要将版本设置为Elasticsearch的某一版本即可,类库版本从5.0.0-alpha4开始。支持嗅探器的Elasticsearch版本从2.x开始。嗅探器类库版本和Elasticsearch版本之间没有任何联系。

Maven配置

如下是使用Maven依赖管理工具时的配置。将配置添加到你的pom.xml文件中:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client-sniffer</artifactId>
    <version>6.2.2</version>
</dependency>
Gradle配置

如下是使用Gradle依赖管理工具时的配置。将配置添加到你的build.gradle文件中:

dependencies {
    compile 'org.elasticsearch.client:elasticsearch-rest-client-sniffer:6.2.2'
}

用法

一旦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线程以及它所占用的资源。Sniffer对象应该跟RestClient有相同的生命周期,并且在关闭时要先关闭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();

我们可以在出现错误时进行Sniffing,这意味着每当出现错误时会立即更新节点列表而不是等待下次更新周期。要实现这个功能,我们需要创建一个SniffOnFailureListener实例,然后在创建RestClient时指定FailureListener。然后当Sniffer创建后,它需要跟这个SniffOnFailureListener实例关联,当出现错误时这个监听器会被调用,并使用Sniffer去执行额外的sniffing。

SniffOnFailureListener sniffOnFailureListener = new SniffOnFailureListener();
RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200))
        .setFailureListener(sniffOnFailureListener) // (1) 
        .build();
Sniffer sniffer = Sniffer.builder(restClient)
        .setSniffAfterFailureDelayMillis(30000) // (2) 
        .build();
sniffOnFailureListener.setSniffer(sniffer); // (3)

(1) 设置监听器到RestClient实例
(2) 当探测到失败后,不但会立即更新节点信息,而且会有一个额外的探测行为会比正常的探测时间来的早一点,默认在失败后一分钟。假设这个事情会恢复正常,但我们希望尽快发现这一点。这里所说的时间间隔可以通过setSniffAfterFailureDelayMillis方法在嗅探器创建时进行自定义。注意如果没有开启失败探测功能,这个最后的配置参数不会就不会产生如上的作用。
(3) 给失败监听器(failure listener)设置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秒。这是在调用节点信息API时作为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();

另外,可以为高级用例提供自定义HostsSniffer实现.这些用例可能需要从外部源而不是从ElasticSearch获取主机。

RestClient restClient = RestClient.builder(
        new HttpHost("localhost", 9200, "http"))
        .build();
HostsSniffer hostsSniffer = new HostsSniffer() {
    @Override
    public List<HttpHost> sniffHosts() throws IOException {
        return null; // (1)
    }
};
Sniffer sniffer = Sniffer.builder(restClient)
        .setHostsSniffer(hostsSniffer).build();

(1) 从外部源获取主机

许可证

Copyright 2013-2017 Elasticsearch

根据Apache许可,版本2.0(“许可”)许可;除非符合许可,否则不得使用此文件。您可以在如下地址获得许可证的副本

http://www.apache.org/licenses/LICENSE-2.0

除非有适用法律的要求或书面同意,根据许可证分发的软件是在“原样”的基础上分发的,没有明示或隐含的任何种类的保证或条件。请参阅许可证中有关许可和限制的具体语言。

高级Java REST客户端(博主正在努力翻译中…)

NOTE! 6.0.0-beta1版本客户端开始支持

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值