ITPub博客

首页 > 大数据 > 数据挖掘 > Flink高性能读写StarRocks内表剖析

Flink高性能读写StarRocks内表剖析

数据挖掘 作者:乐逍遥happy 时间:2025-06-22 21:50:06 0 删除 编辑

  StarRocks 是一种高性能的分布式分析型数据库,广泛应用于实时数据分析场景。Apache Flink 作为流批一体化的计算框架,与 StarRocks 的结合能够高效处理大规模数据。为实现更高的读写性能,推荐使用 StarRocks 官方提供的 flink-connector-starrocks,而非 Flink 官方的 Flink JDBC Connector。

一、Flink-Connector-StarRocks 概述

1.1 为什么选择 Flink-Connector-StarRocks?

相较于 Flink JDBC Connector,StarRocks 自研的 Flink Connector 具有以下显著优势:

  • 高性能并行读取:支持从 StarRocks 集群的各个 Backend(BE)节点并行读取数据,充分利用分布式架构,大幅提升读取效率。

  • 高效批量写入:通过 Stream Load 机制,Flink 在内存中缓存小批量数据后以 HTTP PUT 请求的方式导入,StarRocks 的 Frontend(FE)将请求分发至 BE 节点,由 BE 节点作为 Coordinator 协调导入任务,降低 FE 负载。

  • 事务支持:从 StarRocks 2.4 和 Flink Connector 1.2.4 开始,支持通过两阶段提交(2PC)实现 exactly-once 语义的写入。

  • 灵活性与可扩展性:支持 DataStream API 和 Flink SQL 两种开发方式,满足不同开发需求。

1.2 适用场景

  • 实时 ETL:从 StarRocks 读取数据,经过 Flink 加工后写入目标表。

  • 数据分析:结合 Flink 的流批处理能力,对 StarRocks 数据进行实时或批量分析。

  • 数据湖加速:通过高效读写,加速数据湖与 StarRocks 之间的数据交互。

二、Flink 读取 StarRocks 数据

Flink 支持通过 DataStream API 和 Flink SQL 从 StarRocks 表中读取数据。读取操作要求用户账号具备目标表的 SELECT 权限。

2.1 DataStream API 读取示例(基于 Flink 1.16)

以下是一个完整的 DataStream API 读取示例:

2.1.1 添加依赖

在项目中添加 flink-connector-starrocks 依赖:

    <dependency><groupId>com.starrocks</groupId><artifactId>flink-connector-starrocks</artifactId><version>1.2.10_flink-1.16</version><!-- 对于 Flink 1.19,可使用 <version>1.2.10_flink-1.19</version> --><scope>provided</scope></dependency>

    2.1.2 代码示例

      public class StarRocksSourceApp {public static void main(String[] args) throws Exception {//构建 StarRocksSourceStarRocksSourceOptions options = StarRocksSourceOptions.builder()                          .withProperty("scan-url", "xxx:8030")                          .withProperty("jdbc-url", "jdbc:mysql://xxx:9030")                .withProperty("username", "xxx")                     .withProperty("password", "123456")             .withProperty("table-name", "score_board")            .withProperty("database-name", "unload")               .build();TableSchema tableSchema = TableSchema.builder()                 .field("id", DataTypes.INT())                          .field("name", DataTypes.STRING())                          .field("score", DataTypes.INT())                          .build();StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.addSource(StarRocksSource.source(tableSchema, options)).setParallelism(5).print();env.execute("StarRocks flink source");    }}

      2.2 Flink SQL 读取示例

      Flink SQL 提供了更简洁的声明式方式,适合快速开发。

        CREATE TABLE flink_sr_table(    
        `id` INT,    
        `name` STRING,    
        `score` INT)
        WITH(    
        'connector'='starrocks',    
        'scan-url'='xxx:8030',    
        'jdbc-url'='jdbc:mysql://xxx:9030',    
        'username'='xxx',    
        'password'='xxx',    
        'database-name'='unload',    
        'table-name'='score_board');
        
        
        select * from flink_sr_table;

        三、Flink 写入 StarRocks 数据

        Flink 支持通过 DataStream API 和 Flink SQL 向 StarRocks 表写入数据。写入操作要求用户账号具备目标表的 SELECT 和 INSERT 权限。

        3.1 DataStream API 写入示例(基于 Flink 1.16)

        3.1.1 添加依赖

        与读取相同,添加以下依赖:

          <dependency><groupId>com.starrocks</groupId><artifactId>flink-connector-starrocks</artifactId><version>1.2.10_flink-1.16</version><scope>provided</scope></dependency>

          3.1.2 代码示例

            public class StarRocksSinkApp {public static void main(String[] args) throws Exception {     StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();     String[] records = new String[]{"500\tstarrocks-csv\t100","501\tflink-csv\t100"};     DataStream<String> source = env.fromElements(records);     StarRocksSinkOptions options = StarRocksSinkOptions.builder()                     .withProperty("jdbc-url", "jdbc:mysql://xxx:9030")                               .withProperty("load-url", "xxx:8030")                               .withProperty("database-name", "unload")                               .withProperty("table-name", "score_board")                               .withProperty("username", "xxx")                               .withProperty("password", "xxx")                               .withProperty("sink.properties.format", "csv")                               .withProperty("sink.properties.column_separator", "\t")                               .build();     // Create the sink with the options.     SinkFunction<String> starRockSink = StarRocksSink.sink(options);     source.addSink(starRockSink);     env.execute("StarRocks flink source");     }}

            3.2 Flink SQL 写入示例

            3.2.1 创建表

              CREATE TABLE `score_board` (    
              `id` INT,    
              `name` STRING,    
              `score` INT,    
              PRIMARY KEY (id) NOT ENFORCED) 
              WITH (   
              'connector' = 'starrocks',    
              'jdbc-url' = 'jdbc:mysql://xxx:9030',    
              'load-url' = 'xxx:8030',    
              'database-name' = 'unload',    
              'table-name' = 'score_board',    
              'username' = 'xxx',    
              'password' = 'xxx');
              
              
              INSERT INTO `score_board` VALUES (1, 'starrocks', 99), (2, 'flink', 100);

              3.3 写入并发与批量控制

              • 并发控制:

                • DataStream API:通过 Flink 作业的并行度设置(如  setParallelism)。

                • Flink SQL:通过  sink.parallelism 参数设置写入并发。

              • 批量写入触发条件:

                • 缓存数据大小达到  sink.buffer-flush.max-bytes。

                • 缓存行数达到  sink.buffer-flush.max-rows。

                • 距离上次刷新超过  sink.buffer-flush.interval-ms。

              四、高性能实现原理

              4.1 读取高性能实现

              1. 初始化 :Flink 的 Source 任务通过  StarRocksSourceFunction  连接 StarRocks 的 FE,获取查询计划(QueryPlan),包含数据分片(Tablet)的分布信息。

              2. 并行读取 :根据查询计划,Source 任务并行连接多个 BE 节点,每个子任务通过  TStarrocksExternalService.Client  使用 Thrift RPC 协议直接读取 Tablet 数据。

              3. 核心类 :

                • StarRocksDynamicSourceFunction :负责连接 FE、获取查询计划并分发读取任务。

                • StarRocksSourceBeReader :通过 Thrift RPC 实现 BE 节点的数据读取。


              在StarRocksDynamicSourceFunction构造函数中,会根据查询sql连接FE获取查询计划

              图片
              图片


              open 方法,根据查询计划获取BE Tablet分区,同时构建对应的读取器StarRocksSrouceBeReader

              图片


              run 方法,通过StarRocksSourceBeReader进行循环读取

              图片


              StarRocksSourceBeReader里通过 Thrift RPC 对 BE 进行实际的数据读取

              图片

              4.2 写入高性能实现

              • 批量写入 :通过 Stream Load(或事务性 Stream Load)将数据缓存到内存后批量发送,减少网络交互。
              • 事务性 Stream Load(V2 模式) :
              • 从 StarRocks 2.4 和 Flink 连接器 1.2.4 开始,支持事务性写入,通过两阶段提交(2PC)实现 exactly-once。
              • 异步写入与重试:异步提交数据,支持配置重试次数(如  sink.max-retries )。
              • 内存管理:通过  sink.buffer-flush.max-rows  和  sink.buffer-flush.max-bytes  控制缓存数据量,优化吞吐量与延迟。

              StarRocksDynamicSinkFunction,在invoke方法里对数据进行序列化,然后通过 StarRocksSinkManager 写入

              图片


              DefaultStreamLoader,实现 Stream Load 的 HTTP 请求和响应处理,通过构建 HttpPut 生成对应的 Stream Load 任务

              图片

              具体管理事务的生命周期 TransactionStreamLoader(begin、prepare、commit、 rollback)

              StarRocksSinkManager,在内存攒一批数据,超过条件就flush

              图片

              以上就是简单扼要的剖析flink-connector-starrocks对starrocks高效读写的原理,而jdbc本质还是通过mysql协议对starrocks进行读写操作,就必须经过FE,而这种方式,在读取比较大的结果集时,会对FE造成比较大的负担,因为结果集流量要通过FE;在写入的时候如果频繁的通过构造insert语句请求,也会对FE造成负担。

              更多大数据干货,欢迎关注我的微信公众号—BigData共享


              来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70046653/viewspace-3088587/ ,如需转载,请注明出处,否则将追究法律责任。

              请登录后发表评论 登录
              全部评论

              注册时间:2025-06-05

              • 博文量
                18
              • 访问量
                17427