Elasticsearch 內置的兩個客戶端的區別

Java連接ElasticSearch詳解

Java連接ES有兩種連接方式(即獲得ES的Client)

1、創建一個node,加入集羣中,通過這個node獲得client。

2、通過TransportClient來連接集羣。

區別

第一種方式,相當於額外啓動了一個es的node節點,只是這個node是由我們編碼控制的,可以設置成這個node是不存數據的節點(沒有特殊原因你就應該這麼設置),這個節點的配置和其他的節點沒有什麼區別,也是通過elasticsearch.yml文件來配置,配置文件放在classpath目錄下面,當然你也可以通過編程的方式,在構建node的時候,設置settings參數。

Settings settings = ImmutableSettings.settingsBuilder().put(“client.transport.ping_timeout”, 1000)
.put(“discovery.zen.ping.multicast.enabled”, “false”).put(“timeout”, 1)
.putArray(“discovery.zen.ping.unicast.hosts”, “l-flightdev18.f.dev.cn0.qunar.com:9300”, “l-flightdev17.f.dev.cn0.qunar.com:9300”)
.build();
Node node = NodeBuilder.nodeBuilder().clusterName(“flight_fuwu_order_index”).client(true).settings(settings).node();
Client client = node.client();
第二種方法,相當於獲取了所有node節點的client,發送請求的時候遍歷當前可用的client(這裏可用指的是可以連接,但是node本身不一定可用,比如node正在恢復中,還沒有加入集羣,這會產生問題,見下面)。跟方法一相比,方法二會產生雙跳(double hop),即當前遍歷到node1,但訪問的數據在node2,請求先發到node1,又由node1轉發到node2。

遍歷方式:每次請求通過AtomicInteger進行原子加1(超出最大值後設置成0),按當前可用client數取模。

獲取當前可用client的方法:使用線程池,遍歷所有client,如果client未連接,嘗試一次連接,連接成功加入可用client中,如果client已連接直接加入可用client。

可以通過設置參數client.transport.sniff是否爲true,來設置是使用SimpleNodeSampler還是SniffNodesSampler,默認值爲false,即使用SimpleNodeSampler。

具體實現在org.elasticsearch.client.transport.TransportClientNodesService類中。

簡單的說,SimpleNodeSampler會限制當前可用client一定是在配置中設置的節點中的,而SniffNodesSampler會使用所有發現的client,即使這個client的node,不在配置中。

Settings settings = ImmutableSettings.settingsBuilder().put(“cluster.name”, clustersName).put( “client.transport.ping_timeout”, 1000).put(“discovery.zen.ping.multicast.enabled”, “false”).put( “timeout”, 1)// .put(“client.transport.sniff”, true) .build();

    TransportClient transportClient = new TransportClient(settings);        for (String cluster : StringUtils.split(clusters,",")) {
        transportClient.addTransportAddress(new InetSocketTransportAddress("host1", 9300))
    .addTransportAddress(new InetSocketTransportAddress("host2", 9300));
    }

方法二有個問題,就是當集羣中某個node掛掉之後,重新加入的時候,因爲是通過判斷client是否可以連接,而不是node是否可用,這會導致這個時候使用這個client發送請求的時候產生異常。而方法一不會,因爲還沒加入集羣的node,對於自己創建的node來說是不可見的。

Elasticsearch本身是JAVA開發的,天生對JAVA的支持能力是最好的,所以用JAVA來開發Elasticsearch應該是一個不錯的選擇。可以把JAVA開發看出CS模式,客戶端請求,服務端響應,所有的操作是完全異步的。此外在客戶端上操作,很多的操作可以在客戶端上來完成,增加了系統效率。JAVA客戶端和服務端都是使用相同的程序。

配置

mvn倉庫,在mvn項目中可以在pom.xml增加mvn倉庫。

?
1
2
3
4
5

org.elasticsearch
elasticsearch
${es.version}

打成獨立的jar包。如果你想打成獨立的jar包,幷包含所有的依賴。不能使用mvn的maven-assembly-plugin插件,因爲他不能很好的處理 META-INF/services結構。我們可以用 maven-shade-plugin插件來進行打包。例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

org.apache.maven.plugins
maven-shade-plugin
2.4.1


package
shade







如果你有一個main函數,可以通過調用java -jar yourjar.jar運行時,只需要在插件配置中加入一句話:例如:

?
1
2
3

com.secisland.es.demo.main

可以使用多種方式來調用JAVA客戶端。

一種方式是把節點加入集羣,不存儲數據。

另一種是把節點作爲客戶端連接到集羣。

注意:客戶端版本要和集羣版本一致,否則有可能出現不可預知的錯誤。

嵌入式節點客戶端

實例化一個基於節點的客戶,這是對Elasticsearch執行操作的最簡單的方法。例如:

?
1
2
3
4
5
6
import static org.elasticsearch.node.NodeBuilder.*;
// on startup
Node node = nodeBuilder().node();
Client client = node.client();
// on shutdown
node.close();
當你開始一個節點,它加入了一個Elasticsearch集羣。你可以通過設置cluster.name來配置不同的集羣,或顯式使用clusterName方法來創建對象。在項目工程中可以定義cluster.name,配置在/src/main/resources/elasticsearch.yml文件中。只要在classpath中能找到elasticsearch.yml文件,節點啓動的時候就會加載此文件。配置文件中定義:

?
1
cluster.name: secilog
或者在java代碼中指定:

?
1
2
Node node = nodeBuilder().clusterName(“secilog”).node();
Client client = node.client();
使用客戶端的好處是依賴Elasticsearch服務端的特性吧需要執行的操作自動路由到節點,當加入集羣節點作爲客戶端時,最重要的是不能再此節點上增加數據保存,這可以通過配置來完成。把node.data設置爲false或node.client設置true。這都可以通過NodeBuilder的方法來實現。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import static org.elasticsearch.node.NodeBuilder.*;

// on startup
// 嵌入式節點可以不用打開http端口
Node node =
nodeBuilder()
.settings(Settings.settingsBuilder().put(“http.enabled”, false))
.client(true)
.node();

Client client = node.client();

// on shutdown
node.close();

另一個常見的客戶端用處是用在單位/集成測試中。在這種情況下,只需要啓動一個“本地(local)”節點。這裏的local節點的意思是公用一個 Java虛擬機(JVM)。在這種情況下兩個服務會互相發現自己並形成一個集羣。例如:

?
1
2
3
4
5
6
7
8
import static org.elasticsearch.node.NodeBuilder.*;

// on startup
Node node = nodeBuilder().local(true).node();
Client client = node.client();

// on shutdown
node.close();
嵌入式節點的缺點:

頻繁啓動和停止一個或多個節點在羣集上會創建不必要的噪聲。

就像其他節點一樣嵌入式節點客戶端會響應外部請求。

注意:用eclipse開發的時候有可能會報錯。

Exception in thread “main” java.lang.IllegalStateException: path.home is not configured

解決方法:在main方法的類中右鍵選擇run configurations,在Arguments標籤頁下的vm arguments輸入:-Des.path.home=-Des.path.home即可。比如:

?
1
-Des.path.home=D:\elasticsearch-2.2.0
通過連接的客戶端

客戶端通過TransportClient對象可以使用遠程連接的方式連接Elasticsearch集羣。這種情況下不用加入集羣,比較像傳統的CS程序的架構,比如數據庫連接。例如:

?
1
2
3
4
5
6
7
// on startup
Client client = TransportClient.builder().build()
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(“host1”), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(“host2”), 9300));

// on shutdown
client.close();
注意:如果羣集名稱不是“Elasticsearch”,你必須設置集羣名稱或者使用elasticsearch.yml配置文件在客戶端工程中配置。可以連接一個集羣中的多個節點。

?
1
2
3
Settings settings = Settings.settingsBuilder()
.put(“cluster.name”, “secilog”).build();
Client client = TransportClient.builder().settings(settings).build();
你可以設置client.transport.sniff爲true來使客戶端去嗅探整個集羣的狀態,把集羣中其它機器的ip地址加到客戶端中,這樣做的好處是一般你不用手動設置集羣裏所有集羣的ip到連接客戶端,它會自動幫你添加,並且自動發現新加入集羣的機器。

?
1
2
3
Settings settings = Settings.settingsBuilder()
.put(“client.transport.sniff”, true).build();
TransportClient client = TransportClient.builder().settings(settings).build();
其他參數說明

參數 描述
client.transport.ignore_cluster_name 設置爲true的時候忽略連接節點時的羣集名稱驗證。
client.transport.ping_timeout 等待一個節點的ping響應的時間,默認5秒。
client.transport.nodes_sampler_interval 監聽和連接節點的頻率,默認5秒。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章