【问题标题】:Hive - dynamic partitions: Long loading times with a lot of partitions when updating tableHive - 动态分区:更新表时加载时间很长,分区很多
【发布时间】:2013-08-14 10:31:56
【问题描述】:

我通过 AWS EMR 运行 Hive,并且有一个经常将日志数据解析到 S3 的工作流。我对已解析的 Hive 表使用动态分区(日期和日志级别)。

当我有几 GB 的数据和很多分区时,现在需要永远做的一件事是 Hive 在解析完成后将数据加载到表中。

Loading data to table default.logs partition (dt=null, level=null)
    ...
    Loading partition {dt=2013-08-06, level=INFO}
    Loading partition {dt=2013-03-12, level=ERROR}
    Loading partition {dt=2013-08-03, level=WARN}
    Loading partition {dt=2013-07-08, level=INFO}
    Loading partition {dt=2013-08-03, level=ERROR}
    ...

    Partition default.logs{dt=2013-03-05, level=INFO} stats: [num_files: 1, num_rows: 0, total_size: 1905, raw_data_size: 0]
    Partition default.logs{dt=2013-03-06, level=ERROR} stats: [num_files: 1, num_rows: 0, total_size: 4338, raw_data_size: 0]
    Partition default.logs{dt=2013-03-06, level=INFO} stats: [num_files: 1, num_rows: 0, total_size: 828250, raw_data_size: 0]
    ...
    Partition default.logs{dt=2013-08-14, level=INFO} stats: [num_files: 5, num_rows: 0, total_size: 626629, raw_data_size: 0]
    Partition default.logs{dt=2013-08-14, level=WARN} stats: [num_files: 4, num_rows: 0, total_size: 4405, raw_data_size: 0]

有没有办法克服这个问题并减少这一步的加载时间?

我已经尝试通过存储桶生命周期规则将旧日志存档到 Glacier,希望 Hive 会跳过加载存档分区。好吧,因为这仍然保持文件(路径)在 S3 Hive 中可见,所以无论如何都可以识别存档分区,因此不会获得任何性能。

更新 1

数据的加载是通过简单地将数据插入到动态分区表中来完成的

INSERT INTO TABLE logs PARTITION (dt, level)
SELECT time, thread, logger, identity, message, logtype, logsubtype, node, storageallocationstatus, nodelist, userid, nodeid, path, datablockid, hash, size, value, exception, server, app, version, dt, level
FROM new_logs ;

来自一个包含未解析日志的表

CREATE EXTERNAL TABLE new_logs (
  dt STRING,
  time STRING,
  thread STRING,
  level STRING,
  logger STRING,
  identity STRING,
  message STRING,
  logtype STRING,
  logsubtype STRING,
  node STRING,
  storageallocationstatus STRING,
  nodelist STRING,
  userid STRING,
  nodeid STRING,
  path STRING,
  datablockid STRING,
  hash STRING,
  size STRING,
  value STRING,
  exception STRING,
  version STRING
)
PARTITIONED BY (
  server STRING,
  app STRING
)
ROW FORMAT
  DELIMITED
  FIELDS TERMINATED BY '\t'
STORED AS
  INPUTFORMAT 'org.maz.hadoop.mapred.LogFileInputFormat'
  OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat'
LOCATION 's3://my-log/logs/${LOCATION}' ;

进入新的(已解析的)表

CREATE EXTERNAL TABLE logs (
  time STRING,
  thread STRING,
  logger STRING,
  identity STRING,
  message STRING,
  logtype STRING,
  logsubtype STRING,
  node STRING,
  storageallocationstatus STRING,
  nodelist STRING,
  userid STRING,
  nodeid STRING,
  path STRING,
  datablockid STRING,
  hash STRING,
  size STRING,
  exception STRING,
  value STRING,
  server STRING,
  app STRING,
  version STRING
)
PARTITIONED BY (
  dt STRING,
  level STRING
)
ROW FORMAT
  DELIMITED
  FIELDS TERMINATED BY '\t'
  LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION 's3://my-log/parsed-logs' ;

输入格式(LogFileInputFormat)负责将日志条目解析为所需的日志格式。

更新 2

当我尝试以下操作时

INSERT INTO TABLE logs PARTITION (dt, level)
SELECT time, thread, logger, identity, message, logtype, logsubtype, node, storageallocationstatus, nodelist, userid, nodeid, path, datablockid, hash, size, value, exception, server, app, version, dt, level
FROM new_logs
WHERE dt > 'some old date';

Hive 仍然在日志中加载所有分区。另一方面,如果我使用静态分区,例如

INSERT INTO TABLE logs PARTITION (dt='some date', level)
SELECT time, thread, logger, identity, message, logtype, logsubtype, node, storageallocationstatus, nodelist, userid, nodeid, path, datablockid, hash, size, value, exception, server, app, version, level
FROM new_logs
WHERE dt = 'some date';

Hive 仅加载相关分区,但我需要为我认为可能出现在 new_logs 中的每个日期创建一个查询。通常 new_logs 仅包含今天和昨天的日志条目,但也可能包含较旧的条目。

静态分区是我目前选择的解决方案,但没有其他(更好的)解决方案可以解决我的问题吗?

【问题讨论】:

  • 在插入过程中总共有多少个分区受到影响?从日志来看,似乎存在数据量非常小的分区(total_size) - 也许可以使用更大的(比如每月)分区?您究竟是如何加载数据的?
  • @dimamah 通常只有当前日期会受到插入过程的影响,因为当日志文件上传到 S3 时,我会立即对其进行解析。难道是因为我使用动态分区,Hive 不可能知道在插入过程中哪些分区会受到影响,因此会加载每个可用的分区?请参阅更新的部分。
  • hive 只会更新受影响的分区,这真的很奇怪,只有在您使用动态分区时才需要很长时间。究竟需要很长时间?映射器运行多长时间?减速机运行多长时间?如果有阶段,请说明每个阶段。是否有特定的映射器/减速器长时间运行?请粘贴它的日志。

标签: amazon-s3 hive amazon-emr


【解决方案1】:

在这个缓慢的阶段,Hive 获取它为每个分区构建的文件并将其从临时目录移动到永久目录。您可以在称为移动运算符的“解释扩展”中看到这一点。

因此,对于每个分区,它都是一次移动和对元存储的更新。我不使用 EMR,但我认为将文件移动到 S3 的这种行为对于它需要移动的每个文件都有很高的延迟。

从您写的内容中不清楚的是,您是否在每次运行时都在进行满载。例如为什么你有一个 2013-03-05 分区?您是否正在获取包含此旧日期的新日志数据?如果此数据已经在您的日志表中,您应该修改您的插入语句,如

SELECT fields
FROM new_logs
WHERE dt > 'date of last run';

这样,您只会得到几个存储桶和几个要移动的文件。从 new_logs 中扫描所有这些额外数据仍然很浪费,但您可以通过对 new_logs 进行分区来解决这个问题。

【讨论】:

  • 好东西,会试试看。插入到日志中的日志几乎总是与当前日期相同(如果解析是在午夜后几个小时完成的,则可能是昨天),因为 new_logs 中的日志条目将仅包含最近一小时上传到我们服务器的日志条目或者。真正的旧日期是允许查询我们所有已解析的日志。
  • 尝试按日期限制并没有解决我的问题。我发现唯一可行的解​​决方案是使用静态分区。但这并不完全可取,因为我必须每个日期创建一个查询。如果只有一个查询,我会更好。有什么建议吗?
【解决方案2】:

AWS 在 EMR 3.2.x 及更高版本上将 HIVE 分区恢复时间缩短了一个数量级以上。

我们有一个在 S3 上有超过 20,000 个分区的 HIVE 表。在以前的 EMR 版本中,过去大约需要 80 分钟才能恢复,而现在使用 3.2.x/3.3.x,我们可以在 5 分钟内完成。

【讨论】:

    猜你喜欢
    • 2021-02-06
    • 2012-07-17
    • 2020-01-12
    • 2022-01-21
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    相关资源
    最近更新 更多