flink入门_flink入门(十五到十六)

45023c1f38b2ad8988b9252423731140.png

点击上方蓝字关注我们

36cdabded8524300cb7e3150d738add1.png 747db33d8bc5de42fd0e630735100fb3.png

Flink 读取 Kafka 数据写入到 HBase

文章目录

概述

环境说明

引入依赖

使用flink读取kafka的数据消息

写入hbase

概述

环境说明

scala: 2.12.8 linux下scala安装部署

flink : 1.8.1 Flink1.8.1 集群部署

kafka_2.12-2.2.0 kafka_2.12-2.2.0 集群部署

hbase 2.1 hbase 2.1 环境搭建–完全分布式模式 Advanced - Fully Distributed

hadoop Hadoop 2.8.5 完全分布式HA高可用安装(二环境搭建

引入依赖

org.apache.hbase

hbase-client

2.1.5

org.apache.phoenix

phoenix-core

5.0.0-HBase-2.0

org.apache.flink

flink-java

1.8.1

org.apache.flink

flink-streaming-java_2.11

1.8.1

org.apache.flink

flink-clients_2.11

1.8.1

org.apache.flink

flink-connector-kafka_2.11

1.8.1

使用flink读取kafka的数据消息

public static void main(String[] args) throws Exception {

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

env.enableCheckpointing(1000);

Properties properties = new Properties();

properties.setProperty("bootstrap.servers", "node1:9092");

FlinkKafkaConsumer consumer = new FlinkKafkaConsumer<>("my-test-topic", new SimpleStringSchema(), properties);

//从最早开始消费

consumer.setStartFromEarliest();

DataStream stream = env.addSource(consumer);

stream.print();

//stream.map();

env.execute();

}

启动服务:

启动hadoop集群

启动hbase集群

启动kafka集群

启动flink

执行上述main方法,该main方法会一直监控kafka集群消息。

我们启动kafka客户端来发送几条消息

./kafka-console-producer.sh --broker-list node1:9092 --topic my-test-topic

可以看到java程序控制台输出

4> 111111

4> 2222

写入hbase

编写process来完成写入hbase的操作

import lombok.extern.slf4j.Slf4j;

import org.apache.flink.streaming.api.functions.ProcessFunction;

import org.apache.flink.util.Collector;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.TableName;

import org.apache.hadoop.hbase.client.Connection;

import org.apache.hadoop.hbase.client.ConnectionFactory;

import org.apache.hadoop.hbase.client.Put;

import org.apache.hadoop.hbase.client.Table;

import org.apache.hadoop.hbase.util.Bytes;

@Slf4j

public class HbaseProcess extends ProcessFunction {

private static final long serialVersionUID = 1L;

private Connection connection = null;

private Table table = null;

@Override

public void open(org.apache.flink.configuration.Configuration parameters) throws Exception {

try {

// 加载HBase的配置

Configuration configuration = HBaseConfiguration.create();

// 读取配置文件

configuration.addResource(new Path(ClassLoader.getSystemResource("hbase-site.xml").toURI()));

configuration.addResource(new Path(ClassLoader.getSystemResource("core-site.xml").toURI()));

connection = ConnectionFactory.createConnection(configuration);

TableName tableName = TableName.valueOf("test");

// 获取表对象

table = connection.getTable(tableName);

log.info("[HbaseSink] : open HbaseSink finished");

} catch (Exception e) {

log.error("[HbaseSink] : open HbaseSink faild {}", e);

}

}

@Override

public void close() throws Exception {

log.info("close...");

if (null != table) table.close();

if (null != connection) connection.close();

}

@Override

public void processElement(String value, Context ctx, Collector out) throws Exception {

try {

log.info("[HbaseSink] value={}", value);

//row1:cf:a:aaa

String[] split = value.split(":");

// 创建一个put请求,用于添加数据或者更新数据

Put put = new Put(Bytes.toBytes(split[0]));

put.addColumn(Bytes.toBytes(split[1]), Bytes.toBytes(split[2]), Bytes.toBytes(split[3]));

table.put(put);

log.error("[HbaseSink] : put value:{} to hbase", value);

} catch (Exception e) {

log.error("", e);

}

}

}

然后将上面main方法中的stream.print();改为:

stream.process(new HbaseProcess());

运行main方法,然后在kafka控制台发送一条消息row1:cf:a:aaa。

到hbase 的shell控制台查看test表数据:

hbase(main):012:0> scan 'test'

ROW COLUMN+CELL

row1 column=cf:a, timestamp=1563880584014, value=aaa

row1 column=cf:age, timestamp=1563779499842, value=12

row2 column=cf:a, timestamp=1563451278532, value=value2a

row2 column=cf:age, timestamp=1563779513308, value=13

row2 column=cf:b, timestamp=1563441738877, value=value2

row3 column=cf:c, timestamp=1563441741609, value=value3

上面第一行aaa就是我们新插入的数据。

当然除了process,也可以使用sink,编写HbaseSink类

import lombok.extern.slf4j.Slf4j;

import org.apache.flink.streaming.api.functions.sink.SinkFunction;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.TableName;

import org.apache.hadoop.hbase.client.Connection;

import org.apache.hadoop.hbase.client.ConnectionFactory;

import org.apache.hadoop.hbase.client.Put;

import org.apache.hadoop.hbase.client.Table;

import org.apache.hadoop.hbase.util.Bytes;

@Slf4j

public class HbaseSink implements SinkFunction {

@Override

public void invoke(String value, Context context) throws Exception {

Connection connection = null;

Table table = null;

try {

// 加载HBase的配置

Configuration configuration = HBaseConfiguration.create();

// 读取配置文件

configuration.addResource(new Path(ClassLoader.getSystemResource("hbase-site.xml").toURI()));

configuration.addResource(new Path(ClassLoader.getSystemResource("core-site.xml").toURI()));

connection = ConnectionFactory.createConnection(configuration);

TableName tableName = TableName.valueOf("test");

// 获取表对象

table = connection.getTable(tableName);

//row1:cf:a:aaa

String[] split = value.split(":");

// 创建一个put请求,用于添加数据或者更新数据

Put put = new Put(Bytes.toBytes(split[0]));

put.addColumn(Bytes.toBytes(split[1]), Bytes.toBytes(split[2]), Bytes.toBytes(split[3]));

table.put(put);

log.error("[HbaseSink] : put value:{} to hbase", value);

} catch (Exception e) {

log.error("", e);

} finally {

if (null != table) table.close();

if (null != connection) connection.close();

}

}

}

然后修改main方法代码,运行效果一样的。具体区别后续再分析。

// stream.print();

// stream.process(new HbaseProcess());

stream.addSink(new HbaseSink());

Flink 读取 Kafka 数据写入到 HDFS

1.概述

最近有同学留言咨询,Flink消费Kafka的一些问题,今天笔者将用一个小案例来为大家介绍如何将Kafka中的数据,通过Flink任务来消费并存储到HDFS上。

2.内容

这里举个消费Kafka的数据的场景。比如,电商平台、游戏平台产生的用户数据,入库到Kafka中的Topic进行存储,然后采用Flink去实时消费积累到HDFS上,积累后的数据可以构建数据仓库(如Hive)做数据分析,或是用于数据训练(算法模型)。如下图所示:

50c7aa08629fd1f50d7e4f93771de383.png

2.1 环境依赖

整个流程,需要依赖的组件有Kafka、Flink、Hadoop。由于Flink提交需要依赖Hadoop的计算资源和存储资源,所以Hadoop的YARN和HDFS均需要启动。各个组件版本如下:

组件

版本

Kafka

2.4.0

Flink

1.10.0

Hadoop

2.10.0

2.2 代码实现

Flink消费Kafka集群中的数据,需要依赖Flink包,依赖如下:

org.apache.flink 

flink-connector-filesystem_2.12$ 

org.apache.flink 

flink-connector-kafka-0.11_2.12$ 

org.apache.flink 

flink-streaming-java_2.12$ 

编写消费Topic的Flink代码,这里不对Topic中的数据做逻辑处理,直接消费并存储到HDFS上。代码如下:

/** * Flink consumer topic data and store into hdfs. * * @author smartloli. * * Created by Mar 15, 2020 */

publicclass Kafka2Hdfs { privatestatic Logger LOG = LoggerFactory.getLogger(Kafka2Hdfs.class); publicstaticvoid main(String[] args) { 

if (args.length != 3) { 

LOG.error("kafka(server01:9092), hdfs(hdfs://cluster01/data/), 

flink(parallelism=2) must be exist."); return; 

String bootStrapServer = args[0]; String hdfsPath = args[1]; int parallelism=Integer.parseInt(args[2]); StreamExecutionEnvironment env= StreamExecutionEnvironment.getExecutionEnvironment(); env.enableCheckpointing(5000); env.setParallelism(parallelism); env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); DataStream transction = env.addSource(new FlinkKafkaConsumer010<>("test_bll_data",new SimpleStringSchema(),configByKafkaServer(bootStrapServer)));

// Storage into hdfs BucketingSink sink = new BucketingSink<>(hdfsPath);

sink.setBucketer(new DateTimeBucketer("yyyy-MM-dd")); 

sink.setBatchSize(1024 * 1024 * 1024); 

// this is 1GB sink.setBatchRolloverInterval(1000 * 60 * 60); // one hour producer a file into hdfs transction.addSink(sink); 

env.execute("Kafka2Hdfs"); } 

privatestatic Object configByKafkaServer(String bootStrapServer) { Properties props = new Properties(); props.setProperty("bootstrap.servers", bootStrapServer); props.setProperty("group.id", "test_bll_group"); props.put("enable.auto.commit", "true"); props.put("auto.commit.interval.ms", "1000"); props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); return props; } }

2.3 注意事项

存储到HDFS时,不用添加其他HDFS依赖,只需要Flink采用yarn-cluster模式提交即可;

采用FSDataOutputStream写入时,会先写入缓冲区,放在内存中;

Flink每次做Checkpoint的时候,会Flush缓冲区的数据,以及将Pending(已经完成的文件,但为被Checkpoint记录,可以通过sink.setPendingSuffix("xxx")来设置)结尾的文件记录下来

Flink每60秒(可以通过sink.setInactiveBucketCheckInterval(60 * 1000)来进行设置)检测,如果一个文件的FSDataOutputStream在60秒内(可以通过sink.setInactiveBucketThreshold(60 * 1000)来设置),都还没有接收到数据,Flink就会认为该文件是不活跃的Bucket,那么就会被Flush后关闭该文件;

我们再深入一点查看代码,实际上只是在processingTimeService中注册了当前的时间(currentProcessingTime)+ 60秒不写入的时间(inactiveBucketCheckInterval)。接着通过onProcessIngTime方法去不停的判断是否满足60秒不写入,同时也会判断是否到了滚动时间。代码如下:

publicvoid onProcessingTime(long timestamp) throws Exception { long currentProcessingTime = processingTimeService.getCurrentProcessingTime(); closePartFilesByTime(currentProcessingTime); processingTimeService.registerTimer(currentProcessingTime + inactiveBucketCheckInterval, this); }

在Flink内部封装了一个集合Map> bucketStates = new HashMap<>();用来记录当前正在使用的文件,key是文件的路径,BucketState内部封装了该文件的所有信息,包括创建时间,最后一次写入时间(这里的写入指的是写入缓存区的时间,不是Flush的时间)。当前文件是打开还是关闭,写缓冲区的方法。都在这里。每次Flink要对文件进行操作的时候,都会从这里拿到文件的封装对象;

当程序被取消的时候,当前正在操作的文件,会被Flush,然后关闭。然后将文件的后缀名从in-progress改为pending。这个前后缀都是可以设置,但如果没有什么特殊需求,默认即可。这里拿文件,用的就是上面说的bucketStates这个map。它在close方法中,会去遍历这个map,去做上述的操作;代码如下:

publicvoid close() throws Exception { if (state != null) { for (Map.Entry> entry : state.bucketStates.entrySet()) { closeCurrentPartFile(entry.getValue()); } } }

每次写入的时候,都是会bucketStates这个map中获取对应的对象,如果没有,就会new一个该对象。然后先判断是否需要滚动(通过当前文件大小和滚动时间去判断),然后才将数据写入缓冲区,更新最后写入时间,代码如下:

publicvoid invoke(T value) throws Exception { Path bucketPath = bucketer.getBucketPath(clock, new Path(basePath), value); 

long currentProcessingTime= processingTimeService.getCurrentProcessingTime(); BucketState bucketState= state.getBucketState(bucketPath);

 if (bucketState == null) { bucketState = new BucketState<>(currentProcessingTime); 

state.addBucketState(bucketPath, bucketState);

 } 

if (shouldRoll(bucketState, currentProcessingTime)) { openNewPartFile(bucketPath, bucketState);

}

bucketState.writer.write(value); bucketState.lastWrittenToTime = currentProcessingTime; }

写入和关闭HDFS是通过异步的方式的,异步的超时时间默认是60秒,可以通过 sink.setAsyncTimeout(60 * 1000)去设置

3.总结

Flink消费Kafka数据并写到HDFS的代码实现是比较简短了,没有太多复杂的逻辑。实现的时候,注意Kafka的地址、反序列化需要在属性中配置、以及Flink任务提交的时候,设置yarn-cluster模式、设置好内存和CPU、HDFS存储路径等信息。

fc3dee8d6934b74427f587701105aae4.png

往期推荐

flink入门(一到二)

flink入门(三到五)

flink入门(六到八)

flink入门(十一到十二)

flink入门(十三到十四)

7268c530a140d8daf68891495b24f62c.png 1eb2bfcb2de5e95edb779f8e27b6f72a.png

点个在看,你最好看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最新Flink教程,基于Flink 1.13.2。书中所有示例和案例代码均为双语。这是预览版。 目录 第1 章Flink 架构与集群安装...............................................................................................................................- 1 - 1. 1 Flink 简介................................................................................................................................................... - 1 - 1.1.1 Flink 发展历程.................................................................................................................................- 1 - 1.1.2 Flink 特性.........................................................................................................................................- 2 - 1. 2 Flink 应用场景........................................................................................................................................... - 3 - 1.2.1 事件驱动应用程序.......................................................................................................................... - 3 - 1.2.2 数据分析应用程序.......................................................................................................................... - 4 - 1.2.3 数据管道应用程序.......................................................................................................................... - 5 - 1. 3 Flink 体系架构........................................................................................................................................... - 5 - 1.3.1 Flink 系统架构.................................................................................................................................- 5 - 1.3.2 Flink 运行时架构..............................................................................................................................- 6 - 1.3.3 Flink 资源管理.................................................................................................................................- 8 - 1.3.4 Flink 作业调度..........................................................................................................

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值