大数据面试题整理

1.当用户请求删除一条记录时,hbase为什么不直接删除,而是打上一个删除的标记?

因为hbase的数据通常是保存在HDFS上,而hdfs只允许新增或者追加数据文件,
如果要删除的话要对整个文件进行替换,所以删除操作主要是对删除的数据打上标记.
具体操作:	
当多个storefile进行major_compact全局合并时,就会真正对那些打标记的数据进行删除。
并生成对应的hfile文件。

2. spark执行过程中的stage是如何划分的?

		**stage是根据宽窄依赖将一个spark根据宽窄依赖将一个spark job划分为不同的stage。而宽依赖就是划分的标准,**
		宽依赖:rdd中的partition中的数据依赖父rdd中的所有的partition.(多对一)遇到一个宽依赖就会从中一切为二,划分为两个stage。
	stage分为两种:resultstage和shufflemapstage两种,sparkjob 最后产生的stage为resultstage,中间阶段产生的stage为shufflemapstage。 
	过程:
	dag scheduler 实现spark作业分解成多个stage,每个stage根据partition的个数划分task的个数,
	Task scheduler 主要是将dag scheduler划分的stage(以task形式)分发到Executor执行,通过多个task实现并行运行的功能

3, sparkstreaming数据写入mysql用的什么算子?为什么不用mappartition?

使用foreachpartition
因为map操作不会进行数据计算,只有在actions算子的操作才会进行真正的计算。
代码:
		wordcounts.foreachRDD(rdd => rdd.foreachPartition(line => {
  		   		 Class.forName("com.mysql.jdbc.Driver")
   		   //获取mysql连接
   				   val conn = DriverManager.getConnection("jdbc:mysql://master:3306/test", "root", "123456")
    	  //把数据写入mysql
      try {
        for (row <- line) {
          val sql = "insert into wordcount(titleName,count)values('" + row._1 + "','" + row._2 + "')"
          conn.prepareStatement(sql).executeUpdate()
        }
      } finally {
        conn.close()
      }
    })) 
    ssc.start()
    ssc.awaitTermination()
}

4, spark如何和kafka对接 ?

						spark-steaming-kafka-0.8版本
有两种连接方式:
   		Receiver    和 Direct方法
 Receiver创建:
  			 kafkautils.createstream(ssc,zookeeper,groupId,topics);
  			 需要单独一个线程来接受数据,上面的方式只会从最新的位置开始消费;
   
Driver创建:
			kafkautils.createDirectstream(ssc,kafkaparams,topics)	
			val kafkaparams = map(string,string){键值对类型的参数}
			Receiver方式

该方式只能为0-8版本到之后可以使用,到0-10版本就不好使了
构造函数中的numThreads参数,对应提高sparkstreaming的并行度并没有关系,提高只有kafka的分区数才能提高并行度,增加读写速度
这种情况可能会出现数据丢失问题,在driver端挂掉,Executor重启的时候必然会丢数据,在1.2时增加了一个Write Ahead Logs的机制(在写到Receiver时,写到一个日志中,通常为HDFS),这个机制可以避免数据丢失,但是写到HDFS或者文件系统必然会降低吞吐量。同时启动Write Ahead Logs时,存储结构设置为StorageLevel.MEMORY_AND_DISK_SER,不需要多副本,因为HDFS就是多副本机制
由于应用WAL,所以语义为至少一次
Direct Approach方式
1.没有Recevier,没有Recevier,没有Recevier,重要的事情说三遍 
2.简化并行度:不需要指定numThreads的参数,RDD的分区直接与kafka的分区相等,提高并行度,加大分区。 
3.零数据丢失,吞吐量更好,直接从kafka分区读取 
4.当offset(偏移量)还没有写入kafka,driver就挂了,可能会导致重复写入,也就是会产生至少一次的语义。可以把偏移				量交给sparkStreaming的checkpoint来维护,这样就会达到只有一次的效果。 

5,长时间运行发生oom后如何解决?如何定位到出错是由内存泄露引起的?

  			1.Java堆出现内存溢出异常有两种解决方案。一种是基于内存调整来改变堆区内存大小以便能够存储更多的对象,
  			 但堆内存受到物理内存的限制,当出现无法再扩展堆内存的情况时,
	   		就采用第二种方式,从代码上检查是否存在某些对象的生命周期过长、
  			 持有状态时间过长的情况,尝试减少程序在运行期的内存消耗。
   
   StackLeak()的递归调用使该线程不断地去创建一个栈帧存入该线程的虚拟机栈中,
   最终导致栈满溢出出现StackOverflowError异常。解决StackOverflowError异常的方法同样有从内存大小和Java程序两个方面来解决问题。
   从内存大小上,增加每个线程的虚拟机栈大小,这种方式虽然简便,但在多线程的情况下,随着每个线程所属的虚拟机栈的大小的增加,
   所能执行的线程也就随之减少了,但我们使用这种方式来解决StackOverflowError异常时,通常要权衡这两个反比因素。
   从Java程序上无疑就是检查是否出现方法的不合理递归调用,从而减少栈帧的创建和及时的回收。

6, 列举Linux中查看系统性能的工具(区分CPU、内存、磁盘、网络等)?

			Top命令用于按一定的顺序显示所有正在运行而且处于活动状态的实时进程
			Iotop-监控Linux磁盘I/O
			Netstat-网络状态统计    -ntlp

7. kafka数据丢失怎么解决

	1.定位丢失数据的环节,换个消费group重新消费,若多次消费结果一致,则为producer端丢失数据;若多次消费结果不一致,则为consumer端丢失数据
	kafka丢失数据的原因:
		1.auto.commit.enable = true;当consumer fetch 数据但没有完全处理的时候,刚好到commit interval 触发了提交offset操作,接着consumer 当掉,
				这时fetch的数据没处理完但已经被commit掉,因此没机会再次被处理,数据丢失
		2.网络负载很高或磁盘很忙写入失败,没有自动重试重发消息,没做限速处理,超出了网络带宽限速。kafka一定要配置消息重试机制,重试时间间隔要大于1秒(网络中断时间可能超过1秒)
		3.磁盘坏掉
		4.单批数据长度超过限制,报kafka.common.messagesizetoolargerExecption异常
				Consumer side:fetch.message.max.bytes 客户端抓取每条消息的最大长度
				B	roker side:replica.fetch.max.bytes 消息副本的最大长度
				Broker side:message.max.bytes 接收到producer端消息的最大长度
				Broker side (per topic):max.message.bytes  每条消息的最大长度
		5.leader在未完成副本数follows的备份时就当机,即使选举出新的leader但已经Push的数据因为没备份丢失
		6.kafka的数据一开始存储在pageCache,定期flush到磁盘,如果出现断电数据丢失
				log.flush.interval.message(默认10000)和log.flush.interval.ms(默认3000ms)配置flush间隔"

8.Hdfs的写数据流程和读数据流程?

写:

(1).client向namenode发送文件上传请求;
(2).namenode检查父目录是否存在,以及上传数据是否存在,是否有上传权限,没问题就给客户端发送响应;
(3).接收到响应后,正式向namenode发送文件信息;
(4).namenode根据客户端与机架服务器的位置来分配副本的存放位置,并把副本信息返回给client;
(5).client将文件切分成多个block块,每个块的默认大小为128M,向namenode请求上传第一个block,
(6).namnode检测data的信息,并指定block需要上传到那些节点。	
(7).客户端就近与一台datanode建立连接通道,开始向连接的datanode写入block信息,以packet为单位每秒64k的速度来传递信息,并与各个副本直接建立传输通道,一个block写完开始向副本节点复制块信息;
(8),datanode向namenode发送block的信息,当第一个block向第一个节点写入完成时,namenode就会认为数据上传成功,开始上传第二个block信息
(9),.所有数据块上传成功,给namenode响应;namenode修改元数据信息		
		
读:

1.客户端向namenode发送文件下载的请求;
2.namenode会检查文件是否存在,是否有权限,没问题后开始查询元数据库,返回对应的块以及块存储位置给客户端;
3.客户端拿到数据块存储信息,开始第一个数据块的下载,就近原则,若失败则重试,再失败选择其他节点副本;
4.第一个数据块下载完后,进行crc校验,通过,则下载成功;
5.下载第二个块,重复4,进行文件追加;
6.所有数据块下载成功后,向namanode反馈

9. yarn支持的调度器与 硬件资源种类 ?

	1.resourcemanager     是由   ASM应用程序的管理者,和scheduler调度器组成,
			scheduler    :决定每个应用程序的执行顺序。   
			三种调度器:
							FIFO:按照程序的先后顺序执行
							FAIR:  公平调度器,所有的job评分资源,
							carpacity: 根据计算能力的调度器,按照资源组划分,手动配置资源,
	2.YARN支持内存和CPU两种资源类型的管理和分配

10,udf、udaf、udtf的区别

			udf:用户自定义函数(一对一)
			udaf:用户自定义聚合函数(一对多)
			udtf:用户自定义表函数(多对一)	

11.HBase中rowkey的设计原则?

			不宜过长:内存和磁盘都会存储数据,会消耗性能,
			唯一性,每一列都存储的是不同的属性,如果rowkey相同,会放在一起,形成不同的版本;
			散列性;不要过于集中,保持数据不会过于集中在一个region中,减少数据热点问题
	方式:	
			3.加盐:rowkey前面增加随机数,分散到不同RegionServer,增加吞吐量,读时有额外代价
			4.哈希:同一个rowkey用同一个前缀加盐,负载均衡
			5.反转:反转固定长度的rowkey,经常变化(最没有意义)放前面,有效随机rowkey,牺牲有序性

12. HBase如何实现海量数据的存储写入

	1.put()一条一条的导入,效率低		
	2种是mapreduce的方式来进行写入
	3种是bulklode方式   会根据特定的分隔符来导入数据,  支持的文件格式:    csv : “ , ”   tsv :  "\t"		
		原理是:   先将原始数据直接转化成为hfile文件格式,再将数据加载到hbase中;需要顺序取字段;
			HADOOP_CLASSPATH=`$HBASE_HOME/bin/hbase classpath` hadoop jar $HBASE_HOME/lib/hbase-	server-version.jar importtsv 
				-Dimporttsv.bulk.output=<输出文件夹路径> 
				-Dimporttsv.separator=<分割符> 
				-Dimporttsv.columns= <目标表> <数据源路径>
				-Dimporttsv.columns=HBASE_ROW_KEY,f:a,f:b bulkload_text hdfs://ns1/testdata/bulkload/bulkload_reouse_file.txt
	4,。通过sqoop来导入			

13.Sparkjob的运行架构 ?

1.driver创建的SparkContext向Cluster Manager (资源管理器)提交job,注册并申请运行executor资源;
2.Cluster 	Manager 会检查数据寻找到最合适的节点来调度任务,启动standaloneExecutorBackend,初始化线程池;
3.sparkContext构建DAG图,job 会被拆分成不同stage, 每个stage会被拆分成多个task,并把Taskset发送给TaskScheduler;
4. Executor向sparkContext申请Task,TaskScheduler把task发送给Executor运行同时sparkContext把应用程序发送给Executor;
5.Task在Executor运行完后释放资源

*1.构建DAG:*

		使用算子操作RDD进行各种转换操作,最后通过行动操作触发Spark作业运行。
		提交之后Spark会根据转换过程所产生的RDD之间的依赖关系构建有向无环图
			
*2.DAG切割:*

		DAG切割主要根据RDD的依赖是否为宽依赖来决定切割节点,当遇到宽依赖就将任务划分为一个新的调度阶段(Stage)。
		每个Stage中包含一个或多个Task。这些Task将形成任务集(TaskSet),提交给底层调度器进行调度运行。	
				
*3.任务调度:*

		每一个Spark任务调度器只为一个SparkContext实例服务。当任务调度器收到任务集后负责把任务集以任务的形式分发至Worker节点的Executor进程中执行,如果某个任务失败,任务调度器负责重新分配该任务的计算。
			
*4.执行任务:*

		当Executor收到发送过来的任务后,将以多线程的方式执行任务的计算,
		每个线程负责一个任务,任务结束后会根据任务的类型选择相应的返回方式将结果返回给任务调度器。	
				
		SparkContext可以连接到多种类型的集群管理器 cluster managers  (standalone cluster manager,  Mesos ,YARN),这些 cluster managers 负责跨应用程序分配资源。一旦连接,Spark就获得集群中的节点上的executors,
接下来,它会将应用程序代码发送到executors。最后,SparkContext发送tasks到executors运行。	

14.kafka优化?

producer端:
1.合理选择push数据方式:同步、异步推送数据,发现数据问题改为同步查找问题
2.log.flush.interval.message(默认10000)和log.flush.interval.ms(默认3000ms)配置flush间隔
3.合理选择broker到consumer的接口 high-level封装了对partition和offset的管理,默认定期自动commit offset,可能丢数据
low-level自己管理spout线程和partition之间的对应关系和每个partition已消费的offset(定期写到zk),基本保证不丢数据,重启后可从zk读offset
4.异步考虑leader未完成副本数follows备份就当机的情况 设置回滚类型的batch数 broker端:
1.broker接收消息的最大字节数要比消费端消费的最大字节数要小,
2.broker可赋值的消息的最大字节数要比接收的最大字节数大 comsumer端:
1.关闭自动更新offset,等数据处理后手动更新offset
2.消费前验证offset

15.有写过自定义函数udf ?

临时:
1.创建类继承hive的UDF类;
2.实现evaluate方法;
3.打jar包到Linux本地;
4.add jar path 把jar包放在hive的classpath;
5.create temporary function myfun as ‘com.definefunction’ 创建一个临时函数,关联自定义函数的类; 永久:
1.打jar包到hdfs;
2.create function myfun as ‘com.definefunction’ using jar ‘hdfs://hdp02/hive-1.0-SNAPSHOT.jar’ 用UDF自定义函数,监测各个参数是否合格

17.hive的优化?

1.解决数据倾斜
2.减少job数量
3.设置合理的map reduce 的 task数量
4.小文件合并
5.慎用count(distinct)
6.配置上;列裁剪(只select 需要查询的列),分区分桶裁剪()
7.合理选择文件存储格式(TextFile(默认,不支持块压缩)、RCFile(列式存储,按行分块,写慢)、ORCFile(ORC升级版,不支持模式演进)、Parquet(树状数据结构,支持模式演进,写慢))
8.小表放在join左边前置
9.优先过滤数据
10.启用mapjoin(hive.auto.convert.join是否自动转换为mapjoin;hive.mapjoin.smalltable.filesize刷入内存表的大小,默认25M;hive.mapjoin.maxsize处理最大行数)
11.避免一个SQL包含复杂逻辑,用中间表完成
12.并行执行,hive.exec.parallel 是否开启并行;hive.exec.parallel.thread.number 允许最大并行度,默认8
13.中间数据压缩,最好使用snappy,hive.exec.compress.intermediate是否中间压缩;hive.intermediate.compression.codec = compress.SnappyCodec;
14.结果数据压缩,snappy不支持并行,最好使用LZO算法;hive.exec.compress.output是否结果压缩;mapred.output.compression.codec = compress.GzipCodec;
15.JVM重用,JVM实例在同一个Job重新使用N次,在mapred-site.xml配置mapred.job.reuse.num.tasks

18.spark的数据倾斜怎么处理的?

Spark在做Shuffle时,默认使用HashPartitioner(非Hash Shuffle)对数据进行分区。如果并行度设置的不合适,可能造	成大量不相同的Key对应的数据被分配到了同一个Task上,造成该Task所处理的数据远大于其它Task,从而造成数据倾斜。

如果调整Shuffle时的并行度,使得原本被分配到同一Task的不同Key发配到不同Task上处理,则可降低原Task所需处理的数据量,从而缓解数据倾斜问题造成的短板效应。

18.mapreduce的数据倾斜怎么处理的?

产生原因:
分组  注:group by 优于distinct
group
情形:group by 维度过小,某值的数量过多
后果:处理某值的reduce非常耗时

去重
distinct
count(distinct xx)
情形:某特殊值过多
后果:处理此特殊值的reduce耗时

连接
join
情形1:其中一个表较小,但是key集中
后果1:分发到某一个或几个Reduce上的数据远高于平均值
情形2:大表与大表,但是分桶的判断字段0值或空值过多

19.ETL数据清洗

Etl的三个工具:

ETL的设计分三部分:数据抽取、数据的清洗转换、数据的加载。
**数据仓库分为ODS    操作性数据、DW  指标数据, DM   数据集市 ,三部分。**
ETL主要过程就是通常的做法是从业务系统到ODS做清洗,将脏数据和不完整数据过滤掉,在从ODS到DW的过程中转换,进行一些业务规则的计算和聚合。
	设置参数:
	set hive.map.aggr=true;
    set hive.groupby.skewindata=true;
	mapreduce.task.io.sort.factor(default:10)来减少merge的次数,从而减少磁盘的操作;
    自定义combiner,还可以调参min.num.spill.for.combine,默认是3,也就是说spill的文件数在默认情况下由三个的时候就要进行combine操作,最终减少磁盘数据;

代码实现:改变partition的个数

public class Screw2Partition extends Partitioner 
{
     @Override
     public int getPartition(Text text, IntWritable intWritable, int numPartitions) 
     {
         Random r = new Random();
         //返回的是分区的随机的一个ID
         return r.nextInt(numPartitions);
     }
优点:
支持多种异构数据源的连接。(部分)    
图形化的界面操作十分方便。
处理海量数据速度快、流程更清晰等。

你可能感兴趣的:(大数据面试题整理)