大数据面试题

Hive

1. hive的函数

Hive

- hive的函数
	内置函数:
		数学函数:
			取整函数:round(double a) 返回double类型的整数值部分(遵循四舍五入)
			指定精度取整函数:round(double a, int d) 返回指定精度d的double类型
			向下取整函数:floor(double a) 返回等于或者小于该double变量的最大的整数
			向上取整函数:ceil(double a) 返回等于或者大于该double变量的最小的整数
			取随机数函数:rand(),rand(int seed) 返回一个0到1范围内的随机数。如果指定种子seed,则会返回固定的随机数
			幂运算函数:pow(double a, double p) 返回a的p次幂
			绝对值函数:abs(double a)  abs(int a) 返回数值a的绝对值
		字符串函数
			字符串长度函数:length(string A) 返回字符串A的长度
			字符串反转函数:reverse(string A) 返回字符串A的反转结果
			字符串连接函数:concat(string A, string B…) 返回输入字符串连接后的结果,支持任意个输入字符串
			字符串连接函数-带分隔符:concat_ws(string SEP, string A, string B…) 返回输入字符串连接后的结果,SEP表示各个字符串间的分隔符
			字符串截取函数:substr(string A, int start),substring(string A, int start) 返回字符串A从start位置到结尾的字符串
			字符串截取函数:substr(string A, int start, int len),substring(string A, intstart, int len) 返回字符串A从start位置开始,长度为len的字符串
			字符串转大写函数:upper(string A) ucase(string A) 返回字符串A的大写格式
			字符串转小写函数:lower(string A) lcase(string A) 返回字符串A的小写格式
			去空格函数:trim(string A) 去除字符串两边的空格
			左边去空格函数:ltrim(string A) 去除字符串左边的空格
			右边去空格函数:rtrim(string A) 去除字符串右边的空格
			正则表达式替换函数:regexp_replace(string A, string B, string C) 将字符串A中的符合java正则表达式B的部分替换为C。注意,在有些情况下要使用转义字符,类似oracle中的regexp_replace函数。
			URL解析函数:parse_url(string urlString, string partToExtract [, stringkeyToExtract]) 返回URL中指定的部分。partToExtract的有效值为:HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO
			分割字符串函数:split(string str, stringpat) 按照pat字符串分割str,会返回分割后的字符串数组
		日期函数
		条件函数
	表生成函数
	开窗函数
		窗口函数
			NTILE
			ROW_NUMBER:从1开始,按照顺序,生成分组内记录的序列
			RANK:生成数据项在分组中的排名,排名相等会在名次中留下空位(相同时排名值会重复,总数不会变,故相同时排名值会跳跃而不连续)
			DENSE_RANK:生成数据项在分组中的排名,排名相等会在名次中不会留下空位(总数会减少,并且排名值不会跳跃)
		hive 聚合函数
			count()、sum()、avg()、max()、min()
		分析窗口函数 
			LAG:LAG(col,n,DEFAULT) 用于统计窗口内往上第n行值第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)
			LEAD:与LAG相反LEAD(col,n,DEFAULT) 用于统计窗口内往下第n行值第一个参数为列名,第二个参数为往下第n行(可选,默认为1),第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL)
			FIRST_VALUE:取分组内排序后,截止到当前行,第一个值
			LAST_VALUE:取分组内排序后,截止到当前行,最后一个值
			特别注意:如果不指定ORDER BY,则进行排序混乱,会出现错误的结果
	自定义函数
		自定义UDF:
			编程步骤:
			(1)继承org.apache.hadoop.hive.ql.UDF
			(2)需要实现evaluate函数;evaluate函数支持重载;
			注意事项:
			(1)UDF必须要有返回类型,可以返回null,但是返回类型不能为void;
			(2)UDF中常用Text/LongWritable等类型,不推荐使用java类型;
		自定义UDTF

- UDF,UDTF,UDAF的区别
	UDF:一进一出
	UDAF:聚集函数,多进一出(类似于:count/max/min)
	UDTF:一进多出;如lateral view explore()

- hive中split、coalease及collect_list函数
	split:字符串切割转化为数组
	coalease:返回参数中第一个非空值,如果所有值都为空,则返回空
	collect_list:列出该字段所有值,不去重

- Hive如何处理小文件的问题
	哪些会产生小文件:
		源数据本身、
		动态分区会产生大量小文件、
		reduce个数越多, 小文件越多、
		按分区插入数据的时候会产生大量的小文件, 文件个数 = maptask个数 * 分区数
	造成的影响:
		小文件会开很多map,一个map开一个JVM去执行,所以这些任务的初始化,启动,执行会浪费大量的资源,严重影响性能
		HDFS存储太多小文件, 会导致namenode元数据特别大, 占用太多内存, 制约了集群的扩展
	解决方法:
		1. 调整参数进行合并(设置map输入/输出、reduce输出等相关参数)
		2. 针对按分区插入数据的时候产生大量的小文件的问题, 可以使用DISTRIBUTE BY rand() 将数据随机分配给Reduce,这样可以使得每个Reduce处理的数据大体一致.
		3. 使用Sequencefile作为表存储格式,不要用textfile,在一定程度上可以减少小文件
		4. 使用hadoop的archive归档
		5. 使用CombineFileInputFormat

- hive数仓分层如何保证每层数据的正确性?
	数据治理

- hive如何结合数据设置压缩和存储格式
	在计算的过程中(DWD、DWM、DWS、APP),为了不影响执行的速度,可以浪费一点磁盘空间,采用orcfile+SNAPPY的方式,提升hive的执行速度。
	DWD明细层根据业务的需要,灵活选用ZLIB或SNAPPY。

- hive底层解析及sparksql底层执行与hive区别,hive数据修改如何实现?
	sparksql底层加了catalyst优化器,
	hive中一般不会去修改数据,常用来分析查询操作,保留历史数据情况下,使用渐变维,拉链表

- 分区表和分桶表如何使用,什么场景
	分区表:用来分区,也就是分文件夹
	分桶表:是分文件,提高查询效率,还有在抽样查询时使用
		桶表的数据加载,由于桶表的数据加载通过hdfs dfs -put文件或者通过load data均不好使,只能通过insert overwrite

- hive表的桶表的数量怎么确定的❌
	位置:列的值做哈希取余 决定数据应该存储到哪个桶
	bucket个数会决定在该表或者该表的分区对应的hdfs目录下生成对应个数的文件,而mapreduce的个数是根据文件块的个数据确定的map个数。

- Hive的优化
	1. Fetch抓取:某些查询不必使用MapReduce计算时,比如在全局查找、字段查找、limit查找等都不走mapreduce
	2. 本地模式:在hive输入数据量非常小时,hive可以通过本地模式在单台机器上处理所有任务
	3. Join优化:
		大小表join:用MapJoin把小表全部加载到内存在map端进行join,避免reducer处理
		大表join大表
			空key过滤
			空key转换:赋一个随机的值
	4. SQL优化:
		列裁剪:只读取查询中所需要用到的列
		分区裁剪:查询的过程中减少不必要的分区
		Group by:可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。参数设置开启map端聚合
		笛卡尔积:尽量避免笛卡尔积,即避免join的时候不加on条件,或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积。
	5. 动态分区调整:基于查询参数的位置去推断分区的名称,从而建立分区。使用Hive的动态分区,需要进行相应的配置。
		参数设置
		(1)开启动态分区功能(默认true,开启)
		(2)设置为非严格模式
		(3)在所有执行MR的节点上,最大一共可以创建多少个动态分区。
		(4)在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。
		(5)整个MR Job中,最大可以创建多少个HDFS文件。
		(6)当有空分区生成时,是否抛出异常。一般不需要设置。
	6. 调整合适的map数
		增加map数:一个文件大小小于block块(小于128M),但这个文件只有少量字段,却存了几千万条数据,一个map处理肯定非常耗时
		减少map数:当一个任务有很多小文件,文件大小又远远小于block块大小,每个文件都会被当作一个块,用一个map处理,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费
	7. 设置合适的reduce数
		Reduce的个数对整个作业的运行性能有很大影响。如果Reduce设置的过大,那么将会产生很多小文件,对NameNode会产生一定的影响,而且整个作业的运行时间未必会减少;如果Reduce设置的过小,那么单个Reduce处理的数据将会加大,很可能会引起OOM异常。
	8. 并行执行
		设置参数hive.exec.parallel值为true,就可以开启并发执行。Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。有些阶段是可以并行执行,这样可能使得整个job的执行时间缩短
	9. 严格模式
		开启严格模式需要修改hive.mapred.mode值为strict,开启严格模式可以禁止3种类型的查询。
			1)对于分区表,在where语句中必须含有分区字段作为过滤条件来限制范围,否则不允许执行。
			2)对于使用了order by语句的查询,要求必须使用limit语句。
			3)限制笛卡尔积的查询。
	10. JVM重用:JVM重用是Hadoop调优参数,JVM重用可以使得JVM实例在同一个job中重新使用N次(特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。)
	11. 推测执行:根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。
	12. 存储方式和压缩方式:存储格式压缩格式尤为关键,可以提升计算速度,减少存储空间,降低网络io,磁盘io

- Hive的数据倾斜问题
	原因:
		有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完。
	Hive中会出现数据倾斜的地方:
		join产生的数据倾斜、count(distinct)、group by、一些窗口函数中用了partition by一会造成数据倾斜
	解决方案:
		join产生的数据倾斜:
			大表join小表:小表缓存到内存中
			大表和大表的join:
				其中一张表的多是空值或者0比较多时:异常值赋一个随机值来分散key,均匀分配给多个reduce去执行
				当key值都是有效值时:设置每个节点的reduce处理数据大小
		group by 造成的数据倾斜:配置在map端进行聚合
		count(distinct)以及其他参数不当的数据倾斜:设置适合的reduce个数

- Hive的文件类型和压缩格式
	在计算的过程中(DWD、DWM、DWS、APP),为了不影响执行的速度,可以浪费一点磁盘空间,采用orcfile+SNAPPY的方式,提升hive的执行速度。DWD明细层根据业务的需要,灵活选用ZLIB或SNAPPY。

- sort by、order by、cluster by、distrbute by区别
	order by:全局排序,只有一个reducer
	sort  by:mapreduce内部排序,在进入reduce前完成排序(局部排序)
	distrbute by:分区排序,结合sort by使用,但hive要求distrbute by要写在sort by之前
	cluster by:当distrbute by和sort by字段相同时,可以使用cluster by方式,但是排序方式只能是倒序排序,不能指定排序规则(ASC或DESC)

- null在hive底层如何存储
	用\N 存储

- Hive SQL的执行过程
	1. client提交sql到driver驱动器
	2. 解析器(SQL Parser):将SQL字符转换成抽象语法树AST
	3. 编译器(Physical Plan):将AST编译生成逻辑执行计划
	4. 优化器(Query Optimizer):对逻辑执行计划进行优化
	5. 执行器(Execution):把逻辑执行计划转换成可以运行的物理计划(MR进行计算)

- Hive分区
	是指按照数据表的某列或某些列分为多个区,区从形式上可以理解为文件夹
	通过关键字 partitioned by(name string)声明该表是分区表 

- 内部表和外部表的区别?
	在创建内部表时,在时候location指定数据路径时候,会将该路径下的数据移动到该表所在的目录下,于此同时在删除内部表的数据,会删除数据同时也会删除该表所在的元数据,该管理表不适用于其他工具共享数据
	外部表在创建表时候需要添加一个关键子,external,该表不完全管理该表,所以在删除该表,只会删除该表的元数据,不会删除数据,适合与其他工具共享数据
	场景:根据业务,看数据是否需要共享,来创建外部表和内部表


数仓
- OLAP和OLTP的理解
	OLTP:在数据库联机的日常操作,通常对少数记录进行查询、修改。用户较为关心操作的响应时间、数据的安全性、完整性和并发支持的用户数等问题,具有事物性,存储业务数据,为捕获数据
	OLAP:针对某些主题的历史数据进行分析,支持管理决策;存储的一般是历史数据,为分析数据

- 接触过数仓建模不?
	业务建模,生成业务模型,主要解决业务层面的分解和程序化。
	领域建模,生成领域模型,主要是对业务模型进行抽象处理,生成领域概念模型。
	逻辑建模,生成逻辑模型,主要是将领域模型的概念实体以及实体之间的关系进行数据库层次的逻辑化。
	物理建模,生成物理模型,主要解决,逻辑模型针对不同关系型数据库的物理化以及性能等一些具体的技术问题。
	Lambda 架构
		

- 拉链表
	解决缓慢渐变维问题(SCD2),经常在需要保留历史数据时,会使用到

- 大型数仓架构分层
	1.数据运营层ODS:
		(1)存放接入的原始数据(业务数据和日志数据) 
		(2)数据落地到ODS层前,不要做过多的清洗,方便追溯数据;可以通过sparkSQL完成数据清洗ETL后保存到DW层
	2.数据仓库层DW(中间层数据),当业务比较多时,可以细分为: 
		2.1 数据明细层:DWD(Data WareHouse Detail)
			(1)保持和ODS层一样的粒度,不做粒度的上卷和下钻 
			(2)将维度表退化到事实表中,减少两者之间关联,退化指的是将维度表中字段添加到事实表中(拓宽)
			(3)可以将ODS层相同主题的数据汇总在一张表中
			(4)对ODS层数据进行清洗加工处理
		2.2 数据中间层:DWM(Data WareHouse Middle)
			(1)此层不是必要的,可以被DWS层替代
			(2)对DWD层数据按照日期(如天)进行初步的汇总
		2.3 数据服务层:DWS(Data WareHouse Service)
			(1)也叫作数据集市(DM)或者宽表层 
			(2)通常会有以某一个维度为中心,组成跨主题的宽表
				比如 统计一个用户的当日的签到数、收藏数、评论数、抽奖数、订阅数、点赞数、浏 览商品数、添加购物车数、下单数、支付数、退款数、点击广告数组成宽表
			(3)统计多个时间粒度的数据,按天按月等统计
	3.数据应用层APP:
		 (1)又叫做ADS层
		(2)面向业务定制的报表层,复用性不强
		(3)一般存放在ES,MYSQL,Redis来供线上系统使用,或者放在Hive中供数据分析和数据 挖掘使用
	4.维表层 Dimension 
		4.1高基数维度数据:
			(1)指的是数据量很大的维度表,如用户表和商品表 
		4.2低基数维度数据
			(1)指的是数据量较少的维度表,一般是配置表

	注意: 1.数据集市在有些公司并不是指DWS层,整个公司是一个数仓,而一个部门用的数据对应一个数据集市

- ods有哪些数据? 来自哪些系统? 
	最细粒度的事务事实表, 维度表. 
- dws具体做了哪些设计? 满足了一些什么业务? dws怎么划分主题域的? 大概的逻辑是什么样的? 什么逻辑关系? 
- 数仓模型怎么设计的?设计模型的流程?
- 用的是cdh还是apache,为什么

- 数据仓库0-1建设
	1.系统分析,确定主题
		·操作出现的频率,即业务部门每隔多长时间做一次查询分析。
		·在系统中需要保存多久的数据,是一年、两年还是五年、十年。
		·用户查询数据的主要方式,如在时间维度上是按照自然年,还是财政年。
		·用户所能接受的响应时间是多长、是几秒钟,还是几小时。
	2.选择满足数据仓库系统要求的软件平台
		·数据库对大数据量(TB级)的支持能力。
		·数据库是否支持并行操作。
		·能否提供数据仓库的建模工具,是否支持对元数据的管理。
		·能否提供支持大数据量的数据加载、转换、传输工具(ETL)。
		·能否提供完整的决策支持工具集,满足数据仓库中各类用户的需要。
	3.建立数据仓库的逻辑模型
		(1)确定建立数据仓库逻辑模型的基本方法。
		(2)基于主题视图,把主题视图中的数据定义转到逻辑数据模型中。
		(3)识别主题之间的关系。
		(4)分解多对多的关系。
		(5)用范式理论检验逻辑数据模型。
		(6)由用户审核逻辑数据模型。
	4.逻辑数据模型转化为数据仓库数据模型
	具体步骤如下:
		(1)删除非战略性数据:数据仓库模型中不需要包含逻辑数据模型中的全部数据项,某些用于操作处理的数据项要删除。
		(2)增加时间主键:数据仓库中的数据一定是时间的快照,因此必须增加时间主键。
		(3)增加派生数据:对于用户经常需要分析的数据,或者为了提高性能,可以增加派生数据。
		(4)加入不同级别粒度的汇总数据:数据粒度代表数据细化程度,粒度越大,数据的汇总程度越高。粒度是数据仓库设计的一个重要因素,它直接影响到驻留在数据仓库中的数据量和可以执行的查询类型。显然,粒度级别越低,则支持的查询越多;反之,能支持的查询就有限。
	对数据操作的效率与能得到数据的详细程度是一对矛盾,通常,人们希望建成的系统既有较高的效率,又能得到所需的详细资料。实施数据仓库的一个重要原则就是不要试图包括所有详细数据,因为90%的分析需求是在汇总数据上进行的。试图将粒度细化到最低层,只会增加系统的开销,降低系统的性能。
	5.数据仓库数据模型优化
		数据仓库设计时,性能是一项主要考虑因素。在数据仓库建成后,也需要经常对其性能进行监控,并随着需求和数据量的变更进行调整。
		优化数据仓库设计的主要方法是:
			·合并不同的数据表。
			·通过增加汇总表避免数据的动态汇总。
			·通过冗余字段减少表连接的数量,不要超过3~5个。
			·用ID代码而不是描述信息作为键值。
			·对数据表做分区。
	6.数据清洗转换和传输
		由于业务系统所使用的软硬件平台不同,编码方法不同,业务系统中的数据在加载到数据仓库之前,必须进行数据的清洗和转换,保证数据仓库中数据的一致性。
		在设计数据仓库的数据加载方案时,必须考虑以下几项要求:
			·加载方案必须能够支持访问不同的数据库和文件系统。
			·数据的清洗、转换和传输必须满足时间要求,能够在规定的时间范围内完成。
			·支持各种转换方法,各种转换方法可以构成一个工作流。
			·支持增量加载,只把自上一次加载以来变化的数据加载到数据仓库。
	7.开发数据仓库的分析应用
		建立数据仓库的最终目的是为业务部门提供决策支持能力,必须为业务部门选择合适的工具实现其对数据仓库中的数据进行分析的要求。
		信息部门所选择的开发工具必须能够:
			·满足用户的全部分析功能要求。数据仓库中的用户包括了企业中各个业务部门,他们的业务不同,要求的分析功能也不同。如有的用户只是简单的分析报表,有些用户则要求做预测和趋势分析。
			·提供灵活的表现方式。分析的结果必须能够以直观、灵活的方式表现,支持复杂的图表。使用方式上,可以是客户机/服务器方式,也可以是浏览器方式。
		事实上,没有一种工具能够满足数据仓库的全部分析功能需求,一个完整的数据仓库系统的功能可能是由多种工具来实现,因此必须考虑多个工具之间的接口和集成性问题,对于用户来说,希望看到的是一致的界面。

hbase

- hadoop和HBase比较
	hadoop:分布式文件系统HDFS来存储海量数据,并使用 MapReduce 来处理。Hadoop擅长于存储各种格式的庞大的数据,任意的格式甚至非结构化的处理
		缺点:
			Hadoop主要是实现批量数据的处理,并且通过顺序方式访问数据
			要查找数据必须搜索整个数据集, 如果要进行随机读取数据,效率较低
	HBase:
		是建立在HDFS之上,提供高可靠性、高性能、列存储、可伸缩、实时读写
		仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务
		主要用来存储结构化和半结构化的松散数据
		支持的数据类型:byte[]
		不支持join等复杂操作,不支持复杂的事务(行级的事务)

- HBase的批量装载Bulk load进行大量数据操作为什么高效
	Bulk Load就是直接将数据写入到StoreFile(HFile)中,从而绕开与HBase的交互,HFile生成后,直接一次性建立与HBase的关联即可。使用BulkLoad,绕过了Write to WAL,Write to MemStore及Flush to disk的过程

- 数据写入HBase的方式
	普通的put方式是将每一条数据依次写到Hbase中,当数据量比较多时,会产生很多io次数
	解决方案
		离线业务:使用Bulkload方式将数据以HFile格式写到HDFS中,再将文件和Hbase表之间关联起来 
		实时业务:比如Flink中,使用BufferedMutator替代put方式,它有一个缓存,先将数据写到缓存中,当缓存满了后,一次性将缓存数据写到Hbase中

- 你们项目中rowkey是怎么设计的?
	1. 官方设计原则:
		RowKey长度设计原则(10~100个字节,越短越好,不超过16个字节)
		RowKey散列原则:如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位字节采用散列字段处理,由程序随即生成。低位放时间字段,这样将提高数据均衡分布,各个regionServer负载均衡的几率。
		RowKey唯一性:
	2. 避免数据热点:
		反转策略:如果设计出的rowkey在数据分布上不均匀,但rowkey尾部的数据却呈现出了良好的随机性,可以考虑将rowkey的翻转,或者直接将尾部的bytes提前到rowkey的开头。反转策略可以使rowkey随机分布,但是牺牲了rowkey的有序性
			利于Get操作,但不利于Scan操作,因为数据在原rowkey上的自然顺序已经被打乱
		加盐策略:Salting(加盐)的原理是在原rowkey的前面添加固定长度的随机数,也就是给rowkey分配一个随机前缀使它和之间的rowkey的开头不同;随机数能保障数据在所有Regions间的负载均衡
			缺点:增加了读的消耗,因为添加的是随机数,基于原rowkey查询时无法知道随机数是什么,那样在查询的时候就需要去各个可能的Regions中查找,加盐对比读取是无力的
		哈希策略:基于 rowkey的完整或部分数据进行 hash,然后截取hash后的末几位,作为前缀与原rowkey拼接形成rowkey; hash 包含 MD5、sha1、sha256 或 sha512 等算法;
			缺点:利于get,不利于 Scan,因为打乱了原rowkey的自然顺序
		预分区:
			默认情况,一个HBase的表只有一个Region,被托管在一个RegionServer中,默认Region的大小为10G
			每个Region有两个重要的属性:Start Key、End Key,表示这个Region维护的ROWKEY范围
			如果只有一个Region,那么Start Key、End Key都是空的,没有边界。所有的数据都会放在这个Region中,但当数据越来越大时,要到达分裂的阈值才会将Region分裂,取一个Mid Key来分裂成两个Region
			在此过程中,会产生两个问题:
				1)数据往一个region上写,会有写热点问题。
				2)分裂(split)操作会带来资源消耗。
			预分区的方法:
				1、指定 start key、end key来分区
				2、指定分区数量、分区策略
					分区策略:
						- HexStringSplit: ROWKEY是十六进制的字符串作为前缀的
						- DecimalStringSplit: ROWKEY是10进制数字字符串作为前缀的
						- UniformSplit: ROWKEY前缀完全随机
				3、使用JavaAPI创建预分区

- Hbase怎么加载hive的表
	1、创建hive映射生成hbase的表
	2、去hbase库中查看,已经创建好了hbaseFromhive表
	3、hive加载数据,Hive中的映射表不能直接插入数据,所以需要通过将数据加载到另一张中间表,然后通过查询中间表将数据加载到hive映射表。

- Hbase 为啥快
	自动分块:HBase表通过Region分布在集群上,随着数据的增长,区域被自动拆分和重新分布
	HBase通过MapReduce支持大规模并行处理,将HBase用作源和接收器
	HBase支持块Cache和Bloom过滤器进行大容量查询优化
	通过主键(row key)和主键的range来检索数据,支持单行事务
	和phoniex整合,支持二级索引

- HBase的事务
	HBase 支持特定场景下的 ACID(单行事物),即当对同一行进行 Put 操作时保证完全的 ACID。
	简单理解为针对一行的操作,是有事务性保障的。
	HBase没有混合读写事务。也就是说,我们无法将读操作、写操作放入到一个事务中。

- Hbase调优
	1.HDFS优化(hdfs-site.xml)
		保证RPC调用会有较多的线程数:
			dfs.namenode.handler.count:NameNode服务默认线程数,的默认值是10,根据机器的可用内存可以调整为50~100
			dfs.datanode.handler.count:属性默认值为10,是DataNode的处理线程数,如果HDFS客户端程序读写请求比较多,可以调高到15~20,设置的值越大,内存消耗越多,不要调整的过高,一般业务中,5~10即可
		副本数的调整:
			dfs.replication:如果数据量巨大,且不是非常之重要,可以调整为2~3,如果数据非常之重要,可以调整为3~5。
		文件块大小的调整:
			dfs.blocksize:块大小定义,该属性应该根据存储的大量的单个文件大小来设置,如果大量的单个文件都小于100M,建议设置成64M块大小,对于大于100M或者达到GB的这种情况,建议设置成256M,一般设置范围波动在64M~256M之间
	2.HBase优化
		优化DataNode允许的最大文件打开数:
			hdfs-site.xml文件中`dfs.datanode.max.transfer.threads`:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096
		优化延迟高的数据操作的等待时间:
			hdfs-site.xml文件中`dfs.image.transfer.timeout`:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。
		优化数据的写入效率:
			mapred-site.xml文件中,`mapreduce.map.output.compress`、`mapreduce.map.output.compress.codec`:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec
		优化DataNode存储:
			hdfs-site.xml中`dfs.datanode.failed.volumes.tolerated`:默认为0,意思是当DataNode中有一个磁盘出现故障,则会认为该DataNode shutdown了。如果修改为1,则一个磁盘出现故障时,数据会被复制到其他正常的DataNode上,当前的DataNode继续工作。
		设置RPC监听数量:
			默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。
		优化HStore文件大小:
			默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。
		优化hbase客户端缓存:
			用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。
		指定scan.next扫描HBase所获取的行数:
			该参数定义了在扫描器上调用next方法时取回的行的数量。该数字越高,在扫描过程中客户端向Region Server发出的RPC调用越少。该数字越高也意味着客户端使用的内存越多。

- Hbase的更新操作

- 预分区
	预分区可以避免一开始的热点问题
	指的是预先按照rowkey范围生成若干个分区,这样一开始数据就会分到不停region中处理 
	弊端:当rowkey范围不确定时,不好划分

- WAL预写日志
	wal预写日志可以在Hbase服务器宕机后,恢复memstore中数据 
	默认是开启的

- Hbase的读写流程
	读流程:
		1. 首先Client连接zookeeper, 找到hbase:meta表所在的regionserver;
		2. 请求hbase:meta表的regionserver,扫描hbase:meta表,根据namespace、表名和rowkey在meta表中找到需要读取rowkey所在的region是由哪个regionserver负责的;
		3. 找到这个region对应的regionserver,然后想该regionServer发出读数据请求
		4. regionserver收到了请求之后,扫描对应的region返回数据到Client
	写流程:
		- Client 向 Zookeeper 发起获取元数据位置的请求,即获取hbase:meta表位于哪个RegionServer。
		- Zookeeper 返回元数据所在位置(在哪个RegionServer的哪个Region里)给Client
		- Client向元数据所在的 RegionServer 发起读取元数据请求,即读取hbase:meta表。注:Client 只能接触 RegionServer,所有的访问 Region 操作,都是由对应的 RegionServer 来完成。
		- 元数据所在的 RegionServer 会返回元数据信息给 Client
		- Client 根据元数据信息(hbase:meta表),得知数据该写入哪个RegionServer 的哪个Region中。并将该Table的Region信息,以及meta表的位置信息缓存在客户端的Meta Cache,方便下次访问。
		- Client 向目标 Region 所在的 RegionServer 发起写入数据的请求
		- RegionServer 先将数据顺序写入(追加)到WAL,确保 RegionServer 宕机不丢失数据,WAL写入完成之后,再将数据写入MemStore中,数据会在 MemStore 进行排序
		- 最后向客户端发送ack,告知写入完成

- HBase如何构建二级索引
	Phoenix的插件,可以满足二级索引

spark

spark和hadoop

hadoop:基于HDFS存储,基于MapReduce计算,MR的task是以进程的方式运行,存储在磁盘,延迟高
spark:基于RDD构建DAG,task基于线程的方式运行,存储在内存,延迟低,有容错机制

spark运行模式

local:启动一个JVM进程,里面运行Task任务,Task任务并行运行数目依据分配CPU Core核数,在Spark应用中,一个Task任务运行,需要1Core CPU。
standalone:
yarn: yarn负责资源管理,Spark 负责任务调度和计算,好处:计算资源按需伸缩,集群利用率高,共享底层存储,避免数据跨集群迁移。

Spark的提交方式?有什么区别

Local:开发时使用
Standalone: 是Spark自带的,如果一个集群是Standalone的话,那么就需要在多台机器上同时部署Spark环境
YARN:建议大家在生产上使用该模式,统一使用YARN进行整个集群作业(MR、Spark)的资源调度
YARN-Client模式下,Application Master仅仅向YARN请求Executor,Client会和请求的Container通信来调度他们工作,也就是说Client不能离开
YARN-Cluster模式下,Driver运行在AM(Application Master)中,它负责向YARN申请资源,并监督作业的运行状况。当用户提交了作业之后,就可以关掉Client,作业会继续在YARN上运行,因而YARN-Cluster模式不适合运行交互类型的作业;

spark提交任务参数说明

--master 指定Master的地址,默认为Local
--class: 你的应用的启动类 (如 org.apache.spark.examples.SparkPi)
--deploy-mode: 是否发布你的驱动到worker节点(cluster) 或者作为一个本地客户端 (client) (default: client)
--conf: 任意的Spark配置属性, 格式key=value. 如果值包含空格,可以加引号“key=value” application-jar: 打包好的应用jar,包含依赖. 这个URL在集群中全局可见。 比如hdfs:// 共享存 储系统, 如果是 file:// path, 那么所有的节点的path都包含同样的jar application-arguments: 传给main()方法的参数
--executor-memory1G 指定每个executor可用内存为1G
--total-executor-cores 2 指定每个executor使用的cup核数为2个

Cluster和Client模式区别

最最本质的区别是:Driver程序运行在哪里。
Client:Driver 在本地运行,Executor在集群的Worker节点上运行;应用程序运行结果会在客户端显示
Cluster:无论是Driver还是Executor都是运行在Worker节点上;应用的运行结果不能在客户端显示

spark提交任务的流程

Spark yarn的运行机制

spark所需资源如何计算出来的,然后再去分配。

spark源码中task分为几类,为什么这么划分?

两类
task执行的其实就是我们的算子
shuffleMapTask:spark程序执行的是shuffleMapTask,那么执行完这个stage后还要执行下一个stage
resultTask:会调用action算子的实际处理函数,对读出的数据进行处理.

RDD定义

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算的集合。
Dataset:一个数据集合,用于存放数据的。
Distributed:RDD中的数据是分布式存储的,可用于分布式计算。
Resilient:RDD中的数据可以存储在内存中或者磁盘中。
  • RDD属性:
    1.一个分区列表:数据集的基本组成单位 – 分区列表
    2.一个函数会被作用在每一个分区; – 计算函数
    3.一个RDD会依赖于其他多个RDD; – 依赖关系
    4.RDD的分区函数;(可选) – 分区函数(默认是hash)
    5.存储存取每个Partition的优先位置(可选) – 最佳位置

RDD分区的数据取决于哪些因素?

第一点:RDD分区的原则是使得分区的个数尽量等于集群中的CPU核心(core)数目,这样可以充分利用CPU的计算资源;
第二点:在实际中为了更加充分的压榨CPU的计算资源,会把并行度设置为cpu核数的 2~3倍;
第三点:RDD分区数和启动时指定的核数、调用方法时指定的分区数、如文件本身分区 数有关系

常用的算子:

  • Transformation:
    map、filter、flatMap、mapPartitions、partitionBy、groupByKey、reduceByKey、sortByKey、join
  • Action:
    reduce、collect、count、first、take、aggregate、saveAsTextFile、countByKey

宽窄依赖,join算子是什么算子

窄依赖:是看父RDD对应的partition最多被子RDD的一个partition使用
从失败恢复角度看,窄依赖的失败恢复更有效
宽(shuffle)依赖:是多个子RDD的partition会依赖同一个RDD的partition
join算子得看是否发生shuffle来决定是什么算子。

为什么要设计宽窄依赖

1.对于Spark的并行计算,窄依赖可以进行并行计算,而宽依赖就无法实现
2.对于Spark的容错,需要使用宽窄依赖实现(通过RDD的依赖关系形成血统)
3.对于Spark的stage的划分依据是宽依赖

RDD的缓存

为什么需要缓存?
容错机制
1-缓存可以帮助我们对一些较为昂贵的算子保存在内存或磁盘
2-避免重复的计算
哪些缓存方式?
persist方法或cache方法
cache其实也是调用了persist方法(存储级别 MEMORY_ONLY)

RDD的Checkpoint

作用:切断做checkpoint RDD的依赖关系,将RDD 数据保存到可靠存储(如支持分布式存储和副本机制的HDFS)以便数据恢复;(更加可靠的数据持久化)
为什么有了缓存还要有checkpoint?
缓存或磁盘都易丢失,分布式存储介质更安全,如HDFS

checkpoint原理机制

当RDD使用cache机制从内存中读取数据,如果数据没有读到,会使用checkpoint机制读取数据。此时如果没有checkpoint机制,那么就需要找到父RDD重新计算数据;使用checkpoint首先需要调用sparkContext的setCheckpointDir方法,设置一个容错文件系统目录;
之后在RDD所处的job运行结束后,会启动一个单独的job来将checkpoint过的数据写入之前设置的文件系统持久化,进行高可用。所以后面的计算在使用该RDD时,如果数据丢失了,但是还是可以从它的checkpoint中读取数据,不需要重新计算。

DAG是怎么形成的

触发Action,一旦触发Action就形成了一个完整的DAG
触发一个job形成一个DAG
DAG(Directed Acyclic Graph)叫做有向无环图,原始的RDD通过一系列的转换就形成了 DAG,根据RDD之间依赖关系的不同将DAG划分成不同的Stage(调度阶段)。
对于窄依赖, partition的转换处理在一个Stage中完成计算。对于宽依赖,由于有Shuffle的存在,只能在 parent RDD处理完成后,才能开始接下来的计算,因此宽依赖是划分Stage的依据。

为什么要划分Stage?

并行计算
一个复杂的业务逻辑如果有shuffle,那么就意味着前面阶段产生结果后,才能执行下一个阶段,即下一个阶段的计算要依赖上一个阶段的数据。那么我们按照shuffle进行划分(也就是按照宽依赖就行划分),就可以将一个DAG划分成多个Stage阶段,在同一个Stage中,会有多个算子操作,可以形成一个pipeline流水线,流水线内的多个平行的分区可以并行执行。

Spark中的stage划分方式

划分stage是为了并行计算
对于窄依赖,partition的转换处理在stage中完成计算,不划分(将窄依赖尽量放在在同一个stage中,可以实现流水线计算)
对于宽依赖,由于有shuffle的存在,只能在父RDD处理完成后,才能开始接下来的计算, 也就是说需要要划分stage

Spark的shuffle过程

在spark的stage划分当中,宽依赖之间会划分stage,而Stage之间就是Shuffle,在Spark的中,负责shuffle过程的执行、计算和处理的组件主要就是ShuffleManager,也即shuffle管理器。
ShuffleManager随着Spark的发展有两种实现的方式,分别为HashShuffleManager和SortShuffleManager,因此spark的Shuffle有Hash Shuffle和Sort Shuffle两种。HashShuffleManager有着一个非常严重的弊端,就是会产生大量的中间磁盘文件,进而由大量的磁盘IO操作影响了性能。
后面优化为SortShuffleManager,SortShuffleManager相较于HashShuffleManager来说,有了一定的改进。主要就在于,每个Task在进行shuffle操作时,虽然也会产生较多的临时磁盘文件,但是最后会将所有的临时文件合并(merge)成一个磁盘文件,因此每个Task就只有一个磁盘文件。在下一个stage的shuffle read task拉取自己的数据时,只要根据索引读取每个磁盘文件中的部分数据即可。
SortShuffle:
(1)该模式下,数据会先写入一个内存数据结构中(默认5M),此时根据不同的shuffle算子,可能选用不同的数据结构。
如果是reduceByKey这种聚合类的shuffle算子,那么会选用Map数据结构,一边通过Map进行聚合,一边写入内存;
如果是join这种普通的shuffle算子,那么会选用Array数据结构,直接写入内存。 
接着,每写一条数据进入内存数据结构之后,就会判断一下,是否达到了某个临界阈值。如果达到临界阈值的话,那么就会尝试将内存数据结构中的数据溢写到磁盘,然后清空内存数据结构。
(2)shuffle中的定时器:
定时器会检查内存数据结构的大小,如果内存数据结构空间不够,那么会申请额外的内存,申请的大小满足如下公式:
applyMemory=nowMenory * 2 - oldMemory
申请的内存=当前的数据内存情况 * 2 - 上一次的内存情况
意思就是说内存数据结构的大小的动态变化,如果存储的数据超出内存数据结构的大小,将申请内存数据结构存储的数据 * 2 - 内存数据结构的设定值的内存大小空间。申请到了,内存数据结构的大小变大,内存不够,申请不到,则发生溢写。
(3)排序
在溢写到磁盘文件之前,会先根据key对内存数据结构中已有的数据进行排序。
(4)溢写
排序过后,会分批将数据写入磁盘文件。默认的batch数量是10000条,也就是说,排序好的数据,会以每批1万条数据的形式分批写入磁盘文件。
写入磁盘文件是通过Java的BufferedOutputStream实现的。BufferedOutputStream是Java的缓冲输出流,首先会将数据缓冲在内存中,当内存缓冲满溢之后再一次写入磁盘文件中,这样可以减少磁盘IO次数,提升性能。
(5)merge
一个task将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,也就会产生多个临时文件。
最后会将之前所有的临时磁盘文件都进行合并,这就是merge过程,此时会将之前所有临时磁盘文件中的数据读取出来,然后依次写入最终的磁盘文件之中。
此外,由于一个task就只对应一个磁盘文件,也就意味着该task为Reduce端的stage的task准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个task的数据在文件中的start offset与end offset。
SortShuffleManager由于有一个磁盘文件merge的过程,因此大大减少了文件数量。比如第一个stage有50个task,总共有10个Executor,每个Executor执行5个task,而第二个stage有100个task。
由于每个task最终只有一个磁盘文件,因此此时每个Executor上只有5个磁盘文件,所有Executor只有50个磁盘文件。

spark在shuffle过程中,bypass机制与普通SortShuffleManager运行机制的不同在于:

第一,磁盘写机制不同;
第二,不会进行排序。
触发bypass机制的条件:
shuffle map task的数量小于spark.shuffle.sort.bypassMergeThreshold参数的值(默认200)或者不是聚合类的shuffle算子(比如groupByKey)

Spark的任务调度流程:

第一步:客户端提交jar包,提交一个application
第二步:根据提交的application以及rdd的依赖关系和血统lineage划分DAG
第三步:DAG送给DAGScheduler
第四步:DAGScheduler划分stage,划分taskSet
第五步:将taskSet送给taskScheduler
第六步:taskScheduler接收到taskSet
第七步:taskScheduler将接收到的taskset分解成为一个个的task,等待将task送给executor去执行
以上七部:都是Driver程序负责的职责,Driver程序一般都是运行在worker里面,使用cluster模式
第八步:将分解之后的task与executor进行通信,将task放到executor里面去执行

Spark的共享变量 使用场景 (在项目中)

广播变量:
	广播变量用来把变量在所有节点的内存之间进行共享,在每个机器上缓存一个只读的变 量,而不是为机器上的每个任务都生成一个副本;
举例:
累加器:
	累加器支持在所有不同节点之间进行累加计算(比如计数或者求和);

Spark 并行度

Spark作业中,各个stage的task数量,代表了Spark作业在各个阶段stage的并行度!
资源的并行度:由节点数(executor)和cpu数(core)决定的
数据的并行度:task的数据,partition大小
task的数目和很多因素有关,资源的总core数,spark.default.parallelism参数, spark.sql.shuffle.partitions参数,读取数据源的类型,shuffle方法的第二个参数,repartition 的数目等
Task数量,设置成Application总CPU Core数量的2~3倍

spark和hive如何整合

1.将hive-site.xml拷贝到spark安装路径conf目录
2.将mysql的连接驱动包拷贝到spark的jars目录下
3.测试连接
SparkSql整合hive就是获取hive表中的元数据信息,然后通过SparkSql来操作数据。

spark调优都做过哪些方面的

开发调优:
	1- 避免创建重复的rdd,多次就可以使用persist进行持久化
	2- 尽可能复用同一个rdd  如果rdd的血缘关系比较长,就可以checkpoint存储 
	3- 避免使用shuffle算子,因为shuffle算子比较耗时耗内存
	4- 使用高性能的算子
		使用reduceByKey|aggregateByKey替代groupByKey 
		使用mapPartitions替代map 
		使用foreachPartitions替代foreach
	5- 使用Kryo序列化类替代原生的Java序列化类,可以降低序列化后的空间 
	6- 使用空间占有率更低数据类型
资源调优:
	在spark-submit时,设置参数调优num-executors、executor-memory、executor-cores、driver-memory。参数调优:spark.default.parallelism、spark.storage.memoryFraction、spark.shuffle.memoryFraction
并行度调优:
资源的并行度:由节点数(executor)和CPU数(core)决定;数据的并行度:task数量和partition大小
数据倾斜调优

spark的数据倾斜

1.聚合源数据:按key来分组,将key对应的所有的values全部用一种特殊的格式拼接到一个字符串里面去,对key进行group,直接对key进行了聚合。那么也就意味着,每个key就只对应一条数据,就不需要执行shffule操作了,也就根本不可能导致数据倾斜。
你可能没有办法对每个key聚合出来一条数据。那么也可以做一个妥协,对每个key对应的数据,10万条。有好几个粒度,比如10万条里面包含了几个城市、几天、几个地区的数据,现在放粗粒度。直接就按照城市粒度,做一下聚合,几个城市,几天、几个地区粒度的数据,都给聚合起来。
2.过滤导致倾斜的key:业务和需求允许情况下,在hive查询源数据时直接过滤导致倾斜的key
3.提高shuffle操作reduce端并行度。在调用groupByKey、countByKey、reduceByKey传入进去适合的参数。(没有从根本上解决数据倾斜,缓解和减轻shuffle reduce task的数据压力,以及数据倾斜的问题)
4.使用随机key实现双重聚合。groupByKey、reduceByKey比较适合使用这种方式。先针对多个组,进行key的局部聚合。接着,再去除掉每个key的前缀,然后对所有的key进行全局的聚合。
5.将reduce join转换为map join。先将所有相同的key,对应的value汇聚到一个task中,然后再进行join。两个RDD(一大一小),将小的RDD广播(broadcast)出去,就不会shuffle了
6.sample采样倾斜key单独进行join。将发生数据倾斜的key,单独拉出来,放到一个RDD中去。就用这个原本会倾斜的key RDD跟其他RDD单独去join一下,这个时候key对应的数据可能就会分散到多个task中去进行join操作。(适用于一个key或者少数几个key对应的数据量特别多,也可以给这些key加上随机前缀)

spark中groupbykey和reducebykey的区别 shuffle区别

reduceByKey:按照key进行聚合,在shuffle之前有combine(预聚合)操作,返回结果是RDD[k,v]
groupByKey:按照key进行分组,直接进行shuffle

Spark shuffle与mr shuffle的区别

1.与MapReduce完全不一样的是,MapReduce它必须将所有的数据都写入本地磁盘文件以后,才能启动reduce操作,来拉取数据。为什么?因为mapreduce要实现默认的根据key的排序!所以要排序,肯定得写完所有数据,才能排序,然后reduce来拉取。
2.但是Spark不需要,spark默认情况下,是不会对数据进行排序的。因此ShuffleMapTask每写入一点数据,ResultTask就可以拉取一点数据,然后在本地执行我们定义的聚合函数和算子,进行计算。
3.spark这种机制的好处在于,速度比mapreduce快多了。但是也有一个问题,mapreduce提供的reduce,是可以处理每个key对应的value上的,很方便。但是spark中,由于这种实时拉取的机制,因此提供不了直接处理key对应的values的算子,
只能通过groupByKey,先shuffle,有一个MapPartitionsRDD,然后用map算子,来处理每个key对应的values。就没有mapreduce的计算模型那么方便。

spark sql底层如何解析、执行

SQL -> DF -> DS -> catalyst计划生成 -> RDD/DAG 物理计划 -> Resource/Scheduler Manager调度 -> Tungsten底层优化器

SparkSQL中,catalyst优化器

Step 1 : 解析 SQL, 并且生成 AST (抽象语法树)
Step 2 : 在 AST 中加入元数据信息, 做这一步主要是为了一些优化
Step 3 : 对已经加入元数据的 AST, 输入优化器, 进行优化(谓词下推、列值裁剪)
Step 4 : 上面的过程生成的 AST 其实最终还没办法直接运行, 这个 AST 叫做逻辑计划, 结束后, 需要生成物理计划, 从而生成 RDD 来运行
Catalyst 的主要运作原理是分为三步, 先对 SQL 或者 Dataset 的代码解析, 生成逻辑计划, 后对逻辑计划进行优化, 再生成物理计划, 最后生成代码到集群中以 RDD 的形式运行
Catalyst执行策略:
  基于规则优化/Rule Based Optimizer/RBO;比如谓词下推、列值裁剪
  基于代价优化/Cost Based Optimizer/CBO;
Catalyst工作流程:
  SQL语句首先通过Parser模块被解析为语法树,此棵树称为Unresolved Logical Plan;
  Unresolved Logical Plan通过Analyzer模块借助于数据元数据解析为Logical Plan;
  此时再通过各种基于规则的Optimizer进行深入优化,得到Optimized Logical Plan;
  优化后的逻辑执行计划依然是逻辑的,需要将逻辑计划转化为Physical Plan。
Catalyst工作流程核心点:
  第一点、Parser,第三方类库ANTLR实现。将sql字符串切分成Token,根据语义规则解析成一颗AST语法树;
  第二点、Analyzer,Unresolved Logical Plan,进行数据类型绑定和函数绑定;
  第三点、Optimizer,规则优化就是模式匹配满足特定规则的节点等价转换为另一颗语法树;

Spark的窗口函数

sparkStreaming中的reduceByKeyAndWindow
切分批次:几秒一次
窗口大小(WindowInterval,每次统计数据范围)和滑动大小(每隔多久统计一次),都必须时批处理时间间隔BatchInterval整数倍。
滑动大小<窗口大小 数据会重复计算
滑动大小>窗口大小 数据会丢失
滑动大小=窗口大小 数据不会丢失且计算一次

Lambda架构?

高容错、低延时和可扩展
三层架构:
	批处理层(Batch Layer):负责数据的存储和产生随意的视图数据(批处理)
	速度层(Speed Layer):对更新到serving layer带来的高延迟的一种补充、快速、增量的算法和最终Batch Layer会覆盖speed layer。(实时处理)
	服务层(Serving Layer):负责建立索引和呈现视图,以便于它们可以被非常好被查询到(查询视图)

Spark Streaming的理解

将流式数据按照时间间隔BatchInterval划分为很多部分,每一部分Batch(批次),针对每批次数据Batch当做RDD进行快速分析和处理。

SparkStreaming具体流程

1.客户端提交作业后启动 Driver ,Driver是 spark作业的Master 。
2.每个作业包含多个Executor,每个Executor以线程的方式运行task,Spark Streaming至少包含一个 receiver task 。
3.Receiver 接收数据后生成Block,并把 BlockId 汇报给Driver,然后备份到另外一个Executor上。
4.ReceiverTracker 维护Reciver汇报的BlockId。
5.Driver定时启动 JobGenerator ,根据Dstream的关系生成逻辑RDD,然后创建Jobset,交给JobScheduler。
6.JobScheduler 负责调度Jobset,交给DAGScheduler,DAGScheduler根据逻辑RDD,生成相应的Stages,每个stage包含一到多个task。
7.TaskScheduler 负责把task调度到Executor上,并维护task的运行状态。
8.当tasks,stages,jobset完成后,单个batch才算完成。

Streaming 工作原理

按照时间间隔划分数据为微批次(Micro-Batch),每批次数据当做RDD,再进行处理分析
1.首先创建StreamingContext流式上下文实例对象,整个流式应用环境构建,底层还是SparkContext。
2.双流Join,可以从多个数据源端实时消费数据进行处理
3.接收器接收数据,启动每个接收器Receiver以后,实时从数据源端接收数据(比如TCP Socket),也是按照时间间隔将接收的流式数据划分为很多Block(块)。
4.汇报接收Block报告,接收器Receiver将实时汇报接收的数据对应的Block信息,当BatchInterval时间达到以后,StreamingContext将对应时间范围内数据block当做RDD,加载SparkContext处理数据。
	整个Streaming运行过程中,涉及到两个时间间隔:
		批次时间间隔:BatchInterval
		每批次数据的时间间隔,每隔多久加载一个Job;
		Block时间间隔:BlockInterval
		接收器划分流式数据的时间间隔,可以调整大小,官方建议最小值不能小于50ms;
		默认值为200ms,属性:spark.streaming.blockInterval,调整设置

Sparkstreaming读取kafka数据的两种方式,为什么选择直连方式

Receiver接收方式:
KafkaUtils.createDstream
Receiver作为常驻的Task运行在Executor等待数据,但是一个Receiver效率低,需要开启多个,再手动合并数据(union),再进行处理,很麻烦;Receiver那台机器挂了,可能会丢失数据,所以需要开启WAL(预写日志)保证数据安全,那么效率又会降低!
Receiver方式是通过zookeeper来连接kafka队列,调用Kafka高阶API,offset存储在zookeeper,由Receiver维护。spark在消费的时候为了保证数据不丢也会在Checkpoint中存一份offset,可能会出现数据不一致,所以不管从何种角度来说,Receiver模式都不适合在开发中使用了,已经淘汰了
Direct直连方式:
KafkaUtils.createDirectStream
Direct方式是直接连接kafka分区来获取数据,从每个分区直接读取数据大大提高了并行能力
Direct方式调用Kafka低阶API(底层API),offset自己存储和维护,默认由Spark维护在checkpoint中,消除了与zk不一致的情况
当然也可以自己手动维护,把offset存在mysql、redis中,所以基于Direct模式可以在开发中使用,且借助Direct模式的特点+手动操作可以保证数据的Exactly once 精准一次

SparkStreaming集成Kafka采用Direct方式消费数据,如下三个方面优势:

第一、简单的并行度(Simplified Parallelism)
	1.读取topics的总的分区数目 = 每批次RDD中分区数目;
	2.topic中每个分区数据 被读取到 RDD中每个分区进行处理
第二、高效(Efficiency)
	1.处理数据比使用Receiver接收数据高效很多
	2.使用Receiver接收数据的时候,要将数据存储到Executor、为了可靠性还需要将数据存储文件系统中WAL
第三、Exactly-once semantics
	1.能保证一次性语义,从Kafka消费数据仅仅被消费一次,不会重复消费或者不消费
	2.在Streaming数据处理分析中,需要考虑数据是否被处理及被处理次数,称为消费语义
		At most once:最多一次,比如从Kafka Topic读取数据最多消费一次,可能出现不消费,此时数据丢失;
		At least once:至少一次,比如从Kafka Topic读取数据至少消费一次,可能出现多次消费数据;
		Exactly once:精确一次,比如从Kafka topic读取数据当且仅当消费一次,不多不少,最好的状态

spark中foreach foreachparition foreachRDD的区别

作用范围不同:
foreachRDD作用于DStream中每一个时间间隔的RDD
foreachPartition作用于每一个时间间隔的RDD中的每一个partition
foreach作用于每一个时间间隔的RDD中的每一个元素

spark 如何容错,和flink 对比,如何?

血统lineage,缓存,检查点机制

Structured Streaming最核心的思想就是将实时到达的数据看作是一个不断追加的unbound table无界表,到达流的每个数据项就像是表中的一个新行被附加到无边界的表中,用静态结构化数据的批处理查询方式进行流计算。

Structured Streaming输出模式

追加模式(Append mode)
	默认模式,其中只有自从上一次触发以来,添加到 Result Table 的新行将会是outputted to the sink。只有添加到Result Table的行将永远不会改变那些查询才支持这一点。这种模式保证每行只能输出一次(假设 fault-tolerant sink )。
	例如,只有select, where, map, flatMap, filter, join等查询支持 Append mode。只输出那些将来永远不可能再更新的数据,然后数据从内存移除。没有聚合的时候,append和update一致;有聚合的时候,一定要有水印,才能使用。
完全模式(Complete mode)
	每次触发后,整个Result Table将被输出到sink,aggregation queries(聚合查询)支持。全部输出,必须有聚合。
更新模式(Update mode)
	只有 Result Table rows 自上次触发后更新将被输出到 sink。与Complete模式不同,因为该模式只输出自上次触发器以来已经改变的行。如果查询不包含聚合,那么等同于Append模式。只输出更新数据(更新和新增)。

StructuredStreaming集成 Kafka

Structured Streaming保证了端到端的 exactly-once,Structured Streaming消费Kafka数据,采用的是poll方式拉取数据
注意事项:
	注意以下Kafka参数属性可以不设置,如果设置的话,Kafka source或者sink可能会抛出错误:
		1)、group.id:Kafka source将会自动为每次查询创建唯一的分组ID;
		2)、auto.offset.reset:在将source选项startingOffsets设置为指定从哪里开始。结构化流管理内部消费的偏移量,而不是依赖Kafka消费者来完成。这将确保在topic/partitons动态订阅时不会遗漏任何数据。注意,只有在启动新的流式查询时才会应用startingOffsets,并且恢复操作始终会从查询停止的位置启动;
		3)、key.deserializer/value.deserializer:Keys/Values总是被反序列化为ByteArrayDeserializer的字节数组,使用DataFrame操作显式反序列化keys/values;
		4)、key.serializer/value.serializer:keys/values总是使用ByteArraySerializer或StringSerializer进行序列化,使用DataFrame操作将keysvalues/显示序列化为字符串或字节数组;
		5)、enable.auto.commit:Kafka source不提交任何offset;
		6)、interceptor.classes:Kafka source总是以字节数组的形式读取key和value。使用ConsumerInterceptor是不安全的,因为它可能会打断查询;

structuredStreaming时间窗口

在结构化流Structured Streaming中窗口数据统计时间是基于数据本身事件时间EventTime字段统计,更加合理性
在Streaming流式数据处理中,按照时间处理数据,其中时间有三种概念:
	1)事件时间EventTime,表示数据本身产生的时间,该字段在数据本身中;
	2)注入时间IngestionTime,表示数据到达流式系统时间,简而言之就是流式处理系统接收到数据的时间;
	3)处理时间ProcessingTime,表示数据被流式系统真正开始计算操作的时间。
基于事件时间窗口聚合操作:基于窗口的聚合(例如每分钟事件数)只是事件时间列上特殊类型的分组和聚合,其中每个时间窗口都是一个组,并且每一行可以属于多个窗口/组。
事件时间EventTime是嵌入到数据本身中的时间,数据实际真实产生的时间。

延迟数据处理:

2.1后提供水位,机制来设置和判断消息的有效性,如可以获取消息本身的时间戳,然后根据该时间戳来判断消息的到达是否延迟(乱序)以及延迟的时间是否在容忍的范围内(延迟的数据是否处理)。
Watermarking 水位:
通过指定event-time列(上一批次数据中EventTime最大值)和预估事件的延迟时间上限(Threshold)来定义一个查询的水位线watermark。
Watermark = MaxEventTime - Threshod
第一点:执行第一批次数据时,Watermarker为0,所以此批次中所有数据都参与计算;
第二点:Watermarker值只能逐渐增加,不能减少;
第三点:Watermark机制主要解决处理聚合延迟数据和减少内存中维护的聚合状态;
第四点:设置Watermark以后,输出模式OutputMode只能是Append和Update;
	设置水位线Watermark以后,不同输出模式OutputMode,结果输出不一样:
	Update模式:总是倾向于“尽可能早”的将处理结果更新到sink,当出现迟到数据时,早期的某个计算结果将会被更新;
	Append模式:推迟计算结果的输出到一个相对较晚的时刻,确保结果是稳定的,不会再被更新,比如:12:00 - 12:10窗口的处理结果会等到watermark更新到12:11之后才会写入到sink。
	如果用于接收处理结果的sink不支持更新操作,则只能选择Append模式。

Structured Streaming可以使用deduplication对有无Watermark的流式数据进行去重操作:

第一、无 Watermark:对重复记录到达的时间没有限制。查询会保留所有的过去记录作为状态用于去重;
第二、有 Watermark:对重复记录到达的时间有限制。查询会根据水印删除旧的状态数据;

StructuredStreaming 概述,作用

StructuredStreaming是吸取了在开发Spark SQL和Spark Streaming过程中的经验教训,以及社区和客户的反馈,重新开发的全新流式引擎,致力于为批处理和流处理提供统一的高性能API。
统一了流、批的编程模型,可以使用静态数据批处理一样的方式来编写流式计算操作,并且支持基于event_time的时间窗口的处理逻辑。
背后的主要模型是Micro Batch(微批处理),也就是将数据流切成等时间间隔(BatchInterval)的小批量任务来执行。重新设计的全新流式引擎。本质上,这是一种micro-batch(微批处理)的方式处理,用批的思想去处理流数据。

Structured Streaming连续处理

连续处理(Continuous Processing)是“真正”的流处理,之所以说“真正”是因为 continuous mode是传统的流处理模式,通过运行一个long-running的operator用来处理数据。continuous mode 处理模式只要一有数据可用就会进行处理
缺点是不容易做扩展,优点是延迟更低
从Spark 2.3开始,连续处理模式才出现,目前仅支持以下类型的查询:
	第一、数据源Sources:Kafka source(支持所有选项)及Rate source(仅仅适合测试)。
	第二、接收器Sinks:Kafka sink(支持所有选项)、Console sink(适合调试)。
	第三、DataFrame Operations操作:在连续模式下仅支持类似 map 的 Dataset/DataFrame 操作,即仅投影(select,map,flatMap,mapPartitions等)和选择(where,filter等)。
		连续处理引擎启动多个长时间运行的任务,这些任务不断从源中读取数据,处理数据并连续写入接收器。 查询所需的任务数取决于查询可以并行从源读取的分区数。 因此,在开始连续处理查询之前,必须确保群集中有足够的核数并行执行所有任务。

如何对task进行管理?调大\调小

从spark内存管理回答

spark的实例没有足够的资源执行job会导致什么情况发生?

首先job会执行,会导致执行该job时候集群资源不足,导致执行job结束也没有分配足够的资源,分配了部分Executor,该job就开始执行task,应该是task的调度线程和Executor资源申请是异步的;如果想等待申请完所有的资源再执行job的:需要将spark.scheduler.maxRegisteredResourcesWaitingTime设置的很大;spark.scheduler.minRegisteredResourcesRatio 设置为1,但是应该结合实际考虑否则很容易出现长时间分配不到资源,job一直不能运行的情况。

rdd跟dataframe和dataset的区别? 如何转化?

在项目中sparkJob 出现哪些bug 以及如何解决

Spark的有哪些api

sparkstreaming每批次处理数据有多少rdd及job生成,数据接收时间如何设定

sparkingstreaming整合kafka读取数据格式是什么形式,如何处理数据积压,什么是反压,反压机制需要默认开启吗,如何设置反压机制?

spark MLLIB哪些算法?如何使用

kafka

- 生产者分区写入策略
	生产者写入消息到topic,Kafka将依据不同的策略将数据分配到不同的分区中
		1.轮询分区策略(默认)
			可以最大限度保证所有消息平均分配到一个分区
			如果在生产消息时,key为null,则使用轮询算法均衡地分配分区
		2.随机分区策略
			每次都随机地将消息分配到每个分区
		3.按key分区分配策略
			按key分配策略,有可能会出现「数据倾斜」
		4.乱序问题
			轮询策略、随机策略都会导致一个问题,生产到Kafka中的数据是乱序存储的。
			而按key分区可以一定程度上实现数据有序存储——也就是局部有序,但这又可能会导致数据倾斜,所以在实际生产环境中要结合实际情况来做取舍。
		5.自定义分区策略

- 消费者组Rebalance机制
	1.Rebalance再均衡
		是Kafka中确保Consumer group下所有的consumer如何达成一致,分配订阅的topic的每个分区的机制。
		Rebalance触发的时机有:
			1.消费者组中consumer的个数发生变化。
			2.订阅的topic个数发生变化
			3.订阅的topic分区数发生变化
	2.Rebalance的不良影响
		发生Rebalance时,consumer group下的所有consumer都会协调在一起共同参与,Kafka使用分配策略尽可能达到最公平的分配
		Rebalance过程会对consumer group产生非常严重的影响,Rebalance的过程中所有的消费者都将停止工作,直到Rebalance完成

- 消费者分区分配策略
	1. Range范围分配策略(默认)
		确保每个消费者消费的分区数量是均衡的。
		注意:Rangle范围分配策略是针对每个Topic的。
	2. RoundRobin轮询策略
		将消费组内所有消费者以及消费者所订阅的所有topic的partition按照字典序排序(topic和分区的hashcode进行排序),然后通过轮询方式逐个将分区以此分配给每个消费者。
	3. Stricky粘性分配策略
		分区分配尽可能均匀
		在发生rebalance的时候,分区的分配尽可能与上一次分配保持相同
		注:没有发生rebalance时,Striky粘性分配策略和RoundRobin分配策略类似。
		Striky粘性分配策略,保留rebalance之前的分配结果。这样,只是将原先consumer2负责的两个分区再均匀分配给consumer0、consumer1。这样可以明显减少系统资源的浪费,

- 副本机制
	副本的目的就是冗余备份,当某个Broker上的分区数据丢失时,依然可以保障数据可用。因为在其他的Broker上的副本是可用的。
	ACK=0,不等待broker确认,直接发送下一条数据,性能最高,但存在数据丢失
	ACK=1,等待leader副本确认接受后,才会发送下一条数据,性能中等
	ACK=all/-1,等待所有副本将数据同步后,才会发送下一条数据,性能最慢

- 高级(High Level)API
	不需要执行去管理offset,直接通过ZK管理;也不需要管理分区、副本,由Kafka统一管理
	消费者会自动根据上一次在ZK中保存的offset去接着获取数据
	在ZK中,不同的消费者组(group)同一个topic记录不同的offset,这样不同程序读取同一个topic,不会受offset的影响
	缺点:
		不能控制offset,例如:想从指定的位置读取
		不能细化控制分区、副本、ZK等

- 低级API
	自己来控制offset,可以自己控制连接分区,对分区自定义负载均衡。使用低级API,我们可以将offset不一定要使用ZK存储,我们可以自己来存储offset。
	缺点:
		比较复杂,需要执行控制offset,连接到哪个分区,并找到分区的leader。

- 如何进行手动消费分区中的数据呢?
	1.不再使用之前的 subscribe 方法订阅主题,而使用 「assign」方法指定想要消费的消息
	2.一旦指定了分区,就可以就像前面的示例一样,在循环中调用「poll」方法消费消息
		注意:
			1.当手动管理消费分区时,即使GroupID是一样的,Kafka的组协调器都将不再起作用
			2.如果消费者失败,也将不再自动进行分区重新分配

- 分区的leader与follower
	1.Kafka中的leader负责处理读写操作,而follower只负责副本数据的同步
	2.如果leader出现故障,其他follower会被重新选举为leader
	3.follower像一个consumer一样,拉取leader对应分区的数据,并保存到日志数据文件中

- 谈一谈ISR、AR、OSR
	分区的所有副本称为 「AR」(Assigned Replicas——已分配的副本)
	所有与leader副本保持一定程度同步的副本(包括 leader 副本在内)组成 「ISR」(In-Sync Replicas——在同步中的副本)
	由于follower副本同步滞后过多的副本(不包括 leader 副本)组成 「OSR」(Out-of-Sync Replias)
	AR = ISR + OSR
	正常情况下,所有的follower副本都应该与leader副本保持同步,即AR = ISR,OSR集合为空。

- Kafka的Leader挂了,如何保证kafka提供正常的服务
	进行Leader选举,因为Kafka的吞吐量很高、延迟很低,所以选举leader必须非常快
	Controller介绍
		1.Kafka启动时,会在所有的broker中选择一个controller
		2.前面leader和follower是针对partition,而controller是针对broker的
		3.创建topic、或者添加分区、修改副本数量之类的管理任务都是由controller完成的
		4.Kafka分区leader的选举,也是由controller决定的
	Controller的选举
		1.在Kafka集群启动的时候,每个broker都会尝试去ZooKeeper上注册成为Controller(ZK临时节点)
		2.但只有一个竞争成功,其他的broker会注册该节点的监视器
		3.一点该临时节点状态发生变化,就可以进行相应的处理
		4.Controller也是高可用的,一旦某个broker崩溃,其他的broker会重新注册为Controller
	Controller选举partition leader
		1.所有Partition的leader选举都由controller决定
		2.controller会将leader的改变直接通过RPC的方式通知需为此作出响应的Broker
		3.controller读取到当前分区的ISR,只要有一个Replica还幸存,就选择其中一个作为leader否则,则任意选这个一个Replica作为leader
		4.如果该partition的所有Replica都已经宕机,则新的leader为-1
	为什么不能通过ZK的方式来选举partition的leader
		1.Kafka集群如果业务很多的情况下,会有很多的partition
		2.假设某个broker宕机,就会出现很多的partiton都需要重新选举leader
		3.如果使用zookeeper选举leader,会给zookeeper带来巨大的压力。所以,kafka中leader的选举不能使用ZK来实现

- leader负载均衡
	1.Preferred Replica
		Kafka中引入了一个叫做「preferred-replica」的概念,意思就是:优先的Replica
		在ISR列表中,第一个replica就是preferred-replica
		第一个分区存放的broker,肯定就是preferred-replica
	2.确保leader在broker中负载均衡
		杀掉test主题的某个broker,这样kafka会重新分配leader。等到Kafka重新分配leader之后,再次启动kafka进程。此时:观察test主题各个分区leader的分配情况。此时,会造成leader分配是不均匀的,所以可以执行以下脚本来重新分配leader:

- Kafka数据写入流程
	1.生产者先从 zookeeper 的 "/brokers/topics/主题名/partitions/分区名/state"节点找到该 partition 的leader
	2.生产者在ZK中找到该ID找到对应的broker
	3.broker进程上的leader将消息写入到本地log中(顺序写)
	4.follower从leader上拉取消息,写入到本地log(顺序写),并向leader发送ACK
	5.leader接收到所有的ISR中的Replica的ACK后,并向生产者返回ACK。

- Kafka数据消费流程
	1.两种消费模式
		kafka采用拉取模型,由消费者自己记录消费状态,每个消费者互相独立地顺序拉取每个分区的消息。
		消费者可以按照任意的顺序消费消息。比如,消费者可以重置到旧的偏移量,重新处理之前已经消费过的消息;或者直接跳到最近的位置,从当前的时刻开始消费。
	2.Kafka消费数据流程
		1.每个consumer都可以根据分配策略(默认RangeAssignor),获得要消费的分区
		2.获取到consumer对应的offset(默认从ZK中获取上一次消费的offset)
		3.找到该分区的leader,拉取数据
		4.消费者提交offset

- Kafka的数据存储形式
	一个topic由多个分区组成
		一个分区(partition)由多个segment(段)组成
		一个segment(段)由多个文件组成(log、index、timeindex)

- Kafak的数据重复问题
	解决数据重复消费,Exactly-Once:仅有一次(事务性的保障,保障消息有且仅被处理一次)

- Kafka幂等性  负载均衡   为什么能实现海量吞吐
	幂等性原理
		为了实现生产者的幂等性,Kafka引入了 Producer ID(PID)和 Sequence Number的概念。
		PID:每个Producer在初始化时,都会分配一个唯一的PID,这个PID对用户来说,是透明的。
		Sequence Number:针对每个生产者(对应PID)发送到指定主题分区的消息都对应一个从0开始递增的Sequence Number。

- Kafka数据丢失总结
	1.怎么发现数据丢失
		如果是开发或者测试环境,此种情况下,我们知道数据源有多少条数据,此时可以根据处理结果数据量来判断是否出现数据丢失.
		如果是生产环境,可以从两方面入手,
			一是查看每日业务分析结果是否符合正常走向,比如节假日的 订单数应该比工作日要高;
			二是监控源数据数据量和消费端数据量
	2.如果出现数据丢失,怎么判断是那一部分丢失的
		Kafka数据丢失可能出现在生产者 broker(概率最低)和消费端 
		换一个消费者组重新消费,看结果是否变化,这样可以判断是否是消费端数据丢失
	3.Kafka出现数据丢失原因,以及对应改善
		3.1 消费端 consumer
			`当消费模式是at most once时,可能会出现数据丢失
			此时需要关闭offset自动提交
			在消费者消费数据的时候,只要每个消费者记录好offset值即可,就能保证数据不丢失。保证确保消息只被处理一次处理,同时确保幂等性
		3.2 生产端 producer
			生产者连接leader写入数据时,可以通过ACK机制(设置为-1或all)来确保数据已经成功写入
			`当网络负载很高或者磁盘很忙时,可能会出现写入失败的情况,配置retries大于0
			此时可以配置以下参数来优化:
				props.put("acks", "all");
					提高ack级别,默认级别是1 
						0级别:表示生产端只写入数据,不验证数据是否写入成功 
						1级别:会检验数据是否成功写入leader,是否写入副本不管
						-1(all)级别:会校验数据是否成功写入所有的副本
				props.put("compression.type", "gzip"); 设置压缩方式,减少存储量
				props.put("linger.ms", "50"); 设置生产端写入数据的间隔时间,默认连续写入,这样可以缓解Kafka的负载
				props.put("retries ", 30); 设置写入失败后的重试次数,默认为0,有时因为网络波动导致写入失败
				props.put("reconnect.backoff.ms ", 20000); 设置生产端和Kafka重连间隔的时间,默认是50ms,比较短,解决网络波动影响
				props.put("retry.backoff.ms", 20000); 设置生产端重新写入时间隔,默认也是50ms
		3.3 broker端 
			当设置副本数后,如果ack级别设置为all,此时一般broker端一般不会出现数据丢失
			生产者通过分区的leader写入数据后,所有在ISR中follower都会从leader中复制数据,这样,可以确保即使leader崩溃了,其他的follower的数据仍然是可用的

- 数据积压
	1.数据写入MySQL失败,由于数据写入到MySQL中报错,导致消费分区的offset一直没有提交,所以数据积压严重。
	2.网络延迟消费失败,因为当天网络抖动,通过查看Kafka的消费者超时配置为50ms,随后,将消费的时间修改为500ms后问题解决。

- kafka的message数据格式是什么形式,对于消息的key主要用处是什么?如何结合key实现分区?如果key为null如何排序?

- Kafka监控工具Kafka-eagle

- Kafka的调优

- Kafka的数据积压的问题

- Kafka为什么快

- 如何保证Kafka精准消费方式有几种

- 项目中数据是怎么到kafka的

- 如何设置kafka的偏移量 具体步骤  干了什么

- 你们项目里用到了kafka,说一说它的作用

- 项目中的Kafka怎么设计的
- 有用过命令使用kafka吗?
- 用什么工具查看kafka中的数据结够?
	kafkaTool
- 项目中存储在kafka中的数据格式?
- kafka的内部机制

hdoop

- hdfs读写流程
	读流程:
		1. client向NameNode发起RPC请求,来确认请求文件block所在位置
		2. NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode都会返回含有该block副本的DataNode地址,这些返回的DN地址会按照集群拓扑结构得出DN与客户端距离,然后排序,排序两个规则:网络拓扑结构距离Client近的排靠前,心跳机制中超时汇报的、DN状态为STALE的排靠后
		3. Client选取排序靠前的DN来读取block,如果客户端本身就是DN,那么将本地直接获取数据(短路读取特性)
		4. 底层本质建立Socket Stream(FSDataInputStream),重复调用父类DataInputStream的read方法,直到这个块上的数据读取完毕
		5. 当读完列表的block后,若文件读取还没结束,客户端会继续向NN获取下一批block列表
		6. 读取完一个block都会进行CheckSum验证,如果读取DataNode时出现错误,客户端会通知NameNode,然后从下一个拥有该block副本的DN继续读取。
		7. Read方法是并行读取block信息的,不是一块一块读取的,NameNode只是返回client请求包含块的DN地址,并不是返回请求块的数据。
		8. 最终读取来的所有block会合并成一个完整的最终文件。
	写流程:
		1. Client发起文件上传请求,通过RPC与NameNode建立通讯,NN检查目标文件是否存在、父目录是否存在且客户端是否有上传权限,返回是否可以上传。
		2. Client接收到可以上传后,请求上传第一个Block到哪些DataNode服务器上。
		3. NameNode根据配置文件中指定的备份数量以及机架感知原理进行文件分配,返回可用的DataNode地址给Client,如:A、B、C
		4. Client请求NameNode返回可用DN地址中的一台(A)上传数据(本质是一个RPC调用,简历pipeline),A收到请求后会继续调用B,然后B调用C,将整个Pipeline建立完成,然后逐级返回client
		5. Client开始向A上传第一个block(先将磁盘读取数据放到一个本地内存缓存),以packet为单位(默认64K),A收到packet就会传输给B,B传给C,A每传一个packet会放入一个应答队列等待应答。
		6. 数据被分割成一个个packet数据包在pipeline上依次传输,在pipeline反方向上,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipelineack发送给Client
		7. 当第一个block传输完成后,client再次请求NameNode上传第二个block

- block块的划分 设置

- MR 编写八个步骤
	读取文件解析成(key,value),代指(k1,v1)
	执行自定义map逻辑,将(k1,v1)-转换为(k2,v2)输出
	分区 相同key(即k2)的数据发送到同一个reduce里面去,形成一个集合
	排序 对数据进行字典排序
	规约 在map端对对数据进行一次聚合,减少输出的k2数量
	分组 将相同的数据发送到同一组里面
	自定义reduce逻辑,接受(k2,v2)转换成(k3.v3)进行输出
	输出

- mr的优化
	1. 数据输入阶段
		在执行MR任务前,将小文件进行合并,大量的小文件会产生大量的map任务,增加map任务装载的次数,而任务的装载比较耗时,从而导致MR运行速度比较慢。有大量小文件时,我们常采用combineTextInputFormat来作为输入,解决输入端大量小文件场景。
	2. Map阶段
		a) 减少溢写(spill)次数:通过调整io.sort.mb及sort.spill.percent参数值,增大触发spill的内存上限,减少spill次数,从而减少磁盘IO。
		b) 减少合并(merge)次数:通过调整io.sort.factor参数,增大merge的文件数目,减少merge的次数,从而缩短mr处理时间。
		c) 在map之后,不影响业务逻辑前提下,先进性combiner处理,减少IO。
	3. Reduce阶段
		a) 合理设置map和reduce数:两个都不能设置太少,也不能设置太多。太少,会导致task等待,延长处理时间;太多,会导致map、reduce任务间竞争资源,造成处理超时等错误。
		b) 设置map、reduce共存:调整slowstart.completedmaps参数,使map运行到一定程度后,reduce也开始运行,减少reduce的等待时间。
		c) 规避使用reduce:因为reduce在用于连接数据集的时候将会产生大量的网络消耗。通过将MapReduce参数setNumReduceTasks设置为0来创建一个只有map的作业。
		d) 合理设置reduce端的buffer:默认情况下,数据达到一个阈值的时候,buffer中的数据就会写到磁盘,然后reduce会从磁盘中获得所有的数据。也就是说,buffer和reduce是没有直接关联的,中间多了一个写磁盘->读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得buffer中的数据可以直接传输到reduce,从而减少IO开销。这样一来,设置buffer需要内存,读取数据需要内存,reduce计算也需要内存,所以要根据作业的运行情况进行调整。
	4. Shuffle阶段
		给shuffle过程尽量多的提供内存空间,以防出现内存溢出现象,可以由参数mapred.child.java.opts来设置,任务节点上的内存大小应尽量大。
	5. 其它调优属性
		MapReduce还有一些基本的资源属性的配置,这些配置的相关参数都位于mapred-default.xml文件中,我们可以合理配置这些属性提高MapReduce性能。

- MR的运行原理说一下

- MR的执行流程中,并说一些过程中进行了几次排序

- Shuffle过程为啥需要三次排序

- yarn调度原理

- yarn client和yarn cluster的区别?

- 小文件的处理
	archive归档
	使用CombineFileInputFormat
	文件存储格式使用Sequencefile

- Yarn的调度的方式有哪些
	在yarn中有三种调度器可以选择:FIFO Scheduler、capacity scheduler、fair scheduler
	1. FIFO Scheduler
		把应用按提交的顺序排成一个队列,这是一个先进先出的队列,在进行资源分配的时候,先给队列中最上面的应用分配资源,待上面的应用需求满足后再给下一个分配。
	2. Capacity Scheduler
		的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用先进先出(FIFO)策略。
		a. 支持多个队列,每个队列可配置一定资源,每个队列采用FIFO调度策略
		b. 为了防止同一个用户作业独占队列中的资源,该调度器会对同一个用户提交的作业所占资源量进行限定
		c. 首先,计算每个队列中正在运行的任务数与其应该分得的计算资源之间的比值,选择一个该比值最小的队列—最闲的
		d. 其次,按照作业优先级和提交时间顺序,同时考虑用户资源量限制和内存限制队列内任务排序
		e. 三个队列同时按照任务的先后顺序异常执行,比如,job1、job2,、job3分别在队列最前面,先运行,也是并行运行
	3. Fair Scheduler
		在fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源,当第二个小任务提交后,Fair调度器会分配一般的资源给这个小任务,让这两个任务公平的共享集群资源。
	需要注意的是,Fair调度器,从第二个任务提交到获取资源会有一定的延迟,因为它需要等待第一个任务释放占用的container。小任务执行完成后也会释放自己占有的资源。最终效果就是Fair调度器即得到了高的资源利用率又能保证小的任务及时完成。

- Hadoop的shuffle过程
	1. Collect阶段:将MapTask的结果输出到默认大小为100M的环形缓冲区,保存K、V、partition分区信息等
	2. Spill阶段:当内存中的数据量达到一定阈值的时候,就会将数据写入到本地磁盘,再将数据写入磁盘之前需要将数据进行一次排序的操作,如果配置了combiner,还会降有相同分区号和Key的数据进行排序。
	3. Merge阶段:把所有溢写出的临时文件进行一次合并操作,以确保一个MapTask最终只产生一个中间数据文件。
	4. Copy阶段:ReduceTask启动Fetcher线程到已经完成MapTask的节点上复制一份属于自己的数据,这些数据默认保存在内存的缓冲区中,当内存的缓冲区达到一定阈值的时候,就会将数据写到磁盘上
	5. 在ReduceTask远程复制数据的同时,会在后台开启两个线程对内存到本地的数据文件进行合并操作。
	6. Sort阶段:在对数据进行合并的同时,会进行排序操作,由于MapTask阶段已经对数据进行局部的排序,ReduceTask只需保证copy的数据的最终整体有效性即可。

- Hadoop集群的底层通信原理
	一、RPC(Remote Procedure Call  ) :远程过程调用
		1、RPC是远程过程调用协议,实现调用者和被调用者二地之间的连接和通信。其基本通信模型是基于client/server进程间相互通信模型
		2、利用HADOOP的RPC框架实现Server和Client远程通信
	二、动态代理

- Map任务失败了 如何处理

面试题

Sqoop
- 空值的问题
- 数据不一致性问题
- 数据倾斜的问题
- sqoop怎么增量导入数据
- sqoop导出100G的数据需要多久?
# spark跟sqoop 的调优主要做了哪些事情?
# sqoop的原理和工作机制? 
# sqoop程序的调优, 参数设置? 
# sqoop数据倾斜用row_num不会导致性能下降吗? 
	两害相权取其轻嘛. 性能下降没办法, 总体性能会比之前要好.
Flume
- flume 数据断点续传
Scala
- Scala的api 有哪些
- Scala的闭包
- Scala的逆变及协变及柯里化

mysql
MYSQL索引分为哪几种
Mysql事务隔离级别
Mysql的优化
# count(1),count(字段),count(*)有啥区别
关系型数据库之间的关系有哪些
	 一对一:表和表之间相同字段的连接
	 一对多:表和表之间通过外键连接
	 多对多:需要一个中间表来连接
关系型数据库的索引的数据结构
	 Hash树
	 二叉查找树
	 B tree
	 B+ tree

其它
项目架构

项目流程

项目职责

项目周期 项目人员 项目人员配置

传统数据开发和大数据开发有什么区别
说说你理解的大数据?
实时项目的数据延迟多高?
实时项目的数据量多大?
oozie调度原理
- 你们这些项目,数据量大概是多少
Redis的应用场景及数据结构

求重复数据的sql

工具的任务调度 
- Tez 和spark , impala 作为hive的执行引擎  请你选择哪个  请讲明理由

- 数据突然增多  是什么原因  数据突然减少  是什么原因   如何知道丢失数据

- 数据量 集群规模

Impala和kylin, druid ,clickhouse的区别

sql风格dsl风格,写过最难的sql是什么

标签如何做调度,哪些参数?多久调度一次?

用户画像数据量有多少?

画像标签映射谁来定?

多态在内存中的位置

linux中的最大进程数,
	 主进程<253
	 辅助进程+主进程 <=255
	 通过ps -ef | wc -l查看进程

数组和链表有什么区别

二叉树的时间复杂度是多少 

常用的业务型数据库有哪些?
怎么看执行计划
之前的数据量大概多大
之前项目中遇到了哪些问题,怎么解决的。
HashMap1.7和hashmap1.8的区别

平安智慧企业-大数据开发(数据团队)初试和复试:
初试主要问了spark,mr等内容, 印象较深的是使用过哪些map join的算子(reduceByKey/aggregateByKey)? 使用过哪些hive的时间函数(date_format, date_sub,date_add,next_day)? spark shuffle跟mr的shuffule区别?

复试:
# udf是怎么写的? 是全局的吗? 
# 清洗规范讨论, 主要指的哪些? 
# 有哪些数据倾斜的情况? 如何解决?
# 数据倾斜: id数据格式统一转换成int的目的是什么? 为什么这样比较快? 有没有做过测试? 
# 刚刚说的是reduce端的数据倾斜, map端的数据倾斜呢? 如果是已经合并过的文件,如何还有map端倾斜如何解决? 
# ck的特性? 出于什么原因要用它? 
# 实时做过什么项目? 如何保证kafka的数据不丢失不重复?
# 实时有没有跟批量结合, 建立容错机制? 
# 有没有用过pg数据库? gauss跟greenplum有什么区别? 
# 数仓建立在hive上? gauss干啥的?

软通动力:(35分钟)
# 自我介绍
# 项目介绍,(将熟悉的项目)
# 数据量,单表最大数据量多大?数据多少条?
# 项目中你负责哪一块
# 你做过哪些指标,具体说几个,(除了订单量,订单金额方面的指标,其他指标有哪些)
# 单表数据量那么大的情况下,开发的时候有没有遇到过性能瓶颈?
# 数据倾斜出现的场景和处理措施
# 除了这个,除了键值类型的数据倾斜还遇到过其他的数据倾斜吗?
# 你们开发方面怎么去保证数据质量?开发的指标和模型怎么验证?
# 你了解mapjoin吗?
# 业务中怎么取两天前的数据?(主要是get到他说的主要是想问你用什么函数?)
# 取id字段为301开头的方式?
# 了解like和alike的区别吗?
# 怎么分组拿top5?

平安外包-- 电话面试

问题如下:
1.平常用使用的编程语言是什么?
回答:Java和Scala

2离线计算框架用的是是什么语言?flink有没有接触?
回答:离线框架使用的是hive和Spark,Flink没有用过,但后期有计划自主学习

3.spark的driver的功能是什么?
Spark的任务调度流程:
第一步:客户端提交jar包,提交一个application
第二步:根据提交的application以及rdd的依赖关系和血统lineage划分DAG
第三步:DAG送给DAGScheduler
第四步:DAGScheduler划分stage,划分taskSet
第五步:将taskSet送给taskScheduler
第六步:taskScheduler接收到taskSet
第七步:taskScheduler将接收到的taskset分解成为一个个的task,等待将task送给executor去执行
以上七部:都是Driver程序负责的职责,Driver程序一般都是运行在worker里面,使用cluster模式
第八步:将分解之后的task与executor进行通信,将task放到executor里面去执行

4.如何对task进行管理?调大\调小
回答:task的划分是由每个stage的分区数量来划分的,因此控制读取数据源的分区数量设置并行度可以简介估算出task数量
面试官:我问的是如何管理task?
回答:task管理可以在Spark web UI上监测到,具体的task执行状况
面试官:我问的不是这个,我的意思是你们程序里是怎么样调整task大小的?
回答:我不会!

5.spark的实例没有足够的资源job执行会导致什么情况发生?
回答:有可能导致内存溢出(瞎说的)
面试官:还有么?
回答:暂时想不到了

6.平常使用中groupbykey要比reducebykey更好一些,你能说一下groupbykey与reducebykey的区别?
回答:实际上使用中reducebykey要比groupbykey好一些,因为reducebykey底层会有预聚合的过程
回来看了讲义再总结的答案:
1.reducebykey是指分组后进行reduc函数操作,group只是进行分组操作
2.ruducebykey的分组是会在map端预聚合,groupbykey因为是存粹进行分组所有不会有预聚合的操作,因此当gropbykey+map()能实现和reducrbykey一样的效果,但是确没有预聚合的优点

7.spark的shuffle过程能讲一下么?
回答:shuffle有两个过程一个是前一个task shuffle write,一个是后一个task shuffle read.
前一个task会将数据shuffle write 到内存中并进行排序,然后溢写成小文件,形成小文件过多后就会进行小文件合并,最终合并成两个大文件,一 个是数据文件,一个是索引文件.后一个task再重文件中读取数据
查看讲义:
在spark的stage划分当中,宽依赖之间会划分stage,而Stage之间就是Shuffle,如图中的stage0,stage1和stage3之间就会产生Shuffle
在Spark的中,负责shuffle过程的执行、计算和处理的组件主要就是ShuffleManager,也即shuffle管理器。ShuffleManager随着Spark的发 展有两种实现的方式,分别为HashShuffleManager和SortShuffleManager,因此spark的Shuffle有Hash Shuffle和Sort Shuffle两种。
Hash Shuffle和Sort Shuffle的过程略.........

8.那你们程序中溢写的阀值设置多少?
回答:128M(瞎说的)

9.为什么是128M?
回答:系统默认值就是128M,除了一些特殊场景一般系统默认值都是比较优化的(瞎说的)

讲义参考:
spark.shuffle.file.buffer
参数说明:该参数用于设置shuffle write task的BufferedOutputStream的buffer缓冲大小(默认是32K)。将数据写到磁盘文件之前,会先写入buffer缓冲中,待缓冲写满之后,才会溢写到磁盘。
调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如64k),从而减少shuffle write过程中溢写磁盘文件的次数,也就可以减少磁盘IO次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。

10.说一下scala特质是什么?
回答:特质和java接口功能上是一样的,只是特质的接入比java接口灵活一些
讲义:
cala中没有Java中的接口(interface),替代的概念是——特质
trait  定义:
l  特质是scala中代码复用的基础单元
l  它可以将方法和字段定义封装起来,然后添加到类中
l  与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。
l  特质的定义和抽象类的定义很像,但它是使用trait关键字


11.scala中伴生类和伴生对象了解吗?
回答:伴生对象和java中的静太类似,编写程序过程中常用伴生对象,这样可以直接类名调用成员,编写代码会简洁一些

深圳数澜科技(初试40分钟,电话面)
1,项目介绍,负责的模块,技术
2,hive中的数据来自那几个业务系统的数据库
3,数据量,每天的数据量,整体的数据量(离职的时候存储了多大的数据),服务器多少台,配置是什么样的(记得和之前问的数据来自那几个业务系统的数据库对应,有点翻车了)
4,hive分层设计
5,hive的模型设计
6,随便说下几个维度表
7,为什么采用星型模型
8,说下yarn的资源调度,如果任务出问题了怎么去看,如果19888端口不能访问是什么原因。
9,任务调度使用过什么工具,为什么使用这样类型的(他们公司是自研的工具)
10,rdd,df,ds
11,hbase的内部架构,rowkey设计
12,hbase的分裂,预分区
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

erainm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值