Flink 1.12 读取kafka 写入hbase | 自定义HbaseSink | 含源码

本文介绍如何使用Apache Flink 1.12从Kafka流读取数据,并通过自定义HBaseSink将数据写入HBase,包括配置参数、数据解析和表设计。适合Flink和HBase集成应用开发者参考。
摘要由CSDN通过智能技术生成

Flink 1.12 读取kafka 写入hbase | 自定义HbaseSink | 含源码

maven依赖在之前的帖子有写,是共用的,可以做参考

[Flink1.12读取Kafka数据写入到Hdfs | 含maven依赖 | FileSink]( Flink1.12读取Kafka数据写入到Hdfs | 含maven依赖 | FileSink_MIDSUMMER_yy的博客-CSDN博客 )

首先是主类的代码

public class KafkaToHbase {

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

        //读取配置文件
        String config_path=args[0];
        ParameterTool parameterTool = ParameterTool.fromPropertiesFile(new FileInputStream(new File(config_path)))
                .mergeWith(ParameterTool.fromSystemProperties())
                .mergeWith(ParameterTool.fromMap(getenv()));

        //创建环境
        StreamExecutionEnvironment env = FlinkEnvUtils.creatEnv();

        //配置文件放入流式环境
        env.getConfig().setGlobalJobParameters(parameterTool);

        //配置kafka
        Properties props = new Properties();
        props.setProperty("bootstrap.servers", parameterTool.get("kafka_ips"));
        props.setProperty("group.id", parameterTool.get("kakfa.group.name"));
        FlinkKafkaConsumer<String> consumer = new FlinkKafkaConsumer<>(parameterTool.get("kakfa.topic.name"), new SimpleStringSchema(), props);
        consumer.setCommitOffsetsOnCheckpoints(true);
        consumer.setStartFromGroupOffsets();

        DataStream<String> stream = env.addSource(consumer);

        stream.addSink(new HbaseSink()).name("kafkaTohbase_test");

        env.execute();

    }

    private static Map<String, String> getenv()
    {
        Map<String, String> map = new HashMap();
        for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }

}

跟之前一样,传参只有一个配置文件

HbaseSink的代码如下

import org.apache.commons.lang.StringUtils;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;

import java.io.IOException;
import java.io.Serializable;

public class HbaseSink<IN>
        extends RichSinkFunction<String>
        implements Serializable {


    private static final long serialVersionUID = 1L;
    private HBaseUtil hbaseUtil;
    private static int keyIDPos;
    private static int optypePos;
    private static String tableName;
    private static String columnFamily;
    private static String column;

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);

        ParameterTool params = (ParameterTool)getRuntimeContext().getExecutionConfig().getGlobalJobParameters();

        tableName = params.get("hbase.table.name");
        columnFamily = params.get("hbase.table.column.family");
        column = params.get("hbase.table.column");
        keyIDPos = params.getInt("record.keyID.field.Pos") ;
        optypePos = params.getInt("record.op.type.field.Pos");
        this.hbaseUtil = new HBaseUtil(params, tableName);
    }

    public void invoke(String s)
            throws IOException
    {
        if ((s.contains("\n")) || (s.contains("\r")) || (s.contains("\r\n"))) {
            s = s.trim();
        }
        String[] str = s.split(String.valueOf('\007'));

        String keyID = str[(keyIDPos - 1)];
        keyID = new StringBuilder(keyID).reverse().toString();
        String op_type = str[(optypePos - 1)];
        String rowkey = keyID;
        if ((op_type.toUpperCase().equals("INSERT")) || (op_type.toUpperCase().equals("UPDATE"))) {
            this.hbaseUtil.insertRow(rowkey, columnFamily, column.split(","), str);
        } else if (op_type.toUpperCase().equals("DELETE")) {
            this.hbaseUtil.deleteRow(rowkey);
        }
    }

    public void close()
            throws Exception
    {
        this.hbaseUtil.close();
    }
}

我这边Hbase表的设计是单列簇的,这样子跟上游的Oracle格式差不多,就不用有太多处理

上游是ogg写入kafka的,所以会自带插入类型(INSERT、UPDATE、DELETE),这个ogg配置写入kafka后面会再搞一个文章单独说

只要上游能确保kafka存储的信息中含有插入类型即可,或者纯新增操作都可以对上面的代码进行变动

hbase.table.name指的是表名

hbase.table.column.family指的是列簇名

hbase.table.column指的是列的列表,我在配置文件用逗号隔开

record.keyID.field.Pos指的是主键的坐标,我的kafka里每个记录的分割符是’\007’

record.op.type.field.Pos指的是插入类型

下面是HBaseUtil的相关代码

import org.apache.flink.api.java.utils.ParameterTool;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

public class HBaseUtil {

    private Connection conn;
    private Table htable;

    public HBaseUtil(ParameterTool params, String tablename)
            throws IOException
    {
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.property.clientPort", "xxx");
        conf.set("hbase.zookeeper.quorum", "xxx,xxx,xxx");
        conf.set("hbase.master", "xxx:xxx,xxx:xxx");
        conf.set("mapreduce.output.fileoutputformat.compress", "false");
        conf.set("zookeeper.znode.parent", "xxx");
        conf.setInt("hbase.rpc.timeout", 20000);
        conf.setInt("hbase.client.operation.timeout",30000);
        conf.setInt("hbase.client.scanner.timeout.period",200000);

        this.conn = ConnectionFactory.createConnection(conf);

        openTable(tablename);
    }

    public void openTable(String tablename)
            throws IOException
    {
        TableName tableName = TableName.valueOf(tablename);
        this.htable = this.conn.getTable(tableName);
    }


    public void insertRow(String rowkey, String columnFamily, String[] column, String[] value)
            throws IOException
    {
        Put put = new Put(Bytes.toBytes(rowkey));
        for (int i = 0; i < column.length; i++) {
            put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column[i]), Bytes.toBytes(value[i]));
        }
        this.htable.put(put);
    }

    public void deleteRow(String rowkey)
            throws IOException
    {
        Delete de = new Delete(Bytes.toBytes(rowkey));

        this.htable.delete(de);
    }

    public void close()
            throws IOException
    {
        if (this.htable != null) {
            this.htable.close();
        }
        if (this.conn != null) {
            this.conn.close();
        }
    }
}

在构造函数里把xxx的内容根据自己集群的内容进行填充即可

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要实现Flink实时读取Kafka并将数据写入HBase数据库,您可以使用FlinkKafka源(FlinkKafkaConsumer)和HBase的TableSinkHBaseTableSink)。以下是一个示例代码片段,展示如何实现这一功能: ``` val env = StreamExecutionEnvironment.getExecutionEnvironment() // 设置Kafka消费者配置 val kafkaProps = new Properties() kafkaProps.setProperty("bootstrap.servers", "localhost:9092") kafkaProps.setProperty("group.id", "flink-kafka-hbase") // 创建Kafka数据流 val kafkaConsumer = new FlinkKafkaConsumer[String]("topic-name", new SimpleStringSchema(), kafkaProps) val kafkaStream = env.addSource(kafkaConsumer) // 将Kafka数据流转换为HBase数据流 val hbaseStream = kafkaStream.map(new MapFunction[String, Put]() { override def map(value: String): Put = { val put = new Put(Bytes.toBytes("row key")) put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("column"), Bytes.toBytes(value)) put } }) // 设置HBase表格的配置 val hbaseConfig = HBaseConfiguration.create() hbaseConfig.set(TableOutputFormat.OUTPUT_TABLE, "table-name") hbaseConfig.set("hbase.zookeeper.quorum", "localhost") hbaseConfig.set("hbase.zookeeper.property.clientPort", "2181") // 将HBase数据流写入表格 val hbaseSink = new HBaseTableSink(hbaseConfig) hbaseStream.addSink(hbaseSink) // 执行Flink任务 env.execute("Read from Kafka and write to HBase") ``` 在上面的代码中,我们首先创建了一个FlinkKafkaConsumer对象并使用它创建了一个Kafka数据流。接下来,我们将Kafka数据流转换为HBase数据流,并在每个记录上创建一个Put对象,该对象包HBase表格的行键和列。 然后,我们设置了HBase表格的配置,并使用HBaseTableSinkHBase数据流写入表格。最后,我们通过调用env.execute()方法来执行Flink任务。 请注意,在实际使用中,您需要根据您的特定情况对代码进行相应的修改。例如,您需要修改Kafka主题的名称、HBase表格的名称和行键等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MIDSUMMER_yy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值