Flink的sink实战之三:cassandra3

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 实践flink数据集sink到cassandra3

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

  • 本文是《Flink的sink实战》系列的第三篇,主要内容是体验Flink官方的cassandra connector,整个实战如下图所示,我们先从kafka获取字符串,再执行wordcount操作,然后将结果同时打印和写入cassandra:

在这里插入图片描述

软件版本

  • 本次实战的软件版本信息如下:
  • cassandra:3.11.6
  • kafka:2.4.0(scala:2.12)
  • jdk:1.8.0_191
  • flink:1.9.2
  • maven:3.6.0
  • flink所在操作系统:CentOS Linux release 7.7.1908
  • cassandra所在操作系统:CentOS Linux release 7.7.1908
  • IDEA:2018.3.5 (Ultimate Edition)

    关于cassandra

  • 本次用到的cassandra是三台集群部署的集群,搭建方式请参考《ansible快速部署cassandra3集群》

    准备cassandra的keyspace和表

  • 先创建keyspace和table:
  • cqlsh登录cassandra:
    cqlsh 192.168.133.168
    
  • 创建keyspace(3副本):

    CREATE KEYSPACE IF NOT EXISTS example
      WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '3'};
    
  • 建表:

    CREATE TABLE IF NOT EXISTS example.wordcount (
      word text,
      count bigint,
      PRIMARY KEY(word)
      );
    

    准备kafka的topic

  • 启动kafka服务;
  • 创建名为test001的topic,参考命令如下:

    ./kafka-topics.sh \
    --create \
    --bootstrap-server 127.0.0.1:9092 \
    --replication-factor 1 \
    --partitions 1 \
    --topic test001
    
  • 进入发送消息的会话模式,参考命令如下:

    ./kafka-console-producer.sh \
    --broker-list kafka:9092 \
    --topic test001
    
  • 在会话模式下,输入任意字符串然后回车,都会将字符串消息发送到broker;

    源码下载

  • 如果您不想写代码,整个系列的源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本章的应用在flinksinkdemo文件夹下,如下图红框所示:

在这里插入图片描述

两种写入cassandra的方式

  • flink官方的connector支持两种方式写入cassandra:
  • Tuple类型写入:将Tuple对象的字段对齐到指定的SQL的参数中;
  • POJO类型写入:通过DataStax,将POJO对象对应到注解配置的表和字段中;

  • 接下来分别使用这两种方式;

    开发(Tuple写入)

  • 《Flink的sink实战之二:kafka》中创建了flinksinkdemo工程,在此继续使用;
  • 在pom.xml中增加casandra的connector依赖:
<dependency>
  <groupId>org.apache.flink</groupId>
  <artifactId>flink-connector-cassandra_2.11</artifactId>
  <version>1.10.0</version>
</dependency>
  • 另外还要添加flink-streaming-scala依赖,否则编译CassandraSink.addSink这段代码会失败:
<dependency>
  <groupId>org.apache.flink</groupId>
  <artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
  <version>${flink.version}</version>
  <scope>provided</scope>
</dependency>
  • 新增CassandraTuple2Sink.java,这就是Job类,里面从kafka获取字符串消息,然后转成Tuple2类型的数据集写入cassandra,写入的关键点是Tuple内容和指定SQL中的参数的匹配:
package com.bolingcavalry.addsink;

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.PrintSinkFunction;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.cassandra.CassandraSink;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.util.Collector;
import java.util.Properties;


public class CassandraTuple2Sink {
   
   
    public static void main(String[] args) throws Exception {
   
   
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        //设置并行度
        env.setParallelism(1);

        //连接kafka用到的属性对象
        Properties properties = new Properties();
        //broker地址
        properties.setProperty("bootstrap.servers", "192.168.50.43:9092");
        //zookeeper地址
        properties.setProperty("zookeeper.connect", "192.168.50.43:2181");
        //消费者的groupId
        properties.setProperty("group.id", "flink-connector");
        //实例化Consumer类
        FlinkKafkaConsumer<String> flinkKafkaConsumer = new FlinkKafkaConsumer<>(
                "test001",
                new SimpleStringSchema(),
                properties
        );

        //指定从最新位置开始消费,相当于放弃历史消息
        flinkKafkaConsumer.setStartFromLatest();

        //通过addSource方法得到DataSource
        DataStream<String> dataStream = env.addSource(flinkKafkaConsumer);

        DataStream<Tuple2<String, Long>> result = dataStream
                .flatMap(new FlatMapFunction<String, Tuple2<String, Long>>() {
   
   
                             @Override
                             public void flatMap(String value, Collector<Tuple2<String, Long>> out) {
   
   
                                 String[] words = value.toLowerCase().split("\\s");

                                 for (String word : words) {
   
   
                                     //cassandra的表中,每个word都是主键,因此不能为空
                                     if (!word.isEmpty()) {
   
   
                                         out.collect(new Tuple2<String, Long>(word, 1L));
                                     }
                                 }
                             }
                         }
                )
                .keyBy(0)
                .timeWindow(Time.seconds(5))
                .sum(1);

        result.addSink(new PrintSinkFunction<>())
                .name("print Sink")
                .disableChaining();

        CassandraSink.addSink(result)
                .setQuery("INSERT INTO example.wordcount(word, count) values (?, ?);")
                .setHost("192.168.133.168")
                .build()
                .name("cassandra Sink")
                .disableChaining();

        env.execute("kafka-2.4 source, cassandra-3.11.6 sink, tuple2");
    }
}
  • 上述代码中,从kafka取得数据,做了word count处理后写入到cassandra,注意addSink方法后的一连串API(包含了数据库连接的参数),这是flink官方推荐的操作,另外为了在Flink web UI看清楚DAG情况,这里调用disableChaining方法取消了operator chain,生产环境中这一行可以去掉;
  • 编码完成后,执行mvn clean package -U -DskipTests构建,在target目录得到文件flinksinkdemo-1.0-SNAPSHOT.jar
  • 在Flink的web UI上传flinksinkdemo-1.0-SNAPSHOT.jar,并指定执行类,如下图红框所示:

在这里插入图片描述

  • 启动任务后DAG如下:

在这里插入图片描述

  • 去前面创建的发送kafka消息的会话模式窗口,发送一个字符串"aaa bbb ccc aaa aaa aaa";
  • 查看cassandra数据,发现已经新增了三条记录,内容符合预期:

在这里插入图片描述

  • 查看TaskManager控制台输出,里面有Tuple2数据集的打印结果,和cassandra的一致:

在这里插入图片描述

  • DAG上所有SubTask的记录数也符合预期:
    在这里插入图片描述

开发(POJO写入)

  • 接下来尝试POJO写入,即业务逻辑中的数据结构实例被写入cassandra,无需指定SQL:
  • 实现POJO写入数据库,需要datastax库的支持,在pom.xml中增加以下依赖:
<dependency>
  <groupId>com.datastax.cassandra</groupId>
  <artifactId>cassandra-driver-core</artifactId>
  <version>3.1.4</version>
  <classifier>shaded</classifier>
  <!-- Because the shaded JAR uses the original POM, you still need
                 to exclude this dependency explicitly: -->
  <exclusions>
    <exclusion>
    <groupId>io.netty</groupId>
    <artifactId>*</artifactId>
    </exclusion>
  </exclusions>
</dependency>
package com.bolingcavalry.addsink;

import com.datastax.driver.mapping.annotations.Column;
import com.datastax.driver.mapping.annotations.Table;

@Table(keyspace = "example", name = "wordcount")
public class WordCount {
   
   

    @Column(name = "word")
    private String word = "";

    @Column(name = "count")
    private long count = 0;

    public WordCount() {
   
   
    }

    public WordCount(String word, long count) {
   
   
        this.setWord(word);
        this.setCount(count);
    }

    public String getWord() {
   
   
        return word;
    }

    public void setWord(String word) {
   
   
        this.word = word;
    }

    public long getCount() {
   
   
        return count;
    }

    public void setCount(long count) {
   
   
        this.count = count;
    }

    @Override
    public String toString() {
   
   
        return getWord() + " : " + getCount();
    }
}
  • 然后创建任务类CassandraPojoSink:
package com.bolingcavalry.addsink;

import com.datastax.driver.mapping.Mapper;
import com.datastax.shaded.netty.util.Recycler;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.PrintSinkFunction;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.cassandra.CassandraSink;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.util.Collector;

import java.util.Properties;

public class CassandraPojoSink {
   
   
    public static void main(String[] args) throws Exception {
   
   
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        //设置并行度
        env.setParallelism(1);

        //连接kafka用到的属性对象
        Properties properties = new Properties();
        //broker地址
        properties.setProperty("bootstrap.servers", "192.168.50.43:9092");
        //zookeeper地址
        properties.setProperty("zookeeper.connect", "192.168.50.43:2181");
        //消费者的groupId
        properties.setProperty("group.id", "flink-connector");
        //实例化Consumer类
        FlinkKafkaConsumer<String> flinkKafkaConsumer = new FlinkKafkaConsumer<>(
                "test001",
                new SimpleStringSchema(),
                properties
        );

        //指定从最新位置开始消费,相当于放弃历史消息
        flinkKafkaConsumer.setStartFromLatest();

        //通过addSource方法得到DataSource
        DataStream<String> dataStream = env.addSource(flinkKafkaConsumer);

        DataStream<WordCount> result = dataStream
                .flatMap(new FlatMapFunction<String, WordCount>() {
   
   
                    @Override
                    public void flatMap(String s, Collector<WordCount> collector) throws Exception {
   
   
                        String[] words = s.toLowerCase().split("\\s");

                        for (String word : words) {
   
   
                            if (!word.isEmpty()) {
   
   
                                //cassandra的表中,每个word都是主键,因此不能为空
                                collector.collect(new WordCount(word, 1L));
                            }
                        }
                    }
                })
                .keyBy("word")
                .timeWindow(Time.seconds(5))
                .reduce(new ReduceFunction<WordCount>() {
   
   
                    @Override
                    public WordCount reduce(WordCount wordCount, WordCount t1) throws Exception {
   
   
                        return new WordCount(wordCount.getWord(), wordCount.getCount() + t1.getCount());
                    }
                });

        result.addSink(new PrintSinkFunction<>())
                .name("print Sink")
                .disableChaining();

        CassandraSink.addSink(result)
                .setHost("192.168.133.168")
                .setMapperOptions(() -> new Mapper.Option[] {
   
    Mapper.Option.saveNullFields(true) })
                .build()
                .name("cassandra Sink")
                .disableChaining();

        env.execute("kafka-2.4 source, cassandra-3.11.6 sink, pojo");
    }

}
  • 从上述代码可见,和前面的Tuple写入类型有很大差别,为了准备好POJO类型的数据集,除了flatMap的匿名类入参要改写,还要写好reduce方法的匿名类入参,并且还要调用setMapperOptions设置映射规则;
  • 编译构建后,上传jar到flink,并且指定任务类为CassandraPojoSink:

在这里插入图片描述

  • 清理之前的数据,在cassandra的cqlsh上执行TRUNCATE example.wordcount;
  • 像之前那样发送字符串消息到kafka:

在这里插入图片描述

  • 查看数据库,发现结果符合预期:

在这里插入图片描述

  • DAG和SubTask情况如下:
    在这里插入图片描述

  • 至此,flink的结果数据写入cassandra的实战就完成了,希望能给您一些参考;

欢迎关注阿里云开发者社区博客:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
相关文章
|
20天前
|
分布式计算 大数据 Apache
ClickHouse与大数据生态集成:Spark & Flink 实战
【10月更文挑战第26天】在当今这个数据爆炸的时代,能够高效地处理和分析海量数据成为了企业和组织提升竞争力的关键。作为一款高性能的列式数据库系统,ClickHouse 在大数据分析领域展现出了卓越的能力。然而,为了充分利用ClickHouse的优势,将其与现有的大数据处理框架(如Apache Spark和Apache Flink)进行集成变得尤为重要。本文将从我个人的角度出发,探讨如何通过这些技术的结合,实现对大规模数据的实时处理和分析。
55 2
ClickHouse与大数据生态集成:Spark & Flink 实战
|
1月前
|
消息中间件 关系型数据库 MySQL
大数据-117 - Flink DataStream Sink 案例:写出到MySQL、写出到Kafka
大数据-117 - Flink DataStream Sink 案例:写出到MySQL、写出到Kafka
138 0
|
1月前
|
消息中间件 NoSQL Kafka
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
132 0
|
3月前
|
大数据 API 数据处理
揭秘!Flink如何从默默无闻到大数据界的璀璨明星?起源、设计理念与实战秘籍大公开!
【8月更文挑战第24天】Apache Flink是一款源自Stratosphere项目的开源流处理框架,由柏林理工大学等机构于2010至2014年间开发,并于2014年捐赠给Apache软件基金会。Flink设计之初即聚焦于提供统一的数据处理模型,支持事件时间处理、精确一次状态一致性等特性,实现了流批一体化处理。其核心优势包括高吞吐量、低延迟及强大的容错机制。
64 1
|
3月前
|
SQL 关系型数据库 测试技术
实时数仓 Hologres操作报错合集之执行Flink的sink操作时出现报错,是什么原因
实时数仓Hologres是阿里云推出的一款高性能、实时分析的数据库服务,专为大数据分析和复杂查询场景设计。使用Hologres,企业能够打破传统数据仓库的延迟瓶颈,实现数据到决策的无缝衔接,加速业务创新和响应速度。以下是Hologres产品的一些典型使用场景合集。
|
3月前
|
API C# Shell
WPF与Windows Shell完美融合:深入解析文件系统操作技巧——从基本文件管理到高级Shell功能调用,全面掌握WPF中的文件处理艺术
【8月更文挑战第31天】Windows Presentation Foundation (WPF) 是 .NET Framework 的关键组件,用于构建 Windows 桌面应用程序。WPF 提供了丰富的功能来创建美观且功能强大的用户界面。本文通过问题解答的形式,探讨了如何在 WPF 应用中集成 Windows Shell 功能,并通过具体示例代码展示了文件系统的操作方法,包括列出目录下的所有文件、创建和删除文件、移动和复制文件以及打开文件夹或文件等。
76 0
|
3月前
|
存储 SQL Java
实时数仓 Hologres产品使用合集之如何使用Flink的sink连接
实时数仓Hologres是阿里云推出的一款高性能、实时分析的数据库服务,专为大数据分析和复杂查询场景设计。使用Hologres,企业能够打破传统数据仓库的延迟瓶颈,实现数据到决策的无缝衔接,加速业务创新和响应速度。以下是Hologres产品的一些典型使用场景合集。
|
4月前
|
消息中间件 NoSQL Redis
实时计算 Flink版产品使用问题之配置了最大连续失败数不为1,在Kafka的精准一次sink中,如果ck失败了,这批数据是否会丢失
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
NoSQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之如何确保多并发sink同时更新Redis值时,数据能按事件时间有序地更新并且保持一致性
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
6月前
|
SQL 消息中间件 Kafka
实时计算 Flink版产品使用合集之支持sink到多分区的kafka ,还能保持有序吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。