全部产品
Search
文档中心

云原生大数据计算服务 MaxCompute:MaxCompute UDF(Java)常见问题

更新时间:Sep 21, 2023

本文为您介绍使用Java语言编写的MaxCompute UDF的常见问题。

类或依赖问题

调用MaxCompute UDF运行代码时的常见类或依赖问题如下:

  • 问题现象一:运行报错描述为ClassNotFoundExceptionSome dependencies are missing

    • 产生原因:

      • 原因一:创建MaxCompute UDF时指定的资源JAR包不正确。

      • 原因二:MaxCompute UDF依赖的资源JAR包未上传至MaxCompute,例如依赖的第三方包没有上传。

      • 原因三:调用MaxCompute UDF运行代码时,所处的项目不正确。即MaxCompute UDF不在MaxCompute项目中。例如MaxCompute UDF注册到了开发项目,但却在生产项目执行调用操作。

      • 原因四:文件资源不存在或资源类型不正确。例如PY文件,资源类型是PY,但MaxCompute UDF代码中get_cache_file需要的类型是FILE。

    • 解决措施:

      • 原因一的解决措施:检查JAR包的正确性,并确认JAR包中已经包含需要的类,重新打包并上传至MaxCompute项目。更多打包上传操作,请参见打包、上传及注册

      • 原因二的解决措施:将MaxCompute UDF依赖的第三方包作为资源上传至MaxCompute项目,然后在注册函数时,依赖资源列表中添加此包。更多上传资源及注册函数操作,请参见添加资源注册函数

      • 原因三的解决措施:在报错的项目下通过MaxCompute客户端执行list functions;命令,确保MaxCompute UDF是真实存在的,且MaxCompute UDF的类和依赖的资源正确。

      • 原因四的解决措施:通过MaxCompute客户端执行desc function <function_name>;命令,确保Resources列表已覆盖所有需要的文件资源。如果资源类型不匹配,可执行add <file_type> <file_name>;重新添加资源。

  • 问题现象二:运行报错描述为NoClassDefFoundErrorNoSuchMethodError或错误码为ODPS-0123055

    • 产生原因:

      • 原因一:用户上传的JAR包中包含的第三方库的版本与MaxCompute内置的第三方库的版本不一致。

      • 原因二:Java沙箱限制。作业Instance的Stderr中出现java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "createClassLoader")详细信息,表示是沙箱限制。MaxCompute UDF在分布式环境中运行时收到Java沙箱的限制。更多Java沙箱限制信息,请参见Java沙箱

    • 解决措施:

      • 原因一的解决措施:使用maven-shade-plugin解决版本不一致问题并修改Import路径,重新打包为JAR包并上传至MaxCompute项目。更多打包上传操作,请参见打包、上传及注册

      • 原因二的解决措施:请参见Java沙箱限制问题

Java沙箱限制问题

  • 问题现象:调用MaxCompute UDF访问本地文件、外网或分布式文件系统,创建Java线程等时,代码运行会报错

  • 产生原因:网络限制问题 ,MaxCompute UDF默认不支持访问网络。

  • 解决措施:请根据业务情况填写并提交网络连接申请表单,MaxCompute技术支持团队会及时联系您完成网络开通操作。表单填写指导,请参见网络开通流程

性能问题

调用MaxCompute UDF运行代码时的常见性能问题如下:

  • 问题现象一:运行报错描述为 kInstanceMonitorTimeout

    • 产生原因:MaxCompute UDF处理时间过长导致超时。默认情况下UDF处理数据的时间是有限制,在处理一批(通常情况下为1024条)记录时,必须在1800秒内处理完。这个时间限制并不是针对Worker的总运行时间,而是处理一小批记录的时间。通常情况下SQL处理数据的速率超过了万条/秒,该限制只是为了防止MaxCompute UDF中出现死循环,导致长时间占用CPU资源的情况。

    • 解决措施:

      • 如果实际计算量很大,可以在MaxCompute UDF的实现Java类的方法中调用ExecutionContext.claimAlive来重置计时器。

      • 重点优化MaxCompute UDF代码逻辑。后续调用MaxCompute UDF时,可同时在Session级别配置如下参数辅助调节MaxCompute UDF运行过程,提升处理速度。

        参数

        说明

        set odps.function.timeout=xxx;

        调整UDF运行超时时长。默认值为1800s。可根据实际情况酌情调大。取值范围为1s~3600s。

        set odps.stage.mapper.split.size=xxx;

        调整Map Worker的输入数据量。默认值为256 MB。可根据实际情况酌情调小。

        set odps.sql.executionengine.batch.rowcount=xxx;

        调整MaxCompute一次处理的数据行数。默认值为1024行。可根据实际情况酌情调小。

  • 问题现象二:运行报错描述为errMsg:SigKill(OOM)OutOfMemoryError

    • 产生原因:MaxCompute运行作业主要分为三个阶段:Map、Reduce和Join。如果处理的数据量比较大,会导致各个阶段的每个Instance处理的时间比较长。

    • 解决措施:

      • 如果是fuxiruntime相关代码报错,您可以通过设置如下资源参数提升处理速度。

        参数

        说明

        set odps.stage.mapper.mem=xxx;

        调整Map Worker的内存大小。默认值为1024 MB。可根据实际情况酌情调大。

        set odps.stage.reducer.mem=xxx;

        调整Reduce Worker的内存大小。默认值为1024 MB。可根据实际情况酌情调大。

        set odps.stage.joiner.mem=xxx;

        调整Join Worker的内存大小。默认值为1024 MB。可根据实际情况酌情调大。

        set odps.stage.mapper.split.size=xxx;

        调整Map Worker的输入数据量。默认值为256 MB。可根据实际情况酌情调大。

        set odps.stage.reducer.num=xxx;

        调整Reduce阶段的Worker数量。可根据实际情况酌情调大。

        set odps.stage.joiner.num=xxx;

        调整Join阶段的Worker数量。可根据实际情况酌情调大。

      • 如果是Java代码本身报错,可以在调整上述参数的同时,通过set odps.sql.udf.jvm.memory=xxx;参数调大Jvm内存。

更多参数详细信息,请参见SET操作

UDTF相关问题

调用Java UDTF运行代码时的常见问题如下:

  • 问题现象一:运行报错描述为Semantic analysis exception - only a single expression in the SELECT clause is supported with UDTF's

    • 产生原因:在SELECT语句中调用Java UDTF时,存在Java UDTF与其他列或表达式混用的问题,Java UDTF暂不支持该用法。错误示例如下。

      select b.*, 'x', udtffunction_name(v) from table lateral view udtffunction_name(v) b as f1, f2;
    • 解决措施:您可以将Java UDTF与Lateral View配合使用。命令示例如下。

      select b.*, 'x' from table lateral view udtffunction_name(v) b as f1, f2;
  • 问题现象二:运行报错描述为Semantic analysis exception - expect 2 aliases but have 0

    • 产生原因:Java UDTF代码中没有指定输出列名。

    • 解决措施:您可以在调用Java UDTF的SELECT语句中通过as子句给出列名。命令示例如下。

      select udtffunction_name(paramname) as (col1, col2);