大数据复习

一、Linux、

1.在linux操作系统中,init一共有7级别
init 0 停机
init 1 单用户
init 2 多用户,没有网络文件系统 (NFS)
init 3 多用户,有网络文件系统 Network File System
init 4 安全模式
init 5 桌面模式
init 6 重启
注意:一定是在root用户下
2.一个linux操作系统启动过程:
a、内核引导
b、init级别
c、系统初始化
d、连接终端
e、用户登录
3、Linux目录结构
  bin:binary缩写,存放linux操作命令
  etc:linux操作系统中配置文件,以及子目录
  root:root用户,home位置
  home:每一个用户都有一个自己独有文件夹,这个文件夹以用户名作为文件夹的名字
  /:根
  ./:当前路径
  ../:上一级目录
4.Linux常用的命令:

cd
[root@linux ~]# cd /etc
[root@linux etc]# cd sysconfig/
[root@linux sysconfig]# cd network-scripts/
ls
ls 查看子目录,或者当前文件夹下所有文件
ls -a 表示查看包含. 文件或者文件夹
ls -l 表示查看文件的详细信息,包含文件的权限、文件的用户、用户组、创建时间
案例:查看etc文件的夹下所有文件的详细信息
[root@linux networking]# ls -al /etc
pwd
pwd:显示当前目录的所有信息
[root@linux networking]# pwd
/etc/sysconfig/networking

mkdir
[root@linux ~]# mkdir /miaomiao 创建一个文件夹
[root@linux /]# rmdir /miaomiao 删除一个文件夹
[root@linux /]# mkdir -pv /miao/zhaowei 创建有子目录的文件夹,需要加-p(表示父目录不存在,则创建)/

vi

创建一个文件:
vi /a/a.txt
:wq 保存并且退出

cp
复制一个文件:
[root@linux a]# cp /tmp/VMwareTools-10.0.0-2977863.tar.gz /a
[root@linux a]# cp /a/a.txt /tmp/newname.txt

rm
删除一个文件:
rm /a/a.txt
删除某一个文件,默认友好性提示
-i 默认
-f 强制
-v 显示

mv  移动一个文件:

[root@linux tmp]# mv VMwareTools-10.0.0-2977863.tar.gz /usr
5.linux操作系统关机命令:
shutdown -h now 立刻关机
init 0 停机
shutdow -r now 重启
reboot 重启
vim/vi

6.linux操作系统中几个常用编辑软件:
windows操作---notepad
gedit ---linux编辑软件,好处:熟悉(notepad)缺点:只能桌面版linux使用
vi linux 最基本文本编辑器,在服务器的应用上远大于类似于gedit桌面软件
vi编辑器内设,超多命令
vi编辑器有三种不同状态(模式)
1、命令行模式
2、插入模式(编辑模式)
3、低行模式(末行模式)
末行模式--->:w 保存 :q 退出 :wq 保存并退出
在末行模式--->:set nu 设置行数
:set nonu 取消行数
在命令行模式-->dd 删除当前行
u 撤销
7.文件的输入
echo命令
[root@linux tmp]# echo hello java >a.txt 替换文件的内容
[root@linux tmp]# echo hello hadoop >>a.txt 追加
[root@linux tmp]# echo hello miaomiao >b.txt 如果原文件不存在,则创建原文件,并且追加内容
cat命令
显示一个文件的内容: [root@linux tmp]# cat a.txt
hello java
合并多个文件内容到一个文件中(文件重定向)
[root@linux tmp]# cat a.txt b.txt >> c.txt
把a.txt、b.txt的内容合并c.txt中
注意:> 和 >> 区别
> :表示覆盖
>>:表示追加
head 和 tail 一个表示头、一个表示尾
[root@linux tmp]# head -n 1 c.txt
hello java
[root@linux tmp]# tail -n 1 c.txt
hello miaomiao
https://www.cnblogs.com/scrit/p/5854197.html 参考
find命令:
1、根据名字查询 -name (-iname)
[root@linux tmp]# find /tmp -name 'a.txt' 区分大小写
/tmp/a.txt
[root@linux tmp]# find /tmp -iname 'A.TXT' 不区分大小写
/tmp/a.txt
[root@linux tmp]# find /tmp -name 'a*'
/tmp/a.txt
/tmp/aa.txt
2、用户、用户组 -user 、-group
[root@linux tmp]# find ./ -user gdm
./pulse-KN4J0YcoFVZl
./orbit-gdm
./orbit-gdm/linc-976-0-ae50e492c100
./orbit-gdm/linc-964-0-4c3ccbbe81826
./orbit-gdm/linc-975-0-2d67b2f12ed3d
[root@linux tmp]# find ./ -group gdm
./pulse-KN4J0YcoFVZl
./orbit-gdm
./orbit-gdm/linc-976-0-ae50e492c100
./orbit-gdm/linc-964-0-4c3ccbbe81826
./orbit-gdm/linc-975-0-2d67b2f12ed3d
3、根据文件大小 -size[b、k、M、 G]
[root@linux tmp]# find /tmp -size 1k 在tmp文件夹中找出大于0k 小于等于 1k的文件
[root@linux tmp]# find /tmp -size +1k 在tmp文件夹中找出大于1k的文件
[root@linux tmp]# find /tmp -size -50k 小于50-1 k文件
4、根据时间查找 -atime(最后的访问时间) -ctime(改变时间) -mtime(修改时间)
-amin 、-cmin、-mmin
[root@linux tmp]# find /tmp -type f -amin -50 -size -3k
/tmp/aa.txt
du 检查磁盘大小
[root@linux tmp]# du -ah /tmp
top 检查系统内存使用情况
free 检查系统磁盘利用率
locate 查找
[root@linux tmp]# locate a.txt
ifconfig 查询当前系统的IP地址
[root@linux tmp]# ifconfig
在windows操作系统中,ipconfig用来查找ip地址
[root@linux tmp]# date 查看当前时间
Tue Jun 11 11:38:03 CST 2019
时间同步:
ntpd 服务
[root@linux tmp]# service ntpd start
Starting ntpd: [ OK ]
[root@linux tmp]# service ntpd stop
Shutting down ntpd: [ OK ]
[root@linux tmp]# service ntpd restart
Shutting down ntpd: [FAILED]
Starting ntpd: [ OK ]
关闭防火墙服务:
iptables
[root@linux tmp]# service iptables stop 关闭防火墙
[root@linux tmp]# service iptables start 启动防火墙
[root@linux tmp]# service iptables restart 重启防火墙
[root@linux tmp]# service iptables statu
ping
ping www.baidu.com 来检测网络是否正常
时间同步的命令time.nuri.net 国内比较好的服务器(211.115.194.21)
1、安装ntpdate,执行以下命令
# yum install ntpdate -y
2、手工同步网络时间,执行以下命令,将从time.nist.gov同步时间
[root@linux tmp]# ntpdate time.nuri.net 时间同步
sun---Stanford University Network
文件的压缩:
bzip2/bunzip2 filename
[root@linux tmp]# bzip2 a.txt 压缩一个文件
[root@linux tmp]# bunzip2 a.txt.bz2 解压
[root@linux tmp]# bzip2 a.txt b.txt c.txt
[root@linux tmp]# bunzip2 a.txt.bz2 b.txt.bz2 c.txt.bz2
bzip2 不能压缩一个文件夹
gzip/gunzip
[root@linux a]# gzip a.txt 压缩一个文件
[root@linux a]# gunzip a.txt.gz 解压一个文件
[root@linux tmp]# gzip aa.txt c.txt
[root@linux tmp]# gunzip aa.txt.gz c.txt.gz
***不可以压缩一个文件夹
zip/unzip
[root@linux tmp]# zip -r test.gz aa.txt c.txt 压缩
adding: aa.txt (stored 0%)
adding: c.txt (deflated 15%)
[root@linux tmp]# unzip test.gz 解压
Archive: test.gz
replace aa.txt? [y]es, [n]o, [A]ll, [N]one, [r]ename: A
extracting: aa.txt
inflating: c.txt
tar 企业中大多数压缩和解压缩必用的工具
-z gzip方式
-j bzip2方式
-x 抽取、解压
-v 显示
-c 合并、压缩
-f 目标文件
[root@linux tmp]# tar -zcvf txt.tar.gz aa.txt c.txt 压缩
[root@linux tmp]# tar -zxvf txt.tar.gz -C /usr 解压
-C 表示目标路径

二、Hadoop

1、海量数据的存储
a、分布式文件系统----解决了单个硬盘无法存储海量数据---网络
HDFS(Hadoop Distributed File System )Hadoop分布式文件系统。是根据google发表的论文翻版的。

HDFS架构


namenode--管理文件系统的命名空间。它维护着文件系统树及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件和编辑日志文件。NameNode也记录着每个文件中各个块所在的数据节点信息,但它并不永久保存块的位置信息,因为这些信息在系统启动时由数据节点重建。
单点故障----HA--zookeeper作用

搭建HA集群,启动自动容灾

zookeeper的作用

  1.数据发布与订阅   2.负载均衡 3.命名服务(Naming Service) 4.分布式通知/协调 5.集群管理与Master选举 6.分布式锁 7.分布式队列

namenode---维护一个目录信息,一个块大概150字节---未来namenode将会成为
集群发展瓶颈--->联邦
datanode---是文件存储的基本单元,它将Block存储在本地文件系统中,保存了Block的Meta-data同时周期性地将所有存在的Block信息发送给NameNode
负责存储数据

DataNode会定期(dfs.heartbeat.interval配置项配置,默认是3秒)向namenode发送心跳,
如果Namenode长时间没有接受到datanode发送的心跳,我们在50070的nn管理界面上就会看到它的lastcontact
字段越来越大,至到最后变为dead,namenode就会认为该DataNode失效

心跳线 3秒
检测datanode死亡时间 10分30秒
secondarynamenode---合并fsimage和fsedits然后再发给namenode
不是namenode的备份
辅助namenode工作
文件的上传流程图

 

文件下载流程图


----HDFS常见配置
block大小---128MB

一、为什么HDFS中块(block)不能设置太大,也不能设置太小?

1. 如果块设置过大,

一方面,从磁盘传输数据的时间会明显大于寻址时间,导致程序在处理这块数据时,变得非常慢;另一方面,mapreduce中的map任务通常一次只处理一个块中的数据,如果块过大运行速度也会很慢。

2. 如果块设置过小,

一方面存放大量小文件会占用NameNode中大量内存来存储元数据,而NameNode的内存是有限的,不可取;另一方面文件块过小,寻址时间增大,导致程序一直在找block的开始位置。因而,块适当设置大一些,减少寻址时间,那么传输一个由多个块组成的文件的时间主要取决于磁盘的传输速率。

二、 HDFS中块(block)的大小为什么设置为128M?

1. HDFS中平均寻址时间大概为10ms;

2. 寻址时间为传输时间的1%时,为最佳状态;所以最佳传输时间为1s

3. 目前磁盘的传输速率普遍为100MB/s;block大小就为100MB,所以默认的block大小为128MB。但是实际在工业生产中,磁盘传输速率为200MB/s时,一般设定block大小为256MB,磁盘传输速率为400MB/s时,一般设定block大小为512MB

MapReduce---Mapper---处理同一个块信息,如果块太大,就会导致Mapper数量减少,导致机器浪费。
块的存储策略--->参考hadoop权威指南 复本的存放策略

---HDFS调优

块大小调优---512MB

package 大小
检查datanode失效时间
---Hbase 存储在HDFS上,元数据信息靠zookeeper进行维护
HDFS升级版本,有格式文件---HFile
1、Hbase架构从宏观角度


HMaster ----打杂的,维护分区信息,负载均衡,当一个RegionServer宕机后会 
重新分配分区。或者新增一个regionserver,也会重新分配分区。跨RegionServer的工作。

HRegionServer 存放分区 Region、HLog
region
|---多个Store ----每一个Store存储的是一个列族
|--StoreFile 、MemStore ---->在hbase中为什么列族数目不易过多
|--HFile ---二进制序列化文件---存储在Hadoop的HDFS上
HFile结构重点
Zookeeper ---维护Hbase元数据信息。
----zookeeper在Hbase中起到作用


Client
2、Hbase 其实不是那么快,只不过相对大数据来说显得不那么慢。
Hbase底层写入,或者读取流程-

 

、Hbase跟HDFS之间的交互

HDFS--->Hbase
Hbase-->HDFS

在hbase中创建一个表
hbase(main):008:0> create 'user_sysc',{NAME =>'info'}
在hive中创建一个外部表
hive> CREATE EXTERNAL TABLE user_sysc (key int, value string) ROW FORMAT SERDE 'org.apache.hadoop.hive.hbase.HBaseSerDe'
> STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
> WITH SERDEPROPERTIES ( 'serialization.format'='\t', 'hbase.columns.mapping'=':key,info:value', 'field.delim'='\t')
> TBLPROPERTIES ('hbase.table.name'='user_sysc';
hive> create table user_info(key int,value string)
> row format
> delimited fields terminated by ',';
hive> load data local inpath '/tmp/sys.txt' into table user_info;
hive> insert overwrite table user_sysc
> select key,value from user_info;
在hbase中scan
hbase(main):010:0> scan 'user_sysc'
ROW COLUMN+CELL
1 column=info:value, timestamp=1565075189891, value=a
2 column=info:value, timestamp=1565075189891, value=b
3 column=info:value, timestamp=1565075189891, value=c
hbase(main):012:0> deleteall 'user_sysc','1'
在hive中查询
hive> select * from user_sysc;

5、row-key 设计,预分区


MapReduce----计算模型,计算框架,可以通过横向扩展节点数提高计算能力
如何编写一个MapReduce代码


shuffle阶段--分区、排序、合并


合并相同的key的value值,根据key进行排序
shuffle阶段


shuffle调优:


1、机子本身
2、增大jvm的内存,增加reduce内存,增加reduce的个数
3、配置角度,map端压缩
4、自定义partition,本地的reduce--combine,key键的设计
数据倾斜问题:
1、key值--二次设计key
2、增加reduce个数
3、增加partition等等
常见hadoop的数据类型:
IntWritable----Text
常见的输入格式类:
TextFileInputFormat、KeyValueFileInputFormat----
自定义输入格式类,自定义输出格式类
MapReduce---升级版Hive---把hql语句转换为MapReduce任务
select * ----不会转换
Hive----9分学mysql,1分学hive
Hive存储依赖HDFS,计算靠MapReduce,元数据--Mysql

分桶表 ----Hadoop MapReduce partition key的hash值取模桶的个数

分桶表的本质就是hadoop的partition
hive (hive)> create table student_bkt(id string,name string,sex string,age int,department string)
> clustered by (id) sorted by(id asc,name desc) into 4 buckets
> row format delimited fields terminated by ',';
hive (hive)> set hive.strict.checks.bucketing=false;
hive (hive)> load data local inpath '/tmp/students' into table student_bkt;
hive (hive)> create table student_bkts(id string,name string,sex string,age int,department string)
> clustered by(id) sorted by(age desc) into 4 buckets;
hive (hive)> insert overwrite table student_bkts
> select id,name,sex,age,department from student_bkt;
注意:分桶排序,根据每个分桶单独进行排序的。

管理表(内部表):
[root@hadoop1 tmp]# vi students
hive (hive)> create table student(id string,name string,sex string,age int,department string)
> row format
> delimited fields terminated by ',';
hive (hive)> load data local inpath '/tmp/students' into table student;
通过hdfs命令查询:
hive (hive)> dfs -lsr /user/hive/warehouse/hive.db;
通过hiveql语句:
hive (hive)> select * from student;
外部表(external):
hive (hive)> create external table etl_student(id string,name string,sex string,age int,department string)
> row format
> delimited fields terminated by ','
> location '/hive/student';
hive (hive)> dfs -mkdir -p /hive/student;
hive (hive)> dfs -put /tmp/students /hive/student/;
hive (hive)> select * from etl_student;
总结:外部表和内部表
1、除了一些数据处于共享情况,使用外部表
2、其他情况使用内部表。
创建表的过程中,外部表和内部表(管理表)===>
create table(管理表)
create external table (外部表)
分区表:
1、hive中分区表跟Hadoop分区(partition)区别?
hive中分区表指的是表中有不同子文件夹,代表不同的分区

hive (hive)> create table student(id string,name string,sex string,age int,department string)
> partitioned by(city string)
> row format
> delimited fields terminated by ',';


hive数据倾斜
1、key值 null ,类型不匹配
2、map join
3、增加reduce的个数
hive调优

一、Hadoop 框架计算特性
1、数据量大不是问题,数据倾斜是个问题
2、jobs 数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次 汇总,产生十几个 jobs,耗时很长。原因是 map reduce 作业初始化的时间是比较长的
3、sum,count,max,min 等 UDAF,不怕数据倾斜问题,hadoop 在 map 端的汇总合并优化,使 数据倾斜不成问题
4、count(distinct userid),在数据量大的情况下,效率较低,如果是多 count(distinct userid,month)效率更低,因为 count(distinct)是按 group by 字段分组,按 distinct 字段排序, 一般这种分布方式是很倾斜的,比如 PV 数据,淘宝一天 30 亿的 pv,如果按性别分组,分 配 2 个 reduce,每个 reduce 期望处理 15 亿数据,但现实必定是男少女多
二、优化常用手段
1、好的模型设计事半功倍
2、解决数据倾斜问题
3、减少 job 数
4、设置合理的 MapReduce 的 task 数,能有效提升性能。(比如,10w+级别的计算,用 160个 reduce,那是相当的浪费,1 个足够)
5、了解数据分布,自己动手解决数据倾斜问题是个不错的选择。这是通用的算法优化,但 算法优化有时不能适应特定业务背景,开发人员了解业务,了解数据,可以通过业务逻辑精 确有效的解决数据倾斜问题
6、数据量较大的情况下,慎用 count(distinct),group by 容易产生倾斜问题
7、对小文件进行合并,是行之有效的提高调度效率的方法,假如所有的作业设置合理的文 件数,对云梯的整体调度效率也会产生积极的正向影响
8、优化时把握整体,单个作业最优不如整体最优
三、排序选择
cluster by:对同一字段分桶并排序,不能和 sort by 连用
distribute by + sort by:分桶,保证同一字段值只存在一个结果文件当中,结合 sort by 保证 每个 reduceTask 结果有序
sort by:单机排序,单个 reduce 结果有序
order by:全局排序,缺陷是只能使用一个 reduce
一定要区分这四种排序的使用方式和适用场景
四、怎样做笛卡尔积
当 Hive 设定为严格模式(hive.mapred.mode=strict)时,不允许在 HQL 语句中出现笛卡尔积, 这实际说明了 Hive 对笛卡尔积支持较弱。因为找不到 Join key,Hive 只能使用 1 个 reducer 来完成笛卡尔积。
当然也可以使用 limit 的办法来减少某个表参与 join 的数据量,但对于需要笛卡尔积语义的 需求来说,经常是一个大表和一个小表的 Join 操作,结果仍然很大(以至于无法用单机处 理),这时 MapJoin才是最好的解决办法。MapJoin,顾名思义,会在 Map 端完成 Join 操作。 这需要将 Join 操作的一个或多个表完全读入内存。
PS:MapJoin 在子查询中可能出现未知 BUG。在大表和小表做笛卡尔积时,规避笛卡尔积的 方法是,给 Join 添加一个 Join key,原理很简单:将小表扩充一列 join key,并将小表的条 目复制数倍,join key 各不相同;将大表扩充一列 join key 为随机数。
精髓就在于复制几倍,最后就有几个 reduce 来做,而且大表的数据是前面小表扩张 key 值 范围里面随机出来的,所以复制了几倍 n,就相当于这个随机范围就有多大 n,那么相应的, 大表的数据就被随机的分为了 n 份。并且最后处理所用的 reduce 数量也是 n,而且也不会 出现数据倾斜。
五、怎样写 in/exists 语句
虽然经过测验,hive1.2.1 也支持 in/exists 操作,但还是推荐使用 hive 的一个高效替代方案:left semi join
比如说:
select a.id, a.name from a where a.id in (select b.id from b);
select a.id, a.name from a where exists (select id from b where a.id = b.id);
应该转换成:
select a.id, a.name from a left semi join b on a.id = b.id;
六、设置合理的 maptask 数量
Map 数过大
  Map 阶段输出文件太小,产生大量小文件
  初始化和创建 Map 的开销很大
Map 数太小
  文件处理或查询并发度小,Job 执行时间过长
  大量作业时,容易堵塞集群
在 MapReduce 的编程案例中,我们得知,一个MR Job的 MapTask 数量是由输入分片 InputSplit 决定的。而输入分片是由 FileInputFormat.getSplit()决定的。一个输入分片对应一个 MapTask, 而输入分片是由三个参数决定的:

输入分片大小的计算是这么计算出来的:
long splitSize = Math.max(minSize, Math.min(maxSize, blockSize))
默认情况下,输入分片大小和 HDFS 集群默认数据块大小一致,也就是默认一个数据块,启 用一个 MapTask 进行处理,这样做的好处是避免了服务器节点之间的数据传输,提高 job 处 理效率
两种经典的控制 MapTask 的个数方案:减少 MapTask 数或者增加 MapTask 数
1、 减少 MapTask 数是通过合并小文件来实现,这一点主要是针对数据源
2、 增加 MapTask 数可以通过控制上一个 job 的 reduceTask 个数
因为 Hive 语句最终要转换为一系列的 MapReduce Job 的,而每一个 MapReduce Job 是由一 系列的 MapTask 和 ReduceTask 组成的,默认情况下, MapReduce 中一个 MapTask 或者一个 ReduceTask 就会启动一个 JVM 进程,一个 Task 执行完毕后, JVM 进程就退出。这样如果任 务花费时间很短,又要多次启动 JVM 的情况下,JVM 的启动时间会变成一个比较大的消耗, 这个时候,就可以通过重用 JVM 来解决:
set mapred.job.reuse.jvm.num.tasks=5
七、小文件合并
文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的 结果文件来消除这样的影响:
set hive.merge.mapfiles = true ##在 map only 的任务结束时合并小文件
set hive.merge.mapredfiles = false ## true 时在 MapReduce 的任务结束时合并小文件
set hive.merge.size.per.task = 256*1000*1000 ##合并文件的大小
set mapred.max.split.size=256000000; ##每个 Map 最大分割大小
set mapred.min.split.size.per.node=1; ##一个节点上 split 的最少值
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; ##执行 Map 前进行小文件合并
八、设置合理的 reduceTask 的数量
Hadoop MapReduce 程序中,reducer 个数的设定极大影响执行效率,这使得 Hive 怎样决定 reducer 个数成为一个关键问题。遗憾的是 Hive 的估计机制很弱,不指定 reducer 个数的情 况下,Hive 会猜测确定一个 reducer 个数,基于以下两个设定:
1、hive.exec.reducers.bytes.per.reducer(默认为 256000000)
2、hive.exec.reducers.max(默认为 1009)
3、mapreduce.job.reduces=-1(设置一个常量 reducetask 数量)
计算 reducer 数的公式很简单: N=min(参数 2,总输入数据量/参数 1) 通常情况下,有必要手动指定 reducer 个数。考虑到 map 阶段的输出数据量通常会比输入有 大幅减少,因此即使不设定 reducer 个数,重设参数 2 还是必要的。
依据 Hadoop 的经验,可以将参数 2 设定为 0.95*(集群中 datanode 个数)。
九、合并 MapReduce 操作
Multi-group by 是 Hive 的一个非常好的特性,它使得 Hive 中利用中间结果变得非常方便。 例如:
FROM (SELECT a.status, b.school, b.gender FROM status_updates a JOIN profiles b ON (a.userid =
b.userid and a.ds='2009-03-20' ) ) subq1
INSERT OVERWRITE TABLE gender_summary PARTITION(ds='2009-03-20')
SELECT subq1.gender, COUNT(1) GROUP BY subq1.gender
INSERT OVERWRITE TABLE school_summary PARTITION(ds='2009-03-20')
SELECT subq1.school, COUNT(1) GROUP BY subq1.school
上述查询语句使用了 multi-group by 特性连续 group by 了 2 次数据,使用不同的 group by key。 这一特性可以减少一次 MapReduce 操作
十、合理利用分桶:Bucketing 和 Sampling
Bucket 是指将数据以指定列的值为 key 进行 hash,hash 到指定数目的桶中。这样就可以支 持高效采样了。如下例就是以 userid 这一列为 bucket 的依据,共设置 32 个 buckets
CREATE TABLE page_view(viewTime INT, userid BIGINT,
page_url STRING, referrer_url STRING,
ip STRING COMMENT 'IP Address of the User')
COMMENT 'This is the page view table'
PARTITIONED BY(dt STRING, country STRING)
CLUSTERED BY(userid) SORTED BY(viewTime) INTO 32 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '1'
COLLECTION ITEMS TERMINATED BY '2'
MAP KEYS TERMINATED BY '3'
STORED AS SEQUENCEFILE;
通常情况下,Sampling 在全体数据上进行采样,这样效率自然就低,它要去访问所有数据。 而如果一个表已经对某一列制作了 bucket,就可以采样所有桶中指定序号的某个桶,这就 减少了访问量。
如下例所示就是采样了 page_view 中 32 个桶中的第三个桶的全部数据:
SELECT * FROM page_view TABLESAMPLE(BUCKET 3 OUT OF 32);
如下例所示就是采样了 page_view 中 32 个桶中的第三个桶的一半数据:
SELECT * FROM page_view TABLESAMPLE(BUCKET 3 OUT OF 64);
十一、合理利用分区:Partition
Partition 就是分区。分区通过在创建表时启用 partitioned by 实现,用来 partition 的维度并不 是实际数据的某一列,具体分区的标志是由插入内容时给定的。当要查询某一分区的内容时 可以采用 where 语句,形似 where tablename.partition_column = a 来实现。
创建含分区的表
CREATE TABLE page_view(viewTime INT, userid BIGINT,
page_url STRING, referrer_url STRING,
ip STRING COMMENT 'IP Address of the User')
PARTITIONED BY(date STRING, country STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '1'
STORED AS TEXTFILE;
载入内容,并指定分区标志
load data local inpath '/home/hadoop/pv_2008-06-08_us.txt' into table page_view
partition(date='2008-06-08', country='US');
查询指定标志的分区内容
SELECT page_views.* FROM page_views
WHERE page_views.date >= '2008-03-01' AND page_views.date <= '2008-03-31' AND
page_views.referrer_url like '%xyz.com';
十二、Join 优化
总体原则:
  1、 优先过滤后再进行 Join 操作,最大限度的减少参与 join 的数据量
  2、 小表 join 大表,最好启动 mapjoin
  3、 Join on 的条件相同的话,最好放入同一个 job,并且 join 表的排列顺序从小到大
在使用写有 Join 操作的查询语句时有一条原则:应该将条目少的表/子查询放在 Join 操作 符的左边。原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加 载进内存,将条目少的表放在左边,可以有效减少发生 OOM 错误的几率。对于一条语句 中有多个 Join 的情况,如果 Join 的条件相同,比如查询
INSERT OVERWRITE TABLE pv_users
SELECT pv.pageid, u.age FROM page_view p
JOIN user u ON (pv.userid = u.userid)
JOIN newuser x ON (u.userid = x.userid);
如果 Join 的 key 相同,不管有多少个表,都会则会合并为一个 Map-Reduce 任务,而不 是”n”个,在做 OUTER JOIN 的时候也是一样
如果 join 的条件不相同,比如:
INSERT OVERWRITE TABLE pv_users
SELECT pv.pageid, u.age FROM page_view p
JOIN user u ON (pv.userid = u.userid)
JOIN newuser x on (u.age = x.age);
Map-Reduce 的任务数目和 Join 操作的数目是对应的,上述查询和以下查询是等价的
--先 page_view 表和 user 表做链接
INSERT OVERWRITE TABLE tmptable
SELECT * FROM page_view p JOIN user u ON (pv.userid = u.userid);
-- 然后结果表 temptable 和 newuser 表做链接
INSERT OVERWRITE TABLE pv_users
SELECT x.pageid, x.age FROM tmptable x JOIN newuser y ON (x.age = y.age);
在编写 Join 查询语句时,如果确定是由于 join 出现的数据倾斜,那么请做如下设置:
set hive.skewjoin.key=100000; // 这个是 join 的键对应的记录条数超过这个值则会进行 分拆,值根据具体数据量设置
set hive.optimize.skewjoin=true; // 如果是 join 过程出现倾斜应该设置为 true
十三、Group By 优化
1、Map 端部分聚合
并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进 行部分聚合,最后在 Reduce 端得出最终结果。
MapReduce 的 combiner 组件参数包括:
set hive.map.aggr = true 是否在 Map 端进行聚合,默认为 True
set hive.groupby.mapaggr.checkinterval = 100000 在 Map 端进行聚合操作的条目数目
2、使用 Group By 有数据倾斜的时候进行负载均衡
set hive.groupby.skewindata = true
当 sql 语句使用 groupby 时数据出现倾斜时,如果该变量设置为 true,那么 Hive 会自动进行 负载均衡。策略就是把 MR 任务拆分成两个:第一个先做预汇总,第二个再做最终汇总
在 MR 的第一个阶段中,Map 的输出结果集合会缓存到 maptaks 中,每个 Reduce 做部分聚 合操作,并输出结果,这样处理的结果是相同 Group By Key 有可能被分发到不同的 Reduce 中, 从而达到负载均衡的目的;第二个阶段 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成 最终的聚合操作。
十四、合理利用文件存储格式
创建表时,尽量使用 orc、parquet 这些列式存储格式,因为列式存储的表,每一列的数据在 物理上是存储在一起的,Hive 查询时会只遍历需要列数据,大大减少处理的数据量。
十五、本地模式执行 MapReduce
Hive 在集群上查询时,默认是在集群上 N 台机器上运行, 需要多个机器进行协调运行,这 个方式很好地解决了大数据量的查询问题。但是当 Hive 查询处理的数据量比较小时,其实 没有必要启动分布式模式去执行,因为以分布式方式执行就涉及到跨网络传输、多节点协调 等,并且消耗资源。这个时间可以只使用本地模式来执行 mapreduce job,只在一台机器上 执行,速度会很快。启动本地模式涉及到三个参数:
set hive.exec.mode.local.auto=true 是打开 hive 自动判断是否启动本地模式的开关,但是只 是打开这个参数并不能保证启动本地模式,要当 map 任务数不超过
hive.exec.mode.local.auto.input.files.max 的个数并且 map 输入文件大小不超过
hive.exec.mode.local.auto.inputbytes.max 所指定的大小时,才能启动本地模式。
十六、并行化处理
一个 hive sql 语句可能会转为多个 mapreduce Job,每一个 job 就是一个 stage,这些 job 顺序 执行,这个在 cli 的运行日志中也可以看到。但是有时候这些任务之间并不是是相互依赖的, 如果集群资源允许的话,可以让多个并不相互依赖 stage 并发执行,这样就节约了时间,提 高了执行速度,但是如果集群资源匮乏时,启用并行化反倒是会导致各个 job 相互抢占资源 而导致整体执行性能的下降。启用并行化:
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=8; //同一个 sql 允许并行任务的最大线程数
十七、设置压缩存储
1、压缩的原因
Hive 最终是转为 MapReduce 程序来执行的,而 MapReduce 的性能瓶颈在于网络 IO 和 磁盘 IO,要解决性能瓶颈,最主要的是减少数据量,对数据进行压缩是个好的方式。压缩 虽然是减少了数据量,但是压缩过程要消耗 CPU 的,但是在 Hadoop 中, 往往性能瓶颈不 在于 CPU,CPU 压力并不大,所以压缩充分利用了比较空闲的 CPU
2、常用压缩方法对比

3、压缩方式的选择
压缩比率
压缩解压缩速度
是否支持 Split
4、压缩使用
Job 输出文件按照 block 以 GZip 的方式进行压缩:
set mapreduce.output.fileoutputformat.compress=true // 默认值是 false
set mapreduce.output.fileoutputformat.compress.type=BLOCK // 默认值是 Record
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默认值是 org.apache.hadoop.io.compress.DefaultCodec
Map 输出结果也以 Gzip 进行压缩:
set mapred.map.output.compress=true
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.GzipCodec // 默认值是 org.apache.hadoop.io.compress.DefaultCodec
对 Hive 输出结果和中间都进行压缩:
set hive.exec.compress.output=true // 默认值是 false,不压缩
set hive.exec.compress.intermediate=true // 默认值是 false,为 true 时 MR 设置的压缩才启用


--rollup
人物画像,通过不同的维度,来分析同一段数据,进行汇总
两个小知识点:
Flume 日志采集系统

Flume---source讲解
NetCat
Exec Source:监控文件,实时获取文件中信息的写入
#定义数据源的配置信息
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /tmp/flume/exec.log
a1.sources.r1.restart = true
注意:还有其他属性,但是只有type,command是必选属性,其他省略不写
测试:
[root@hadoop1 ~]# vi flume-exec.sh
#!/bin/bash
echo "开始执行flume-exec数据源命令"
flume-ng agent -c /usr/apache-flume-1.8.0-bin/conf/ -f /flume/myflume_exec.conf -n a1 -Dflume.root.logger=INFO,console
[root@hadoop1 ~]# sh flume-exec.sh
[root@hadoop1 flume]# echo hello java >>/tmp/flume/exec.log
Spooling Directory Source:监控文件夹中出现的新文件
[root@hadoop1 ~]# cp /flume/myflume.conf /flume/myflume_spooldir.conf
[root@hadoop1 ~]# vi /flume/myflume_spooldir.conf
#定义数据源的配置信息
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /tmp/flume
测试:
[root@hadoop1 ~]# cp flume-exec.sh flume-spooldir.sh
[root@hadoop1 ~]# vi flume-spooldir.sh
注意:Spooldir用来监控文件夹中新文件信息。
Avro Source:监听Avro端口并从外部Avro客户端流接收事件。当与另一个(前一跳)
source上的内置Avro接收器相结合时,它可以创建分层收集拓扑
[root@hadoop1 ~]# cp /flume/myflume.conf /flume/myflume_avro.conf
[root@hadoop1 ~]# vi /flume/myflume_avro.conf
#定义数据源的配置信息
a1.sources.r1.type = avro
a1.sources.r1.bind = hadoop1
a1.sources.r1.port = 55555
[root@hadoop1 ~]# cp flume-exec.sh flume-evro.sh
[root@hadoop1 ~]# vi flume-evro.sh
[root@hadoop1 ~]# sh flume-evro.sh
[root@hadoop1 flume]# flume-ng avro-client --conf /usr/apache-flume-1.8.0-bin/conf/ -H hadoop1 -p 55555 -F /tmp/flume/avro.txt
[root@hadoop1 flume]# mkdir avro
[root@hadoop1 flume]# cd avro
[root@hadoop1 avro]# ls
[root@hadoop1 avro]# vi a.txt
[root@hadoop1 avro]# vi b.txt
[root@hadoop1 flume]# flume-ng avro-client --conf /usr/apache-flume-1.8.0-bin/conf/ -H hadoop1 -p 55555 --dirname /tmp/flume/avro
Thrift Source:使用的极少
Flume--channel讲解:
Memory Channel:
事件以可配置的最大大小存储在内存队列中。对于需要更高吞吐量并且准备在代理失败
时丢失阶段数据的流来说,这是理想的。
优点:效率高
缺点:容易丢失数据
[root@hadoop1 flume]# cp myflume.conf myflume_memory.conf
[root@hadoop1 flume]# vi myflume_memory.conf
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100
a1.channels.c1.transactionCapacity = 100
[root@hadoop1 ~]# cp flume-exec.sh flume-memory.sh
[root@hadoop1 ~]# vi flume-memory.sh
测试:
[root@hadoop1 ~]# sh flume-memory.sh
[root@hadoop1 flume]# nc hadoop1 44444

JDBC Channel:
1.8.0版本中只有一个内置数据库,Derby
事件存储在由数据库支持的持久存储中。JDBC通道目前支持嵌入式Derby。
这是一个持久的通道,对于可恢复性非常重要的流来说是理想的。
[root@hadoop1 ~]# vi /flume/myflume_exec.conf
#定义管道的配置信息
a1.channels.c1.type = jdbc
测试:
[root@hadoop1 ~]# sh flume-exec.sh
[root@hadoop1 flume]# echo hello jdbc >> /tmp/flume/exec.log
Kafka Channel:注意----讲完Kafka消息队列时再研究
File Channel:
优点:数据不易丢失,写入磁盘中 ---- 安全
缺点:相对于memory类型来说,效率慢,时间长
[root@hadoop1 ~]# cp /flume/myflume_memory.conf /flume/myflume_file.conf
[root@hadoop1 ~]# vi /flume/myflume_file.conf
#定义管道的配置信息
a1.channels.c1.type = file
测试:
[root@hadoop1 ~]# cp flume-memory.sh flume-file.sh
[root@hadoop1 ~]# vi flume-file.sh
[root@hadoop1 ~]# sh flume-file.sh
[root@hadoop1 flume]# nc hadoop1 44444
Flume Sinks:
HDFS Sink:
[root@hadoop1 ~]# cp /flume/myflume_file_roll.conf /flume/myflume_hdfs.conf
[root@hadoop1 ~]# vi /flume/myflume_hdfs.conf
#定义数据下沉的位置
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://hadoop1:9000/flume/events/%y-%m-%d/%H%M/%S
a1.sinks.k1.hdfs.filePrefix = events-
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
a1.sinks.k1.hdfs.useLocalTimeStamp=true
测试:
[root@hadoop1 ~]# cp flume-file-roll.sh flume-hdfs.sh
[root@hadoop1 ~]# vi flume-hdfs.sh
启动HDFS:
[root@hadoop1 ~]# start-dfs.sh
[root@hadoop1 ~]# sh flume-hdfs.sh
修改myflume_hdfs.conf
添加:
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = Text
再测试:
[root@hadoop1 ~]# sh flume-hdfs.sh
[root@hadoop1 ~]# nc hadoop1 44444
[root@hadoop1 sink]# hadoop fs -cat /flume/events/19-07-22/1140/00/events-.1563767132461
Hive Sink
Logger Sink:
Avro Sink:
File Roll Sink:
将事件存储在本地文件系统上
[root@hadoop1 ~]# cp /flume/myflume.conf /flume/myflume_file_roll.conf
[root@hadoop1 ~]# vi /flume/myflume_file_roll.conf
#定义数据下沉的位置
a1.sinks.k1.type = file_roll
a1.sinks.k1.sink.directory = /tmp/flume/sink
#默认一次性写入
a1.sinks.k1.sink.rollInterval = 0
测试:
[root@hadoop1 ~]# cp flume-exec.sh flume-file-roll.sh
[root@hadoop1 ~]# vi flume-file-roll.sh
[root@hadoop1 ~]# sh flume-file-roll.sh
[root@hadoop1 ~]# nc hadoop1 44444
[root@hadoop1 ~]# vi /flume/myflume_file_roll.conf
#10秒写一个文件
a1.sinks.k1.sink.rollInterval = 10
注意:如果不设置roolInterval----则每30秒写一个文件,如果不想写入多个文件
则设置roolInterval为0
HBaseSinks:
[root@hadoop1 ~]# zkServer.sh start
[root@hadoop1 ~]# start-hbase.sh
[root@hadoop1 ~]# cp /flume/myflume.conf /flume/myflume_hbase.conf
[root@hadoop1 ~]# vi /flume/myflume_hbase.conf
a1.sinks.k1.type = hbase
a1.sinks.k1.table = 1808_table
a1.sinks.k1.columnFamily = f1
a1.sinks.k1.serializer = org.apache.flume.sink.hbase.RegexHbaseEventSerializer
测试:
[root@hadoop1 ~]# cp flume-exec.sh flume-hbase.sh
[root@hadoop1 ~]# vi flume-hbase.sh
[root@hadoop1 ~]# sh flume-hbase.sh
[root@hadoop1 ~]# nc hadoop1 44444
hbase(main):002:0> scan '1808_table'
Kafka Sink
Avro Sink---->agent To agent
[root@hadoop1 ~]# cp /flume/myflume_spooldir.conf /flume/myflume_agent1.conf
[root@hadoop1 ~]# cp /flume/myflume_spooldir.conf /flume/myflume_agent2.conf
[root@hadoop1 ~]# vi /flume/myflume_agent1.conf
#定义agent的别名,分别定义source、channel、sink
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#定义数据源的配置信息
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /tmp/flume
#定义数据下沉的位置
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop1
a1.sinks.k1.port = 44444
#定义管道的配置信息
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100
a1.channels.c1.transactionCapacity = 100
#绑定数据源跟管道,绑定管道跟下沉位置
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
[root@hadoop1 ~]# vi /flume/myflume_agent2.conf
#定义agent的别名,分别定义source、channel、sink
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#定义数据源的配置信息
a1.sources.r1.type = avro
a1.sources.r1.bind = hadoop1
a1.sources.r1.port = 44444
#定义数据下沉的位置
#定义数据下沉的位置
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://hadoop1:9000/flume/events/%y-%m-%d/%H%M/%S
a1.sinks.k1.hdfs.filePrefix = events-
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
a1.sinks.k1.hdfs.useLocalTimeStamp=true
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = Text
#定义管道的配置信息
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100
a1.channels.c1.transactionCapacity = 100
#绑定数据源跟管道,绑定管道跟下沉位置
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
测试:
[root@hadoop1 ~]# flume-ng agent -c /usr/apache-flume-1.8.0-bin/conf/ -f /flume/myflume_agent2.conf -n a1 -Dflume.root.logger=INFO,console
[root@hadoop1 ~]# flume-ng agent -c /usr/apache-flume-1.8.0-bin/conf/ -f /flume/myflume_agent1.conf -n a1 -Dflume.root.logger=INFO,console
[root@hadoop1 ~]# hadoop fs -cat /flume/events/19-07-22/1450/00/events-.1563778398610
扇入:Fan In Flow
多个数据源,一个channel,一个sinks
[root@hadoop1 ~]# cp /flume/myflume.conf /flume/myflume_fanin.conf
[root@hadoop1 ~]# vi /flume/myflume_fanin.conf
#定义agent的别名,分别定义source、channel、sink
#注意多个source、channel之间使用空格隔开
a1.sources = r1 r2
a1.sinks = k1
a1.channels = c1
#定义数据源r1的配置信息
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /tmp/flume/fanin1.log
#定义数据源r2的配置信息
a1.sources.r2.type = exec
a1.sources.r2.command = tail -F /tmp/flume/fanin.log
#定义数据下沉的位置
a1.sinks.k1.type = file_roll
a1.sinks.k1.sink.directory = /tmp/flume
#定义管道c1的配置信息
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100
a1.channels.c1.transactionCapacity = 100
#绑定数据源跟管道,绑定管道跟下沉位置
a1.sources.r1.channels = c1
a1.sources.r2.channels = c1
a1.sinks.k1.channel = c1
[root@hadoop1 ~]# flume-ng agent -c /usr/apache-flume-1.8.0-bin/conf/ -f /flume/myflume_fanin.conf -n a1 -Dflume.root.logger=INFO,console
扇出:Fan Out Flow
一个数据源,多个channel,多个sinks
[root@hadoop1 ~]# vi /flume/myflume_fanout.conf
#定义agent的别名,分别定义source、channel、sink
#注意多个source、channel之间使用空格隔开
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2
#定义数据源r1的配置信息
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /tmp/flume/fanin1.log
#定义数据下沉的位置
a1.sinks.k1.type = file_roll
a1.sinks.k1.sink.directory = /tmp/flume
#定义数据下沉的位置
a1.sinks.k2.type = logger
#定义管道c1的配置信息
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100
a1.channels.c1.transactionCapacity = 100
a1.channels.c2.type = jdbc
#绑定数据源跟管道,绑定管道跟下沉位置
a1.sources.r1.channels = c1 c2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2
测试:
[root@hadoop1 ~]# flume-ng agent -c /usr/apache-flume-1.8.0-bin/conf/ -f /flume/myflume_fanout.conf -n a1 -Dflume.root.logger=INFO,console


channel---memory 优缺点:优点快,缺点数据易丢失
---jdbc 中性 相对file 要快 ,相对memory慢
---file 优缺点:优点数据持久化,安全;缺点慢

 

转载于:https://www.cnblogs.com/lazhaoqian/p/11340063.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值