Flink 反序列化 Kafka JSON 数据失败问题 Failed to deserialize consumer record ConsumerRecord

Flink 反序列化 Kafka JSON 数据失败问题

在这里插入图片描述

一、问题背景

在大数据实时处理场景中,Apache Flink 常常与 Apache Kafka 结合使用,Flink 从 Kafka 中消费数据并进行处理。在一次使用 Flink 从 Kafka 消费 JSON 格式数据的实践中,遇到了反序列化失败的问题,具体错误信息如下:

Caused by: java.io.IOException: Failed to deserialize consumer record ConsumerRecord(topic = topic1, partition = 1, leaderEpoch = 44, offset = 8617774, CreateTime = 1740029586322, serialized key size = 33, serialized value size = 161, headers = RecordHeaders(headers = [], isReadOnly = false), key = [B@42d7ac3c, value = [B@2ef12211).
    at org.apache.flink.connector.kafka.source.reader.deserializer.KafkaDeserializationSchemaWrapper.deserialize(KafkaDeserializationSchemaWrapper.java:59)
    at org.apache.flink.connector.kafka.source.reader.KafkaRecordEmitter.emitRecord(KafkaRecordEmitter.java:53)
    ... 14 more
Caused by: java.io.IOException: Failed to deserialize JSON '{"stationId":6734209033006750407,"signalStrength":1639955230,"latitude":1.4559117913765512E308,"longitude":1.7529912112369154E307,"ts":"2025-02-20 05:33:06.322"}'.
    at org.apache.flink.formats.json.JsonParserRowDataDeserializationSchema.deserialize(JsonParserRowDataDeserializationSchema.java:97)
    at org.apache.flink.formats.json.JsonParserRowDataDeserializationSchema.deserialize(JsonParserRowDataDeserializationSchema.java:42)
    at org.apache.flink.api.common.serialization.DeserializationSchema.deserialize(DeserializationSchema.java:82)
    at org.apache.flink.streaming.connectors.kafka.table.DynamicKafkaDeserializationSchema.deserialize(DynamicKafkaDeserializationSchema.java:115)
    at org.apache.flink.connector.kafka.source.reader.deserializer.KafkaDeserializationSchemaWrapper.deserialize(KafkaDeserializationSchemaWrapper.java:56)
    ... 15 more
Caused by: org.apache.flink.formats.json.JsonParseException: Fail to deserialize at field: stationId.
    at org.apache.flink.formats.json.JsonParserToRowDataConverters.lambda$createRowConverter$43b82837$1(JsonParserToRowDataConverters.java:419)
    at org.apache.flink.formats.json.JsonParserToRowDataConverters.lambda$wrapIntoNullableConverter$ca96cb8f$1(JsonParserToRowDataConverters.java:463)
    at org.apache.flink.formats.json.JsonParserRowDataDeserializationSchema.deserialize(JsonParserRowDataDeserializationSchema.java:91)
    ... 19 more

从错误信息可知,Flink 在反序列化 Kafka 消息时,在 stationId 字段处失败,下面将深入分析原因并给出解决方案。

二、错误原因分析

2.1 数据类型不匹配

JSON 数据中 stationId 的值为 6734209033006750407,这是一个非常大的整数。如果 Flink 表定义中 stationId 字段的数据类型不能容纳这么大的数值,就会导致反序列化失败。例如,若将其定义为 INT 类型,其取值范围通常是 -21474836482147483647,显然无法存储该值。

2.2 字段定义不一致

Flink 表定义的字段名、顺序或者数据类型与 JSON 数据不匹配,也会造成反序列化错误。比如,JSON 数据中的字段名是 stationId,而 Flink 表定义里写成了 station_id,就会导致反序列化失败。

2.3 JSON 格式问题

尽管 JSON 数据表面上看起来格式正确,但可能存在隐藏的编码问题或者特殊字符,从而影响反序列化。不过从错误信息来看,这个可能性相对较小。

三、解决方案

3.1 调整 Flink 表定义的数据类型

如果 stationId 可能是一个很大的整数,可将其数据类型定义为 BIGINT

import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;

public class FlinkKafkaJsonDeserialization {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);

        String createTableSql = "CREATE TABLE kafka_source_table (\n" +
                "    stationId BIGINT,\n" +
                "    signalStrength INT,\n" +
                "    latitude DOUBLE,\n" +
                "    longitude DOUBLE,\n" +
                "    ts TIMESTAMP(3)\n" +
                ") WITH (\n" +
                "    'connector' = 'kafka',\n" +
                "    'topic' = 'topic1',\n" +
                "    'properties.bootstrap.servers' = 'your_bootstrap_servers',\n" +
                "    'format' = 'json'\n" +
                ")";

        tableEnv.executeSql(createTableSql);

        // 后续可以进行其他操作,例如将数据写入其他表
        String sinkTableSql = "CREATE TABLE sink_table (\n" +
                "    stationId BIGINT,\n" +
                "    signalStrength INT,\n" +
                "    latitude DOUBLE,\n" +
                "    longitude DOUBLE,\n" +
                "    ts TIMESTAMP(3)\n" +
                ") WITH (\n" +
                "    'connector' = 'jdbc',\n" +
                "    'url' = 'jdbc:postgresql://your_host:your_port/your_database',\n" +
                "    'table-name' = 'your_table_name',\n" +
                "    'username' = 'your_username',\n" +
                "    'password' = 'your_password'\n" +
                ")";

        tableEnv.executeSql(sinkTableSql);

        String insertSql = "INSERT INTO sink_table SELECT * FROM kafka_source_table";
        tableEnv.executeSql(insertSql);

        env.execute("Flink Kafka JSON Deserialization");
    }
}

3.2 检查字段定义

要确保 Flink 表定义的字段名、顺序和数据类型与 JSON 数据完全一致。例如,JSON 数据中的字段名是 stationId,Flink 表定义里也应该是 stationId。可以仔细对比 JSON 数据结构和 Flink 表定义,避免出现拼写错误或数据类型不匹配的情况。

四、总结

在使用 Flink 从 Kafka 消费 JSON 数据时,反序列化失败是一个常见的问题,通常是由数据类型不匹配、字段定义不一致或 JSON 格式问题引起的。通过调整 Flink 表定义的数据类型、仔细检查字段定义以及处理特殊字符和编码问题

Caused by: java.lang.RuntimeException: Writing records to stream load failed. at org.apache.doris.flink.table.DorisDynamicSinkFunction.checkFlushException(DorisDynamicSinkFunction.java:431) at org.apache.doris.flink.table.DorisDynamicSinkFunction.waitAsyncFlushingDone(DorisDynamicSinkFunction.java:490) at org.apache.doris.flink.table.DorisDynamicSinkFunction.flush(DorisDynamicSinkFunction.java:479) at org.apache.doris.flink.table.DorisDynamicSinkFunction.doClose(DorisDynamicSinkFunction.java:558) ... 14 common frames omitted Caused by: java.lang.OutOfMemoryError: Java heap space Caused by: java.io.IOException: Failed to deserialize consumer record ConsumerRecord(topic = smartxma_chat.chat_record, partition = 3, leaderEpoch = 0, offset = 139344, CreateTime = 1758801081210, serialized key size = 9, serialized value size = 9510, headers = RecordHeaders(headers = [], isReadOnly = false), key = [B@3e00b62c, value = [B@457f27d9). at org.apache.flink.connector.kafka.source.reader.deserializer.KafkaDeserializationSchemaWrapper.deserialize(KafkaDeserializationSchemaWrapper.java:57) at org.apache.flink.connector.kafka.source.reader.KafkaRecordEmitter.emitRecord(KafkaRecordEmitter.java:51) ... 14 common frames omitted Caused by: java.io.IOException: Corrupt binlog JSON message '{"destination":"","dbName":"smartxma_chat","tblName":"chat_record","opType":"INSERT","exeTime":1758801080000,"seq":1703131282931744,"endTran":true,"cells":[{"key":true,"updated":true,"colName":"id","colValue":"465413568","toNull":false,"currentColName":"id"},{"key":false,"updated":true,"colName":"tenant_id","colValue":"msxf1525335877730667a80fd","toNull":false,"currentColName":"tenant_id"}. at org.apache.flink.formats.json.msxf.BinlogDeserializationSchema.deserialize(BinlogDeserializationSchema.java:234) at org.apache.flink.streaming.connectors.kafka.table.DynamicKafkaDeserializationSchema.deserialize(DynamicKafkaDeserializationSchema.java:113) at org.apache.flink.connector.kafka.source.reader.deserializer.KafkaDeserializationSchemaWrapper.deserialize(KafkaDeserializationSchemaWrapper.java:54) ... 15 common frames omitted Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded 2025-09-27 16:30:19.057 [ods_smartxma_chat:doris_ods_chat_record_kefu:1] [flink-akka.actor.default-dispatcher-4] INFO o.a.f.r.resourcemanager.slotmanager.DeclarativeSlotManager - Received resource requirements from job 83c969ccfcfd8f8bbd49fa294472716d: [ResourceRequirement{resourceProfile=ResourceProfile{UNKNOWN}, numberOfRequiredSlots=3}]
最新发布
09-28
<think>首先,用户的问题是关于一个错误日志:"Caused by: java.lang.RuntimeException: Writing records to stream load failed." 后面跟着一系列的堆栈跟踪和另一个错误 "Caused by: java.lang.OutOfMemoryError: Java heap space" 和 "Caused by: java.io.IOException: Failed to deserialize consumer record" 以及更深层的 "Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded"。 我的回答需要: 1. 使用中文回答问题。 2. 在回答完问题后,提出3-5个相关问题。 3. 相关问题必须以§§相关问题§§开头,禁止换行分散。 4. 第一行必须完整输出 "§§相关问题§§"。 5. 基于用户的问题和我的回答提出问题。 分析错误: - 主要错误是写入Doris流失败,原因是Java堆内存溢出(OutOfMemoryError: Java heap space)。 - 更深层错误是反序列化Kafka记录时失败,由于JSON消息损坏(java.io.IOException: Corrupt binlog JSON message),最终导致GC开销限制超标(GC overhead limit exceeded)。 - 日志涉及Flink、Doris、Kafka组件。 我需要解释这个错误的原因和解决方案: - **根本原因**:可能是内存不足导致反序列化失败,触发OOM。JSON消息可能太大或格式错误,但核心是内存管理问题。 - **上下文**:发生在Flink作业中,从Kafka读取数据,尝试写入Doris时失败。 - **潜在问题**:堆空间设置不足、数据倾斜(特定分区数据量大)、JSON序列化/反序列化问题、GC策略不当。 回答结构: 1. **解释错误**:简要说明错误序列。 2. **原因分析**:详细描述可能原因。 3. **解决方案建议**:提供修复步骤。 4. **预防措施**:如何避免类似问题。 5. **添加相关问题**:在最后,以指定格式。 确保回答完整: - 使用中文。 - 结束时输出 "§§相关问题§§" 然后列出3-5个问题。 - 问题基于对话历史和我的回答。 列出相关问题(3-5个): 1. 如何在Flink中优化内存设置以防止OOM错误? 2. Doris sink配置的最佳实践是什么? 3. 如何处理Kafka中的大消息或格式错误消息? 4. GC开销限制超标和堆内存溢出的区别及优先级? 5. 如何监控Flink作业的内存使用? 确保问题符合规则:基于用户问题和我的回答。 最终回答框架: - 回答部分:解释错误、原因、修复建议。 - 结束部分:§§相关问题§§ 然后1. ... 2. ... 3. ... 4. ...(根据需要4或5个)。 现在,草拟回答: </think>这个错误发生在Flink作业中,涉及从Kafka读取数据并写入Doris时出现的内存管理问题。核心错误链是: 1. **Doris写入失败**:`java.lang.RuntimeException: Writing records to stream load failed`,表明Doris sink操作异常。 2. **堆内存溢出**:深层原因`java.lang.OutOfMemoryError: Java heap space`,表示JVM堆空间不足。 3. **反序列化失败**:`java.io.IOException: Failed to deserialize consumer record`,在解析Kafka消息时出错。 4. **JSON消息损坏**:`Corrupt binlog JSON message`,日志显示部分JSON数据截断(如`"cells":[{"key":true,...`未完整)。 5. **GC资源耗尽**:最终`java.lang.OutOfMemoryError: GC overhead limit exceeded`,确认垃圾回收无法有效释放内存。 ### 根本原因分析 1. **内存泄漏或不足**: - Flink TaskManager堆空间(`-Xmx`)设置过小,无法处理大消息(如序列化后9510 bytes的Kafka记录)。 - 反序列化逻辑缺陷:`BinlogDeserializationSchema`在解析损坏JSON时未正确处理异常,导致无效对象累积占用内存。 2. **数据问题**: - Kafka消息损坏(如截断的binlog JSON),触发反复重试和内存压力。 - 分区数据倾斜:`partition=3`可能接收远大于其他分区的数据量。 3. **资源配置不当**: - Flink Slot不足:日志显示`numberOfRequiredSlots=3`,但实际资源分配可能不匹配。 - 并行度与数据量不匹配,尤其在关闭Sink时(`doClose`方法)积累的记录过多。 ### 修复与优化步骤 #### 1. 紧急处理 ```bash # 增加TaskManager堆内存(临时方案) env.java.opts.taskmanager: "-Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200" ``` - 在Flink配置中优先提升堆大小,缓解OOM。 #### 2. 代码级修复 - **反序列化增强**:添加JSON格式校验和异常处理 ```java // 在BinlogDeserializationSchema中增加校验 public void deserialize(...) throws IOException { try { // 解析逻辑 } catch (JsonProcessingException e) { LOG.warn("Skip corrupt message: {}", new String(message)); // 记录并跳过损坏消息 } } ``` - **资源释放优化**:在`DorisDynamicSinkFunction`中确保flush失败时及时清理缓冲区。 #### 3. 配置调优 | 组件 | 参数建议 | 目的 | |------------|-----------------------------------|--------------------------| | **Flink** | `taskmanager.memory.task.heap.size: 4096m` | 扩大堆空间 | | **Kafka** | `max.partition.fetch.bytes: 10485760` | 允许更大消息(默认1MB) | | **Doris** | `sink.batch.size: 5000` | 减小批次大小,降低内存压力 | #### 4. 数据质量保障 - **Kafka端校验**:在生产侧添加JSON schema验证(如使用Confluent Schema Registry)。 - **监控告警**:部署Prometheus监控Flink的`numRecordsOut`和`currentSendTime`指标,异常时告警。 ### 预防策略 1. **压力测试**:使用JMeter模拟峰值流量(如10K条/秒),验证内存稳定性。 2. **日志分析自动化**:集成ELK栈,实时检测`Corrupt binlog`错误模式。 3. **资源预留**:设置TaskManager堆外内存(`taskmanager.memory.managed.fraction: 0.3`)以分担堆压力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值