在初始化TransportClient的时候,我们将嗅探模式开启,即client.transport.sniff设置为true.
Settings settings = Settings.settingsBuilder()
.put("client.transport.sniff", true).put("cluster.name", clusterName).build();
然后通过TransportClient client = TransportClient.builder().settings(settings).build(); 获取客户端。
再向客户端添加ES节点
client.addTransportAddresses(addrs);
在测试环境的ES集群包含3个节点node1,node2,node3。
我们将这3个节点都添加给client,即addrs中包含了node1,node2,node3的信息。
NodeSampler 有2个子类SniffNodesSampler,SimpleNodeSampler。如果开启了嗅探模式用SniffNodesSampler,否则用SimpleNodeSampler:
if (this.settings.getAsBoolean("client.transport.sniff", false)) {
this.nodesSampler = new TransportClientNodesService.SniffNodesSampler();
} else {
this.nodesSampler = new TransportClientNodesService.SimpleNodeSampler();
}
由于我们用的是嗅探模式,所以只关注SniffNodesSampler。
Iterator i$x = nodesToPing.iterator();
while(i$x.hasNext()) {
final DiscoveryNode listedNode = (DiscoveryNode)i$x.next();
TransportClientNodesService.this.threadPool.executor("management").execute(new Runnable() {
public void run() {
try {
if (!TransportClientNodesService.this.transportService.nodeConnected(listedNode)) {
try {
if (TransportClientNodesService.this.nodes.contains(listedNode)) {
TransportClientNodesService.this.logger.trace("connecting to cluster node [{}]", new Object[]{listedNode});
TransportClientNodesService.this.transportService.connectToNode(listedNode);
} else {
TransportClientNodesService.this.logger.trace("connecting to listed node (light) [{}]", new Object[]{listedNode});
TransportClientNodesService.this.transportService.connectToNodeLight(listedNode);
}
这里有2中连接,第一种是light connect,另外一种是fully connect。Light connect只建立1个channel,而fullyconnect建立了13个channel用于通信。13个channel的分布如下:
this.connectionsPerNodeRecovery = this.settings.getAsInt("transport.netty.connections_per_node.recovery", settings.getAsInt("transport.connections_per_node.recovery", 2));
this.connectionsPerNodeBulk = this.settings.getAsInt("transport.netty.connections_per_node.bulk", settings.getAsInt("transport.connections_per_node.bulk", 3));
this.connectionsPerNodeReg = this.settings.getAsInt("transport.netty.connections_per_node.reg", settings.getAsInt("transport.connections_per_node.reg", 6));
this.connectionsPerNodeState = this.settings.getAsInt("transport.netty.connections_per_node.high", settings.getAsInt("transport.connections_per_node.state", 1));
this.connectionsPerNodePing = this.settings.getAsInt("transport.netty.connections_per_node.ping", settings.getAsInt("transport.connections_per_node.ping", 1));
首次都会建立light connect。
TransportClientNodesService.this.transportService.sendRequest(listedNode, "cluster:monitor/state", (TransportRequest)TransportClientNodesService.this.headers.applyTo(Requests.clusterStateRequest().clear().nodes(true).local(true)), TransportRequestOptions.options().withType(Type.STATE).withTimeout(TransportClientNodesService.this.pingTimeout), new BaseTransportResponseHandler() {
public void handleResponse(ClusterStateResponse response) {
clusterStateResponses.put(listedNode, response);
latch.countDown();
}
}
HashSet newNodes = new HashSet();
HashSet newFilteredNodes = new HashSet();
Iterator i$xx = clusterStateResponses.entrySet().iterator();
while(true) {
while(i$xx.hasNext()) {
Entry entry = (Entry)i$xx.next();
if (!TransportClientNodesService.this.ignoreClusterName && !TransportClientNodesService.this.clusterName.equals(((ClusterStateResponse)entry.getValue()).getClusterName())) {
TransportClientNodesService.this.logger.warn("node {} not part of the cluster {}, ignoring...", new Object[]{((ClusterStateResponse)entry.getValue()).getState().nodes().localNode(), TransportClientNodesService.this.clusterName});
newFilteredNodes.add(entry.getKey());
} else {
Iterator i$xxx = ((ClusterStateResponse)entry.getValue()).getState().nodes().dataNodes().values().iterator();
while(i$xxx.hasNext()) {
ObjectCursor cursor = (ObjectCursor)i$xxx.next();
newNodes.add(cursor.value);
}
}
}
1~4这个过程默认没5秒钟会执行一次,因此集群的节点变化对client是可以感知到的。下图是transportClient 嗅探模式下创建连接的过程:
综上所述client最终会与listedNodes中的每个节点建立1个lightConnect ,与ES集群中每个节点建立一个full connect 。1个lightConnect=1个tcp连接;1个fullConnect=13个tcp连接。因此在本文的例子中transportClient将与集群中的每个节点建立14个tcp连接。
建立了fullConnect的节点都会放入nodes中用于处理请求。Client将会用round-robin的算法决定nodes中哪个节点处理请求。代码如下:
private int getNodeNumber() {
int index = this.randomNodeGenerator.incrementAndGet();
if (index < 0) {
index = 0;
this.randomNodeGenerator.set(0);
}
return index;
}
public void execute(TransportClientNodesService.NodeListenerCallback callback, ActionListener listener) {
List nodes = this.nodes;
this.ensureNodesAreAvailable(nodes);
int index = this.getNodeNumber();
TransportClientNodesService.RetryListener retryListener = new TransportClientNodesService.RetryListener(callback, listener, nodes, index);
DiscoveryNode node = (DiscoveryNode)nodes.get(index % nodes.size());
try {
callback.doWithNode(node, retryListener);
} catch (Throwable var8) {
listener.onFailure(var8);
}
}