文章中如果有图看不到,可以点这里去 csdn 看看。从那边导过来的,文章太多,没法一篇篇修改好。

【流式处理系统】使用 Flink 消费数据并处理落库的完整方案

可以完全在 Flink 中完成数据消费、计算加工和结果落库的整个流程,不需要将数据拉到本地服务处理。以下是完整的实现方案:

方案架构

数据源 → Flink(消费+处理) → MySQL

在这里插入图片描述

具体实现步骤

1. 添加依赖

首先确保你的 Flink 项目中包含以下依赖(Maven 示例):

<!-- Flink 基础依赖 -->
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-java</artifactId>
    <version>${flink.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
</dependency>

<!-- 数据源连接器(以Kafka为例) -->
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-kafka</artifactId>
    <version>${flink.version}</version>
</dependency>

<!-- MySQL连接器 -->
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-jdbc</artifactId>
    <version>${flink.version}</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>

2. Flink 数据处理代码示例

import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.connector.jdbc.JdbcConnectionOptions;
import org.apache.flink.connector.jdbc.JdbcExecutionOptions;
import org.apache.flink.connector.jdbc.JdbcSink;

import java.util.Properties;

public class FlinkToMysqlJob {
    public static void main(String[] args) throws Exception {
        // 1. 创建执行环境
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        
        // 2. 配置Kafka消费者(数据源)
        Properties properties = new Properties();
        properties.setProperty("bootstrap.servers", "localhost:9092");
        properties.setProperty("group.id", "flink-group");
        
        FlinkKafkaConsumer<String> kafkaSource = new FlinkKafkaConsumer<>(
            "input-topic", 
            new SimpleStringSchema(), 
            properties
        );
        
        // 3. 添加数据源
        DataStream<String> stream = env.addSource(kafkaSource);
        
        // 4. 数据处理(示例:解析JSON、过滤、转换)
        DataStream<Order> orders = stream
            .map(new MapFunction<String, Order>() {
                @Override
                public Order map(String value) throws Exception {
                    // 解析JSON字符串为Order对象
                    return parseOrderFromJson(value);
                }
            })
            .filter(order -> order.getAmount() > 0); // 过滤无效订单
        
        // 5. 数据聚合(示例:按用户ID分组,计算总金额)
        DataStream<UserOrderSummary> userSummaries = orders
            .keyBy(Order::getUserId)
            .timeWindow(Time.minutes(5)) // 5分钟窗口
            .aggregate(new OrderAggregator()); // 自定义聚合函数
        
        // 6. 配置MySQL Sink
        JdbcConnectionOptions jdbcOptions = new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
            .withUrl("jdbc:mysql://localhost:3306/your_db")
            .withDriverName("com.mysql.cj.jdbc.Driver")
            .withUsername("username")
            .withPassword("password")
            .build();
        
        // 7. 添加MySQL Sink
        userSummaries.addSink(JdbcSink.sink(
            "INSERT INTO user_order_summary (user_id, total_amount, order_count, window_end) " +
            "VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE " +
            "total_amount = VALUES(total_amount), order_count = VALUES(order_count)",
            (statement, summary) -> {
                statement.setString(1, summary.getUserId());
                statement.setDouble(2, summary.getTotalAmount());
                statement.setInt(3, summary.getOrderCount());
                statement.setTimestamp(4, new java.sql.Timestamp(summary.getWindowEnd()));
            },
            JdbcExecutionOptions.builder()
                .withBatchSize(100)
                .withBatchIntervalMs(200)
                .withMaxRetries(5)
                .build(),
            jdbcOptions
        ));
        
        // 8. 执行任务
        env.execute("Flink Kafka to MySQL Job");
    }
    
    // 自定义聚合函数示例
    public static class OrderAggregator implements AggregateFunction<Order, Accumulator, UserOrderSummary> {
        @Override
        public Accumulator createAccumulator() {
            return new Accumulator();
        }
        
        @Override
        public Accumulator add(Order order, Accumulator accumulator) {
            accumulator.userId = order.getUserId();
            accumulator.totalAmount += order.getAmount();
            accumulator.orderCount++;
            return accumulator;
        }
        
        @Override
        public UserOrderSummary getResult(Accumulator accumulator) {
            return new UserOrderSummary(
                accumulator.userId,
                accumulator.totalAmount,
                accumulator.orderCount,
                System.currentTimeMillis()
            );
        }
        
        @Override
        public Accumulator merge(Accumulator a, Accumulator b) {
            a.totalAmount += b.totalAmount;
            a.orderCount += b.orderCount;
            return a;
        }
    }
    
    // 辅助类
    public static class Accumulator {
        public String userId;
        public double totalAmount = 0;
        public int orderCount = 0;
    }
}

关键点说明

  1. 数据消费:Flink 提供了各种数据源的连接器(Kafka、RabbitMQ、文件等)

  2. 数据处理:可以在 Flink 中完成:

    • 数据清洗和转换(map、filter)
    • 复杂计算(process function)
    • 窗口聚合(window、aggregate)
    • 状态管理(state)
  3. 结果存储

    • 使用 JdbcSink 将结果写入 MySQL
    • 支持批处理写入(提高性能)
    • 支持重试机制(提高可靠性)
  4. 优势

    • 全流程在 Flink 中完成,避免数据移动开销
    • 利用 Flink 的分布式计算能力,处理大规模数据
    • 支持 exactly-once 语义,保证数据一致性

部署方式

  1. 本地运行:直接运行 main 方法(开发测试用)
  2. Standalone 集群:打包后提交到 Flink 集群
  3. YARN/K8s:在生产环境部署

注意事项

  1. 根据你的数据源类型选择合适的连接器
  2. 对于高吞吐场景,调整 MySQL Sink 的批处理参数
  3. 考虑使用连接池管理数据库连接
  4. 生产环境需要配置 checkpoint 和状态后端

这种方案比将数据拉到本地处理更高效、更可靠,特别适合大规模数据处理场景。

posted @ 2025-09-03 16:46  NeoLshu  阅读(9)  评论(0)    收藏  举报  来源