大数据开发面试

一、Linux &Shell

1、常用高级命令

常用命令:ls、cd、tail、cat、vim、chmod、chown、tar、mv、cp

序号

命令

说明
1 top

实时显示系统中各进程的资源占用状况(CPU/内存/执行时间)

2 netstat

查看端口占用情况 netstat -tunlp | grep 端口号

3 free -m

查看系统内存使用情况

4 df -h

查看磁盘存储情况 -h:以熟悉的单位

5 iostat 查看IO
6 jmap -heap

查看某个进程内存(堆内存)

7 ps -ef

查看进程

8

du -sh

查看路径下的磁盘使用情况,例如:$ du -sh /opt/*

9 find

按文件名查找:find 路径 -name "文件名"

按文件类型查找:find 路径 -type 类型

按文件大小查找:find 路径 -size 范围

按照文件日期查找:find 路径 -ctime/-mtime/-atime -n/+n 

按深度查找:find 路径 -maxdepth/-mindepth n(层数)

2、查看内存/磁盘/IO/端口的命令

同上

3、shell常用工具

awk:切分字符串

cut:列截取

sort:排序

sed:不打开文件的情况下增删改查

4、写过哪些脚本

4.1 各框架群起群关脚本、xsync(循环、判断类)
#! /bin/bash
case $1
"start")
  for i in hadoop102 hadoop103 hadoop104
  do
    ssh $i "xx-start.sh"
  done
;;
"stop")
  for i in hadoop102 hadoop103 hadoop104
  do
    ssh $i "xx-stop.sh"
  done
;;
esac
4.2 DataX配置文件生成脚本

MySQL -> HDFS

HDFS -> MySQL

#! /bin/bash

DATAX_HOME=/opt/module/datax

#DataX导出路径不允许存在空文件,该函数作用为清理空文件
handle_export_path(){
  for i in `hadoop fs -ls -R $1 | awk '{print $8}'`; do
    hadoop fs -test -z $i
    if [[ $? -eq 0 ]]; then
      echo "$i文件大小为0,正在删除"
      hadoop fs -rm -r -f $i
    fi
  done
}

#数据导出
export_data() {
  datax_config=$1
  export_dir=$2
  handle_export_path $export_dir
  $DATAX_HOME/bin/datax.py -p"-Dexportdir=$export_dir" $datax_config
}

case $1 in
  "ads_coupon_stats")
    export_data /opt/module/datax/job/export/gmall_report.ads_coupon_stats.json /warehouse/gmall/ads/ads_coupon_stats
  ;;

  "all")
    export_data /opt/module/datax/job/export/gmall_report.ads_coupon_stats.json /warehouse/gmall/ads/ads_coupon_stats
  ;;
esac
4.3 Hive数据装载脚本

ODS -> DWD/DIM -> DWS -> ADS

HiveSql -e "sql" 
              -f sql文件 sql.txt

#!/bin/bash 
#定义变量 
APP=gmall
获取时间   
	传入  按照传入时间
	不传  T+1 
sql="
	先按照当前天 写sql => 遇到时间 $do_date  遇到表 {$APP}.
	自定义函数 UDF  UDTF    {$APP}.
"
执行sql

5、单双引号的区别

"":解析特殊符号

'':强引用,保持原样

嵌套使用时看外层

vim test.sh

#! /bin/bash
do_date=$1
echo '$do_date'
echo "$do_date"
echo "'$do_date'"
echo '"$do_date"'
echo `date

sh a.sh 2023-11-27

$do_date
2023-11-27
'2023-11-27'
"$do_date"
2023年 11月 27日 星期一 09:55:52 CST

       

       

二、Hadoop

1、入门

1.1 端口号(默认)
NameNode ResourceManager 历史服务器
web端 9870 8088 19888
通信/服务端 8020 8032 10020
1.2 配置文件

core-default.xml

hdfs-default.xml

yarn-default.xml

mapred-default.xml

core-site.xml

hdfs-site.xml

yarn-site.xml

mapred-site.xml

workers(主要for群起脚本用,不影响正常运行)

2、HDFS

2.1 读写流程

1)读流程

        ① 客户端向NameNode请求下载文件

        ② NameNode返回目标文件的元数据

        ③ 客户端根据元数据信息,向DataNode1请求读取数据blk_1

        ④ DataNode1传输数据给客户端

        ⑤ 客户端向DataNode2请求读取数据blk_2

        ⑥ DataNode2传输数据给客户端

2)写流程

        ① 客户端向NameNode请求上传文件

        ② NameNode检查权限和目录结构后响应客户端可以上传

        ③ 客户端向NameNode请求上传第一个Block,请NameNode返回DataNode节点

        ④ NameNode返回DateNode1、DateNode2、DateNode3存储节点

        ⑤ 客户端向DateNode1请求建立Block传输通道,DN1与DN2、DN2与DN3请求建立通道

        ⑥ DN3返回应答成功给DN2、DN2返回应答成功给DN1、DN1返回应答成功给客户端

        ⑦ 客户端向DN1传输数据Packet(包含128个chunk512byte+chunksum4byte)

        ⑧ 传输完成后,客户端向NameNode再次请求上传下一个Block,DN向NN返回元数据信息

注意:HDFS写入流程时候,某台DataNode挂掉如何运行?

DN突然挂掉,客户端接收不到该DN发送的ack确认,会通知NN,NN检查并确认后通知闲置的DN去复制副本,并将挂掉的DN下线,待其恢复后,删除该节点中曾拷贝的不完整副本数据

2.2 小文件问题

1)危害

① 存储:占用NN内存,导致存储效率低

        每个文件块(默认最大128M)无论大小,都会占用NameNode一个元数据,约150byte -> 增加寻址时间

HDFS的NameNode内存

1)Hadoop2.x系列,配置NameNode默认2000m

2)Hadoop3.x系列,配置NameNode内存是动态分配的

        NameNode内存最小值1G,每增加100万个文件block,增加1G内存。

② 计算:任务多,Mapper数量多,资源占用高,利用率低

        默认是按照单个文件进行切片的,每个小文件都是一个切片,即需要一个MapTask(最大切片128M*1.1),而Container资源分配相同默认1个MapTask内存1G,造成资源浪费

2)解决

① 存储:

 a.源头上:不产生小文件

        Flume:HDFS Sink文件滚动参数(hdfs.rollInterval、hdfs.rollSize、hdfs.rollCount -> 滚动时间间隔30min、大小128M、事件数/数据条数0)

        ADS层:

insert into ads_t select xx from dws_t; 
--每天查询的结果为一条数据,但都会生成一个新的文件,是典型的小文件问题

--解决
insert overwrite ads_t
select xx,xx
from dws_t
union all --不产生新文件 合并
select * from ads_t;

        Hive参数:执行SQL获取结果后自动合并

b.已经存在小文件:

        Har归档(HDFS命令,把一个目录下的文件合并打包成一个HAR文件)

        手动合并

② 计算:

CombineTextInputFormat:合并多个小文件

预聚合:减少中间小文件(减少shuffle)

开启JVM重用:仅MR引擎可用(hive on spark无效:MR是任务进程jps -> YarnChild,Spark是任务时线程ExecutorBackend -> 线程池 -> 多个进程jps -> CoarseGrainedExecutorBackend,一个进程申请一个JVM,开启后可以在同一个job中重用JVM)

JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间。

<property>

    <name>mapreduce.job.jvm.numtasks</name>

    <value>10</value>

    <description>How many tasks to run per jvm,if set to -1 ,there is  no limit</description>

</property>   

参数设置:开启任务后小文件自动合并

<property>
        <name>mapreduce.input.fileinputformat.split.minsize</name>
        <value>134217728</value>
</property>

2.3 块大小问题

取决于磁盘读写速度

普通的机械硬盘 100m/s  =>  128m

固态硬盘普通的 300m/s  => 256m

内存镜像     500-600m/s  => 512m

最佳状态是寻址速度为读写速度的1% -> 寻址速度一般为10ms,故读写速度为1s -> 目前磁盘的传输速率普遍为100MB/s -> Block大小为1s*100MB/s,即100MB

本地模式:32M

1.x版本:64M

2.x版本:128M

3.x版本:128M

Hive:256M(orc、parquet)

大公司:256M、512M

块太小会增加寻址时间,块太大会增加传输数据的时间

2.4 副本数

默认3副本,可改hdfs-site.xml中的dfs.replication参数

副本节点选择:

① 第一个副本在客户端所处节点上(本地节点)

② 第二个副本在另一个机架的随机一个节点(其他机架一个节点)

③ 第三个副本在第二个副本所在机架的随机一个节点(其他机架另一个节点)

2.5 NameNode内存

Hadoop2.x系列,配置NameNode默认2000m

Hadoop3.x系列,配置NameNode内存是动态分配的

        NameNode内存最小值1G,每增加100万个文件block,增加1G内存

3、MR

3.1 Shuffle

Map方法之后,Reduce方法之前

① MapTask通过hadoop序列化writer,收集map()方法输出的kv,添加分区信息放到环形缓冲区

② 环形缓冲区达到溢写阈值后进行分区、快排,再溢写(数据&索引)到本地磁盘(默认100M,80%后反向溢写 -> 不停机)

③ 在不影响业务逻辑的情况下可以先进行Combiner预聚合

④ 如果有多次溢写产生多个文件,先进行merge归并排序再压缩或直接写到磁盘

⑤ ReduceTask根据分区号,拉取数据拷贝到内存缓冲,内存不足时溢出到磁盘(内存为Reduce内存1G的70%,溢写阈值为2/3)

⑥ 再对每个Map来的数据归并排序,把相同key的数据放在一起,按照key进行分组

⑦ 相同的key调用一次reduce()方法

3.2 优化

4、Yarn

4.1 工作机制

4.2 调度器

1)先进先出调度器(FIFO):单队列,队列内部先进先出(生产环境几乎不用)

2)容量调度器(Capacity Scheduler):多队列,队列内部先进先出,优先选择资源利用率低的队列,按照作业的优先级和提交时间顺序分配资源,Apache的默认资源调度器(Application并行度要求不高,只有离线)

3)公平调度器(Fair Scheduler):多队列,优先选择资源缺额比例大的,队列内资源充足的情况下可以多任务运行,CDH的默认资源调度器(Application并行度要求高,实时)

生产环境怎么创建队列?

队列的设置:默认存在一个Default队列

        业务:业务需求,登录注册、购物车、下单

        框架:mr、hive、spark、flink

        部门:大数据、业务部门1

        人员:一般新入职员工独立队列

创建多队列的好处?

避免员工不小心写递归死循环代码,把所有资源全部耗尽

实现任务的降级使用,特殊时期保证重要的任务队列资源充足

5、补充:Hadoop脑裂

1)原因

Leader故障,系统改朝换代,当Follower完成全部工作并成为新Leader后,原Leader又恢复了(故障可能是暂时断开或系统暂时变慢、不能及时响应、但NameNode进程还在),且由于某种原因,对应的ZKFC没有把它设置为Standby,原Leader还认为自己是Leader,客户端向其发出的请求仍会响应

2)解决办法

通常不会出现,如果出现则意味着多个NameNode数据不一致,只能选择保留其中一个的数据

例如:现在有三台Namenode,分别为nn1、nn2、nn3,出现脑裂,想要保留nn1的数据

关闭nn2和nn3 -> 在nn2/3节点重新执行数据同步命令:hdfs namenode -bootstrapStandby -> 重新启动nn2和nn3

        

       

三、Zookeeper

ZooKeeper保证了CP,但不能保证每次服务器请求的可用性

1)作为HA的协调者:如 HDFS的HA、YARN的HA。

2)被组件依赖:如Kafka、HBase、CK

1、选举机制

半数机制(比较myid),同时防止了Zookeeper脑裂

2、机器台数

奇数台服务器(台数越多稳定性越好,但通信时间越长,选举时间长)

10台服务器 3台Zookeeper
20 5
50 7
100  11
200 11

3、常用命令

1)增:create

        节点种类:2类 4种(有无序列号、是否持久化)

        有序列号的永久节点、有序列号的临时节点、无序列号的永久节点、无序列号的临时节点

高可用产生的节点,一般都是临时节点(创建该节点的进程挂了,节点自动删除)

2)删:

        delete:删除单个节点

        deleteall:级联删除,删除该节点及所有子节点

一个node节点只能存储1M数据,一般不改,重新创建即可

3)查:

        ls:查看子节点

        get:查看当前节点内容

四、Flume

1、组成

1.1 Source

TailDirSource:可以断点续传、监控多目录多文件

        断点续传:保存偏移量key(文件) - value(位置信息position)        

        偏移量:[iNode(Linux系统种文件的唯一标识) + 绝对路径,pos]

可能出现的问题:TailDirSource遇到更名打印日志框架,会在凌晨将前一天数据完整读取一次产生重复消费,app.*

日志打印:
        2023-11-25 app.log   256byte
        2023-11-26 app.log.2023-11-25   256byte
                           app.log   0byte

 解决:

        直接监控app.log(不监控app.log.*)        × 可能丢数据

        与Java部门沟通,采用不更名的日志打印框架        可能不同意

        修改源码,只按照iNode值判断文件 flume-taildir-source-1.9.0.jar        比较复杂

        修改源码视频地址:https://www.bilibili.com/video/BV1wf4y1G7EQ?p=14&vd_source=891aa1a363111d4914eb12ace2e039af

KafkaSource:上游是Kafka

avroSource:构建多级flume

1.2 Channel

KafkaChannel:数据存储于Kafka,基于磁盘,可靠性高且传输速度快(省去sink)

FileChannel:数据存储于磁盘,安全可靠但传输速度低,默认容量100万个event

MemoryChannel:数据存储于内存,传输速度快但可靠性差,默认容量100个event

生产环境如何选择?

1)如果下一级是Kafka,优先选择Kafka Channel

2)如果是金融、对钱要求准确的公司,选择File Channel

3)如果就是普通的日志,通常可以选择Memory Channel

1.3 Sink

HDFS Sink:下游是HDFS

时间(半个小时) or 大小128m  且 设置Event个数等于0,该值默认10

具体参数:hdfs.rollInterval=1800hdfs.rollSize=134217728hdfs.rollCount=0

avroSink:构建多级flume

2、拦截器

1)时间戳拦截器:日志数据(解决零点漂移问题  处理时间 -> 事件时间)

拦截器可以不用吗?

时间戳拦截器建议使用。如果不用需要采用延迟15-20分钟处理数据的方式,比较麻烦

2)时间戳 + 表名拦截器:业务数据

自定义拦截器步骤:

        ① 实现Interceptor接口

        ② 重写四个方法(初始化initialize()、单个事件intercept(Event event)、多个事件intercept(List<Event> events)、关闭close())

        ③ 创建静态内部类MyBuilder实现Builder接口(创建拦截器实例)

        ④ 打包上传到lib目录下,配置文件中添加全类名$MyBuilder

3、Channel选择器

1)副本Replicating Channel Selector:默认(全分发),将数据发往下一级所有通道

2)多路复用Multiplexing Channel Selector:结合拦截器选择性发往指定通道

4、Sink处理器/SinkGroup

1)Default Sink Processor:默认,只支持单个sink

2)Failover Sink Processor:故障转移,高可用

3)Load balancing Sink Processor:负载均衡,轮流拉取数据(轮询/随机/用户自定义)

5、监控器

Ganglia:Source尝试Put的事件数、Source成功Put的事件数、Sink尝试Take的事件数、Sink成功Take的事件数、Channel中现有的事件数

尝试 >> 成功,说明Flume运行比较差,主要是内存资源不足导致的

Source尝试Put的事件数 = Channel中现有的事件数 + Sink成功Take的事件数(>则表示丢数据)

6、优化

资源:通过Ganglia监控发现资源不足

        ① Flume任务默认内存20M -> flume-env.sh配置文件中修改Flume内存为4G ~ 6G

        ② 增加服务器台数

小文件:修改HDFS Sink三个文件滚动参数

提高吞吐量:调整taildir source的BatchSize大小(默认大小100个Event),瓶颈一般是网络带宽

TailDirSource:重复数据问题解决

7、丢数据问题

没有丢数据:

① 通过Ganglia监控器发现Source成功Put的事件数 = Channel中现有的事件数 + Sink成功Take的事件数

② 组件上采用的TailDirSource + KakfkaChannel 以及 KafkaSource + FileChannel + HDFSSink

③ 同时Source与Channel以及Channel与Sink之间传输数据时都有事务保证(put/take)

五、Hive

1、组成与HQL转换为MR任务的流程

1.1 Hive组成

外部:MySQL、HDFS、MR/Spark/Tez

        元数据存储默认derby数据库(只支持单用户单客户端访问) -> MySQL(多人开发)

        依赖于HDFS存储Hive处理的数据       

        Hive分析数据底层的实现默认是MapReduce引擎(也可配置为Spark或者Tez)

        外部驱动(DataGrip连接)

内部:解析器、编译器、优化器、执行器 

1.2 HQL转换为MR任务的流程

Hive本质是一个Hadoop客户端,用于将HQL转化为MapReduce程序

① 解析器:将HQL转换为抽象语法树AST(提取关键字)

② 编译器:将AST转换为查询块QueryBlock,进一步转换为逻辑执行计划

③ 优化器:对逻辑执行计划进行优化(只有一种优化器MR 参数级优化)

④ 解析器:将逻辑执行计划转换为物理执行计划TaskTree

⑤ 优化器:对物理执行计划进行优化(有3种 MR、Spark、Tez)

⑥ 执行器:将Task提交运行(driver)

2、与MySQL的区别

根本 数据量
其他 MySQL Hive
数据规模 数据量小,百万左右 大数据pb及以上
应用场景 OLTP(Online Transaction Processing,联机事务处理--增删改查) OLAP(Online Analytical Processing,联机分析处理--查,一次写入多次读取)
存储位置 本地 HDFS
计算引擎 传统计算引擎(InnoDB) 分布式计算引擎(MR/Spark/Tez)
查询速度
补充 可以支持动态加字段、修改字段名称/类型、调整字段顺序

综上可以发现,Hive不是数据库,除语言类似外存储和计算都基于Hadoop,而MySQL是用自己的体系

3、内外部表

区别:

1)建表时,external关键字,false即为内部表,true即为外部表

2)删除表时,内部表删除元数据与数据本身,外部表只删除元数据

3)大多数都用外部表,自己使用的临时表才会创建内部表

4、四个By

1)order by:全局排序,只有一个Reduce(SQL级别,效率低),Hash分区

例如:查询员工信息 按工资升序排列

        Spark全局排序:sortBy(T -> K,所有RDD) / sortByKey(K-V,pairRDD),可以并行,同时存在多个Reducer,效率更高,RangePartitioner范围分区器

2)sort by:区内排序,为每个reduce产生一个排序文件

设置reduce个数

set mapreduce.job.reduces=3;

            

查看设置reduce个数

set mapreduce.job.reduces;

例如:根据部门编号降序 查看员工信息

3)distribute by:分区,结合sort by使用

分区规则是根据分区字段的hash码与reduce的个数进行相除后,余数相同的分到一个区

Hive要求distribute by语句要写在sort by语句之前

例如:先按照部门编号分区 再按照员工薪资排序

4)cluster by:当distribute by与sort by字段相同且升序(ASC)时可以代替

以下两种写法等价:

hive (default)>

select  *

from emp

cluster by deptno;

              

hive (default)>

select  *

from emp

distribute by deptno

sort by deptno;

5、函数

5.1 系统函数

1)时间类

date_sub('日期',n):返回指定日期减去n天后的日期

date_add('日期',n):返回指定日期增加n天后的日期

datediff(enddate,startdate):两个日期相差的天数

date_format('日期','yyyy-MM-dd'):日期格式化

unix_timestamp('日期','yyyy/MM/dd HH-mm-ss'):返回当前或指定时间的时间戳

next_day('日期','MO'):下一个周几(不同于下周几)

last_day('日期'):月末

day_of_week():一周中的第几天

week_of_year():一年中的第几周

2)窗口函数

over() + 写在over前的函数、写在括号中的范围

        聚合函数:sum()、avg()、count()、max()、min()...

        排名函数:rank()、dense_rank()、row_number()        不支持自定义窗口

排名函数 rank() dense_rank() row_number()
1 1 1
2 2 2
2 2 3
4 3 4

        跨行取值函数:lead()、lag()、first_value()、last_value

        ntile(n):分成n组,适用于求前%

        范围:(不可混用)

        partition by + order by

        distribute by + sort by

        rows between xx and xxx

num(列名) select sum(num) over(order by num) from t;
1 1
2 3
3 9
3 9
4 13
5 18

3)多维分析函数

grouping_set():自定义

with cube():全

with roll up():层级

5.2 自定义函数

UDF(User-Defined-Function):一进一出,继承GenericUDF,重写核心方法evaluate()

UDTF(User-Defined Table-Generating Functions):一进多出,继承GenericUDTF,重写3个方法(initialize()自定义输出的列名和类型、process()将结果返回forward(result)、close())

6、优化

6.1 建表

分区:防止后续全表扫描

分桶:对未知的复杂的数据进行提前采样

压缩:减少磁盘IO,Hive底层计算引擎默认是MR,可以在Map输出端采用Snappy压缩

文件格式:Text File(Hive默认,行存)-> ORC / Parquet(列存,加快查询速度)

6.2 SQL语句

1)开启谓词下推:join的时候先执行过滤,尽量将过滤操作前移,以减少后续计算步骤的数据量

--是否启动谓词下推(predicate pushdown)优化

set hive.optimize.ppd = true;

          

--为了测试效果更加直观,关闭cbo优化

set hive.cbo.enable=false;

null=null的返回值为null,关联时自动过滤掉null值,谓词下推需保证关联字段is not null

可以explain sql语句查看执行计划

select * from a join b on a.id=b.id where a.id>'xxx'; --下推到a b两张表(过滤条件是关联字段a、b都先where过滤再join)
select * from a join b on a.id=b.id where b.id>'xxx'; --下推到a b两张表
select * from a join b on a.id=b.id where a.name>'xxx'; --下推到a表(过滤条件不是关联字段)
select * from a left join b on a.id=b.id where a.id>'xxx'; --下推到a b两张表
select * from a left join b on a.id=b.id where b.id>'xxx'; --下推到a b两张表
select * from a left join b on a.id=b.id where b.name>'xxx'; --下推到b表(b表特殊字段),同时将left join转换为inner join(3.x才有,之前谓词下推失效)

2)开启CBO优化器:3.x默认开启,2.x默认关闭

        成本优化器(Cost based Optimizer),在有子查询或者Join时会有用,尽量选择最优的方案(Hive会计算同一SQL语句的不同执行计划的计算成本,并选出成本最低的执行计划)

        CBO优化也会完成一部分的谓词下推优化工作,因为在执行计划中,谓词越靠前,整个计划的计算成本就会越低

 

--开启cbo优化 

set hive.cbo.enable=true;

   

--为了测试效果更加直观,关闭map join自动转换

set hive.auto.convert.join=false;

3)开启矢量读取:批量读取1024条

set hive.vectorized.execution.enabled=true;

4)使用MapJoin:大表 join 小表(25M)

5)使用SMBJoin(Sort Merge Bucket Map Join):大表 join 大表

6.3 整体

1)本地模式:默认关闭

--开启自动转换为本地模式,对于小数据集,执行时间

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值