All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aliyun.dts.subscribe.clients.check.util.NodeCommandClient Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
package com.aliyun.dts.subscribe.clients.check.util;

import org.apache.kafka.clients.*;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.Cluster;
import org.apache.kafka.common.Node;
import org.apache.kafka.common.config.AbstractConfig;
import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.common.metrics.JmxReporter;
import org.apache.kafka.common.metrics.MetricConfig;
import org.apache.kafka.common.metrics.Metrics;
import org.apache.kafka.common.metrics.MetricsReporter;
import org.apache.kafka.common.network.ChannelBuilder;
import org.apache.kafka.common.network.Selector;
import org.apache.kafka.common.requests.AbstractRequest;
import org.apache.kafka.common.requests.AbstractResponse;
import org.apache.kafka.common.requests.MetadataRequest;
import org.apache.kafka.common.requests.MetadataResponse;
import org.apache.kafka.common.utils.LogContext;
import org.apache.kafka.common.utils.SystemTime;
import org.apache.kafka.common.utils.Time;

import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class NodeCommandClient {

    public static final ConfigDef DEFAULT_CLIENT_CONFIG = NodeCommandClientConfig.configDef()
            .withClientSaslSupport()
            .withClientSslSupport();

    public static class CommandClientConfig extends AbstractConfig {
        public static CommandClientConfig fromNodeCommandClientConfig(NodeCommandClientConfig NodeCommandClientConfig) {
            return new CommandClientConfig(NodeCommandClientConfig.originals());
        }
        public CommandClientConfig(Map originals) {
            super(DEFAULT_CLIENT_CONFIG, originals);
        }
    }

    public static final class CommandClientProviderException extends RuntimeException {
        public CommandClientProviderException(String message, Exception e) {
            super(message, e);
        }
        public CommandClientProviderException(String message) {
            super(message);
        }
    }

    public static final class CommandClient {
        private final KafkaClient kafkaClient;
        private final CommandClientConfig commandClientConfig;
        private final List reporters;
        private static final int MAX_INFLIGHT_REQUESTS = 100;
        public CommandClient(CommandClientConfig config) {
            commandClientConfig = config;
            final Time time = new SystemTime();

            final Map metricTags = new LinkedHashMap<>();
            final String clientId = commandClientConfig.getString(NodeCommandClientConfig.CLIENT_ID_CONFIG);
            metricTags.put("client-id", clientId);
            final Metadata metadata = new Metadata(commandClientConfig.getLong(
                    NodeCommandClientConfig.RETRY_BACKOFF_MS_CONFIG),
                    commandClientConfig.getLong(NodeCommandClientConfig.METADATA_MAX_AGE_CONFIG), false
            );
            final List addresses = ClientUtils.parseAndValidateAddresses(commandClientConfig.getList(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG));
            metadata.update(Cluster.bootstrap(addresses), Collections.EMPTY_SET, time.milliseconds());

            final MetricConfig metricConfig = new MetricConfig().samples(commandClientConfig.getInt(CommonClientConfigs.METRICS_NUM_SAMPLES_CONFIG))
                    .timeWindow(commandClientConfig.getLong(CommonClientConfigs.METRICS_SAMPLE_WINDOW_MS_CONFIG), TimeUnit.MILLISECONDS)
                    .tags(metricTags);
            reporters = commandClientConfig.getConfiguredInstances(ProducerConfig.METRIC_REPORTER_CLASSES_CONFIG,
                    MetricsReporter.class);
            // TODO: This should come from the KafkaStream
            reporters.add(new JmxReporter("kafka.admin.client"));
            final Metrics metrics = new Metrics(metricConfig, reporters, time);

            final ChannelBuilder channelBuilder = ClientUtils.createChannelBuilder(commandClientConfig);
            final LogContext logContext = createLogContext(clientId);



            final Selector selector = new Selector(
                    commandClientConfig.getLong(NodeCommandClientConfig.CONNECTIONS_MAX_IDLE_MS_CONFIG),
                    metrics,
                    time,
                    "kafka-client",
                    channelBuilder,
                    logContext);

            kafkaClient = new NetworkClient(
                    selector,
                    metadata,
                    clientId,
                    MAX_INFLIGHT_REQUESTS, // a fixed large enough value will suffice
                    commandClientConfig.getLong(NodeCommandClientConfig.RECONNECT_BACKOFF_MS_CONFIG),
                    commandClientConfig.getLong(NodeCommandClientConfig.RECONNECT_BACKOFF_MAX_MS_CONFIG),
                    commandClientConfig.getInt(NodeCommandClientConfig.SEND_BUFFER_CONFIG),
                    commandClientConfig.getInt(NodeCommandClientConfig.RECEIVE_BUFFER_CONFIG),
                    commandClientConfig.getInt(NodeCommandClientConfig.REQUEST_TIMEOUT_MS_CONFIG),
                    time,
                    true,
                    new ApiVersions(),
                    logContext);
        }

        public void close() {
            if (null != kafkaClient) {
                try {
                    kafkaClient.close();
                } catch (Exception e) {
                }
            }
        }

        private Node ensureOneNodeIsReady(final List nodes) {
            Node brokerId = null;
            final long readyTimeout = Time.SYSTEM.milliseconds() + commandClientConfig.getInt(NodeCommandClientConfig.REQUEST_TIMEOUT_MS_CONFIG);
            boolean foundNode = false;
            while (!foundNode && (Time.SYSTEM.milliseconds() < readyTimeout)) {
                for (Node node: nodes) {
                    if (kafkaClient.ready(node, Time.SYSTEM.milliseconds())) {
                        brokerId = node;
                        foundNode = true;
                        break;
                    }
                }
                try {
                    kafkaClient.poll(commandClientConfig.getLong(NodeCommandClientConfig.POLL_MS_CONFIG), Time.SYSTEM.milliseconds());
                } catch (final Exception e) {
                    throw new CommandClientProviderException("Could not poll.", e);
                }
            }
            if (brokerId == null) {
                throw new CommandClientProviderException("Could not find any available broker. " +
                        "Check your NodeCommandClientConfig setting '" + NodeCommandClientConfig.BOOTSTRAP_SERVERS_CONFIG + "'. " +
                        "This error might also occur, if you try to connect to pre-0.10 brokers. " +
                        "Kafka Streams requires broker version 0.10.1.x or higher.");
            }
            return brokerId;
        }

        private ClientResponse sendRequestSync(final ClientRequest clientRequest) {
            try {
                kafkaClient.send(clientRequest, Time.SYSTEM.milliseconds());
            } catch (final Exception e) {
                throw new CommandClientProviderException("Could not send request.", e);
            }
            final long responseTimeout = Time.SYSTEM.milliseconds() + commandClientConfig.getInt(NodeCommandClientConfig.REQUEST_TIMEOUT_MS_CONFIG);
            // Poll for the response.
            while (Time.SYSTEM.milliseconds() < responseTimeout) {
                final List responseList;
                try {
                    responseList = kafkaClient.poll(commandClientConfig.getLong(NodeCommandClientConfig.POLL_MS_CONFIG), Time.SYSTEM.milliseconds());
                } catch (final IllegalStateException e) {
                    throw new CommandClientProviderException("Could not poll.", e);
                }
                if (!responseList.isEmpty()) {
                    if (responseList.size() > 1) {
                        throw new CommandClientProviderException("Sent one request but received multiple or no responses.");
                    }
                    ClientResponse response = responseList.get(0);
                    if (response.requestHeader().correlationId() == clientRequest.correlationId()) {
                        return response;
                    } else {
                        throw new CommandClientProviderException("Inconsistent response received from the broker "
                                + clientRequest.destination() + ", expected correlation id " + clientRequest.correlationId()
                                + ", but received " + response.requestHeader().correlationId());
                    }
                }
            }
            throw new CommandClientProviderException("Failed to get response from broker within timeout");

        }

        private  T doRequest(Node destination, AbstractRequest.Builder builder,
                                                         Class type, String typeName) {
            ensureOneNodeIsReady(Arrays.asList(destination));
            if (null == destination || destination.isEmpty()) {
                throw new CommandClientProviderException("destination is required");
            }
            final ClientRequest clientRequest = kafkaClient.newClientRequest(
                    destination.idString(),
                    builder,
                    Time.SYSTEM.milliseconds(),
                    true);
            final ClientResponse clientResponse = sendRequestSync(clientRequest);

            if (!clientResponse.hasResponse()) {
                throw new CommandClientProviderException("Empty response for client request.");
            }
            if (!type.isAssignableFrom(clientResponse.responseBody().getClass())) {
                throw new CommandClientProviderException("Inconsistent response type for internal topic  " + typeName + "Request. " +
                        "Expected " + typeName + "Response but received " + clientResponse.responseBody().getClass().getName());
            }
            return (T)(clientResponse.responseBody());

        }

        public MetadataResponse fetchMetadata() {
            return doRequest(getAnyReadyBrokerId(), MetadataRequest.Builder.allTopics(),
                    MetadataResponse.class,
                    "MetaData");
        }

        private static final AtomicInteger incrementCounter = new AtomicInteger(100);

        private Node getAnyReadyBrokerId() {
            final Metadata metadata = new Metadata(
                    commandClientConfig.getLong(NodeCommandClientConfig.RETRY_BACKOFF_MS_CONFIG),
                    commandClientConfig.getLong(NodeCommandClientConfig.METADATA_MAX_AGE_CONFIG),
                    false);
            final List addresses = ClientUtils.parseAndValidateAddresses(commandClientConfig.getList(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG));
            metadata.update(Cluster.bootstrap(addresses), Collections.EMPTY_SET, Time.SYSTEM.milliseconds());

            final List nodes = metadata.fetch().nodes();
            return ensureOneNodeIsReady(nodes);
        }
    }

    private static LogContext createLogContext(String clientId) {
        return new LogContext("[NodeCommandClient clientId=" + clientId + "] ");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy