【问题标题】:u-sql job is very slow, when i add a .NET call当我添加 .NET 调用时,u-sql 作业非常慢
【发布时间】:2017-02-21 14:16:58
【问题描述】:

代码在 2000 个小文件 (~10-50 Kb) ~ 1 分钟内执行速度非常快。并行度 = 5。

@arenaData =
    EXTRACT col1, col2, col3
    FROM @in
    USING Extractors.Tsv(quoting : true, skipFirstNRows : 1, nullEscape : "\\N", encoding:Encoding.UTF8);

@res =
    SELECT col1, col2, col3  
    FROM @arenaData;
    OUTPUT @res
    TO @out
    USING Outputters.Csv();

但如果我像这样更改代码,则需要 ~ 1 小时

@arenaData =
    EXTRACT col1, col2, col3
    FROM @in
    USING Extractors.Tsv(quoting : true, skipFirstNRows : 1, nullEscape : "\\N", encoding:Encoding.UTF8);

@res =
    SELECT
         col1.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) AS col1_converted,
, col2, col3

    FROM @arenaData;
    OUTPUT @res
    TO @out
    USING Outputters.Csv();

为什么 .NET 调用这么慢?我需要将源 CSV 文件中的日期格式转换为“yyyy-MM-dd HH:mm:ss”吗?我怎样才能有效地做到这一点?

【问题讨论】:

  • 这听起来不对。必须加载 CLR 并将本机代码调用到 C# 执行中会产生额外的开销,但这不应该是 60 倍更糟。您能否将工作链接(Microsoft dot com 的 usql)发给我,以便我可以请我们的工程团队进行调查?
  • 在将问题发布到 stackoverflow 之前,我为 ADLA 支持团队创建了一张支持票。我为支持团队做了这些测试(JOB 的网址如下):没有 CLR ~2 分钟(MAXDOP = 5):arkadium.azuredatalakeanalytics.net/jobs/… 与一个 CLR 调用相同 ~ 38 分钟(MAXDOP = 5):arkadium.azuredatalakeanalytics.net/jobs/… 时间是改了,因为参数改了,但是问题还是存在。差别太大了
  • 更多测试:使用 CLR + 并行度的相同作业从 5 增加到 20。经过的时间 ~10 分钟 arkadium.azuredatalakeanalytics.net/jobs/… 使用 CLR + 并行度的相同作业从 5 增加到 3。经过的时间~ 59 分钟 + 被我取消 arkadium.azuredatalakeanalytics.net/jobs/…
  • 我从工程团队那里得到了根本原因。我目前正在旅行,但会在今晚/明天晚些时候回复。
  • @MichaelRys 看起来我明白发生了什么。我们有 2880 个小文件。对于他们每个人,我们都有 1 个顶点。我们总共有 2880 个顶点。我已经阅读了一些关于 ADLA 执行模型的信息。并且看起来当分析单元 (AU) 从一个顶点迁移到另一个顶点时,它会重新初始化 CLR COM 服务器。所以在我们的例子中,CLR 被重新初始化了 2880 次。以及我们在开始处理之前合并文件的解决方案。我对吗?我已经测试了这些假设,看起来它们是正确的......想听听你的解释。

标签: azure-data-lake u-sql


【解决方案1】:

很高兴听到您现在的表现越来越好!

您的作业使用在托管代码中执行的表达式在 2800 多个非常小的文件上运行,而不是像 U-SQL 中一些更常见的 C# 表达式那样转换为 C++。

这会导致以下问题:

  1. 您从一定数量的 AU 开始您的工作。然后每个 AU 启动一个 YARN 容器来执行你的部分工作。这意味着需要彻底初始化容器,这需要一些时间(您可以在 Vertex Execution View 中将其视为创建时间)。现在这需要一些时间,如果您的顶点进行大量处理,那么开销不会太大。不幸的是,在您的情况下,小文件的处理速度非常快,因此开销很大。

  2. 如果顶点只执行系统生成的代码,我们将这些代码生成为 C++ 代码,那么我们可以重用容器而无需重新初始化时间。不幸的是,由于遗留了潜在的工件,我们无法重用由托管运行时执行的通用用户代码。所以在这种情况下,我们需要重新初始化容器,这需要时间(超过 2800 次)。

现在,根据您的反馈,我们正在改进我们的重新初始化逻辑(如果您不对内联 C# 表达式做任何花哨的事情,我们仍然可以重新初始化)。此外,一旦我们可以在单个顶点内处理多个小文件而不是每个顶点一个文件,它会变得更好。

您的解决方法是增加文件的大小并尽可能避免自定义代码(当然并非总是可能)出现在过多的顶点中。

【讨论】:

  • 感谢详细解释。我现在也知道一个 AU ~ Apache YARN 容器底层。
  • 总是很高兴看到团队回应客户需求和反馈!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
相关资源
最近更新 更多