六、Hive

6.1 基本架构

面试(串讲二)_hive

6.2 与数据库的比较

 

mysql

hive

速度

数据量小、快

数据量大、快

场景

小数据量的增删查改

大数据量的查询分析

6.3 内部表、外部表

  删除内部表:删元数据、原始数据

  删除外部表:删元数据

  企业怎么用?

    主要用外部表,临时表和测试表用内部表

6.4 4个By

  order by:全局排序,最终只有一个reducer,结合limit一起使用

  sort by:分区内排序

  distribute by:分区,指定数据该进入哪个reducer

  cluster by:当sort by 与 distribute by字段一致时,且升序,可以用cluster by代替

6.5 系统函数

  时间:date_add、date_sub、datediff、next_day、last_day、xxxofxxx、from_unixtime、unix_timestamp、now、date_format

  字符串:substring、split、concat、concat_ws、get_json_object、replace、regexp_replace

  行列转换:

    一行转多行:explode(数组、map)

    多行转一行:collect_list、collect_set

    一列转多列:if、case when

    多列转一列:concat、concat_ws

  空值处理:nvl、if

6.6 窗口函数

  聚合类、排名、lead、lag、first_value、last_value  over(partition by ...order by ... 行的范围)

  行的范围:rows、range

  例如:sum() over()

 

rows

range

1

1

1

2

3

3

3

6

9

3

9

9

4

13

13

5

18

18

  order by 默认行范围:range 上无边界到当前行

6.7 自定义函数

  UDF:一进一出

  UDTF:一进多出

  UDAF:多进一出

  项目里用到了什么?UDTF:用来解析Json数据里面的Array,实现一进多出

  为什么不用get_json_object?它只能一进一出

  怎么实现?定义一个类,继承GenericUDTF,重写3个方法

    初始化方法:输入参数的效验,比如个数、类型,返回类型的约束

    process方法:多次调用fowward

    close()

  完成之后打jar包,上传至HDFS,然后在客户端中输入:



create function 方法名 as 全类名 using jar 'hdfs路径'


  为什么用自定义?

    1、解析Json中的Array,一进多出

    2、方便使用第三方依赖

6.8 优化

  1)map join:大小表,默认打开

  2)列式存储:orc、parquet

    结构更紧凑,压缩比更高,适合查询更新

id

name

age

1

zs

18

2

ls

20

    列式存储:1 2  zs ls  18 20

    行式存储:1 zs 18  2 ls 20

  3)分区、分桶

  4)压缩:lzo、snappy

  5)小文件:

    JVM重用:10

    使用CombineHiveInputFormat来进行切片:256m

    merge:单独再启动一个job,将平均小于16M的文件,合并为一个最大为256M的文件

      map-only:默认开启

      map-reduce:默认关闭,设置为开启

  6)行列过滤:

      避免select *

      能先过滤就先过滤

    谓词下推:在map阶段,提前过滤(若需要详细了解,请参考博客:​)

    两张表关联,过滤条件写在on和写在where有什么区别?

      select xxx from a join b on a.id > 10

      select xxx from a join b where a.id > 10

    首先先判断是什么Join

      如果是内连接,无任何区别

      如果是满外连接,on性能比where差,因为默认开启cbo优化,where可以进行谓词下推

      如果是left join或 right join,再判断条件来自哪张表

        如果判断条件来自保留表,则on性能比where差,因为on不能进行谓词下推

        如果判断条件来自非保留表,则无任何区别,因为默认开启cbo优化,where可以进行谓词下推

  7)Map数量

    切片大小 = max(minSize,min(maxSize,块大小))

  8)reduce数量

    估算机制:输入的数据量 / 单个Reducer处理的数据量

    参数设置:mapred.reduce.tasks,默认 -1,表示不开启

    特殊语法:order by  1个

    优先看是否指定了参数,如果没有,就走估算机制

  9)多引擎

    mr:年月指标

    spark:日常的天指标

    tez:临时用

    若不同引擎结果不一,以MR为主

    如何实现不同Job不同引擎来跑?

      1、部署spark环境

      2、set hive.execution.engine = spark;

         sql

         set hive.execution.engine = mr;

            sql

6.9 数据倾斜

  1)现象:yarn页面,个别reduce执行时间明细特别长,卡在99%

  2)原因:

    数据本身就不均匀

    Null值

    类型不一致

  3)解决方案

    辅助措施:提前Combiner,在不影响最终逻辑的情况下

    数据本身就不均匀:二次聚合

      参数:hive.groupby.skewindata,解决group by数据倾斜,自动实现二次聚合

            hive.optimize.skewjoin,解决join的数据倾斜,自动实现二次聚合

    null值:

      null值无意义,先过滤

      null值有意义,二次聚合,使用到nvl

    类型不一致:先转换类型,再join    a join b on cast(a.id,string) = b.id

6.10 分隔符问题:数据本身携带了hive的分隔符

  问题:hive表字段错误

  解决:

    1、参数 --> 默认分隔符为 \001

    2、mysql表导一张到临时表,再同步到hdfs

    3、让后端人员改

七、Sqoop

7.1 遇到哪些问题

  1)空值问题

mysql 

Hive 

 null

\N 

    导入时:null-string、null-non-string

    导出时:input-null-string、input-null-non-string

  2)导出是,遇到一致性问题

    底层跑的是4个map任务,解决方法就是手动创建一张临时表,将数据导入临时表中,数据全部进入临时表后,再导入到目标表,有两个参数可以设置:



–staging-table mysql表名_tmp \  (将数据先导入临时表)
–clear-staging-table \      (清空临时表)


  3)数据倾斜问题

    我们一天1个G左右,没遇到

    但是以前有个朋友遇到过:split-by 指定自增主键,指定增加map数

7.2 每天业务数据有多少?

  60万日活,平均每天6万订单,每个订单10条数据,每条数据平均1k

  6万 * 10 * 1k = 600000k ≈ 600M左右

7.3 每天几点跑,跑多久?

  00:10开始跑,大概跑10多分钟

7.4 参数



sqoop --import
--connect url
--user
--password
--target-dir
--delete-target-dir
--query 'select xxx from where xxx $condition'
--空值处理的两个参数
--split-by
--mapper


7.5 导出时,parquet问题

  1)先将数据导入到格式为Text格式的临时表中,再导出

  2)一开始就不要用列式存储

  3)hcatalog导出,sqoop参数,要求版本1.4.5

八、Azkaban

8.1 每天几点跑,跑多久?

  第一个脚本:sqoop同步脚本,00:10开始跑

  平均3个多小时,不管怎么跑,早上八点一定会出结果

8.2 日常跑多少指标?活动时多少?

  日常跑100来个指标,有活动时200来个

8.3 任务挂了怎么办?

  告警:邮件、发短信、发微信、发钉钉、打电话

    实现:调用第三方接口,oneAlter

  尝试重启:自动重试、手动重试

  解决问题:看日志(资源不够、业务表发生改变)

          摇人

九、项目架构

9.1 从0到1

  1)集群规模:目前有没有服务器给你用,几台?一共有9台,后来增加到12台

  2)数据量:日志数据每天60G左右,业务数据每天600多M

  3)周期:采用敏捷开发模型,基本上一个月为一个开发周期,比如1.2.3版本号,一个星期更换数据为3的版本号,表示小范围的更新,2这个数据一般一个月更新一次,表示中等规模的更新,1的话一般半年或一年更新一次,表示大的一个版本更迭

  4)资金:服务器买了3台,每台服务4万块,3台一共12万多

  5)人员:5个人,包含组长

  6)指标规划:第一期指标20多个,比如求新老用户、留存率、页面跳转率、活跃人数、每日下单数、每日支付数、每日下单金额等

  7)数据来源:oracle、db2、sqlserver、qp、mysql

9.2 数仓概念

  1)数据来源:前端埋点日志、javaee后台业务服务

  2)产出:报表、用户画像、推荐系统、风控系统

9.3 版本选型

  开源版:apache,大厂

  商业版:cdh、hdp -->cdp,1个节点1万美金/年

    cdh:6.3.2

    hdp:3.1.4

  建议选哪个?建议选apache、虽然成本比较高昂,但安全性强

9.4 集群规模:几台服务器,60万日活

  1)磁盘:半年不扩容

     数仓分层:

      日志:

        ods:6G(压缩后)

        dwd:6G(压缩后)

        dws + dwt:30G,压缩后3G

        ads:忽略

        6 + 6 + 3 = 15G,给个20G

        20G * 3 副本 * 180天 / 0.7 ≈ 15T,给20T

      业务:

        2G * 3副本 * 180天 / 0.7 = 2T

    kafka:之前给1T

    20T + 2T + 1T = 23T

    23T / 8T = 3台

  2)内存:

    7台 * 128G = 896G

    1台服务器的NodeManager给100G -->100G * 7 = 700G

    离线:128M数据 --> 1G内存(占比约1:8),同时跑70G的数据,大约需要600G内存左右

    实时:10 + 几个Job,1个Job10多G,大约需要200G内存左右

    通过计算,7台不太够,建议:9~15台

  3)CPU

    单台20核40线程

    40 * 7 = 280(200给集群 ,80给其他)

    实时:1个Job,6个并行度 --> 6线程,  6 * 10多个 约等于 90线程

    离线:100+ 可用

    通过计算,7台不太够,建议9~15台

十、数仓分层

10.1 建模第一步做什么?

  理清业务逻辑,求出业务表

10.2 ods

  1)使用分区表,避免全表扫描

  2)压缩,减少磁盘空间

  3)保持数据原貌,起到备份的作用

10.3 dwd + dim

  1)清洗工具

    hql、spark、flink、python、kettle

  2)清洗原则

    解析数据

    去重

    核心字段不能为空

    超期数据(爬虫)

    脱敏:md5

  3)清洗比例:万分之一

    若清洗比例较高,找前端和Java开发人员沟通

  4)分区

  5)压缩

  6)列式存储

  7)维度退化

    基于维度建模的星型模型理论

    降维:将某个维度的所有表合并成一张表,以后关联某个维度时,只需要join一次

    sku表、spu表、三级、二级、一级分类、品牌、商品平台属性表、商品销售属性表 -->商品维度表

    省份表、地区表 --> 地区维度表

    活动信息表、活动规则表 --> 活动维度表

  8)维度建模

    (1)选择业务过程,选择需要的业务表

      小公司,30来张,全都要

      大公司,上千张,选择需要的业务模块:下单模块、支付模块、物流模块...

    (2)声明粒度

      什么是粒度?一行数据代表什么行为

      比如订单表的一行数据,代表了一次下单行为

      声明最小粒度:只要不做聚合操作,就已经是能达到的最小粒度

    (3)确定维度:描述某个业务事实的角度

      何时、何地、何人对何物做了何事(时间、地区、用户、商品、下单或支付)

    (4)确定事实

      关注事实的度量值:个数、件数、金额、次数等可统计的量词

      使用业务总线矩阵来计算

10.4 dws:一天的汇总

  1)有哪些宽表:主要参考维度表,有多少维度,就有多少宽表

      地区、用户(会员)、访客(设备)、商品、活动、优惠券

  2)宽表有哪些字段:站在维度的角度,关注事实的度量值

10.5 dwt:一段时间的累计

  目的: 避免重复计算

  1)有哪些宽表:主要参考维度表 ,有多少维度表,就有多少宽表

      地区、用户(会员)、访客(设备)、商品、活动、优惠券

  2)宽表有哪些字段:站在维度的角度,关注事实的 开始时间、结束时间、这段时间度量值的累积、最近一段时间度量值的累积

10.6 ads:

    指标:

    手写:实现思路

    比较难的指标:

十一、数仓业务

11.1 埋点格式

  页面日志、启动日志、曝光日志、事件日志、错误日志

  1)启动日志



{
"common":{},
"start":{}
"err":{},
"ts":xxxxxx
}


  2)其他



{
"common":{},
"actions":[{},{},...],
"display":[{},{},.....],
"page":{},
"err":{},
"ts":xxxx
}


11.2 同步策略

  业务数据MySQL --> Sqoop --> HDFS

  全量数据:数据量小

    sqoop的query  "select * from 表名 where 1=1"

  新增数据:数据量大,历史数据不会变化

    sqoop的query  "select * from 表名 where 创建时间=昨天"

  新增及变化:数据量大,历史数据会变化(后续dim层,使用拉链表)

    sqoop的query  "select * from 表名 where 创建时间 = 昨天 or 操作时间 = 昨天"

  特殊数据:全量导入

11.3 建模理论

  关系建模:业务库MySQL,基于三范式理论的第三范式

    减少数据冗余,取哪个维度就要跟哪个维度join一次

  维度建模:星型模型、雪花模型、星座模型

    降维,取一个维度,只需要join一次,需要数据冗余,不灵活(字段变更)

    星型模型:一张事实表周围围绕着多个一级维度表

    雪花模型:一张事实表周围围绕着多个多级维度表

    星座模型:多个事实表周围围绕着多个一级维度表

11.4 业务库的表发送变化怎么办?

  1)新字段,历史数据需不需要补全

    需要:一点点改,重新跑任务

    不需要:从新增开始,有数据就行,改数仓脚本就行,加上字段

  2)减字段

    改数仓脚本,减去字段

11.5 数仓有几张表

  ods:日志1张,业务27张

  dwd:日志5张,9张事实表,6张维度表

  dws:宽表6张

  dwt:宽表6张

  ads:约30张

  我们公司100张左右

11.6 数仓哪张表最大?

  50G / 5张日志表 = 平均10G

  用户行为宽表:10G * 3 = 每天30多G

11.7 实时资源

  Flink:JobManager,128M~2G

    TaskManager,1)并行度:2的n次方  8

          2)内存:4G

          3)每个TaskManager的slot数:4

    平均一个job至少要10G内存

11.8 平均每张表每天多大?

  日志: 每天每张平均10G

  业务: 每天每张平均 34m左右,大的表 5倍 =》 170M左右,

                小的表 5M左右

11.9 数据治理

  元数据管理:hive表的元数据

  数据质量监控:数据量的监控、重复数据监控、空值监控

    底层实现:SQL

        底层:shell脚本

  权限管理:ranger

11.10 数据中台

11.11 数据湖