1. kafka相关
1.1 怎么解决kafka的数据丢失
producer端: 宏观上看保证数据的可靠安全性,肯定是依据分区数做好数据备份,设立副本数。
broker端: topic设置多分区,分区自适应所在机器,为了让各分区均匀分布在所在的broker中,分区数要大于broker数。 分区是kafka进行并行读写的单位,是提升kafka速度的关键。
Consumer端: consumer端丢失消息的情形比较简单:如果在消息处理完成前就提交了offset,那么就有可能造成数据的丢失。由于Kafka consumer默认是自动提交位移的,所以在后台提交位移前一定要保证消息被正常处理了,因此不建议采用很重的处理逻辑,如果处理耗时很长,则建议把逻辑放到另一个线程中去做。为了避免数据丢失,现给出两点建议: enable.auto.commit=false 关闭自动提交位移 在消息被完整处理之后再手动提交位移。
1.2 Kafka中的ISR、AR是什么?
ISR: In-Sync Replicas 副本同步队列, 由leader维护, 当follower与leader之间的延迟超过阈值时, follower会被从ISR中踢出, 进入OSR
AR: Assigned Replicas 所有副本
1.3 Kafka的message包括哪些信息
一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成 header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成。当magic的值为1的时候,会在magic和crc32之间多一个字节的数据:attributes(保存一些相关属性,比如是否压缩、压缩格式等等);如果magic的值为0,那么不存在attributes属性 body是由N个字节构成的一个消息体,包含了具体的key/value消息
1.4 为什么使用Kafka还需要zookeeper?
Kafka通过zookeeper进行集群管理, 并在集群中存储节点, offset等元信息. 早期版本的kafka在客户端连接时亦需要直接与zookeeper建立连接, 新的kafka客户端使用了自己的通信协议, 不需要客户端直接与zookeeper简历连接. 但是kafka所有的节点依然需要和zookeeper建立连接.
1.5 Kafka是如何存储数据的, 它为什么要这样做
Kafka最核心的思想是使用磁盘,而不是使用内存,可能所有人都会认为,内存的速度一定比磁盘快,我也不例外。在看了Kafka的设计思想,查阅了相应资料再加上自己的测试后,发现磁盘的顺序读写速度和内存持平。 而且Linux对于磁盘的读写优化也比较多,包括read-ahead和write-behind,磁盘缓存等。如果在内存做这些操作的时候,一个是JAVA对象的内存开销很大,另一个是随着堆内存数据的增多,JAVA的GC时间会变得很长,使用磁盘操作有以下几个好处: 磁盘缓存由Linux系统维护,减少了程序员的不少工作。 磁盘顺序读写速度超过内存随机读写。 JVM的GC效率低,内存占用大。使用磁盘可以避免这一问题。 系统冷启动后,磁盘缓存依然可用。
1.6 Kafka中consumer group 是什么概念
对于kafka同一个topic中的一条消息, 会广播给不同的group, 二同一个group中的worker只有一个能得到这条消息.
2. Spark相关
2.1 Spark RDD 什么情况下会产生宽依赖, 什么情况产生窄依赖?
宽依赖 -> 父RDD的分区被子RDD的多个分区使用 例如 groupByKey、reduceByKey、sortByKey等操作会产生宽依赖,会产生shuffle
窄依赖 -> 父RDD的每个分区都只被子RDD的一个分区使用 例如map、filter、union等操作会产生窄依赖
2.2 Spark中的cache与persist缓存方式有何区别?
cache内部还是会调用persist的, 只是缓存的方式会直接使用内存来存储缓存的数据
而persist时则可以选择缓存级别, 分别有:
- MEMORY_ONLY存储于内存
- MEMORY_AND_DISK 优先内存存储, 空间不足则使用磁盘
- DISK_ONLY 存储在磁盘上
2.3 Spark streaming 读取kafka数据的方式有哪几种, 分别是如何做到的
- 通过receiver读取
使用Kafka的高层次Consumer API来实现。receiver从Kafka中获取的数据都存储在Spark Executor的内存中,然后Spark Streaming启动的job会去处理那些数据。然而,在默认的配置下,这种方式可能会因为底层的失败而丢失数据。如果要启用高可靠机制,让数据零丢失,就必须启用Spark Streaming的预写日志机制(Write Ahead Log,WAL)。该机制会同步地将接收到的Kafka数据写入分布式文件系统(比如HDFS)上的预写日志中。所以,即使底层节点出现了失败,也可以使用预写日志中的数据进行恢复。- 通过Direct方式读取(spark 1.3+)
这种方式会周期性地查询Kafka,获得每个topic+partition的最新的offset,从而定义每个batch的offset的范围。当处理数据的job启动时,就会使用Kafka的简单consumer api来获取Kafka指定offset范围的数据。
2.4 RDD: {(1,2),(3,4),(5,6)}执行.mapValues(x=>x*2)的结果?
{(1,4),(3,8),(5,12)}
2.5 datanode 首次加入 cluster 的时候,如果 log 报告不兼容文件版本. 是否需要namenode执行格式化操作,这样处理的原因是?
不需要进行namenode格式化操作,namenode 格式化时会清空 dfs/name 下空两个目录下的所有文件,之后,会在目录 dfs.name.dir 下创建文件, 这样会导致原有数据丢失.
文件版本不兼容,有可能时 namenode 与 datanode 的 数据里的 namespaceID、clusterID 不一致,找到两个 ID 位置,修改为一样即可解决。
3. haoop 相关
3.1 介绍一下Hadoop MapReduce计算框架中的shuffle过程
Map端的shuffle:
Map端会处理输入数据并产生中间结果,这个中间结果会写到本地磁盘,而不是HDFS。每个Map的输出会先写到内存缓冲区中,当写入的数据达到设定的阈值时,系统将会启动一个线程将缓冲区的数据写到磁盘,这个过程叫做spill。 在spill写入之前,会先进行二次排序,首先根据数据所属的partition进行排序,然后每个partition中的数据再按key来排序。partition的目是将记录划分到不同的Reducer上去,以期望能够达到负载均衡,以后的Reducer就会根据partition来读取自己对应的数据。接着运行combiner(如果设置了的话),combiner的本质也是一个Reducer,其目的是对将要写入到磁盘上的文件先进行一次处理,这样,写入到磁盘的数据量就会减少。最后将数据写到本地磁盘产生spill文件(spill文件保存在{mapred.local.dir}指定的目录中,Map任务结束后就会被删除)。最后,每个Map任务可能产生多个spill文件,在每个Map任务完成前,会通过多路归并算法将这些spill文件归并成一个文件。至此,Map的shuffle过程就结束了。
Reduce端的shuffle:
Reduce端的shuffle主要包括三个阶段,copy、sort(merge)和reduce。首先要将Map端产生的输出文件拷贝到Reduce端,但每个Reducer如何知道自己应该处理哪些数据呢?因为Map端进行partition的时候,实际上就相当于指定了每个Reducer要处理的数据(partition就对应了Reducer),所以Reducer在拷贝数据的时候只需拷贝与自己对应的partition中的数据即可。每个Reducer会处理一个或者多个partition,但需要先将自己对应的partition中的数据从每个Map的输出结果中拷贝过来。 接下来就是sort阶段,也成为merge阶段,因为这个阶段的主要工作是执行了归并排序。从Map端拷贝到Reduce端的数据都是有序的,所以很适合归并排序。最终在Reduce端生成一个较大的文件作为Reduce的输入。
3.2 MapReduce中如何进行全排序?
多数情况下会使用单个reduce进行排序, 如果存在性能瓶颈, 可以使用terasort, hadoop自带了teragen和terasort, 分别用于主数据生成和排序.
3.3 如何应对MapReduce计算中出现的倾斜?
- 参数调优(如增加reduce端内存)
- 自定义分区策略
- 在map端进行数据关联
- 在不损害业务的情形下, 剔除那些产生倾斜的key
4. HDFS相关
4.1 请描述HDFS中fsimage文件和edits log的区别
大家都知道namenode与secondary namenode 的关系,当他们要进行数据同步时叫做checkpoint时就用到了fsimage与edit,fsimage是保存最新的元数据的信息,当fsimage数据到一定的大小事会去生成一个新的文件来保存元数据的信息,这个新的文件就是edit,edit会回滚最新的数据。
5. Hbase相关
5.1 请介绍一下HBase适用的场景
半结构化或非结构化数据 - 由于hbase可以动态添加列, 因此对于不确定的数据结构, 非常适合使用hbase
数据在不同列上的量很稀疏 - 行存储的列数是是固定的, 这样导致null的字段浪费存储空间。由于hbase按列存储, null字段不占用空间, 因此这种方式非常适合hbase
多版本数据 - 由于Hbase能够在Value上存储多个版本的数据, 因此对于须要存储变动历史记录的数据, Hbase非常适合.
高并发的写入场景 - HBase采用WAL方式写入, 提供高可用,高并发数据写入
数据处理逻辑相对固定 - 由于HBase不像关系型数据库能灵活支持关联查询, 它更适用于简单的业务场景.
5.2 描述 Hbase 中 scan 和 get 的功能以及实现的异同.
Get按指定RowKey获取唯一一条记录 ,get方法方法处理分两种: 设置了ClosestRowBefore 和没有设置的 rowlock .
主要是用来保证行的事务性,即每个get 是以一个 row 来标记的.一个 row 中可以有很多 family 和 column.
5.3 描述Hbase设计rowKey时的原则
rowkey 长度原则
rowkey 是一个二进制码流,可以是任意字符串,最大长度 64kb,实际应用中一般为 10-100bytes,以 byte[]形式保存,一般设计成定长。建议越短越好,不要超过 16 个字节, 原因如下:
数据的持久化文件 HFile 中是按照 KeyValue 存储的,如果 rowkey 过长会极大影响 HFile 的存储效率 MemStore 将缓存部分数据到内存,如果 rowkey 字段过长,内存的有效利用率就会降低,系统不能缓存更多的数据,这样会降低检索效率。
rowkey 散列原则
如果 rowkey 按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将 rowkey 的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个 RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个 RegionServer 上,这样在数据检索的时候负载会集中在个别的 RegionServer 上,造成热点问题,会降低查询效率。
rowkey 唯一性原则
必须在设计上保证其唯一性,rowkey 是按照字典顺序排序存储的,因此, 设计 rowkey 的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。
5.4 HBase是如何处理RegionServer崩溃的问题的?
HBase RegionServer崩溃后, HMaster 会将其所管理的 region 重新分布到其他活动的RegionServer 上, 由于数据和日志都持久在 HDFS 中,该操作不会导致数据丢失. 所以数据的一致性和安全性是有保障的.
6. ES相关
6.1 详细描述一下ES索引文档的过程?
这里的索引文档应该理解为文档写入ES,创建索引的过程。
- 客户端向集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,请求的节点扮演协调节点的角色。)
- 协调节点接受到请求后,默认使用文档ID参与计算(也支持通过routing),得到该文档属于哪个分片。随后请求会被转到另外的节点。
- 当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache,这个从Momery Buffer到Filesystem Cache的过程就叫做refresh;
- 当然在某些情况下,存在Memery Buffer和Filesystem Cache的数据可能会丢失,ES是通过translog的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到translog中,当Filesystem cache中的数据写入到磁盘中时,才会清除掉,这个过程叫做flush;
- 在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。
- flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时。
补充:关于Lucene的Segement
Lucene索引是由多个段组成,段本身是一个功能齐全的倒排索引。段是不可变的,允许Lucene将新的文档增量地添加到索引中,而不用从头重建索引。对于每一个搜索请求而言,索引中的所有段都会被搜索,并且每个段会消耗CPU的时钟周、文件句柄和内存。这意味着段的数量越多,搜索性能会越低。为了解决这个问题,Elasticsearch会合并小段到一个较大的段,提交新的合并段到磁盘,并删除那些旧的小段。(段合并)
6.2 ES中的倒排索引是什么?
倒排索引,是通过分词策略,形成了词和文章的映射关系表,也称倒排表,这种词典+映射表即为倒排索引。其中词典中存储词元,倒排表中存储该词元在哪些文中出现的位置。
有了倒排索引,就能实现O(1)时间复杂度的效率检索文章了,极大的提高了检索效率。
加分项:
倒排索引的底层实现是基于:FST(Finite State Transducer)数据结构。Lucene从4+版本后开始大量使用的数据结构是FST。FST有两个优点:
- 空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;
- 查询速度快。O(len(str))的查询时间复杂度。