flume采集kafka数据自定义source

文章讲述了如何通过自定义FlumeSource来获取Kafka中数据进入的时间戳,并将其添加到JSON数据中,然后存储到HDFS。首先尝试使用时间戳拦截器失败,因为拦截器在Channel阶段处理数据时无法获取Kafka时间。最终通过创建自定义FlumeSource,从ConsumerRecord中获取timestamp,并将时间戳放入事件头信息中,实现了需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:获取数据进入kafka的时间,并将此时间放入json数据中,flume采集数据按照此时间存放在hdfs中。

解决思路:

1.使用时间戳拦截器获取进入kafka的时间,失败!

kafkasource,时间戳拦截器,filechannel,hdfssink

原因:时间戳拦截器是在channel阶段处理数据,在使用kafkasource获取kafka数据后,在header中没有数据进入kafka的时间

2.使用自定义flume source,成功!

上代码

public class FlumeSourceDemo extends AbstractSource implements Configurable, PollableSource {

    private String GROUP_ID;
    private String KAFKA_SERVER;
    private String KAFKA_TOPIC;
    private Properties props;
    private String KEY_DES;
    private String VALUE_DES;
    private KafkaConsumer consumer;
    private static final Logger logger = LoggerFactory.getLogger("source日志");

    //TODO source数据处理逻辑
    @Override
    public  Status process() throws EventDeliveryException {

        try {
           

            //拉取数据1000毫秒(1秒)
            ConsumerRecords<String, String> records = consumer.poll(1000);

            //创建事件头信息
            HashMap<String, String> hearderMap = new HashMap<>();
            //创建事件
            SimpleEvent event = new SimpleEvent();

            //循环读取records的数据record
            for (ConsumerRecord<String, String> record : records) {
               
                String value = record.value();
                //TODO logger.info("record的value:"+value);
                //将value转成jsonobject
                JSONObject jsonObject = JSON.parseObject(value);
                //TODO logger.info("value转成jsonobject:"+jsonObject);
                //获取record中的timestamp
                String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(record.timestamp());
                //TODO logger.info("record的时间戳"+record.timestamp());
                //TODO logger.info("时间戳"+timestamp);
                //获取record中的action
                String action = jsonObject.getString("action");
                //TODO logger.info("取到的action"+action);
                //将timestamp放入jsonobject
                jsonObject.put("kafkaTime", timestamp);
                //TODO logger.info("jsonobject的数据"+jsonObject);
                String kafkaTime = jsonObject.toString();
                //TODO logger.info("放入时间戳的数据(string格式):"+kafkaTime);
                //给事件设置内容
                event.setBody(kafkaTime.getBytes());
                //给事件设置头信息
                HashMap<String, String> map = new HashMap<>();
                map.put("timestamp",Long.toString(record.timestamp()));
                map.put("action", action);
                //TODO logger.info("header的map:"+map);
                event.setHeaders(map);
                //TODO logger.info("+records中的event:"+event.toString()+",event数据:"+event.getBody());
                //将事件写入channel
                this.getChannelProcessor().processEvent(event);
            }
            

            return Status.READY;
        }catch (Exception e){
            e.printStackTrace();
            return Status.BACKOFF;
        }
    }
    //TODO source初始化
    
    @Override
    public void configure(Context context) {


    }

    @Override
    public synchronized void start() {
        super.start();
        props = new Properties();
        props.setProperty("bootstrap.servers", "****:9092,****:9092,****:9092");
        props.setProperty("group.id", "flumesource");
        props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        consumer = new KafkaConsumer(props);
        consumer.subscribe(Collections.singleton("topic"));
    }

    @Override
    public synchronized void stop() {
        super.stop();
    }

    @Override
    public long getBackOffSleepIncrement() {
        return 0;
    }

    @Override
    public long getMaxBackOffSleepInterval() {
        return 0;
    }
}

每条数据进入kafka的时间都在ConsumerRecord中,自定义source就是要获取ConsumerRecord

中timestamp的值。

注意点:放入event.headers中的时间戳:key:“timestamp”,value:Long.toString(record.timestamp())

record.timestamp()是long类型,往header放入时间时value是Long.toString,不能用String.valueof

### 使用FlumeKafka采集数据并写入HDFS的配置教程 #### 1. Flume简介与适用场景 Flume 是 Cloudera 提供的一个高可用、高可靠、分布式的大规模日志采集、聚合和传输系统[^1]。它能够通过自定义数据发送方收集数据,并将这些数据传递给多种接收端,比如 HDFS 或 Kafka。 当需要将 Kafka 中的数据转存到 HDFS 时,可以通过 Flume 实现这一目标。这种方式相较于手动编写程序更加高效且易于维护。 --- #### 2. 安装与环境准备 在开始配置之前,需确保以下环境已经准备好: - **Flume 已正确安装**:下载 Flume 并解压至指定路径[^1]。 - **Hadoop 和 Java 环境配置正常**:确认 `/etc/profile.d/my_env.sh` 文件中已正确设置 `JAVA_HOME` 和 `HADOOP_HOME` 变量[^3]。 - **Kafka 集群运行状态良好**:确保 Kafka 的 broker 地址和服务正常工作。 - **依赖库加载完成**:将 Hadoop 相关 jar 包复制到 Flume 安装目录下的 lib 子目录中。 --- #### 3. 配置文件详解 以下是完整的 Flume 配置示例,用于从 Kafka 消费数据并将之写入 HDFS。 ##### 3.1 配置 Kafka Source ```properties agent.sources.kafka-source.type = org.apache.flume.source.kafka.KafkaSource agent.sources.kafka-source.zookeeperConnect = kafka_server1:2181,kafka_server2:2181,kafka_server3:2181 agent.sources.kafka-source.topic = your_topic agent.sources.kafka-source.groupId = flume-group agent.sources.kafka-source.channels = memory-channel ``` 说明: - `zookeeperConnect`: 替换为实际的 Zookeeper 连接字符串[^2]。 - `topic`: 替换为目标 Kafka 主题名称。 - `groupId`: 设置 FlumeKafka 中的消费者组 ID。 ##### 3.2 配置 Memory Channel ```properties agent.channels.memory-channel.type = memory agent.channels.memory-channel.capacity = 10000 agent.channels.memory-channel.transactionCapacity = 1000 ``` Memory Channel 是一种简单的内存队列机制,适合低延迟需求的应用场景。 ##### 3.3 配置 HDFS Sink ```properties agent.sinks.hdfs-sink.type = hdfs agent.sinks.hdfs-sink.hdfs.path = hdfs://namenode:8020/flume/kafka-data agent.sinks.hdfs-sink.hdfs.filePrefix = events- agent.sinks.hdfs-sink.hdfs.fileSuffix = .log agent.sinks.hdfs-sink.hdfs.rollInterval = 3600 agent.sinks.hdfs-sink.hdfs.rollSize = 0 agent.sinks.hdfs-sink.hdfs.rollCount = 10000 agent.sinks.hdfs-sink.hdfs.batchSize = 1000 agent.sinks.hdfs-sink.hdfs.fileType = DataStream agent.sinks.hdfs-sink.channel = memory-channel ``` 说明: - `hdfs.path`: 替换为 HDFS 上的目标存储路径。 - `rollInterval`, `rollSize`, `rollCount`: 控制文件滚动策略,分别基于时间间隔、大小限制和记录数限制[^2]。 --- #### 4. 启动 Flume Agent 保存以上配置内容到一个名为 `flume-conf.properties` 的文件中,然后启动 Flume Agent: ```bash $FLUME_HOME/bin/flume-ng agent --conf $FLUME_CONF_DIR \ --name agent_name --conf-file /path/to/flume-conf.properties -Dflume.root.logger=INFO,console ``` 其中: - `$FLUME_HOME`: Flume 安装根目录。 - `$FLUME_CONF_DIR`: Flume 配置文件所在目录。 --- #### 5. Kerberos 认证(可选) 如果 Kafka 集群启用了 Kerberos,则需要额外配置认证信息[^4]。具体步骤包括: - 创建 Keytab 文件并与 Flume 用户关联。 - 修改 Flume 配置文件以支持 JAAS 登录模块。 示例 JAAS 配置片段: ```java Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/path/to/flume.keytab" principal="flume@YOUR_REALM.COM"; }; ``` 将此内容保存为 `jaas.conf` 文件,并通过 `-Djava.security.auth.login.config=/path/to/jaas.conf` 参数传入 JVM。 --- ### 示例代码总结 完整流程涉及以下几个核心组件的协同工作: 1. Kafka Source 收集数据; 2. Memory Channel 缓冲数据; 3. HDFS Sink 将数据持久化到 HDFS。 最终效果是实现从 Kafka 到 HDFS 的无缝数据流转。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值