4

我通过 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 仅包含今天和昨天的日志条目,但也可能包含较旧的条目。

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

4

2 回答 2

1

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

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

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

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

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

于 2013-08-18T08:31:57.053 回答
0

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

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

于 2014-12-24T01:17:42.160 回答