ES的transportClient初始化过程解析

TransportClient的初始化流程

创建client的代码

在初始化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的信息。

初始化客户端流程

  • 1、 addrs中的节点信息将会被放入listedNodes中。
  • 2、 TransportClientNodesService.NodeSampler 的sample()中去建立tcp连接。

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。

1、 将listedNodes的节点信息加载到nodesToPing中

2、 与nodesToPing中的每个节点都建立一个tcp连接。

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的分布如下:

  • recovery:做数据恢复recovery,默认个数2个;
  • bulk:用于bulk请求,默认个数3个;
  • med/reg:典型的搜索和单doc索引,默认个数6个;
  • state:如集群state的发送等,默认个数1个;
  • ping:就是node之间的ping咯。默认个数1个;
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。

3、 通过light connect获取集群的state信息,解析出datanode,生成newNodes

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);
                        }
                    }
                }

4、 与newNodes中的每个节点都建立full connect,并且将newNodes的节点放入nodes中。

1~4这个过程默认没5秒钟会执行一次,因此集群的节点变化对client是可以感知到的。下图是transportClient 嗅探模式下创建连接的过程:
ES的transportClient初始化过程解析_第1张图片

综上所述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);
        }
    }

你可能感兴趣的:(elasticsearch)