唯品会大数据开发工程师社招面经(二)
10、kafka 的数据存在内存还是磁盘
Kafka 最核心的思想是使用磁盘,而不是使用内存,可能所有人都会认为,内存的速度一定
比磁盘快,我也不例外。在看了Kafka 的设计思想,查阅了相应资料再加上自己的测试后,
发现磁盘的顺序读写速度和内存持平。
而且Linux 对于磁盘的读写优化也比较多,包括 read-ahead 和 write-behind,磁盘缓存
等。如果在内存做这些操作的时候,一个是JAVA 对象的内存开销很大,另一个是随着堆内
存数据的增多,JAVA 的 GC 时间会变得很长,使用磁盘操作有以下几个好处:
磁盘缓存由Linux 系统维护,减少了程序员的不少工作。
磁盘顺序读写速度超过内存随机读写。
JVM 的 GC 效率低,内存占用大。使用磁盘可以避免这一问题。
系统冷启动后,磁盘缓存依然可用。
11、怎么解决 kafka 的数据丢失
producer 端:
宏观上看保证数据的可靠安全性,肯定是依据分区数做好数据备份,设立副本数。
broker 端:
topic 设置多分区,分区自适应所在机器,为了让各分区均匀分布在所在的 broker 中,分
区数要大于broker 数。
分区是kafka 进行并行读写的单位,是提升 kafka 速度的关键。
Consumer 端
consumer 端丢失消息的情形比较简单:如果在消息处理完成前就提交了 offset,那么就有可能造成数据的丢失。由于 Kafka consumer 默认是自动提交位移的,所以在后台提交位
移前一定要保证消息被正常处理了,因此不建议采用很重的处理逻辑,如果处理耗时很长,
则建议把逻辑放到另一个线程中去做。为了避免数据丢失,现给出两点建议:
enable.auto.commit=false 关闭自动提交位移
在消息被完整处理之后再手动提交位移
12、fsimage 和 edit 的区别?
大家都知道namenode 与 secondary namenode 的关系,当他们要进行数据同步时叫
做checkpoint 时就用到了 fsimage 与 edit,fsimage 是保存最新的元数据的信息,当
fsimage 数据到一定的大小事会去生成一个新的文件来保存元数据的信息,这个新的文件就
是edit,edit 会回滚最新的数据。
13、列举几个配置文件优化?
1)Core-site.xml 文件的优化
a、fs.trash.interval,默认值: 0;说明: 这个是开启 hdfs 文件删除自动转移到垃圾
箱的选项,值为垃圾箱文件清除时间。一般开启这个会比较好,以防错误删除重要文件。单
位是分钟。
b、dfs.namenode.handler.count,默认值:10;说明:hadoop 系统里启动的任务线
程数,这里改为40,同样可以尝试该值大小对效率的影响变化进行最合适的值的设定。
c、mapreduce.tasktracker.http.threads,默认值:40;说明:map 和 reduce 是通
过http 进行数据传输的,这个是设置传输的并行线程数。14、datanode 首次加入 cluster 的时候,如果 log 报告不兼容文件版本,那需要
namenode 执行格式化操作,这样处理的原因是?
1)这样处理是不合理的,因为那么 namenode 格式化操作,是对文件系统进行格式化,
namenode 格式化时清空 dfs/name 下空两个目录下的所有文件,之后,会在目录
dfs.name.dir 下创建文件。
2)文本不兼容,有可能时 namenode 与 datanode 的 数据里的 namespaceID、
clusterID 不一致,找到两个 ID 位置,修改为一样即可解决。
15、MapReduce 中排序发生在哪几个阶段?这些排序是否可以避免?为什么?
1)一个 MapReduce 作业由 Map 阶段和 Reduce 阶段两部分组成,这两阶段会对数
据排序,从这个意义上说,MapReduce 框架本质就是一个 Distributed Sort。
2)在 Map 阶段,Map Task 会在本地磁盘输出一个按照 key 排序(采用的是快速排
序)的文件(中间可能产生多个文件,但最终会合并成一个),在Reduce 阶段,每个 Reduce
Task 会对收到的数据排序,这样,数据便按照 Key 分成了若干组,之后以组为单位交给
reduce()处理。
3)很多人的误解在 Map 阶段,如果不使用 Combiner 便不会排序,这是错误的,不管
你用不用Combiner,Map Task 均会对产生的数据排序(如果没有 Reduce Task,则不
会排序,实际上Map 阶段的排序就是为了减轻 Reduce 端排序负载)。
4)由于这些排序是 MapReduce 自动完成的,用户无法控制,因此,在 hadoop 1.x 中
无法避免,也不可以关闭,但hadoop2.x 是可以关闭的。
16、hadoop 的优化?
1)优化的思路可以从配置文件和系统以及代码的设计思路来优化
2)配置文件的优化:调节适当的参数,在调参数时要进行测试
3)代码的优化:combiner 的个数尽量与 reduce 的个数相同,数据的类型保持一致,可
以减少拆包与封包的进度
4)系统的优化:可以设置 linux 系统打开最大的文件数预计网络的带宽 MTU 的配置
5)为 job 添加一个 Combiner,可以大大的减少 shuffer 阶段的 maoTask 拷贝过来给
远程的
reduce task 的数据量,一般而言 combiner 与 reduce 相同。
6)在开发中尽量使用 stringBuffer 而不是 string,string 的模式是 read-only 的,如果
对它进行修改,会产生临时的对象,二stringBuffer 是可修改的,不会产生临时对象。
7)修改一下配置:以下是修改 mapred-site.xml 文件
a、修改最大槽位数:槽位数是在各个 tasktracker 上的 mapred-site.xml 上设置的,
默认都是2
<property>
<name>mapred.tasktracker.map.tasks.maximum</name>
<value>2</value>
</property>
<property>
<name>mapred.tasktracker.reduce.tasks.maximum</name>
<value>2</value>
</property>
b、调整心跳间隔:集群规模小于 300 时,心跳间隔为 300 毫秒mapreduce.jobtracker.heartbeat.interval.min 心跳时间
mapred.heartbeats.in.second 集群每增加多少节点,时间增加下面的值
mapreduce.jobtracker.heartbeat.scaling.factor 集群每增加上面的个数,心跳增多少
c、启动带外心跳
mapreduce.tasktracker.outofband.heartbeat 默认是 false
d、配置多块磁盘
mapreduce.local.dir
e、配置 RPC hander 数目
mapred.job.tracker.handler.count 默认是 10,可以改成 50,根据机器的能力
f、配置 HTTP 线程数目
tasktracker.http.threads 默认是 40,可以改成 100 根据机器的能力
g、选择合适的压缩方式,以 snappy 为例:
<property>
<name>mapred.compress.map.output</name>
<value>true</value>
</property>
<property>
<name>mapred.map.output.compression.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
17、设计题
1)采集 nginx 产生的日志,日志的格式为 user ip
time url
htmlId 每天产生的
文件的数据量上亿条,请设计方案把数据保存到HDFS 上,并提供一下实时查询的功能(响
应时间小于3s)
A、某个用户某天访问某个 URL 的次数
B、某个 URL 某天被访问的总次数
实时思路是:使用Logstash + Kafka + Spark-streaming + Redis + 报表展示平台
离线的思路是:Logstash + Kafka + Elasticsearch + Spark-streaming + 关系型数据库
A、B、数据在进入到 Spark-streaming 中进行过滤,把符合要求的数据保存到 Redis 中
18、有 10 个文件,每个文件 1G,每个文件的每一行存放的都是用户的 query,每个文
件的query 都可能重复。要求你按照 query 的频度排序。 还是典型的 TOP K 算法,
解决方案如下:
1)方案 1:
顺序读取10 个文件,按照 hash(query)%10 的结果将 query 写入到另外 10 个文
件(记为)中。这样新生成的文件每个的大小大约也1G(假设 hash 函数是随机的)。 找
一台内存在2G 左右的机器,依次对用 hash_map(query, query_count)来统计每个
query 出现的次数。利用快速/堆/归并排序按照出现次数进行排序。将排序好的 query 和
对应的query_cout 输出到文件中。这样得到了 10 个排好序的文件(记为)。对这 10 个
文件进行归并排序(内排序与外排序相结合)。
2)方案 2:
一般query 的总量是有限的,只是重复的次数比较多而已,可能对于所有的 query,一次性就可以加入到内存了。这样,我们就可以采用 trie 树/hash_map 等直接来统计每
个query 出现的次数,然后按出现次数做快速/堆/归并排序就可以了。
3)方案 3:
与方案1 类似,但在做完 hash,分成多个文件后,可以交给多个文件来处理,采用分
布式的架构来处理(比如MapReduce),最后再进行合并。
#唯品会##社招##面经#