9.Hive内部表和外部表区别
Hive创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。
在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。
这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享元数据。
建内部表
create table student(Sno int,Sname string,Sex string,Sage int,Sdept string)row format delimited fields terminated by ',';
建外部表
create external table student_ext(Sno int,Sname string,Sex string,Sageint,Sdept string)row format delimited fields terminated by',' location '/stu';
10.Hive外部表 有静态 动态 区别是什么?
Hive的分区方式:由于Hive实际是存储在HDFS上的抽象,Hive的一个分区名对应一个目录名,子分区名就是子目录名,并不是一个实际字段。
当我们在插入数据的时候指定分区,其实就是新建一个目录或者子目录,或者在原有的目录上添加数据文件。
Hive分区是在创建表的时候用Partitioned by 关键字定义的,但要注意,Partitioned by子句中定义的列是表中正式的列,但是Hive下的数据文件中并不包含这些列,因为它们是目录名。
静态分区
创建一张静态分区表par_tab,单个分区
create table par_tab (name string,nation string) partitioned by (sex string) row format delimited fields terminated by ',';
这时候通过desc查看的表结构如下
准备本地数据文件par_tab.txt,内容 “名字/国籍”,将以性别(sex)作为分区
jan,china
mary,america
lilei,china
heyong,china
yiku,japan
emoji,japan
把数据插入到表(其实load操作相当于把文件移动到HDFS的Hive目录下)
load data local inpath '/home/hadoop/files/par_tab.txt' into table par_tab partition (sex='man');
因为分区列是表实际定义的列,所以查询分区数据时
hive> select * from par_tab where sex='woman';
OK
lily china woman
nancy china woman
hanmeimei america woman
Time taken: 0.515 seconds, Fetched: 3 row(s)
下面创建一张静态分区表par_tab_muilt,多个分区(性别+日期)
hive> create table par_tab_muilt (name string, nation string) partitioned by (sex string,dt string) row format delimited fields terminated by ',' ;
hive> load data local inpath '/home/hadoop/files/par_tab.txt' into table par_tab_muilt partition (sex='man',dt='2017-03-29');
[hadoop@hadoop001 files]$ hadoop dfs -lsr /user/hive/warehouse/par_tab_muilt
drwxr-xr-x - hadoop supergroup 0 2017-03-29 08:45 /user/hive/warehouse/par_tab_muilt/sex=man
drwxr-xr-x - hadoop supergroup 0 2017-03-29 08:45 /user/hive/warehouse/par_tab_muilt/sex=man/dt=2017-03-29
-rwxr-xr-x 1 hadoop supergroup 71 2017-03-29 08:45 /user/hive/warehouse/par_tab_muilt/sex=man/dt=2017-03-29/par_tab.txt
可见,新建表的时候定义的分区顺序,决定了文件目录顺序(谁是父目录谁是子目录),正因为有了这个层级关系,当我们查询所有man的时候,man以下的所有日期下的数据都会被查出来。如果只查询日期分区,但父目录sex=man和sex=woman都有该日期的数据,那么Hive会对输入路径进行修剪,从而只扫描日期分区,性别分区不作过滤(即查询结果包含了所有性别)。
动态分区
如果用上述的静态分区,插入的时候必须首先要知道有什么分区类型,而且每个分区写一个load data,太烦人。使用动态分区可解决以上问题,其可以根据查询得到的数据动态分配到分区里。其实动态分区与静态分区区别就是不指定分区目录,由系统自己选择。
首先,启动动态分区功能
hive> set hive.exec.dynamic.partition=true;
假设已有一张表par_tab,前两列是名称name和国籍nation,后两列是分区列,性别sex和日期dt,数据如下
hive> select * from par_tab;
OK
lily china man 2013-03-28
nancy china man 2013-03-28
hanmeimei america man 2013-03-28
jan china man 2013-03-29
mary america man 2013-03-29
lilei china man 2013-03-29
heyong china man 2013-03-29
yiku japan man 2013-03-29
emoji japan man 2013-03-29
Time taken: 1.141 seconds, Fetched: 9 row(s)
现在我把这张表的内容直接插入到另一张表par_dnm中,并实现sex为静态分区,dt动态分区(不指定到底是哪日,让系统自己分配决定)
hive> insert overwrite table par_dnm partition(sex='man',dt)
> select name, nation, dt from par_tab;
注意,动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区。
动态分区可以允许所有的分区列都是动态分区列,但是要首先设置一个参数hive.exec.dynamic.partition.mode :
hive> set hive.exec.dynamic.partition.mode;
hive.exec.dynamic.partition.mode=strict
它的默认值是strict,即不允许分区列全部是动态的,这是为了防止用户有可能原意是只在子分区内进行动态建分区,但是由于疏忽忘记为主分区列指定值了,这将导致一个dml语句在短时间内创建大量的新的分区(对应大量新的文件夹),对系统性能带来影响。
所以我们要设置:
hive> set hive.exec.dynamic.partition.mode=nostrict;
11.Hive UDF 函数,如何永久生效
1.在$HIVE_CONF_DIR/下添加文件.hiverc
在文件中添加udf函数
add jar ***.jar
create temporary funcation **** as ***
2.在hive-env.sh配置文件中添加HIVE_AUX_JARS_PATH
然后再使用
3.下载对应的hive源码包重新编译打包
临时注册
1、将导出的hiveudf.jar复制到hdfs上
hadoop fs -copyFromLocal hiveudf.jar hiveudf.jar
2、进入hive,添加jar,
add jar hdfs://localhost:9000/user/root/hiveudf.jar
3、创建一个临时函数
create temporary function my_lower as 'com.example.hive.udf.LowerCase';
4、调用
select LowerCase(name) from teacher;
注:这种方法只能添加临时的函数,每次重新进入hive的时候都要再执行4-6
12.Hive 的sort by、order by、cluster by、Distribute by 各代表什么意思
orderby:会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)。只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
sort by:不是全局排序,其在数据进入reducer前完成排序。
distribute by:按照指定的字段对数据进行划分输出到不同的reduce中。
cluster by:除了具有distribute by的功能外还兼具sort by的功能。
13 sqoop 如何增量抽取到Hive,对应Hive表如何设计
每隔两分钟增量导入数据
#!/bin/sh
export SQOOP_HOME=/usr/share/sqoop-1.4.4
hostname="192.168.1.199"
user="root"
password="root"
database="test"
table="tags"
curr_max=0
function db_to_hive(){
${SQOOP_HOME}/bin/sqoop import --connect jdbc:mysql://${hostname}/${database} --username ${user} --password ${password} --table ${table} --split-by docid --hive-import --hive-table lan.ding
--fields-terminated-by '\t' --incremental append --check-column docid --last-value ${curr_max}
result=`mysql -h${hostname} -u${user} -p${password} ${database}<<EOF
select max(docid) from ${table};
EOF`
curr_max=`echo $result |awk '{print $2}'`
}
if [ $# -eq 0 ];then
while true
do
db_to_hive
sleep 120
done
exit
fi
https://blog.csdn.net/sprita1/article/details/42676307
sqoop import \
--connect jdbc:mysql://192.168.52.130:3306/sqoop \
--username root \
--password 123456 \
-m 1 \
--table emp \
--hive-database 'ruozedata_test' \
--hive-import \
--direct \
--hive-table 'emp_sqopp_test' \
--fields-terminated-by '\t' \
--input-null-non-string '0' \
--input-null-string '' \
--check-column empno \
--incremental append \
--last-value 9999
14Hbase 的rowkey如何设计?请举例
rowkey设计三原则: 1.散列原则(hash打散),2.长度原则(不能太长),3.唯一性(RowKey需要唯一确定一条数据,所以必须唯一)
rowkey长度原则
rowkey是一个二进制码流,可以是任意字符串,最大长度64kb,实际应用中一般为10-100bytes,以byte[]形式保存,一般设计成定长。
建议越短越好,不要超过16个字节,原因如下:
-
数据的持久化文件HFile中是按照KeyValue存储的,如果rowkey过长,比如超过100字节,1000w行数据,光rowkey就要占用100*1000w=10亿个字节,将近1G数据,这样会极大影响HFile的存储效率;
-
MemStore将缓存部分数据到内存,如果rowkey字段过长,内存的有效利用率就会降低,系统不能缓存更多的数据,这样会降低检索效率。
rowkey散列原则
如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率。
rowkey唯一原则
必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。
什么是热点
HBase中的行是按照rowkey的字典顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey设计是热点的源头。
热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他region,由于主机无法服务其他region的请求。
设计良好的数据访问模式以使集群被充分,均衡的利用。为了避免写热点,设计rowkey使得不同行在同一个region,但是在更多数据情况下,数据应该被写入集群的多个region,而不是一个。
下面是一些常见的避免热点的方法以及它们的优缺点:
加盐
这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。
哈希
哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据
反转
第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。
反转rowkey的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题
时间戳反转
一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey的一部分对这个问题十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如 [key][reverse_timestamp] , [key] 的最新值可以通过scan [key]获得[key]的第一条记录,因为HBase中rowkey是有序的,第一条记录是最后录入的数据。
比如需要保存一个用户的操作记录,按照操作时间倒序排序,在设计rowkey的时候,可以这样设计:
[userId反转][Long.Max_Value - timestamp],在查询用户的所有操作记录数据的时候,直接指定反转后的userId,startRow是[userId反转][000000000000],stopRow是[userId反转][Long.Max_Value - timestamp]
如果需要查询某段时间的操作记录,startRow是[user反转][Long.Max_Value - 起始时间],stopRow是[userId反转][Long.Max_Value - 结束时间]
其他一些建议
尽量减少行和列的大小在HBase中,value永远和它的key一起传输的。当具体的值在系统间传输时,它的rowkey,列名,时间戳也会一起传输。如果你的rowkey和列名很大,甚至可以和具体的值相比较,那么你将会遇到一些有趣的问题。HBase storefiles中的索引(有助于随机访问)最终占据了HBase分配的大量内存,因为具体的值和它的key很大。可以增加block大小使得storefiles索引再更大的时间间隔增加,或者修改表的模式以减小rowkey和列名的大小。压缩也有助于更大的索引。
列族尽可能越短越好,最好是一个字符
15hbase的读写流程经过master吗?假如不经过 那么什么流程经过?
读写过程
读过程
(1) 客户端通过zookeeper以及root表和meta表找到目标数据所在的regionserver
(2)联系regionserver查询目标数据
(3)regionserver定位到目标数据所在的region,发出查询请求
(4)region先在memstore中查找,命中则返回
(5)如果在memstore中找不到,则在storefile中扫描(可能会扫描到很多的storefile----bloomfilter布隆过滤器)
补充:布隆过滤器参数类型有2种:
Row、row+col
写过程
(1)client向region server提交写请求
(2)region server找到目标region
(3)region检查数据是否与schema一致
(4)如果客户端没有指定版本,则获取当前系统时间作为数据版本
(5)将更新写入WAL log
(6)将更新写入Memstore(内存)
(7)判断Memstore的是否需要flush为StoreFile文件。
细节描述:
hbase使用MemStore和StoreFile存储对表的更新。
数据在更新时首先写入Log(WAL log)和内存(MemStore)中,MemStore中的数据是排序的,
***当MemStore累计到一定阈值时,就会创建一个新的MemStore,
***并且将老的MemStore添加到flush队列,由单独的线程flush到磁盘上,成为一个StoreFile。
于此同时,系统会在zookeeper中记录一个redo point,表示这个时刻之前的变更已经持久化了。
当系统出现意外时,可能导致内存(MemStore)中的数据丢失,此时使用Log(WAL log)来恢复checkpoint之后的数据。
***StoreFile是只读的,一旦创建后就不可以再修改。因此Hbase的更新其实是不断追加的操作。当一个Store中的
StoreFile达到一定的阈值后,就会进行一次合并(minor_compact, major_compact),将对同一个key的修改合并到一起,
形成一个大的StoreFile,当StoreFile的大小达到一定阈值后,又会对 StoreFile进行split,等分为两个StoreFile。
***由于对表的更新是不断追加的,compact时,需要访问Store中全部的 StoreFile和MemStore,将他们按row key进行合并,
由于StoreFile和MemStore都是经过排序的,并且StoreFile带有内存中索引,合并的过程还是比较快。
经过Master的请求
Master:
1 为Region server分配region
2 负责region server的负载均衡
3 发现失效的region server并重新分配其上的region
4 HDFS上的垃圾文件回收
5 处理schema更新请求
16hbase的hbck命令有了解吗 ?哪些故障 哪些命令
通常在hbase重启的时候会出现数据不一致的问题,就会用到hbck detail查看详细信息进行修复。但是避免使用hbck repair,这个有风险。
hbck是hbase里用来检测 region一致性,表完整性问题及修复损坏的命令行工具。它有2种工作模式:
只读不一致性识别模式(默认模式,但不尝试修复)
多阶段读写修复模式 (如果发现错误,则尝试修复)
注:如果只检查特定的表 则用: hbck ..
常用选项:
1. -details 顾名词义,打印详细结果
2. -fix 用来修复region级别的不一致性。其内部的操作顺序如下
先查是否存在不一致的。
如有表级别的不一致性,则先修复表的不一致问题。
如有region级别的不一致性,则修复该级别的问题。在修复期间region是关闭状态
也可以通过其它方式来修复不一致性,如下:
-fixAssignments repairs unassigned, incorrectly assigned or multiply assigned regions. 修复没有分配的,已分配但不正确的单个region或者多个region。
-fixMeta removes rows from hbase:meta when their corresponding regions are not present in HDFS and adds new meta rows if regions are present in HDFS but not in hbase:meta. 当从hbase:meta表相关的region在hdfs里没有找到,则移除这些行。如果这些region在hdfs里,则在hbase.meta里增加新的行
-repairHoles creates HFiles for new empty regions on the filesystem and ensures that the new regions are consistent. 在空的region里新建一个HFiles,却表新的region是一致的。
-fixHdfsOrphans repairs a region directory that is missing a region metadata file (the .regioninfo file).在region目录里 修复那些缺失region元数据的文件如(.regioninfo)
-fixHdfsOverlaps fixes overlapping regions. You can further tune this argument using the following options: 修复重叠的regions。与此同时结合以下选项:
-maxMerge controls the maximum number of regions to merge. 控制最大合并region的数量。
-sidelineBigOverlaps attempts to sideline the regions which overlap the largest number of other regions. 尝试退出那些与其它region有最大数量的重叠的region
-maxOverlapsToSideline limits the maximum number of regions to sideline. 限制退出region的最大数量。