【面试题】大数据开发第1轮面试

面试总结:

1、HDFS小文件

小文件的产生原因
1) 数据本身的特点:比如我们在 HDFS 上存储大量的图片、短视频、短音频等文件,这些文件本身较小,达不到一个block的大小,而且数量众多。
2) MapReduce产生:例如使用查询一张含有海量数据的表,然后存储在另外一张表中,而这个查询只有简单的过滤条件(比如 select * from iteblog where from = 'hadoop'),这种情况只会启动大量的 Map 来处理,这种情况可能会产生大量的小文件。Reduece 设置不合理,也会产生大量小文件。
3)实时流处理:比如我们使用 Spark Streaming 从外部数据源接收数据,然后经过 ETL 处理之后存储到 HDFS 中。这种情况下在每个 Job 中会产生大量的小文件。

小文件的影响
1)namenode 会记录存储文件的元数据信息,大量小文件会占用大量的namenode内存,从而影响到HDFS的横向扩展能力。
2)使用mapreduce处理这些小文件,每个小文件会启动一个mapreduce,开启一个JVM,这样会占用集群的大量资源。

小文件解决办法
1)使用 HAR File:
运行一个 MapReduce 任务将小文件打包成 HAR 文件,使用 HAR 文件对客户端没有任何影响,所有的原始文件都可见并且可访问的(通过 har://URL)。但在 HDFS 端它内部的文件数减少了。
Hadoop 在进行最终文件的读取时,需要先访问索引数据,所以在效率上会比直接读取 HDFS 文件慢一些。
2)Sequence Files
Sequence Files 使用小文件名作为 key,并且文件内容作为 value,实践中这种方式非常管用。
和 HAR 不同的是,这种方式还支持压缩。该方案对于小文件的存取都比较自由,不限制用户和文件的多少,但是 SequenceFile 文件不能追加写入,适用于一次性写入大量小文件的操作。
3)HBase存储
小文件存储到类似于 HBase 的 KV 数据库里面,也可以将 Key 设置为小文件的文件名,Value 设置为小文件的内容,相比使用 SequenceFile 存储小文件,使用 HBase 的时候我们可以对文件进行修改,甚至能拿到所有的历史修改版本。
4)从 Hadoop 底层解决小文件问题 - HDFS-8998
小文件占用了一个block,把小block合并成大block。

5)从 Hadoop 底层解决小文件问题 - HDFS-8286
把 NameNode 管理的元数据从保存在内存转向保存到第三方KV存储系统里,从而减缓 NameNode 的内存使用。

参考资料:
https://mp.weixin.qq.com/s/2KFZp4bHKw9iNyDPOTim1A
https://issues.apache.org/jira/browse/HDFS-8998
https://issues.apache.org/jira/browse/HDFS-8286

2、kafka 如何实现高吞吐

1)顺序读写
kafka的消息是不断追加到文件中的,这个特性使kafka可以充分利用磁盘的顺序读写性能。
顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,所以速度远快于随机读写。
顺序 I/O: 600MB/s
随机 I/O: 100KB/s
2)零拷贝
零拷贝(zero-copy)"是一种系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存的直接映射,数据不再复制到“用户态缓冲区”。
系统上下文切换减少为2次,可以提升一倍的性能
3)文件分段
kafka的队列topic被分为了多个区partition,每个partition又分为多个段segment,所以一个队列中的消息实际上是保存在N多个片段文件中
kafka的队列topic被分为了多个区partition,每个partition又分为多个段segment,所以一个队列中的消息实际上是保存在N多个片段文件中
4)批量发送
Kafka允许进行批量发送消息,先将消息缓存在内存中,然后一次请求批量发送出去
比如可以指定缓存的消息达到某个量的时候就发出去,或者缓存了固定的时间后就发送出去
如100条消息就发送,或者每5秒发送一次
这种策略将大大减少服务端的I/O次数
5)数据压缩
Kafka还支持对消息集合进行压缩,Producer可以通过GZIP或Snappy格式对消息集合进行压缩
压缩的好处就是减少传输的数据量,减轻对网络传输的压力
Producer压缩之后,在Consumer需进行解压,虽然增加了CPU的工作,但在对大数据处理上,瓶颈在网络上而不是CPU,所以这个成本很值得。

参考资料:
https://mp.weixin.qq.com/s/vf4su_rl-UOGS8vHTCeDrg

3. Spark Streaming 如何消费 Kafka 的数据

两种方式:Receiver-based Approach、Direct Approach (No Receivers)
1)Receiver-based Approach
Receiver 的实现使用了 Kafka 的高级消费者 API,对于所有的 Receivers,接收到的数据将会保存在 Spark executors 中,然后由 SS 启动的 Job 来处理这些数据。

2)Direct Approach (No Receivers)
定期地从 Kafka 的 topic+partition 中查询最新的偏移量,再根据定义的偏移量范围在每个批处理时间间隔里面处理数据。当作业需要处理的数据来临时,Spark 通过调用 Kafka 的低级消费者 API 读取一定范围的数据。

优缺点:
Direct 比 Receiver 好的地方:简化并行、高效、恰好一次语义。
Direct 缺点:需要手动维护读取 Kakfa 的偏移量到 ZooKeeper。

参考资料:
https://mp.weixin.qq.com/s/C-m1ATNL2udLqo51zSe2Ow

4、Scala 隐式转换

隐式转换:我们需要某个类中的一个方法,但是这个类没有提供这样的一个方法,所以我们需要隐式转换,转换成提供了这个方法的类,然后再调用这个方法。
隐式转换实现的方式:
1)通过伴生对象实现
2)写一个专门的类用于转换,需要手动导入方式

5、堆排序

堆排序是利用堆的性质进行的一种选择排序。
堆实际上是一棵完全二叉树,其满足性质:任何一结点大于等于或者小于等于其左右子树结点。
堆分为大顶堆和小顶堆,满足 “任何一结点大于等于其左右子树结点” 的称为大顶堆,满足 “任何一结点小于等于其左右子树结点” 的称为小顶堆。
大顶堆的堆顶肯定是最大的,小顶堆的堆顶是最小的。

void HeapAdjust(int array[], int left, int right)
{
    int index = left;
  
    for (int i = left * 2; i <= right; i = i * 2)
    {
        if (i < right && array[i] < array[i + 1])  // 找到孩子中较大者
            i++;
        if (array[index] > array[i])
            return;
        swap(array[index], array[i]);
        index = i;
    }
}

void HeapSort(int array[], int left, int right)
{
    int len = right - left + 1;
  
    for (int i = len / 2; i >= left; i--)  // 把数组调整成大顶堆
        HeapAdjust(array, i, right);
  
    for (int i = right; i > left; i--)     // 排序
    {
        swap(array[left], array[i]);
        HeapAdjust(array, left, i - 1);
    }
}

堆排序时间复杂度:O(nlogn)
参考资料:
https://mp.weixin.qq.com/s/0H9jQDjG4oMv3nxEcJiCOw

7、Linux 如何查看端口是否占用

netstat -anp | grep 3306
如果端口的连接状态是 listen,说明被占用了。

tcp6       0      0 :::3306                 :::*                    LISTEN      5364/mysqld
tcp6       0      0 192.168.56.10:3306      192.168.56.10:35180     ESTABLISHED 5364/mysqld
tcp6       0      0 192.168.56.10:3306      192.168.56.10:35174     ESTABLISHED 5364/mysqld

参考资料:
https://www.cnblogs.com/shining5/p/8074080.html

8、Impala 和 Spark SQL 的比较

两者都可以很好地处理结构化数据,都是基于内存计算的。
Imapla 是 MPP 分布式查询引擎,适用于即席查询。
Spark SQL 常用于基于Spark RDD 的运算。

个人经验:
实际生产中使用 impala 场景比较多,impala 查询速度快,性能好。但是有一点需要注意,impala 的元数据缓存机制,在写入数据到hive后,不能立即用 impala 查询到数据,因为有缓存机制。需要清理缓存重新索引后,才能在 impala 上查到数据。

invalidata metadata <tablename> ;
或者
refresh <tablename> ; 

这两个方式也有区别,涉及到 schema 变动的,必须使用 invalidata metadata ;

参考资料:
https://mp.weixin.qq.com/s/w7p2oZ-Yt_QYr7kbIkzgrg
https://blog.csdn.net/qq_35995514/article/details/102897599

9、Redis 持久化策略

RDB、AOF持久化策略。

RDB(=Redis DataBase):把数据以快照的形式保存在磁盘上,这是默认的持久化策略,在配置文件里可以配置触发持久化操作的条件。

AOF(Append Only File):将每一个收到的写命令都通过write函数追加到文件中。

优缺点:
1)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
2)在数据丢失的情况下,AOF 丢失的数据比 RDB 少。
3)RDB 文件比 AOF 小

项目 RDB AOF
启动优先级
文件体积
恢复速度
数据安全性 丢数据 根据策略决定
轻重

参考资料:
https://segmentfault.com/a/1190000016021217

10、 Redis 集群

Redis 集群的三种模式:
主从模式复制、哨兵模式、Cluster 模式。
1)主从复制模式
以主库为准,从库内容异步复制主数据库,从而达成主从内容基本一致的情况。
特点:
1.master一般是接受读写的,slave只接受读操作。
2.当master接受写操作后会将命令发送给slave执行,从而实现数据一致性
3.一个master下面可以有多个slave,但是一个slave上面只能有一个master
原理:
1 从服务器连接主服务器发送sync命令。
2 主服务器持久化数据生成rdb文件并缓存这段时间的写命令
3 主服务器向从服务器发送rdb文件和缓存的命令
4 从服务器载入rdb快照后执行缓存的命令(从服务器初始化完成)
5 主服务器每接收到一个写命令就发送给从服务器执行(从服务器初始化完成后的操作)

2)哨兵模式
哨兵模式是建立在主从模式基础之上,从节点使用哨兵模式进行监控主节点,如果主挂了,从库自动升级为主节点,等待主库恢复了,主库会自动变为从库。
此时,如果升级为主库的从节点挂了,此时变为从库的主节点不会变为主库,出现这种问题,我们一般采用的是主从都进行哨兵模式配置,互相监控对方,从而达到高可用。

3)Cluster 模式
cluster模式采用了无中心节点的方式来实现,每个主节点都会与其它主节点保持连接。节点间通过gossip协议交换彼此的信息,同时每个主节点又有一个或多个从节点。
客户端连接集群时,直接与redis集群的每个主节点连接,根据hash算法取模将key存储在不同的哈希槽上;
在集群中采用数据分片的方式,将redis集群分为16384个哈希槽。这些哈希槽分别存储于三个主节点中。
每个节点会保存一份数据分布表,节点会将自己的slot信息发送给其他节点,节点间不停的传递数据分布表。
客户端连接集群时,通过集群中某个节点地址进行连接。客户端尝试向这个节点执行命令时,比如获取某个key值,如果key所在的slot刚好在该节点上,则能够直接执行成功。如果slot不在该节点,则节点会返回MOVED错误,同时把该slot对应的节点告诉客户端,客户端可以去该节点执行命令。

参考资料:
https://mp.weixin.qq.com/s/S1n16saQwuv51rsNvCrlnQ
https://mp.weixin.qq.com/s/oH2uzyVJTiU031WzuehDHA

11.如果目前有一个实际的业务场景,如何数据建模?

1)数仓分层:ODS层 -> DW层(DWD|DWS|DWB) -> ADS层
好处:清晰数据结构、数据血缘追踪、数据血缘追踪、把复杂问题简单化、把复杂问题简单化。

2)建模方法:维度建模 or 关系建模
维度建模:
维度建模以分析决策的需求出发构建模型,构建的数据模型为分析需求服务,因此它重点解决用户如何更快速完成分析需求,同时还有较好的大规模复杂查询的响应性能,更直接面向业务。
星型模型:由一个事实表和一组维表组成。每个维表都有一个维作为主键,所有这些维的主键组合成事实表的主键。强调的是对维度进行预处理,将多个维度集合到一个事实表,形成一个宽表。
优点:技术要求不高,快速上手,敏捷迭代,快速交付;更快速完成分析需求,较好的大规模复杂查询的响应性能
缺点:维度表的冗余会较多,视野狭窄

关系建模:
是数据仓库之父Inmon推崇的、从全企业的高度设计一个3NF模型的方法,用实体加关系描述的数据模型描述企业业务架构,在范式理论上符合3NF,站在企业角度面向主题的抽象,而不是针对某个具体业务流程的实体对象关系抽象。
雪花模型:一个或多个维表没有直接连接到事实表上,而是通过其他维表连接到事实表上时,其图解就像多个雪花连接在一起。
优点:规范性较好,冗余小,数据集成和数据一致性方面得到重视,比如运营商可以参考国际电信运营业务流程规范(ETOM),有所谓的最佳实践。
缺点:需要全面了解企业业务、数据和关系;实施周期非常长,成本昂贵;对建模人员的能力要求也非常高,容易烂尾。

个人理解:
在上一家公司使用的是维度建模,快速迭代快速交付,因为公司业务以及部门之间的协同关系,没办法从一个全局的高度来架构整个数据仓库,只能先跟着项目需求走,完成数据仓库的搭建和后续的报表、用户画像的需求开发。

参考资料:
https://mp.weixin.qq.com/s/lo_nIKpIl5G47XUvsEWtYw

原文地址:https://www.cnblogs.com/bigband/p/13582388.html