flink 源码分析1之RichSinkFunction

本文深入分析Flink的RedisSink和FlinkKafkaProducer的实现,包括RedisSink的open()方法,以及Flink到Kafka的两阶段提交协议。重点探讨了RedisCommandsContainerBuilder、FlinkJedisPoolConfig和FlinkKafkaProducer的构造与功能。

flink sink 2 mysql demo

我们先看一个自定义sink 的demo,将 nc 的数据写入到mysql 中。


import myflink.learn.model.Student;
import myflink.learn.sink.SinkToMySQL;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author wtx
 * @Date 2019/1/23
 */
public class Flink2MysqlDemo {
    public static void main(String[] args) throws Exception {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        env.setParallelism(1);
        // 设置数据源
        DataStream<String> text = env.socketTextStream("localhost", 9000, "\n");

//        DataStream<Student> studentDataStream = text.map(new MapFunction<String, Student>() {
//            @Override
//            public Student map(String s) throws Exception {
//                Student student = new Student();
//                student.setName(s);
//                student.setId(atomicInteger.addAndGet(1));
//                return student;
//            }
//        });

        DataStream<Student> studentDataStream = text.map((str) -> {
            Student student = new Student();
            student.setName(str);
            student.setId(atomicInteger.addAndGet(1));
            return student;
        });

        studentDataStream.addSink(new SinkToMySQL());
        env.execute();
    }
}
@Slf4j
public class SinkToMySQL extends RichSinkFunction<Student> {
    PreparedStatement ps;
    private Connection connection;

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        connection = getConnection();
        String sql = "insert into student(id, name) values(?, ?);";
        ps = this.connection.prepareStatement(sql);
    }

    @Override
    public void close() throws Exception {
        super.close();
        //关闭连接和释放资源
        if (connection != null) {
            connection.close();
        }
        if (ps != null) {
            ps.close();
        }
    }

    @Override
    public void invoke(Student value, Context context) throws Exception {
        //组装数据,执行插入操作
        ps.setInt(1, value.getId());
        ps.setString(2, value.getName());
        ps.executeUpdate();
    }

    private static Connection getConnection() {
        Connection con = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8", "root", "");
        } catch (Exception e) {
            log.error("exception e:", e);
        }
        return con;
    }
}

RichSinkFunction 的类结构

可以看到自定义的sink 继承自RichSinkFunction. 来看 RichSinkFunction 的类结构

 



/**
 * The base interface for all user-defined functions.
 *
 * <p>This interface is empty in order to allow extending interfaces to
 * be SAM (single abstract method) interfaces that can be implemented via Java 8 lambdas.</p>
 */
@Public
public interface Function extends java.io.Serializable {
}
public interface SinkFunction<IN> extends Function, Serializable{
  default void invoke(IN value, Context context) throws Exception {
        invoke(value);
    }
  @Public
    interface Context<T> {
        long currentProcessingTime();
        long currentWatermark();
        Long timestamp();
    }
}

在上面的 SinkFunction 接口中实际只有一个方法,invoke(),将类型为IN 的value 写入到sink 中。Context: 写入value 时的上下文 

@Public
public abstract class AbstractRichFunction implements RichFunction, Serializable {
  private transient RuntimeContext runtimeContext;
  @Override
    public void open(Configuration parameters) throws Exception {}

    @Override
    public void close() throws Exception {}
}

 

而在AbstractRichFunction 只有默认的生命周期方法 open() 和 close() 的空实现。 留给我们自己的比如上面的 SinkToMySQL那样 实现 对于mysql 的 open() close() 另外可以类似的实现对于redis 的sink 类。查看flink-connector-redis 发现已经有了RedisSink 类。
我们先来看看简单的使用:只需要将 new SinkToMySQL() -> new RedisSink

studentDataStream.addSink(new SinkToMySQL());

               ==>

FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build();
studentDataStream.addSink(new RedisSink<Tuple2<String, I
<think>好的,用户想找关于Flink源码分析的文章。之前已经提供了三个引用,我需要先仔细看看这些引用的内容。引用1讲的是Flink在K8s上的集群与资源管理,包括作业管理器和Slot管理;引用2是关于Source原理,特别是SQL解析和AST生成;引用3则涉及用户代码执行,生成StreamGraph的流程。用户之前可能已经询问过相关主题,所以需要结合之前的回答。 用户现在需要更多的源码分析文章解读,可能需要覆盖更多模块,比如作业调度、容错机制、状态管理等。我需要确认现有的引用是否足够,或者是否需要建议其他方向。比如引用3提到了StreamGraph,可以扩展讲讲执行流程。另外,用户可能对实际应用场景感兴趣,比如如何优化资源分配,或者Flink的SQL解析如何影响性能。 还要注意用户的问题生成部分,需要提出相关问题,比如Flink的容错机制如何实现,或者StreamGraph的构建过程。确保问题与现有引用内容相关,同时引导用户深入理解源码结构。最后,保持回答结构清晰,分模块解析,帮助用户逐步掌握Flink源码分析的方法。</think>### Flink源码分析关键模块解读 根据现有技术文档和源码分析线索,Flink核心模块可分为以下三部分进行解读: 一、**集群与资源管理模块** 1. 动态资源分配通过`ResourceManager`实现K8s容器生命周期管理 2. Slot资源池采用两级分配策略:`TaskManager`注册时分配基础Slot,作业提交时动态扩展 3. 作业管理器通过`JobMaster`与`ResourceManager`交互,实现资源协商机制[^1] 二、**SQL处理与流式转换** 1. SQL解析阶段生成`SqlNode`抽象语法树 2. 通过`Planner`将逻辑计划转换为物理执行计划 3. `StreamGraph`生成器将关系代数操作映射为流式计算拓扑[^2] 三、**执行引擎核心流程** ```java // 源码执行路径示例 public JobExecutionResult execute(String jobName) { StreamGraph streamGraph = getStreamGraph(); // 生成流图 optimizePipeline(streamGraph); // 运行时优化 deployToCluster(streamGraph); // 集群部署 } ``` 该流程涉及运行时优化技术,包括算子融合、状态后端选择等关键操作[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值