Task not serializable的原因及解决方法

5 篇文章 0 订阅
4 篇文章 0 订阅

原因及解决方法:

这是一个比较常见的问题,flink、spark,都有可能遇到类似问题。

由于两者都是分布式计算引擎,都不能在算子中传入未经序列化的数据。

所以此类问题:

原因:基本上都是因为在算子中传入了未经序列化的数据。

解决方法:就是找到那个未经序列化的数据,然后在算子前提前定义或者序列化。


项目场景:

我需要将一个util.HashMap[Integer, DataSet[util.Map[String, Object]]]类型的数据,改造为mutable.Iterable[DataSet[(Integer, util.Map[String, Object])]],即将外层map中的key,放入value中的dataSet中去。


问题描述:

报错内容

org.apache.flink.api.common.InvalidProgramException: Task not serializable
Caused by: java.io.NotSerializableException: org.apache.flink.api.scala.DataSet

报错代码

value.map(d => (v._1, d))这行代码会报错

private def sinkToMysql(connection: Connection, statement: Statement, sqlMap: util.HashMap[Integer, DataSet[util.Map[String, Object]]]): Unit = {
    sqlMap.map(v => {
      val value: DataSet[util.Map[String, Object]] = v._2
      //下面这行代码会报错
      value.map(d => (v._1, d))
    })
      .reduce((l, r) => l.union(r))
      .collect()
      .foreach(m => {
        nodeId = m._1
        taskResult = JsonUtil.toJSON(m).toString
        insertSql = String.format("INSERT INTO `sigma`.`sigma_test_task_result`(`id`, `task_id`, `flow_id`, `node_id`, `task_result`, `time`) VALUES (null, '%s', '%s', '%s', '%s', null);", taskId, flowId, nodeId, taskResult)
        addBatch(insertSql, statement)
      })
    //批量插入mysql
    executeBatch(statement)
    //关闭mysql连接
    close(connection, statement, null)
  }

原因分析:

从报错内容中:

Caused by: java.io.NotSerializableException: org.apache.flink.api.scala.DataSet

我们可以得出是因为在map算子中使用了org.apache.flink.api.scala.DataSet类,查看源码后我发现Flink的DataSet类是没有被序列化的,所以会抛出此异常。

我一开始以为是v._2没有被序列化,所以一直在想办法序列化v._2。后来经过朋友的提示,才明白原来是我在v._2的map算子中传入了dataSet。

map算子中只有两个参数,d和v._1,d显然不是dataSet,而v._1是由sqlMap得来的,sqlMap中包含了dataSet,传入v._1相当于传入了v,也就是dataSet,所以我应该对v._1进行修改


解决方案:

将v._1提出来,在v._2的map算子之前进行定义

代码修改为如下:

private def sinkToMysql(connection: Connection, statement: Statement, sqlMap: util.HashMap[Integer, DataSet[util.Map[String, Object]]]): Unit = {
    sqlMap.map(v => {
      //在这里将v._1提出来,在v._2的map算子之前进行定义
      val value1: Integer = v._1
      val value: DataSet[util.Map[String, Object]] = v._2
      value.map(d => (value1, d))
    })
      .reduce((l, r) => l.union(r))
      .collect()
      .foreach(m => {
        nodeId = m._1
        taskResult = JsonUtil.toJSON(m).toString
        insertSql = String.format("INSERT INTO `sigma`.`sigma_test_task_result`(`id`, `task_id`, `flow_id`, `node_id`, `task_result`, `time`) VALUES (null, '%s', '%s', '%s', '%s', null);", taskId, flowId, nodeId, taskResult)
        addBatch(insertSql, statement)
      })
    //批量插入mysql
    executeBatch(statement)
    //关闭mysql连接
    close(connection, statement, null)

    //没有这句代码的话,不会调用env.execute(),会报错
    val tailDataSet: DataSet[util.Map[String, Object]] = sqlMap.last._2
    tailDataSet.output(new CustomCloseOutputFormat[util.Map[String, Object]])
  }

成功解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

启四

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值