环境:

hive: apache-hive-1.1.0

hadoop:hadoop-2.5.0-cdh5.3.2

hive元数据以及stats使用mysql进行存储。

hive stats相关参数如下:

hive.stats.autogather:在insert overwrite命令时自动收集统计信息,默认开启true;设置为true

hive.stats.dbclass:存储hive临时统计信息的数据库,默认是jdbc:derby;设置为jdbc:mysql

hive.stats.jdbcdriver:数据库临时存储hive统计信息的jdbc驱动;设置为com.mysql.jdbc.driver

hive.stats.dbconnectionstring:临时统计信息数据库连接串,默认jdbc:derby:databaseName=TempStatsStore;create=true;设置为jdbc:mysql://[ip:port]/[dbname]?user=[username]&password=[password]

hive.stats.defaults.publisher:如果dbclass不是jdbc或者hbase,那么使用这个作为默认发布,必须实现StatsPublisher接口,默认是空;保留默认

hive.stats.defaults.aggregator:如果dbclass不是jdbc或者hbase,那么使用该类做聚集,要求实现StatsIAggregator接口,默认是空;保留默认

hive.stats.jdbc.timeout:jdbc连接超时配置,默认30秒;保留默认

hive.stats.retries.max:当统计发布合聚集在更新数据库时出现异常时最大的重试次数,默认是0,不重试;保留默认

hive.stats.retries.wait:重试次数之间的等待窗口,默认是3000毫秒;保留默认

hive.client.stats.publishers:做count的job的统计发布类列表,由逗号隔开,默认是空;必须实现org.apache.hadoop.hive.ql.stats.ClientStatsPublisher接口;保留默认

现象:

执行insert overwrite table 没有正确的返回numRows和rawDataSize;结果类似如下

[numFiles=1, numRows=0, totalSize=59, rawDataSize=0]

在hive stats mysql 数据库也没有任何相关的stats插入进来。

先定位问题是hive stats出现问题,由于console打印出来的信息过少,无法精确定位问题;因此设置

hive --hiveconf hive.root.logger=INFO,console ;将详细日志打印出来,发现以下信息:

[Error 30001]: StatsPublisher cannot be initialized. There was a error in the initialization
of StatsPublisher, and retrying might help. If you dont want the query to fail because accurate
statistics could not be collected, set hive.stats.reliable=false

Specified key was too long; max key length is 767 bytes

这个问题比较简单,是由于hive1.1.0,ID column长度默认为4000;而且设置ID为主键,导致报错

org.apache.hadoop.hive.ql.stats.jdbc.JDBCStatsSetupConstants

  // MySQL - 65535, SQL Server - 8000, Oracle - 4000, Derby - 32762, Postgres - large.
  public static final int ID_COLUMN_VARCHAR_SIZE = 4000;

org.apache.hadoop.hive.ql.stats.jdbc.JDBCStatsPublisher:public boolean init(Configuration hconf) 

              if (colSize < JDBCStatsSetupConstants.ID_COLUMN_VARCHAR_SIZE) {
                String alterTable = JDBCStatsUtils.getAlterIdColumn();
                  stmt.executeUpdate(alterTable);
              }

从这个代码知道,如果表的ID column size小于4000,会被自动改为4000;因此只有修改源码将4000->255(mysql采用utf8编码,一个utf8占用3个字节,因此255*3=765<767);并且对于目前集群来说255字节已经够用。

  public static final int ID_COLUMN_VARCHAR_SIZE = 255;

重新编译,打包推送到测试环境。

注:也可以不调整源码,直接将PARTITION_STATS_V2这个表的主键删除,并添加上

CREATE INDEX PARTITION_STATS_V2_IDX01 ON PARTITION_STATS_V2(ID(255));

经过测试发现问题还是存在。

[numFiles=1, numRows=0, totalSize=59, rawDataSize=0]

hive --hiveconf hive.root.logger=INFO,console ;将详细日志打印出来

并没有发现有异常发生。

为了跟踪问题,set hive.stats.reliable=true;

重新执行命令,这次报错,查看job报错信息,发现问题出现在

org.apache.hadoop.hive.ql.stats.jdbc.JDBCStatsAggregator

    try {
      Class.forName(driver).newInstance();
    } catch (Exception e) {
      LOG.error("Error during instantiating JDBC driver " + driver + ". ", e);
      return false;
    }


这个是在yarn上运行,无法找到com.mysql.jdbc.Driver这个类导致,将mysql驱动包,放置于yarn/lib/目录下面,全集群推送,重跑测试脚本,发现问题解决。