大数据面试问题

GC的原理,算法及不一样代使用的算法node

 

hashmap、hashtable、concurrentmap原理,内部算法和逻辑算法

 

数据库的四大原则,缺乏某一原则会有什么后果数据库

 

数据库索引是什么数据结构apache

 

spark streaming若是出错怎么办windows

 

flume若是数据导入HDFS出错怎么办数组

 

flapmap是如何实现的,是否能够写一个缓存

 

 

spark streaming的数据是谁读取的安全

 

流程是什么服务器

 

windows窗体算子网络

 

有这些简单的

 

都以为挺难的

 

还有就是 若是数据太多,kafka读不过来,怎么办

 

还会问 你处理过的数据量有多大? 有没有遇到什么问题?

 

:

而后还会问服务器的问题, 他们说GB级别一些问题发现不了, 他们须要处理过TB以上级别的

Hadoop:    

    50070:HDFS WEB UI端口

    8020 : 高可用的HDFS RPC端口

    9000 : 非高可用的HDFS RPC端口

    8088 : Yarn 的WEB UI 接口

    8485 : JournalNode 的RPC端口

    8019 : ZKFC端口

   19888:jobhistory WEB UI端口

Zookeeper:

    2181 : 客户端链接zookeeper的端口

    2888 : zookeeper集群内通信使用,Leader监听此端口

    3888 : zookeeper端口 用于选举leader

Hbase:

    60010:Hbase的master的WEB UI端口 (旧的) 新的是16010

    60030:Hbase的regionServer的WEB UI 管理端口    

Hive:

    9083  :  metastore服务默认监听端口

    10000:Hive 的JDBC端口

Spark:

    7077 : spark 的master与worker进行通信的端口  standalone集群提交Application的端口

    8080 : master的WEB UI端口  资源调度

    8081 : worker的WEB UI 端口  资源调度

    4040 : Driver的WEB UI 端口  任务调度

    18080:Spark History Server的WEB UI 端口

Kafka:

    9092: Kafka集群节点之间通讯的RPC端口

Redis:

    6379: Redis服务端口

CDH:

    7180: Cloudera Manager WebUI端口

    7182: Cloudera Manager Server 与 Agent 通信端口

JVM优化

要查找和评估器性能瓶颈,首先要知道性能定义,对于jvm调优来讲,咱们须要知道如下三个定义属性,依做为评估基础:

吞吐量:重要指标之一,是指不考虑垃圾收集引发的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标。 

延迟:其度量标准是缩短因为垃圾啊收集引发的停顿时间或者彻底消除因垃圾收集所引发的停顿,避免应用运行时发生抖动。 

内存占用:垃圾收集器流畅运行所须要 的内存数量。 

这三个属性中,其中一个任何一个属性性能的提升,几乎都是以另一个或者两个属性性能的损失做代价,不可兼得,具体某一个属性或者两个属性的性能对应用来讲比较重要,要基于应用的业务需求来肯定。

 

调优总结

年轻代大小选择

    • 响应时间优先的应用:尽量设大,直到接近系统的最低响应时间限制(根据实际状况选择)。在此种状况下,年轻代收集发生的频率也是最小的。同时,减小到达年老代的对象。
    • 吞吐量优先的应用:尽量的设置大,可能到达Gbit的程度。由于对响应时间没有要求,垃圾收集能够并行进行,通常适合8CPU以上的应用。

年老代大小选择

    • 响应时间优先的应用:年老代使用并发收集器,因此其大小须要当心设置,通常要考虑并发会话率和会话持续时间等一些参数。若是堆设置小了,能够会形成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;若是堆大了,则须要较长的收集时间。最优化的方案,通常须要参考如下数据得到:
      • 并发垃圾收集信息
      • 持久代并发收集次数
      • 传统GC信息
      • 花在年轻代和年老代回收上的时间比例

减小年轻代和年老代花费的时间,通常会提升应用的效率

      • 吞吐量优先的应用:通常吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。缘由是,这样能够尽量回收掉大部分短时间对象,减小中期的对象,而年老代尽存放长期存活对象。
    1. 较小堆引发的碎片问题

因 为年老代的并发收集器使用标记、清除算法,因此不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样能够分配给较大的对象。可是,当堆空间 较小时,运行一段时间之后,就会出现“碎片”,若是并发收集器找不到足够的空间,那么并发收集器将会中止,而后使用传统的标记、清除方式进行回收。若是出 现“碎片”,可能须要进行以下配置:

      • -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
      • -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的状况下,这里设置多少次Full GC后,对年老代进行压缩

GC算法

垃圾收集 Garbage Collection 一般被称为“GC”

标记 -清除算法

   “标记-清除”(Mark-Sweep)算法,如它的名字同样,算法分为“标记”和“清除”两个阶段:首先标记出全部须要回收的对象,在标记完成后统一回收掉全部被标记的对象。之因此说它是最基础的收集算法,是由于后续的收集算法都是基于这种思路并对其缺点进行改进而获得的。

它的主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另一个是空间问题,标记清除以后会产生大量不连续的内存碎片,空间碎片太多可能会致使,当程序在之后的运行过程当中须要分配较大对象时没法找到足够的连续内存而不得不提早触发另外一次垃圾收集动做。

复制算法

“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,而后再把已使用过的内存空间一次清理掉。

这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂状况,只要移动堆顶指针,按顺序分配内存便可,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半,持续复制长生存期的对象则致使效率下降。

标记-压缩算法

复制收集算法在对象存活率较高时就要执行较多的复制操做,效率将会变低。更关键的是,若是不想浪费50%的空间,就须要有额外的空间进行分配担保,以应对被使用的内存中全部对象都100%存活的极端状况,因此在老年代通常不能直接选用这种算法。

根据老年代的特色,有人提出了另一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法同样,但后续步骤不是直接对可回收对象进行清理,而是让全部存活的对象都向一端移动,而后直接清理掉端边界之外的内存

 

分代收集算法

GC分代的基本假设:绝大部分对象的生命周期都很是短暂,存活时间短。

“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,这样就能够根据各个年代的特色采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少许存活,那就选用复制算法,只须要付出少许存活对象的复制成本就能够完成收集。而老年代中由于对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收

 

 

内存泄漏检查

    内存泄漏是比较常见的问题,并且解决方法也比较通用,这里能够重点说一下,而线程、热点方面的问题则是具体问题具体分析了。

    内存泄漏通常能够理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的状况下,致使使用完毕的资源没法回收(或没有回收),从而致使新的资源分配请求没法完成,引发系统错误。

    内存泄漏对系统危害比较大,由于他能够直接致使系统的崩溃。

    须要区别一下,内存泄漏和系统超负荷二者是有区别的,虽然可能致使的最终结果是同样的。内存泄漏是用完的资源没有回收引发错误,而系统超负荷则是系统确实没有那么多资源能够分配了(其余的资源都在使用)。

 

hashmap、hashtable、concurrentmap原理,内部算法和逻辑

HashTable

  • 底层数组+链表实现,不管key仍是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap作了相关优化
  • 初始size为11,扩容:newsize = olesize*2+1
  • 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap

  • 底层数组+链表实现,能够存储null键和null值,线程不安全
  • 初始size为16,扩容:newsize = oldsize*2,size必定为2的n次幂
  • 扩容针对整个Map,每次扩容时,原来数组中的元素依次从新计算存放位置,并从新插入
  • 插入元素后才判断该不应扩容,有可能无效扩容(插入后若是扩容,若是没有再次插入,就会产生无效扩容)
  • 当Map中元素总数超过Entry数组的75%,触发扩容操做,为了减小链表长度,元素分配更均匀
  • 计算index方法:index = hash & (tab.length – 1)

ConcurrentHashMap

  • 底层采用分段的数组+链表实现,线程安全
  • 经过把整个Map分为N个Segment,能够提供相同的线程安全,可是效率提高N倍,默认提高16倍。(读操做不加锁,因为HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
  • Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap容许多个修改操做并发进行,其关键在于使用了锁分离技术
  • 有些方法须要跨段,好比size()和containsValue(),它们可能须要锁定整个表而而不只仅是某个段,这须要按顺序锁定全部段,操做完毕后,又按顺序释放全部段的锁
  • 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不须要扩容,有效避免无效扩容

 

 

数据库的四大原则,缺乏某一原则会有什么后果

数据库的ACID四原则及:

        事物的原子性(Atomic)、一致性(Consistent)、独立性(Isolated)及持久性(Durable)。

1.事务的原子性是指一个事务要么所有执行,要么不执行.也就是说一个事务不可能只执行了一半就中止了.好比你从取款机取钱,这个事务能够分红两个步骤:1划卡,2出钱.不可能划了卡,而钱却没出来.这两步必须同时完成.要么就不完成.

        2.事务的一致性是指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变.

        3.事务的独立性是指两个以上的事务不会出现交错执行的状态.由于这样可能会致使数据不一致.

        4.事务的持久性是指事务运行成功之后,就系统的更新是永久的.不会平白无故的回滚.

脏读:在一个事务中读取到另外一个事务没有提交的数据 

不可重复读:在一个事务中,两次查询的结果不一致(针对的update操做) 

 

虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操做) 

经过设置数据库的隔离级别来避免上面的问题(理解) 

read uncommitted 读未提交 上面的三个问题都会出现 

read committed 读已提交 能够避免脏读的发生 

repeatable read 可重复读 能够避免脏读和不可重复读的发生 

serializable 串行化 能够避免全部的问题

 

mr调优、

 

最简单的调优方式

设置Combiner

Combiner在Map端提早进行了一次Reduce处理。 

可减小Map Task中间输出的结果,从而减小各个Reduce Task的远程拷贝数据量,最终表现为Map Task和Reduce Task执行时间缩短。

选择合理的Writable类型

为应用程序处理的数据选择合适的Writable类型可大大提高性能。 

好比处理整数类型数据时,直接采用IntWritable比先以Text类型读入在转换为整数类型要高效。 

若是输出整数的大部分可用一个或两个字节保存,那么直接采用VIntWritable或者VLongWritable,它们采用了变长整型的编码方式,能够大大减小输出数据量。

做业级别调优

增长输入文件的副本数

假设集群有1个Namenode+8个Datanode节点,HDFS默认的副本数为3 

那么map端读取数据的时候,在启动map task的机器上读取本地的数据为3/8,一部分数据是经过网络从其余节点拿到的 

那么若是副本数设置为8会是什么状况? 

至关于每一个子节点上都会有一份完整的数据,map读取的时候直接从本地拿,不须要经过网络这一层了

可是在实际状况中设置副本数为8是不可行的,由于数据自己很是庞大,副本数超过5对集群的磁盘就很是有压力了,因此这项设置须要酌情处理

该配置在hdfs-side.xml的dfs.replication项中设置

 

一、经常使用combiner来减小输入到reduce的数据,防止数据倾斜

二、在数据经过远程到达reduce端进行处理的时候,能够合理的设置归并排序的次数,过多过少都很差,过多可能会写入磁盘,过少可能会增长归并排序数量

三、设置reduce的个数,来均衡原来输入到一个reduce上的数据,防止数据倾斜

 

spark调优,运行原理

1. RDD的持久化 

cahce() 

persist() 

checkpoint() 

2. 避免建立重复的RDD 

3.尽量复用同一个RDD 

相似于多个RDD的数据有重叠或者包含的状况,应该尽可能复用一个RDD,以尽量减小RDD的数量,从而减小算子计算次数 

4.尽可能避免使用shuffle类算子 

spark运行过程当中,最消耗性能的地方就是shuffle过程(简单说,就是将分布在集群中多个节点上的同一个key拉取到同一个节点上进行操做) 

shuffle过程当中,各个节点上相同的key都会先写入本地磁盘文件中,而后其余节点须要经过网络传输拉取各个节点上的磁盘文件中的相同的key,并且相同key都拉取到同一个节点进行聚合操做时,还可能会由于一个节点上处理的key过多,致使内存不够存放,从而溢写到磁盘文件中。 

磁盘IO和网络数据传输也是shuffle性能较差的主要缘由。 

尽可能使用map类的非shuffle算子。 

repartition(重分区)类操做:repartition、repartitionAndSortWithinPartitions、coalesce等 

bykey类操做:reduceByKey、groupByKey、sortByKey等 

join类操做:join、cogroup等 

类如:join –>Broadcast+map (Broadcast:数据量小于1G内的RDD,每份数据放入executor副本中) 

5.使用map-side预聚合的shuffle操做 

由于业务须要,必定要使用shuffle操做,没法用map类算子替代,尽可能使用map-side预聚合的算子。(在每一个节点本地对相同的key进行一次聚合操做) 

map-side预聚合以后,每一个节点本地就只会有一条相同的key,由于多条相同的key都被聚合起来了。其余节点在拉取全部节点上的相同key时,就会大大减小须要拉取的数据数量,从而也就减小了磁盘IO以及网络传输开销。 

一般来讲,在可能的状况下,建议使用reduceByKey或者aggregateByKey算子来替代掉groupByKey算子。由于reduceByKey和aggregateByKey算子都会使用用户自定义的函数对每一个节点本地的相同key进行预聚合。而groupByKey算子是不会进行预聚合的,全量的数据会在集群的各个节点之间分发和传输,性能相对来讲比较差。 

 

groupByKey中 shuffle操做中没有预聚合操做 

 

6.使用高性能的算子 

除了shuffle相关的算子有优化原则外,其余的算子也有相应的优化原则。 

a . 使用mapPartitions替代map。一次函数调用会处理一个partition全部的数据,而不是一次函数调用处理一条。可是可能会出现内存溢出(OOM)问题。 

b . 使用foreachPartitions提到foreach。 

c . 使用filter以后进行coalesce操做。使用filter后,建议使用coalesce算子,手动减小RDD的数据量,将RDD的数据压缩到更少的partition中去。 (coalesce:RDD的分区进行从新划分,repartition只是coalesce接口中shuffle为true的简易实现) 

d . 使用repartitionAndSortWithinPartitions替代repartition与sort类操做。若是须要在repartition重分区后,还有进行排序,建议使用repartitionAndSortWithinPartitions。由于该算子能够一边进行重分区的shuffle操做,一边进行排序(同时进行)。 

7.广播大变量 

在开发中,遇到须要在算子函数中使用外部变量的场景(如配置文件)(尤为是大变量,好比100M以上的大集合)。此时就应该使用Spark的广播功能来提高性能 

在算子函数中使用到外部变量时,默认状况下,spark会将变量复制多个副本,经过网络传递到task中,此时每一个task都有一个变量副本。若使用的外部变量比较大,建议使用Spark的广播功能,对该变量进行广播。广播后的变量会保证每一个executor的内存中,只驻留一份变量副本,而executor中的task执行时共享该executor中的那份变量副本。从而大大减小变量副本的数量,减小网络传输的性能开销,并减小对executor内存的占用开销。

8.使用kryo优化序列化性能 

JAVA序列化:是指把JAVA对象转换位字节序列的过程;而JAVA反序列化是指把字节序列恢复为JAVA对象的过程。 

当两个进程进行远程通讯时,能够相互发送各类类型的数据,包括文本、图片、音频、视频等,而这些数据都会以二进制序列的形式在网络上传送。那么当两个JAVA进程进行通讯时,要实现进程间对象传送就须要JAVA序列化和反序列化。 也就是:发送方须要把这个JAVA对象转换为字节序列,而后再网络上传送;另外一方面,接收方须要从字节序列中回复出JAVA对象。 

JAVA序列化的好处有:实现了数据的持久化,经过序列化能够把数据永久地保存到硬盘上;利用序列化实现远程通讯,即在网络上传送对象的字节序列。

spark中主要有三个地方涉及到了序列化: 

1.在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输 

2.将自定义的类型做为RDD的泛型类型(如JavaRDD,student是自定义类型),全部自定义类型对象都会进行序列化,这种状况下,也要求自定义的类必须实现Serializable接口 

3. 使用可序列化的持久化策略时(如MEMORY_ONLY_SER),spark会将RDD中每一个partition都序列化成一个大的字节数组

对于这三种出现序列化的地方,咱们均可以经过使用Kryo序列化类库,来优化序列化和反序列化。Spark默认使用的是Java的序列化机制,也就是ObjectOutputStream/ObjectInputStream API来进行序列化和反序列化。可是spark同时支持使用Keyo序列化库,Kryo序列化类库的性能比Java序列化类库的性能高不少。

SparkConf().set(“spark.serializer”, “org.apache.spark.serializer.KryoSerializer”)

Scala版本: 

val conf = new SparkConf().setMaster(…).setAppName(…) 

conf.registerKryoClasses(Array(classOf[Counter] )) 

val sc = new SparkContext(conf)

Java版本: 

SparkConf conf = new SparkConf().setMaster(…).setAppName(…) 

conf.registerKryoClasses(Counter.class) 

JavaSparkContext sc = new JavaSparkContext(conf)

若是注册的要序列化的自定义的类型,自己特别大,好比包含了超过100个field。那么就会致使要序列化的对象过大。此时就须要对Kryo自己进行优化。由于Kryo内部的缓存可能不够存放那么大的class对象。此时就须要调用SparkConf.set()方法,设置spark.kryoserializer.buffer.mb参数的值,将其调大。

默认状况下它的值是2,就是说最大能缓存2M的对象,而后进行序列化。能够在必要时将其调大。好比设置为10。

9.优化数据结构 

Java中,有三种类型比较耗费内存: 

1.对象:每一个JAVA对象都有对象头、引用等额外的信息。比较占用内存空间 

2.字符串:每一个字符串内部都有一个字符数组以及长度等额外信息 

3.集合类型:好比HashMap、LinkedList等,由于集合类型内部一般会使用一些内部类来封装集合元素,好比Map.Entry

所以,在Spark编码实现中,特别是对于算子函数中的代码,尽可能不要使用上述的三种数据结构,尽可能使用字符串替代对象,使用原始类型(Int、Long)替代字符串使用数组替代集合类型。能够尽量减小内存占用。

 

mr运行原理

http://www.noobyard.com/article/p-xoqluuet-sz.html

 

数据库索引是什么数据结构

目前大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree做为索引结构

https://blog.csdn.net/FX677588/article/details/76783345

spark streaming若是出错怎么办

 

flume若是数据导入HDFS出错怎么办

 

flapmap是如何实现的,是否能够写一个

 

 

spark streaming的数据是谁读取的

 

流程是什么

 

 

 

 

 

还有就是 若是数据太多,kafka读不过来,怎么办

 

还会问 你处理过的数据量有多大? 有没有遇到什么问题?

 

 

而后还会问服务器的问题, 他们说GB级别一些问题发现不了, 他们须要处理过TB以上级别的