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();
注意:client(true)很重要,这标示当前节点不存储数据
方法一有个问题,如果服务和ES集群不在一个机房,网络延迟会导致作为node节点接入ES集群的服务成为ES集群的短板
第二种方法,相当于获取了所有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来说是不可见的。gitbub上有对这个问题的讨论:https://github.com/elastic/elasticsearch/issues/11202