大数据私房菜-21/4/27

大数据私房菜

Kafka为什么吞吐量大、速度快?

一、顺序读写

Kafka就是使用了磁盘顺序读写来提升的性能。Kafka的message是不断追加到本地磁盘文件末尾的,而不是随机的写入,这使得Kafka写入吞吐量得到了显著提升 。

这种方法有一个缺陷—— 没有办法删除数据 ,所以Kafka是不会删除数据的,它会把所有的数据都保留下来,每个消费者(Consumer)对每个Topic都有一个offset用来表示 读取到了第几条数据 。

二、Page Cache

为了优化读写性能,Kafka利用了操作系统本身的Page Cache,就是利用操作系统自身的内存而不是JVM空间内存。这样做的好处有:

1避免Object消耗:如果是使用 Java 堆,Java对象的内存消耗比较大,通常是所存储数据的两倍甚至更多。

2避免GC问题:随着JVM中数据不断增多,垃圾回收将会变得复杂与缓慢,使用系统缓存就不会存在GC问题

相比于使用JVM或in-memory cache等数据结构,利用操作系统的Page Cache更加简单可靠。首先,操作系统层面的缓存利用率会更高,因为存储的都是紧凑的字节结构而不是独立的对象。其次,操作系统本身也对于Page Cache做了大量优化,提供了 write-behind、read-ahead以及flush等多种机制。再者,即使服务进程重启,系统缓存依然不会消失,避免了in-process cache重建缓存的过程。

通过操作系统的Page Cache,Kafka的读写操作基本上是基于内存的,读写速度得到了极大的提升。

三、零拷贝

通过这种 “零拷贝” 的机制,Page Cache 结合 sendfile 方法,Kafka消费端的性能也大幅提升。这也是为什么有时候消费端在不断消费数据时,我们并没有看到磁盘io比较高,此刻正是操作系统缓存在提供数据。

当Kafka客户端从服务器读取数据时,如果不使用零拷贝技术,那么大致需要经历这样的一个过程:

1.操作系统将数据从磁盘上读入到内核空间的读缓冲区中。

2.应用程序(也就是Kafka)从内核空间的读缓冲区将数据拷贝到用户空间的缓冲区中。

3.应用程序将数据从用户空间的缓冲区再写回到内核空间的socket缓冲区中。

4.操作系统将socket缓冲区中的数据拷贝到NIC缓冲区中,然后通过网络发送给客户端。

kafka与传统的消息队列有什么不同

1.首先kafka会将接收到的消息分区(partition),每个主题(topic)的消息有不同的分区,这样一方面消息的存储就不会受到单一服务器存储空间大小的限制,另一方面消息的处理也可以在多个服务器上并行。

2.其次为了保证高可用,每个分区都会有一定数量的副本(replica)。这样如果有部分服务器不可用,副本所在的服务器就会接替上来,保证应用的持续性。

3.然后保证分区内部消息的消费有序性。

4.Kafka还具有consumer group的概念,每个分区只能被同一个group的一个consumer消费,但可以被多个group消费。

hadoop的ha

Active NameNode 和 Standby NameNode:两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务。

主备切换控制器 ZKFailoverController:ZKFailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。ZKFailoverController 能及时检测到 NameNode 的健康状况,在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换,当然 NameNode 目前也支持不依赖于 Zookeeper 的手动主备切换。

Zookeeper 集群:为主备切换控制器提供主备选举支持。

共享存储系统:共享存储系统是实现 NameNode 的高可用最为关键的部分,共享存储系统保存了 NameNode 在运行过程中所产生的 HDFS 的元数据。主 NameNode 和备NameNode 通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主 NameNode 在确认元数据完全同步之后才能继续对外提供服务。

DataNode 节点:除了通过共享存储系统共享 HDFS 的元数据信息之外,主 NameNode 和备 NameNode 还需要共享 HDFS 的数据块和 DataNode 之间的映射关系。DataNode 会同时向主 NameNode 和备 NameNode 上报数据块的位置信息。

HBase查询为什么这么快?

首先数据量很大的时候,HBase会拆分成多个Region分配到多台RegionServer.
客户端通过meta信息定位到某台RegionServer(也可能是多台),
通过Rowkey定位Region,这当中会先经过BlockCache,这边找不到的话,再经过MemStore和Hfile查询,这当中通过布隆过滤器过滤掉一些不需要查询的HFile。

使用场景

  • 单表数据量超千万,而且并发还挺高。
  • 数据分析需求较弱,或者不需要那么灵活或者实时

用户登录表A,字段:user_id,device_id,login_date,求用户最大连续登录天数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
select
t3.user_id,
max(day_count) max_day
from
(
select
t2.user_id,
count(date_diff) as day_count
from
(
select
t1.user_id,
t1.device_id,
date_sub(login_date,rank) date_dif
from
(
select
A.user_id,
A.device_id,
A.login_date,
rank() over(partition by user_id order by login_date) rank
from A
) t1
) t2
group by user_id
) t3

今日面经

synchronized与volatile的区别

  • volatile是线程同步的轻量级实现,因此volatile性能好于synchronized
  • voaltile修饰变量,synchronized修饰方法和代码块
  • 多线程访问volatile不会发生阻塞,但访问synchronized可能会阻塞
  • volatile可以保证数据的可见性,但不能保证原子性;而synchronized既可以保证原子性,也可以间接保证可见性。
  • volatile解决的是变量在多个线程之间的可见性,而Synchronized解决的是多个线程之间访问资源的同步性

hadoop是什么

Apache Hadoop软件库是一个框架,它允许使用简单的编程模型跨计算机群集分布式处理大型数据集(海量的数据)。

HADOOP的核心组件有:

HDFS(分布式文件系统)

YARN(运算资源调度系统)

MAPREDUCE(分布式运算编程框架)

ArrayList原理,为什么初始是10,为什么扩容1.5倍

优点:

ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快。
ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已。
根据下标遍历元素,效率高。

通过上述:我们大概可知当add一个元素时候的扩容流程。

添加一个元素,首先计算当前的list所需最小的容量大小,是否需要扩容等。当需要扩容时:

1.得到当前的ArrayList的容量(oldCapacity)。

2.计算除扩容后的新容量(newCapacity),其值(oldCapacity + (oldCapacity >> 1))约是oldCapacity 的1.5倍。

这里采用的是移位运算(关于移位运算,后续会讲到)。

为什么采用这种方法呢?应该是出于效率的考虑。

3.当newCapacity小于所需最小容量,那么将所需最小容量赋值给newCapacity。

4.newCapacity大于ArrayList的所允许的最大容量,处理。

5.进行数据的复制,完成向ArrayList实例添加元素操作。

b+树和b树

  1. B+树中只有叶子节点会带有指向记录的指针(ROWID),而B树则所有节点都带有,在内部节点出现的索引项不会再出现在叶子节点中。

  2. B+树中所有叶子节点都是通过指针连接在一起,而B树不会。

B+树的优点:

  1. 非叶子节点不会带上ROWID,这样,一个块中可以容纳更多的索引项,一是可以降低树的高度。二是一个内部节点可以定位更多的叶子节点。

  2. 叶子节点之间通过指针来连接,范围扫描将十分简单,而对于B树来说,则需要在叶子节点和内部节点不停的往返移动。

公平锁和非公平锁

公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。

非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。

redeuce怎么知道从哪里下载map输出的文件

Shuffle是MapReduce处理流程中的一个流程,它的每一个处理步骤是分散在各个maptask和reducetask节点上完成的,整体来看,分为3个操作:

\1.分区partition

\2.Sort根据key排序

\3.Combiner进行局部value的合并

详细流程

  1. maptask收集map方法输出的kv对,放到内存缓冲区中
  2. 从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件
  3. 多个溢出文件会被合并成大的溢出文件
  4. 在溢出过程中,及合并的过程中,都要调用partition进行分组和针对key进行排序
  5. reducetask根据自己的分区号,去各个maptask机器上去响应的结果分区数据
  6. reducetask会取到同一个分区来自不同maptask的结果文件,reducetask会将这些文件再进行合并(归并排序)
  7. 合并成大文件后,Shullfe的过程也就结束了,后面进入reducetask的逻辑运算过程(从文件中取出一个一个的键值对组,调用用户自定义的reduce()方法)

Shullfe中的缓冲区大小会影响到MapReduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快.缓冲区大大小可以通过参数调整,参数:io.sort.mb,默认为100M.

spring ioc和aop

(1)IOC是什么?

注:(Inversion Of Controll 控制反转) 对象之间的依赖关系由容器来建立。

(2)DI是什么?

注:(Dependency Injection 依赖注入) 容器通过调用set方法或者构造器来建立对象之间的 依赖关系。 IOC是目标,DI是手段。

aop

Spring AOP是其实是通过动态代理来实现业务逻辑的插入,是开发者在开发是不用关注其他与业务无关的点,通过代理的方式做到了插拔式操作。