Hive - 动态分区:更新表时需要很长的加载时间和很多分区

时间:2013-08-14 10:31:57

标签: amazon-s3 hive amazon-emr

我通过AWS EMR运行Hive并拥有一个将日志数据频繁解析为S3的作业流程。我为我解析的Hive表使用动态分区(日期和日志级别)。

当我有几千兆字节的数据和大量分区时,有一件事情就是永远在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只包含今天和昨天的日志条目,但也可能包含较旧的条目。

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

2 个答案:

答案 0 :(得分:1)

在这个慢速阶段,Hive会为每个分区获取它构建的文件,并将其从临时目录移动到永久目录。您可以在名为Move Operator的“explain extended”中看到这一点。

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

你写的内容不清楚的是你每次跑步时是否都在做满负荷。例如,为什么你有2013-03-05分区?您是否收到包含此旧日期的新日志数据?如果此数据已存在于您的日志表中,则应修改插入语句,如

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

这样你只会得到一些桶,只有几个文件可以移动。从new_logs扫描所有这些额外数据仍然是浪费,但你可以通过分区new_log来解决这个问题。

答案 1 :(得分:0)

AWS已将EME 3.2.x及以上版本的HIVE分区恢复时间提高了一个多个数量级。

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