Flink SQL 接入 Amazon Kinesis Data Streams 版本迁移、DDL、EFO/Polling、分区与常见坑一篇搞定

文档里已经写得很直白:

  • Flink 2.2:还没有可用的 Kinesis SQL Connector(依赖暂不可用)
  • Connector 不在 Flink 二进制发行包里,上集群需要自己把 jar 带上(lib/ 或 uber-jar)

所以你在博客开头一定要强调一句:

如果你正在用 Flink 2.2,先别在 Maven 里死磕依赖坐标,短期要么等官方发布 2.2 对应版本,要么选用已有可用连接器的 Flink 版本线。

2. 版本与依赖:两套发行版 + TableFactory 冲突必踩

Kinesis SQL Connector 有两套分发包,原因是底层从旧的 SourceFunction/SinkFunction 迁移到新的 Source/Sink 接口。

关键规则:同一个 connector identifier(kinesis)在 Table API/SQL 中只能有一个 TableFactory

也就是说:你的应用依赖里只能放一个相关 artifact,否则会出现 TableFactory 名称冲突。

2.1 依赖与 identifier 对照表(你写博客建议直接贴表)

依赖 Connector 版本 Source connector identifier(接口) Sink connector identifier(接口)
flink-sql-connector-aws-kinesis-streams 5.x+ kinesis(Source) kinesis(Sink)
flink-sql-connector-aws-kinesis-streams 4.x- N/A(不打包 source) kinesis(Sink)
flink-sql-connector-kinesis 5.x+ kinesis(Source), kinesis-legacy(SourceFunction) kinesis(Sink)
flink-sql-connector-kinesis 4.x- kinesis(SourceFunction) kinesis(Sink)

一句话建议:

  • 新项目优先 5.x+ 的 kinesis(新 Source/Sink)
  • 如果你依赖 metadata VIRTUAL 列(后面会说 bug),暂时可能要用 kinesis-legacy

3. 从 v4.x 迁移到 v5.x:没有状态兼容,别幻想"原地升级不丢不停"

文档里明确:Table API/SQL 在 4.x 与 5.x 之间没有 state compatibility,因为底层实现变了。

迁移策略(官方建议思路):

  1. 停掉 v4.x 作业
  2. 启动 v5.x 的 kinesis 表
  3. source.init.position = AT_TIMESTAMP,并把 source.init.timestamp 设到"停作业时间稍早一点"
  4. 接受可能会有 重复处理(re-processed records)

你写博客时可以用一句很工程化的话解释:

迁移不是"状态无缝接管",而是"时间点对齐 + 幂等处理兜底"。

4. 快速开始:创建一张 Kinesis Source 表(Scan Source)

下面这段 DDL 是典型模板(按你的文档):

sql 复制代码
CREATE TABLE KinesisTable (
  `user_id` BIGINT,
  `item_id` BIGINT,
  `category_id` BIGINT,
  `behavior` STRING,
  `ts` TIMESTAMP(3)
)
PARTITIONED BY (user_id, item_id)
WITH (
  'connector' = 'kinesis',
  'stream.arn' = 'arn:aws:kinesis:us-east-1:012345678901:stream/my-stream-name',
  'aws.region' = 'us-east-1',
  'source.init.position' = 'LATEST',
  'format' = 'csv'
);

这里有几个细节很重要:

  • stream.arn 是必填(指向具体 KDS Stream)
  • format 决定序列化/反序列化(Kinesis 本身只存二进制,不理解 schema)
  • PARTITIONED BY 在写入(sink)时会影响分区策略(后面详解)
  • source.init.position 常见就是 LATESTAT_TIMESTAMP

5. Metadata VIRTUAL 列:很香,但新 Source 有 bug,得用 legacy

文档给了一个"已知问题":

  • kinesis(新 Source)目前不支持 VIRTUAL 列
  • 需要 metadata(timestamp / shard-id / sequence-number)时,建议用 kinesis-legacy

metadata 字段含义(只读 VIRTUAL):

  • timestamp:记录写入 stream 的近似时间
  • shard-id:来源 shard
  • sequence-number:shard 内序号

示例 DDL(按文档):

sql 复制代码
CREATE TABLE KinesisTable (
  `user_id` BIGINT,
  `item_id` BIGINT,
  `category_id` BIGINT,
  `behavior` STRING,
  `ts` TIMESTAMP(3),
  `arrival_time` TIMESTAMP(3) METADATA FROM 'timestamp' VIRTUAL,
  `shard_id` VARCHAR(128) NOT NULL METADATA FROM 'shard-id' VIRTUAL,
  `sequence_number` VARCHAR(128) NOT NULL METADATA FROM 'sequence-number' VIRTUAL
)
PARTITIONED BY (user_id, item_id)
WITH (
  'connector' = 'kinesis-legacy',
  'stream' = 'user_behavior',
  'aws.region' = 'us-east-2',
  'scan.stream.initpos' = 'LATEST',
  'format' = 'csv'
);

实战建议:

如果你做的是"延迟观测、按 shard 排障、顺序诊断",metadata 列非常有价值;否则可以先用新 kinesis,等 bug 修复再切。

6. 配置项拆解:写 DDL 时你真正需要关心什么

下面按文档的 Option 分组,把最有用的部分提炼出来。

6.1 Common Options(通用)

  • connectorkinesiskinesis-legacy
  • stream.arn(新)/ stream(legacy):stream 标识
  • format:csv/json/avro 等
  • aws.region:区域
  • aws.endpoint:自定义 endpoint(VPC endpoint / Localstack)
  • aws.trust.all.certificates:测试用,生产不建议开

6.2 Authentication(鉴权)

支持多种 credentials provider(AUTO/BASIC/PROFILE/ASSUME_ROLE/WEB_IDENTITY_TOKEN/CUSTOM),常用落地建议:

  • 生产环境:优先 IAM Role(或 AssumeRole)
  • 开发联调:PROFILE 或 BASIC(避免把 AK/SK 硬编码进 DDL 仓库)

6.3 Source Options(读 Kinesis)

核心关注点有 5 个:

  1. 起始位置
  • source.init.position(新)
  • scan.stream.initpos(legacy)
    常用:LATESTAT_TIMESTAMP(配合 timestamp)
  1. shard 发现频率
  • source.shard.discovery.interval(默认 10s)
  1. 读取模式:POLLING vs EFO
  • source.reader.type = POLLING | EFO
  1. POLLING 关键参数
  • source.shard.get-records.max-record-count:单次拉取上限(默认 10000)
  1. EFO 关键参数
  • source.efo.consumer.name:消费者名
  • source.efo.lifecycle = JOB_MANAGED | SELF_MANAGED
  • 以及订阅/注销超时、DescribeStreamConsumer 的指数退避重试等

直观理解:

  • POLLING 更通用,配置简单
  • EFO(Enhanced Fan-Out)更偏低延迟/高隔离,但要管理 consumer(名称、生命周期、注册/注销)

6.4 Sink Options(写 Kinesis)

写入端你最该盯紧的就三类:

  1. 分区策略
  • sink.partitioner
  • sink.partitioner-field-delimiter
  1. 背压与缓冲
  • sink.batch.max-size(默认 500)
  • sink.requests.max-inflight(默认 16)
  • sink.requests.max-buffered(默认 10000)
  • sink.flush-buffer.size(默认 5242880 bytes)
  • sink.flush-buffer.timeout(默认 5000 ms)
  1. 错误策略
  • sink.fail-on-error(默认 false):失败是否直接 fail 作业(注意:这会显著影响容错与恢复策略)

另外 sink.producer.* 在新体系里属于 legacy 的遗留项:能映射的会映射,不能映射的会 warn。

7. Sink 分区策略:shard 多了之后,不分区你就等着热点

Kinesis 是 shard 架构,写入时 PartitionKey 决定落到哪个 shard。SQL connector 用 sink.partitioner 控制 PartitionKey 的生成方式:

  • fixed:PartitionKey 由 Flink subtask index 推导(每个 subtask 基本固定打到一个分区)
  • random:随机(没有 PARTITION BY 时的默认)
  • 自定义 partitioner:org.mycompany.MyPartitioner

重点规则(很容易踩):

  • 如果表定义了 PARTITION BY,PartitionKey 会由这些字段拼接得到
  • 这时 不能再用 sink.partitioner 改行为,否则直接配置错误
  • 你仍然可以用 sink.partitioner-field-delimiter 控制拼接分隔符(比如 | 或空字符串)

工程建议:

写入有热点 key 的业务(比如 user_id 极度倾斜)要特别注意:PARTITION BY 字段选错了,Kinesis shard 会被打爆。

8. Data Type Mapping:Kinesis 不懂结构,format 才是"schema 的灵魂"

Kinesis 存的就是 Base64 编码的二进制 blob,本身没有 schema。

你在 DDL 里写的字段类型能不能解析,全靠:

  • format = 'csv' / 'json' / 'avro' ...

建议在博客里提醒两点:

  • json 更适合 schema 演进(字段增减)
  • csv 更轻,但对字段顺序、分隔符、空值非常敏感

9. 一套可直接跑的 SQL Pipeline 模板(Source -> Sink)

下面给你一个"能复制粘贴"的结构(你可以按需改字段与 format)。

9.1 Source 表

sql 复制代码
CREATE TABLE kds_source (
  user_id BIGINT,
  item_id BIGINT,
  category_id BIGINT,
  behavior STRING,
  ts TIMESTAMP(3)
) WITH (
  'connector' = 'kinesis',
  'stream.arn' = 'arn:aws:kinesis:us-east-1:012345678901:stream/my-source-stream',
  'aws.region' = 'us-east-1',
  'source.init.position' = 'LATEST',
  'source.reader.type' = 'POLLING',
  'format' = 'json'
);

9.2 Sink 表(Streaming Append / Batch Sink / Unbounded Sink 按文档能力)

sql 复制代码
CREATE TABLE kds_sink (
  user_id BIGINT,
  item_id BIGINT,
  category_id BIGINT,
  behavior STRING,
  ts TIMESTAMP(3)
)
PARTITIONED BY (user_id)
WITH (
  'connector' = 'kinesis',
  'stream.arn' = 'arn:aws:kinesis:us-east-1:012345678901:stream/my-sink-stream',
  'aws.region' = 'us-east-1',
  'sink.batch.max-size' = '500',
  'sink.requests.max-inflight' = '16',
  'sink.requests.max-buffered' = '10000',
  'sink.flush-buffer.timeout' = '5000',
  'format' = 'json'
);

9.3 写入任务

sql 复制代码
INSERT INTO kds_sink
SELECT
  user_id,
  item_id,
  category_id,
  behavior,
  ts
FROM kds_source;

如果你需要更强的分区控制:

  • 没有 PARTITION BY:用 sink.partitioner = fixed/random/custom
  • PARTITION BY:PartitionKey 由字段拼接,必要时调 sink.partitioner-field-delimiter

10. 本地/测试联调:VPC Endpoint / Localstack 一把梭

如果你在测试环境不想直连 AWS,可以用 aws.endpoint 指向内网 endpoint 或 Localstack,同时测试场景下可配置 aws.trust.all.certificates=true(生产别开)。

示例(概念写法):

sql 复制代码
WITH (
  'aws.region' = 'us-east-1',
  'aws.endpoint' = 'http://localhost:4566',
  'aws.trust.all.certificates' = 'true'
)

11. 常见坑清单(写给未来的自己,也写给读者)

  1. 依赖冲突

    同时引入 flink-sql-connector-aws-kinesis-streamsflink-sql-connector-kinesis 会导致 TableFactory 冲突

  2. Flink 2.2 没依赖

    DDL 写得再对,jar 没有就是跑不起来

  3. v4 -> v5 没有状态兼容

    迁移靠时间点对齐,接受重复处理,业务侧做幂等

  4. metadata VIRTUAL 列新 Source 有 bug

    需要 metadata 先用 kinesis-legacy

  5. shard 扩缩容与 shard discovery interval

    扩容后发现慢,先检查 source.shard.discovery.interval

  6. 写入热点
    PARTITION BY 字段选错、分布不均,会把某几个 shard 打到限流

相关推荐
TechubNews2 小时前
BEATOZ区块链专业企业与韩国头部旅游集团MODETOUR从签署MOU迈向网络验证节点合作
大数据·人工智能·区块链
小鸡脚来咯12 小时前
Git 新手入门指南
大数据·git·elasticsearch
说私域16 小时前
基于AI智能名片链动2+1模式服务预约商城系统的社群运营与顾客二次消费吸引策略研究
大数据·人工智能·小程序·开源·流量运营
山峰哥16 小时前
数据库工程核心:SQL调优让查询效率飙升的实战密码
网络·汇编·数据库·sql·编辑器
色空大师17 小时前
mybatis动态sql
sql·mybatis·foreach·where·sql动态语法
zqmattack19 小时前
SQL优化与索引策略实战指南
java·数据库·sql
塔能物联运维19 小时前
隧道照明“智能进化”:PLC 通信 + AI 调光守护夜间通行生命线
大数据·人工智能
lang2015092820 小时前
Jackson 1.x到2.x的演进与Spring集成
数据库·sql·spring
highly200920 小时前
Gitflow
大数据·elasticsearch·搜索引擎