Love.Passion.Dream

大数据中HIVE数据仓库的设计

算起来接触大数据也有半年多了吧,嗯,我是一块砖,哪里需要哪里搬。说大数据其实主要就是hadoop那一套,虽然说我搞hadoop一般,但是我是搞hadoop里面的前端最好的,搞前端的里面hadoop最好的,囧。不管怎样这样无法压抑我要分享的心情。毕竟是个半路出家,所以也就不去分析哪些比较深的hadoop技术问题了,这个一般出问题我也都是找平台那边的同学。主要就来谈谈hadoop生态圈中很重要的一部分:Hive数据库 ... 的设计。

这里说的设计就是hive数据表的schema设计。下面是一个hive表的schema的例子:

CREATE TABLE base_user_activity (
    user_id STRING,
    type STRING COMMENT 'in (impression, click)',
    log_time STRING COMMENT 'The timestamp of this pingback log'
    )
COMMENT 'demo'
PARTITIONED BY (dt STRING, hour STRING, quarter STRING)
ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '\t'
    LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

这是我随手写的一个demo,是用来存放用户行为信息,每一行对于用户的一个操作,有一个用户id和这次行为的类型,曝光或者是点击,最后还有pingback记录的时间。这个算是最最基础的一个表了,存放了最原始的信息(不过当然还有更原始的nginx收集的日志)。这是按照每个15分钟作为一个分区。从schema的定义来看hql的语法基本和sql差不多,hive被设计的时候也是为了能够让开发人员能够通过hql来快速构建mapreduce的任务,hive数据的存储是作为文本存放在HDFS上的,所以最后应用要访问数据的时候还需要将hive中的结果导入到mysql之类的能够快速读取的介质中,hive只是用于计算的。

好了,这一段算是科普,也不再过多的介绍。下面重点开始我自己在hive数据仓库设计中的一些积累:

分层设计:

数据从原始日志收集到最终生产出有价值的数据需要经过一系列处理,处理过程可以分层去一步一步操作,通常数据越往后数据量越小,维度越少,数据更直观。我将数据仓库分为三层,分别是:

base 层,基本表。 表中一条记录对应一条日志,存放的信息比较原始,有些特殊的数据可以直接从该类表中得到。

middle 层,中间表。 通常是对基本表在一个时间段内的基本累加和一些基本处理。中间表的存在可以大大提高总体的数据计算速度。

report 表,报告层。 表的数据量比较小,通常已经可以直接导入到mysql中提供给各个应用。

每一层设计原则:

以下是针对各个层次的表设计的一些基本原则:

base表

  • 每一条记录对应一条日志,并且每一项数据对应日志中的一项信息。

  • 最好不要做任何处理和验证过滤,使得base表能够最大限度的保留细节。防止排查问题的时候还需要从原始日志中找数据。

  • 每一条日志尽量包含住够多的信息,需要日志发送端尽可能的发送住够的信息。

  • 按照日志的属性分开多个base表存放。比如故障分析的数据信息和用户行为的数据应该分开存放。一方面能够提高后续计算的速度,另一方面也能节省一些没空的字段用于减少空间,最后清理历史数据的时候也方便通过数据属性设置清理策略。

  • 按照时间分区,分区的时间段短一些,通常可以设置为15分钟。当然也可以按照实际的日志量去设置这个时间。

middle表

  • 处理掉base中需要处理的信息,避免后续的每一个report表都要维护同样的处理逻辑。

  • 只过滤部分特别分散的纬度,比如用户id,其他纬度尽量保留,在时间维度上对base表的数据进行累加。

  • 针对类似UV这样的数据而构建的middle表,因为要暴露用户id,所以其它维度可以忽略。并且时间分区要设置得长一些,通常是一天。

  • 编写 hql 脚本的时候一定要考虑性能,计算时间最好不要超过分区时间的一半。

report表

  • report表尽可能从middle表得到数据,这样能够更多的保证计算的速度和准确性。

  • 可以根据实际数据情况在report表中也分为多级,通常除了用户UV这一的数据之外最好一小时作为分区,这一方便debug,不然如果纬度设置为一天,那么调试的时候会死人。可以在小时的基础上再加上天的数据。

其他一些通用设计原则:

  • 命名一定要明确,不可以出现同样的命名其中包含的数据不一致。尤其是在某些表中某项数据可能会按照某些条件过滤掉一部分,这种情况最好重新取一个名字。

  • 如果某一个表有某一项数据的细分,那么最好这个表中不要再按照这个细分做过滤。不然累加的结果和原来的总数据不一致的时候会令人疑惑。

  • 同样的一个字段在不同的表中数据类型要一致。

  • 针对数据的紧急程度和数据量有一套设置队列优先级,reducer个数等参数的标准。

  • 表命名要规范,可以参考 [base|middle|report][name][xxx]_[daily|...]

关于存储:

  • 关键性的数据将其base表或者包含足够维度的middle表尽可能的存放长的时间,从冷存储中导入数据简直就是噩梦啊。另外比起查询hdfs上的原始信息,base表更方便。所以base中保存尽可能多的信息,然后节约出原始日志存放的空间来存放base表。

  • hive 中的最终提供给各项应用的report表占用空间不大,尽可能的存放时间长一些。

** 最后再提一句,数据仓库是基础,一定要设计得清晰,规范 **