一、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=1800,hdfs.rollSize=134217728 且 hdfs.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)本地模式:默认关闭
--开启自动转换为本地模式,对于小数据集,执行时间