【Flink】Sink 下沉算子 『print() | addSource() 』

1. Flink 直接连接的数据源

* 将数据输出到控制台

stream.print()

2. Flink使用连接器连接的数据源

  • 在 Flink 中,将数据写入外部系统,其实并不是一件难事。与外部系统的交互在任何一个处理算子中都可以实现。例如在 MapFunction 中,我们完全可以构建一个到 Redis 的连接,然后将当前处理的结果保存到 Redis 中。如果考虑到只需建立一次连接,我们也可以利用RichMapFunction,在 open() 生命周期中做连接操作。
  • 这样看起来很方便,却会带来很多问题。Flink 作为一个快速的分布式实时流处理系统,对稳定性和容错性要求极高。一旦出现故障,我们应该有能力恢复之前的状态,保障处理结果的正确性。这种性质一般被称作“状态一致性”。Flink 内部提供了一致性检查点(checkpoint)来保障我们可以回滚到正确的状态;但如果我们在处理过程中任意读写外部系统,发生故障后就很难回退到从前了。
  • 为了避免这样的问题,Flink 的 DataStream API 专门提供了通过连接器向外部写入数据的方法:addSink(连接器)

2.1 将数据输出到Kafka (用于无界流数据的实际场景)

真正让Flink 与 Kafka密不可分的是,Flink 与 Kafka 的连接器提供了端到端的精确一次(exactly once)语义保证,这在实际项目中是最高级别的一致性保证。

  1. 首先在 pom.xml 文件中导入 kafka 依赖:

    <dependency>
    	<groupId>org.apache.flink</groupId>
    	<artifactId>flink-connector-kafka_${scala.binary.version}</artifactId>
    	<version>${flink.version}</version>
    </dependency>
    
    <!-- 一般是将数据转为json格式写入到kafka,所以为了后面的例子演示,还导入json依赖 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.75</version>
    </dependency>
    
  2. 启动 Kafka 集群

  3. 再使用env.addSink(new FlinkKafkaProducer<>())将数据写入到kafka。例如:

    Properties properties = new Properties();
    properties.put("bootstrap.servers", "hadoop102:9092"); // kafka地址
    
    env
          .fromCollection(waterSensors)
          .map(JSON::toJSONString)
          .addSink(new FlinkKafkaProducer<String>(
          				"clicks",  // 要写入的kafka的主题
          				new SimpleStringSchema(),  // 序列化器
          				properties 
          );
    

    实际情况下更多的是使用FlinkKafkaProducer类的这个构造器:

    Properties sinkConfig = new Properties();
    sinkConfig.setProperty("bootstrap.servers", "hadoop102:9092,hadoop103:9092,hadoop104:9092");
    
    env
          .fromCollection(waterSensors)
          .map(JSON::toJSONString)
          .addSink(new FlinkKafkaProducer<WaterSensor>(
          				"default",  // 默认topic, 这个一般用不上
          				new KafkaSerializationSchema<WaterSensor>() {  // 自定义的序列化器
    	                    @Override
    	                    public ProducerRecord<byte[], byte[]> serialize(WaterSensor element,
    	                                                                    @Nullable Long timestamp) {
    	                        String s = JSON.toJSONString(element);
    	                        return new ProducerRecord<>("s1", s.getBytes(StandardCharsets.UTF_8));
    	                    }
                		},
                		sinkConfig,  // kafka的配置
                		FlinkKafkaProducer.Semantic.AT_LEAST_ONCE  // 一致性语义: 现在只能传入至少一次
          );
    

2.2 将数据输出到Redis (用于无界流数据的实际场景)

Redis 是一个开源的内存式的数据存储,提供了像字符串(string)、哈希表(hash)、列表(list)、集合(set)、排序集合(sorted set)、位图(bitmap)、地理索引和流(stream)等一系列常用的数据结构。因为它运行速度快、支持的数据类型丰富,在实际项目中已经成为了架构优化必不可少的一员,一般用作数据库、缓存,也可以作为消息代理。

  1. 首先在 pom.xml 文件中导入 kafka 依赖:

    <dependency>
    	<groupId>org.apache.bahir</groupId>
    	<artifactId>flink-connector-redis_2.11</artifactId>
    	<version>1.0</version>
    </dependency>
    
  2. 启动 Redis 集群

  3. 再使用env.addSink(new RedisSink<>())将数据写入到Redis。例如:

FlinkJedisPoolConfig conf = new 
FlinkJedisPoolConfig.Builder().setHost("hadoop102").build();
env
	.addSource(new ClickSource())
	.addSink(new RedisSink<Event>(
		conf, // Jedis 的连接配置
		new RedisMapper() { // 说明怎样将数据转换成可以写入 Redis 的类型
			@Override // 返回命令描述符
			public String getKeyFromData(Event e) {
				return e.user;
			}
			@Override
			public String getValueFromData(Event e) {
				return e.url;
			}
			@Override
			public RedisCommandDescription getCommandDescription() {
				return new RedisCommandDescription(RedisCommand.HSET, "clicks");
			}
		}
	);

2.3 将数据输出到 Elasticsearch (用到了再写)

2.4 将数据输出到 MySQL(JDBC) (用到了再写)

2.5 将数据输出到 文件系统 (用到了再写)

2.6 自定义 Sink 输出 (用到了再写)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ElegantCodingWH

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

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

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

打赏作者

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

抵扣说明:

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

余额充值