使用Kafka、Elasticsearch、Grafana搭建业务监控系统(二)Kafka

系列目录

使用Kafka、Elasticsearch、Grafana搭建业务监控系统(一)技术选择
使用Kafka、Elasticsearch、Grafana搭建业务监控系统(二)Kafka
使用Kafka、Elasticsearch、Grafana搭建业务监控系统(三)Elasticsearch
使用Kafka、Elasticsearch、Grafana搭建业务监控系统(四)Grafana(填坑ing)

一、Kafka是什么

Kafka是LinkedIn开源的分布式发布-订阅消息系统,目前归属于Apache定级项目。Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务。

Kafka中的一些基本概念:

  • producer:消息生产者,发布消息到 kafka 集群的终端或服务。
  • broker:kafka 集群中包含的服务器。
  • topic:每条发布到 kafka 集群的消息属于的类别,即 kafka 是面向 topic 的。
  • partition:partition 是物理上的概念,每个 topic 包含一个或多个 partition。kafka 分配的单位是 partition。
  • consumer:从 kafka 集群中消费消息的终端或服务。
  • consumer group:high-level consumer API 中,每个 consumer 都属于一个 consumer group,每条消息只能被 consumer group 中的一个 Consumer 消费,但可以被多个 consumer group 消费。
  • replica:partition 的副本,保障 partition 的高可用。
  • leader:replica 中的一个角色, producer 和 consumer 只跟 leader 交互。
  • follower:replica 中的一个角色,从 leader 中复制数据。
  • controller:kafka 集群中的其中一个服务器,用来进行 leader election 以及 各种 failover。
  • zookeeper:kafka 通过 zookeeper 来存储集群的 meta 信息。

Kafka原理可以参考kafka原理和实践(一)原理:10分钟入门,本地windows下测试环境搭建参考Windows平台下kafka环境的搭建,本文不过多介绍
下面主要介绍Kafka结合spring的配置/使用、项目中的一些细节以及遇到的坑

二、spring-kafka配置

pom文件配置
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>0.11.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>1.1.6.RELEASE</version>
        </dependency>

公司kafka使用的0.11.0.1版本,spring全家桶就不写上去了,项目一开始用的公司通用版本4.1.6,后来改用的4.2.5版本(这个坑在elasticsearch篇会提到)

consumer配置
    <!-- 大数据埋点kafka -->
    <bean id="consumerProperties" class="java.util.HashMap">
        <constructor-arg>
            <map>
                <entry key="bootstrap.servers" value="xxx.xx.xx.xx:xxxx" /><!--brokers集群 -->
                <entry key="group.id" value="business-monitor" /><!--消费者群组ID,发布-订阅模式,即如果一个生产者,多个消费者都要消费,那么需要定义自己的群组,同一群组内的消费者只有一个能消费到消息 -->
                <entry key="enable.auto.commit" value="false" /><!--如果为true,消费者的偏移量将在后台定期提交。 -->
                <!--<entry key="auto.commit.interval.ms" value="1000" />如果设置为自动提交(enable.auto.commit=true),这里设置自动提交周期 -->
                <entry key="session.timeout.ms" value="30000" /><!--在使用Kafka的组管理时,用于检测消费者故障的超时 -->
                <entry key="fetch.max.bytes" value="3000000" /> <!-- 一次fetch记录的最大容量 -->
                <entry key="max.poll.records" value="1000" /> <!-- 一次poll的记录数 -->
                <entry key="key.deserializer"
                    value="org.apache.kafka.common.serialization.StringDeserializer" />
                <entry key="value.deserializer"
                    value="org.apache.kafka.common.serialization.StringDeserializer" />
            </map>
        </constructor-arg>
    </bean>
    
    
    
    <!-- 创建consumerFactory bean -->
    <bean id="consumerFactory"
        class="org.springframework.kafka.core.DefaultKafkaConsumerFactory">
        <constructor-arg ref="consumerProperties" />
    </bean>
    
    
    
    <!-- 消费埋点数据topic名称为A的消息 -->
    <!-- 消费者容器配置信息 -->
    <bean id="containerProperties-A"
        class="org.springframework.kafka.listener.config.ContainerProperties">
        <!--配置topic -->
        <constructor-arg value="A" />
        <!-- ref的值就是之后注入spring的监听类名 -->
        <property name="messageListener" ref="NgLogConsumerListener" />
        <!--设置手动提交 -->
        <property name="ackMode" value="MANUAL" />
    </bean>
    <!--容器 -->
    <bean id="messageListenerContainer-A"
        class="org.springframework.kafka.listener.ConcurrentMessageListenerContainer"
        init-method="doStart">
        <constructor-arg ref="consumerFactory" />
        <constructor-arg ref="containerProperties-A" />
    </bean>
    
    
    <!-- 消费埋点数据topic名称为B的消息 -->
    <!-- 消费者容器配置信息 -->
    <bean id="containerProperties-B"
        class="org.springframework.kafka.listener.config.ContainerProperties">
        <!-- 重要!配置topic -->
        <constructor-arg value="B" />
        <!-- ref的值就是之后注入spring的监听类名 -->
        <property name="messageListener" ref="NgLogConsumerListener" />
        <!--设置手动提交 -->
        <property name="ackMode" value="MANUAL" />
    </bean>
    <!--容器 -->
    <bean id="messageListenerContainer-B"
        class="org.springframework.kafka.listener.ConcurrentMessageListenerContainer"
        init-method="doStart">
        <constructor-arg ref="consumerFactory" />
        <constructor-arg ref="containerProperties-B" />
    </bean>
    
    <!-- 消费更多的topic同理 -->

consumer配置如上所示,说几个重要参数:
bootstrap.servers:部署的brokers集群,用,分隔
group.id:消费者群组id,同一个groupid下只有一个消费者能消费到数据,这样解决了在多jvm下重复消费的问题
enable.auto.commit:offset是否自动提交,我这里设置为了false,即手动提交,后面会有说明
fetch.max.bytes: 一次fetch记录的最大容量,根据实际业务决定
max.poll.records:一次poll的记录数,根据实际业务决定

producer配置

埋点数据已经存储在大数据方的kafka中,我们并不是生产者,只需要消费就行了。
当然,在之后的迭代中我们开发了对外的SDK,只要pom引入我们的sdk就可以将想要分析的数据存储在我们提供的Kafka中,这在之后会有详细介绍

三、代码实现

因为消费过程中还会有复杂的业务逻辑,所以我们将消费Service放入线程池中异步执行。

配置spring线程池
	<!-- 线程池 -->
    <bean id="kafkaConsumerTaskExecutor"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 核心线程数 -->
        <property name="corePoolSize" value="25" />
        <!-- 最大线程数 -->
        <property name="maxPoolSize" value="50" />
        <!-- 队列最大长度 -->
        <property name="queueCapacity" value="3000" />
        <!-- 线程池维护线程所允许的空闲时间 -->
        <property name="keepAliveSeconds" value="300" />
        <!-- 线程池销毁前,调用shutdown方法,而不是shutdownNow方法 -->
        <property name="waitForTasksToCompleteOnShutdown" value="true" />
        <!-- 线程池对拒绝任务(无线程可用)的处理策略 -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
        </property>
    </bean>

具体参数值根据业务来决定

消费代码

//import包省略

@Component
public class NgLogConsumerListener implements BatchAcknowledgingMessageListener<String, String> {

    /**
     * 日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(NgLogConsumerListener.class);

    @Autowired
    private NgLogConsumerService ngLogConsumerService;

    /**
     * 消费处理线程池
     */
    @Autowired
    @Qualifier("kafkaConsumerTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public void onMessage(List<ConsumerRecord<String, String>> data, Acknowledgment acknowledgment) {

        if (CollectionUtils.isEmpty(data)) {
            return;
        }

        final List<ConsumerRecord<String, String>> consumerRecordList = data;

        try {
            threadPoolTaskExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    //监听后的具体逻辑(处理数据写入ES)
                    ngLogConsumerService.handleData(consumerRecordList);
                }
            });
        } catch (Exception e) {
            LOGGER.error("往消费线程池添加任务异常. data={}, ExceptionMsg={}", JSON.toJSONString(data), e.getMessage(), e);
            return;
        }

        try {
            //手动提交offset
            acknowledgment.acknowledge();
        } catch (Exception e) {
            LOGGER.error("send ack error. data={}, ExceptionMsg={}", JSON.toJSONString(data), e.getMessage(), e);
        }
    }
}

这样一套Kafka的消费流程就结束了,上面的消费代码中有几个注意的地方:

  • 因为我们配置的手动提交,所以需要实现BatchAcknowledgingMessageListener这个类,并且在最后通过acknowledgment.acknowledge();手动提交偏移量。如果是自动提交则需要实现BatchMessageListener
    还有2个可以实现的类:MessageListenerAcknowledgingMessageListener,从名字上就可以看出来这两个区别在于不是批量处理的
  • 之后通过遍历data,其中的value就是我们写入的内容

之后就是具体的业务逻辑了,也就是处理数据,写入ES,但在这之前我们再看看之前提到的producer

四、提供生产者sdk

项目初期我都是在消费客户端已经存储在大数据端的埋点数据,但随着项目的迭代,项目组其他项目想接入监控项目。这时候我就需要向运维申请一个自用的Kafka环境,并提供接入方一个写入Kafka的sdk以及数据规约。

定义接入方数据格式

接入系统需要提供的业务数据为javabean:AgentMessage,其中包含3个参数

字段名是否必填类型描述取值
appNameString业务名 用于命名topic以及ES索引
不填则从jvm参数中读取app.name参数 建议不填写
举例:“projectname”
typeString业务功能名 用于决定ES中的type名举例:“businessname”
sourcecom.alibaba.fastjson.JSONObject业务数据,接入方需将数据封装为JSONObject接入方自己决定,用于以后grafana分析

说明:appName是公司规定的每个项目的名字,存在jvm参数中,也可以手动提供
type相当于是你要分析业务的名称,比如download、install,我们会将其作为ES中type的名字
source就是真正的业务数据,我们要求使用方封装为JSONObject,方便维护

sdk pom文件
<dependencies>
    <!-- kafka client -->
    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>0.11.0.1</version>
    </dependency>
    <!-- json start -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.29</version>
        <scope>provided</scope>
    </dependency>
    <!-- json end -->

    <!-- 其余依赖省略 根据实际情况添加 -->
    <dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <!-- 发布到公司私服 参数根据实际情况填写 -->
    <distributionManagement>
        <repository>
            <id>nexus-releases</id>
            <name>Local Nexus Repository</name>
            <url>http://nexus.********</url>
        </repository>
    </distributionManagement>
sdk util
//省略import包

public class MonitorUtil {

    /**
     * log
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorUtil.class);

    private static volatile Producer<String, String> producer;

    private static String appName;

    private static volatile ThreadPoolExecutor executor;

    /**
     * 单条收集数据
     * 
     * @Description:
     * @param message
     *            需要将业务参数封装成 AgentMessage
     * @Author:
     * @see:
     * @since: 1.0
     */
    public static void sendData(AgentMessage message) {
        final AgentMessage finalMessage = message;
        ThreadPoolExecutor executor = getExecutor();
        try {
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    send(finalMessage);
                }
            });
        } catch (Exception e) {
            LOGGER.error("往生产线程池添加任务异常,message:{},errorMsg:{}", JSON.toJSONString(finalMessage), e.getMessage(), e);
        }
    }

    /**
     * 发送kafka模板
     */
    private static void send(final AgentMessage message) {
        final Producer<String, String> producer = getProducer();
        // 如果使用者未提供appName,则使用jvm中的参数
        if (StringUtils.isBlank(message.getAppName())) {
            if (!StringUtils.isBlank(appName)) {
                message.setAppName(appName);
            } else {
                LOGGER.warn("jvm获取不到appName并且使用者也未提供appName");
                return;
            }
        }
        //topic名称由前缀+项目名组成
        String topic = "monitor_" + message.getAppName();
        producer.send(new ProducerRecord<String, String>(topic, JSON.toJSONString(message)), new Callback() {
            @Override
            public void onCompletion(RecordMetadata metadata, Exception e) {
                if (e != null) {
                    LOGGER.error("send record error,msg:{},errorMsg:{}", JSON.toJSONString(message), e.getMessage(), e);
                }
            }
        });
    }

    /**
     * 创建线程池
     */
    private static ThreadPoolExecutor getExecutor() {
        if (executor == null) {
            synchronized (MonitorUtil.class) {
                if (executor == null) {
                    BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(3000);
                    RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
                    executor = new ThreadPoolExecutor(25, 50, 300, TimeUnit.SECONDS, queue, handler);
                }
            }
        }
        return executor;
    }

    /**
     * 单例模式--懒加载
     */
    private static Producer<String, String> getProducer() {
        if (producer == null) {
            synchronized (MonitorUtil.class) {
                if (producer == null) {
                    producer = new KafkaProducer<>(createProps());
                }
            }
        }
        return producer;
    }

    /**
     * 创建kafka所需要的配置文件
     */
    private static Properties createProps() {
        // 从jvm里拿到app Name 用于topic的名字以及以后ES索引的前缀
        appName = System.getProperty("app.name");

        Properties props = new Properties();
        // 服务器ip:端口号,集群用逗号分隔
        props.put("bootstrap.servers", ConfigManager.get("monitor.kafka.bootstrap.servers"));
        // 即所有副本都同步到数据时send方法才返回, 以此来完全判断数据是否发送成功, 理论上来讲数据不会丢失.
        props.put("acks", ConfigManager.get("monitor.kafka.acks", "all"));
        // 发送失败重试次数
        props.put("retries", ConfigManager.getInteger("monitor.kafka.retries", 3));
        // 批处理条数:当多个记录被发送到同一个分区时,生产者会尝试将记录合并到更少的请求中。这有助于客户端和服务器的性能。
        props.put("batch.size", ConfigManager.getInteger("monitor.kafka.batch.size", 16384));
        // 批处理延迟时间上限:即10ms过后,不管是否达到批处理数,都直接发送一次请求
        props.put("linger.ms", ConfigManager.getInteger("monitor.kafka.linger.ms", 10));
        // 即32MB的批处理缓冲区
        props.put("buffer.memory", ConfigManager.getInteger("monitor.kafka.buffer.memory", 33554432));
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        return props;
    }
}

使用者调用MonitorUtil.sendData(AgentMessage message)方法即可,内部采用了异步处理,保证主线业务的通畅

The producer is thread safe and sharing a single producer instance across threads will generally be faster than having multiple instances.

由于KafkaProducer是线程安全的,并且官方推荐我们使用一个实例去发送消息,所以我们这里采用单例模式创建KafkaProducer
参考:Class KafkaProducer<K,V>官方文档

介绍一下producer的参数以及我自定义的默认值:

字段名是否必填描述取值(根据实际业务调整)
monitor.kafka.bootstrap.serverskafka服务器地址,集群用逗号分隔。由业务监控系统提供需接入方填写,具体值请咨询业务监控开发人员
monitor.kafka.acks0: 不需要进行确认,速度最快。存在丢失数据的风险。
1: 仅需要Leader进行确认,不需要ISR进行确认。是一种效率和安全折中的方式。
all: 需要ISR中所有的Replica给予接收确认,速度最慢,安全性最高,但是由于ISR可能会缩小到仅包含一个Replica,所以设置参数为all并不能一定避免数据丢失。
[all, 0, 1] 默认all
monitor.kafka.retries发送失败重试次数默认3
monitor.kafka.batch.size批处理条数:当多个记录被发送到同一个分区时,生产者会尝试将记录合并到更少的请求中。这有助于客户端和服务器的性能。默认16384字节(16kb)
monitor.kafka.linger.ms批处理延迟时间上限:即N ms过后,不管是否达到批处理数,都直接发送一次请求默认10ms
monitor.kafka.buffer.memory批处理缓冲区默认33554432字节(32MB)

先说明一下避免误解:ConfigManager是公司的中间件,用来读取配置中心的数据。ConfigManager.get(String key, String defaultValue)两个参数分别为key和默认值(读取不到就使用默认值),monitor.kafka这个前缀只是我用在配置中心的,Properties 中的参数是没有的这个前缀的

producer性能影响关键的2个参数:batch.size以及linger.ms

batch.size

The producer will attempt to batch records together into fewer requests whenever multiple records are being sent to the same partition. This helps performance on both the client and the server. This configuration controls the default batch size in bytes.
No attempt will be made to batch records larger than this size.
Requests sent to brokers will contain multiple batches, one for each partition with data available to be sent.
A small batch size will make batching less common and may reduce throughput (a batch size of zero will disable batching entirely). A very large batch size may use memory a bit more wastefully as we will always allocate a buffer of the specified batch size in anticipation of additional records.

producer将试图批处理消息记录,以减少请求次数。这将改善client与server之间的性能。这项配置控制默认的批量处理消息字节数。不会试图处理大于这个字节数的消息字节数。
发送到brokers的请求将包含多个批量处理,其中会包含对每个partition的一个请求。
较小的批量处理数值比较少用,并且可能降低吞吐量(0则会仅用批量处理)。较大的批量处理数值将会浪费更多内存空间,这样就需要分配特定批量处理数值的内存大小。

linger.ms

The producer groups together any records that arrive in between request transmissions into a single batched request. Normally this occurs only under load when records arrive faster than they can be sent out. However in some circumstances the client may want to reduce the number of requests even under moderate load. This setting accomplishes this by adding a small amount of artificial delay—that is, rather than immediately sending out a record the producer will wait for up to the given delay to allow other records to be sent so that the sends can be batched together. This can be thought of as analogous to Nagle’s algorithm in TCP. This setting gives the upper bound on the delay for batching: once we get batch.size worth of records for a partition it will be sent immediately regardless of this setting, however if we have fewer than this many bytes accumulated for this partition we will ‘linger’ for the specified time waiting for more records to show up. This setting defaults to 0 (i.e. no delay). Setting linger.ms=5, for example, would have the effect of reducing the number of requests sent but would add up to 5ms of latency to records sent in the absence of load.

producer组将会汇总任何在请求与发送之间到达的消息记录一个单独批量的请求。通常来说,这只有在记录产生速度大于发送速度的时候才能发生。然而,在某些条件下,客户端将希望降低请求的数量,甚至降低到中等负载一下。这项设置将通过增加小的延迟来完成–即,不是立即发送一条记录,producer将会等待给定的延迟时间以允许其他消息记录发送,这些消息记录可以批量处理。这可以认为是TCP种Nagle的算法类似。这项设置设定了批量处理的更高的延迟边界:一旦我们获得某个partition的batch.size,他将会立即发送而不顾这项设置,然而如果我们获得消息字节数比这项设置要小的多,我们需要“linger”特定的时间以获取更多的消息。 这个设置默认为0,即没有延迟。设定linger.ms=5,例如,将会减少请求数目,但是同时会增加5ms的延迟。

配置这2个参数的目的是让我们实现批量发送的需求,batch.size默认值是16kb,这个可以根据实际业务量进行调整;linger.ms默认值是0ms,相等于立刻发送,这里我修改为10ms
满足batch.size和linger.ms之一,producer便开始发送消息。

到这里,提供给接入方的sdk就开发完成了,发布到私服后接入方只要pom依赖一下就好了

作为消费方,由于Kafka的broker地址不一样,还需要在配置文件中再配置一个map以及监听的topic,监听类代码同上

五、遇到的坑及一些细节

  1. consumerfetch.message.max.bytes是老的配置,在0.9.0.0版本后采用新的配置,应该替换为fetch.max.bytes,否则启动服务时会有warn日志
    在这里插入图片描述
    详细参数说明请参考New Consumer Configs
  2. 对kafka的指定topic新增groupid后,发现大量数据进入监控系统,消费了历史数据。
    原因分析:消费方对已存在的topic建立新groupid准备消费数据,是可以设置消费的初始offset。默认情况下是从消费方启动服务的当前时间开始消费新数据,不会消费历史数据。但是监控系统在上线1.0.1版本后,发现有功能bug导致回滚,而此时在kafka server端已经给监控系统创建好了group,并且offset已经置为1.0.1版本的上线时间时的值。在1.0.2版本上线后,导致期间的产生的大量数据进入系统。
    解决方案:提前识别风险,停止消费数据,请kafka管理员协助处理
    这里再科普一下consumer的一个参数auto.offset.reset

earliest
当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
latest
当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
none
topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常

默认值是latest,我遇到的问题就是之前已经给该group创建offset了,所以隔了1天再上线还是消费了大量历史数据,这是需要提前识别出来并且规避的

  1. 出现Kafka 提交offset失败的warn日志并且有重复消费的情况

Offset commit failed with a retriable exception. You should retry committing offsets. The underlying error was: The request timed out.

分析原因可能是下面2个情况:

  • jvm单次从kafka获取数据,处理速度不够快,超时了

  • jvm正常处理,自动commit的时候连接kafka的网络有波动,导致commit失败jvm正常处理,自动commit的时候连接kafka的网络有波动,导致commit失败

    解决方案:将自动提交改为手动提交,具体方法参照上面代码

六、结语

监控系统的第一步Kafka已经全部结束了,下面将介绍第二步:写入ES
使用Kafka、Elasticsearch、Grafana搭建业务监控系统(三)Elasticsearch

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Kafka连接Elasticsearch可以通过使用Kafka Connect来实现。Kafka Connect是一个开源工具,用于将Kafka与其他数据存储系统集成。 要将KafkaElasticsearch连接起来,你需要执行以下步骤: 1. 安装和配置Kafka Connect:首先,你需要安装和配置Kafka Connect。你可以从Apache Kafka的官方网站下载并安装Kafka。安装完成后,你需要配置Kafka Connect的连接器。 2. 下载并配置Elasticsearch连接器:Kafka Connect提供了一个Elasticsearch连接器,用于将数据从Kafka发送到Elasticsearch。你可以从Confluent Hub或其他地方下载并安装该连接器。安装完成后,你需要配置连接器以指定KafkaElasticsearch的连接信息。 3. 配置任务和转换:一旦安装和配置了Elasticsearch连接器,你需要创建一个任务来定义从KafkaElasticsearch的数据流。你可以指定要读Kafka主题、Elasticsearch索引和转换操作等。 4. 启动Kafka Connect:在所有必要的配置都完成后,你可以启动Kafka Connect,并提交你的任务。Kafka Connect将会读Kafka主题中的数据,并将其写入到Elasticsearch索引中。 这样,你就可以通过Kafka Connect将KafkaElasticsearch连接起来,并且实现数据的传输和同步。请注意,这只是一个基本的概述,实际操作中可能会有一些细节和配置的差异。你可以参考Kafka Connect和Elasticsearch连接器的官方文档以获更详细的信息和指南。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值