知识回顾
1、请简述 HBase 的数据结构和存储架构
数据结构:
hbase数据结构包括:命名空间,行键,列簇,列,时间戳,数据ceil。
- 命名空间:类似于关系型的数据库,存放表的空间
- 行键:也就是rowkey,唯一标识
- 列簇:也就是一个大的类,一个数据集,数量是固定的
- 列:列就是通俗的一列,一个列簇可以拥有多个列,列可以增加
时间戳:每次的数据更新都会跟新时间戳,可以通过时间戳获取最新的数据,也解决了hdfs不能随时间修改的弊端- 数据ceil:也就是hbase中的数据全是字符串类型
存储架构:
Client(客户端)、Master(主节点)、HRegionServer(维护HRegion)、HLog(日志)、HRegion(维护若干个Store)、Store(具体数据存放)、StoreFile(持久化到HDFS)、MemStore(内存存储)、Zookeeper(监控集群和存放root映射信息)
2、请简述 HBase 查询数据的流程
首先访问zookeeper,获取meta文件所在HRegionServer的位置,获取meta文件加载之内存,获取rowkey对应HRegion的位置由于存在多个HRegion中,故此创建多个HRegionScanner,StoreScanner扫描器,先扫描MemStore是否存储在,再扫描StoreFile,最后返回结果
3、请简述 HBase 写询数据的流程
首先建立连接,将写入操作追加到HLog日志中,在获取zookeeper中meta文件的位置信息,获取meta中指定的rowkey映射的HRegion信息后,进行数据写入,写到MemStore,默认达到128MB时,进行一个刷写到硬盘,变成StoreFile,随着不断的StoreFile变多,StoreFile会进行一个数据的的合并
4、请阐述 Spark 中的缓存机制 cache 和 persist 与 checkpoint 的区别与联系
cache:
控制算子之一,cache() = persist() = persist(StorageLevel.Memory_Only),相当于persist的一种情况,属于惰性加载,第一次不会使用缓存只有二次运算才会使用(代码实现如下)persist:
控制算子之一:支持持久化,常用的模式有Memory_Only和Memory_and_Diskcheckpoint:
主要用于持久化RDD,将结果持久化到具体的文件中,也是惰性加载(代码实现如下)- 三者都是控制算子,对数据的不同形式的一种控制和持久化,其中cache基于内存,checkpoints基于硬盘,而persist则是最全面的多种模式皆可实现
/*控制算子之cache()惰性加载*/
object CtrlCache {
def main(args: Array[String]): Unit = {
//创建连接
val context = new SparkContext(new SparkConf().setMaster("local").setAppName("cache" + System.currentTimeMillis()))
//获取数据元
val value: RDD[String] = context.textFile("src/main/resources/user.log")
//启动缓存
value.cache()
//记录时间
val start: Long = System.currentTimeMillis()
//统计数据行数
val count: Long = value.count()
//记录结束时间
val end: Long = System.currentTimeMillis()
//输出结果
println("数据共"+count+"行,耗时:"+(end-start)+"s")
//记录时间
val start1: Long = System.currentTimeMillis()
//统计数据行数
val count1: Long = value.count()
//记录结束时间
val end1: Long = System.currentTimeMillis()
//输出结果
println("数据共"+count1+"行,耗时:"+(end1-start1)+"s")
}
}
/*控制算子 checkpoint*/
object CheckPoint {
def main(args: Array[String]): Unit = {
//创建连接
val context = new SparkContext(new SparkConf().setMaster("local").setAppName("cache" + System.currentTimeMillis()))
//获取数据元
val value: RDD[String] = context.textFile("src/main/resources/user.log")
//设置检查点路径
context.setCheckpointDir("./point")
//对数据进行分区
val partiton: RDD[String] = value.flatMap(_.split(" "))
//获取分区数
println("分区数:"+partiton.getNumPartitions)
//持久化
value.checkpoint()
//持久化数量
value.count()
context.stop()
}
}
5、RDD 的五大属性?请列举出常用的 RDD 算子及作用?
- 五大属性:
① RDD由一组partition分区组成
② RDD之间相互依赖
③ RDD计算出最佳的计算位置
④ 分区器用于key -value的RDD上
⑤ 函数作用在每一个分片上- RDD常用算子以及作用:
– 转换算子:
map:进一出一,对数据进行切分等处理
flatMap:与map类似先map后flat,多用于分区
sortByKey:用于k-vRDD上,排序
reduceByKey:将相同的Key的数据进行处理
– 行动算子:
count:返回数据集中的元素个数
foreach:循环遍历数据集中每个元素
collect:将计算结果回收到Driver端
– 控制算子:cache ,persist,checkpoint(略)
6、Spark 宽窄依赖的作用是什么?
宽依赖:
意味着父RDD与子RDD之间的partition分区关系是一对多,这样会导致shuffle洗牌的产生
窄依赖:
意味着父RDD与子RDD之间的partition分区之间的关系是一对一或者是多对一的关系,不会产生shuffle洗牌操作
作用:spark通过宽窄依赖来划分stage