头条数仓模型开发工程师 -面筋一

uid tm

u1 10:00:05
u1 10:00:10
u1 10:00:15

u1 10:20:00
u2 10:31:00

求:超过2min算不在线,统计停留时长
解:分组排序,表自关联,交叉错位相减

select
a.uid,
a.start_tm,
a.start_tms,
a.rank,
(end_tms-start_tm) as stop_tms,
case (end_tms-start_tm) > 120000 then 1 else 0 as morn_2mins_flag
from
(
select
uid,
tm as start_tm,
unix_timestamp™ as start_tms,
row_number() over(partition by uid order by unix_timestamp™) as rank
from
tmp.data
) a
left join
(
select
uid,
tm,
tms,
rank
from
(
select
uid,
tm as end_tm,
unix_timestamp™ as end_tms,
row_number() over(partition by uid order by unix_timestamp™) as rank
from
tmp.data
) b
where b.rank > 1
) b
on a.uid = b.uid and a,rank = (b.rank - 1)

6.数据格式如下
empid dt is_work
e1 2019-11-01 1
e1 2019-11-02 1
e1 2019-11-03 1
e1 2019-11-04 1
e1 2019-11-06 1
e2 2019-11-03 1
e2 2019-11-04 1
e2 2019-11-05 1
e3 2019-11-03 1
e3 2019-11-04 1
e3 2019-11-05 1

求:判断连续打卡4天的员工

连续时间判断有个技巧就是排序后的数减去指定时间下的一个差值,最后这个值,如果连续的那么这个值是一样的,如果不连续就不一样

select
uid
,diff_value
,min(login_date) as login_date_min
,max(login_date) as login_date_max
,count(1) as nums
from
(
select
uid
,login_date
,((row_number() over(partition by uid order by login_date)) - datediff(login_date,‘2020-10-01’)) diff_value
from
test
) tmps
group by
uid
,diff_value

7.数据格式如下:
uid play_tm
u1 5
u2 3
u3 10
u4 15
u5 7

求:计算累计时长与总时长及其排名,类似以下
uid play_tm rank inc_tm sum_tm
u4 15 1 15 40
u3 10 2 25 40
u5 7 3 32 40
u1 5 4 37 40
u2 3 5 40 40

select
uid,
play_tm,
rank,
sum(play_tm) over(partition by 1 order by rn asc rows between unbounded preceding and current row) as inc_tm
from
(
select
uid,
paly_tm,
sum(play_tm) over(partition by uid order by paly_tm decs) as rank
from
data
) a

t1
userid,user_name
1,a
2,b
3,c

t2
userid,city
1,北京
1,上海

求有过出行记录但没有去过北京的用户name

select
userid,
name,
concat_ws(’,’,collect_list(city)) as city_info_list
from
(
select
userid,
name
from
t1
) a
inner join
(
select
userid,
city
from t2
) b
on a.userid = b.userid
group by
userid,
name
having city_info_list not like “%北京%”

数据结构:

List , Set, Map都是接口,前两个继承至Collection接口,Map为独立接口
Set下有HashSet,LinkedHashSet,TreeSet
List下有ArrayList,Vector,LinkedList
Map下有Hashtable,LinkedHashMap,HashMap,TreeMap
Collection接口下还有个Queue接口,有PriorityQueue类

Vector、ArrayList、LinkedList 有何区别?
Vector 是 Java 早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择,毕竟同步是有额外开销的。Vector 内部是使用对象数组来保存数据,可以根据需要自动的增加容量,当数组已满时,会创建新的数组,并拷贝原有数组数据。
ArrayList 是应用更加广泛的动态数组实现,它本身不是线程安全的,所以性能要好很多。与 Vector 近似,ArrayList 也是可以根据需要调整容量,不过两者的调整逻辑有所区别,Vector 在扩容时会提高 1 倍,而 ArrayList 则是增加 50%。
LinkedList 顾名思义是 Java 提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的。

集合

Set:
TreeSet
LinkHashSet
HashSet

List:
ArrayList
LinkList
Vector

Queue:
LinkList
PriorityQueue

— List 有序,可重复

ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高
扩容:0.5倍
Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低
扩容:1倍
LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高
—Set 无序,唯一

HashSet
底层数据结构是哈希表。(无序,唯一)
如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals()
HashSet 是HashMap具体实现

LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一

TreeSet
底层数据结构是红黑树。(唯一,有序)

  1. 如何保证元素排序的呢?
    自然排序
    比较器排序
    2.如何保证元素唯一性的呢?
    根据比较的返回值是否是0来决定

Map

Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。

TreeMap是有序的,HashMap和HashTable是无序的。
Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。
这就意味着:

Hashtable是线程安全的,HashMap不是线程安全的。
HashMap效率较高,Hashtable效率较低。
如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。 查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized关键字,而HashMap的源码中则没有。
Hashtable不允许null值,HashMap允许null值(key和value都允许)
父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap

HashTable 同步 线程安全
TreeMap 自然排序
LinkHashMap 插入排序

一、HashMap
hash函数:
(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
第一步 获取HashCode
第二部 高位参与运算
找寻数组中位置:
h & (length-1); h = hash
//第三步 取模运算

哈希冲突
1. 开放寻址法, 发生冲突,继续寻找下一块未被占用的存储地址
2. 散列函数法
3. 链地址法 数组+链表的方式

hashMap key 如何put值?

  1. key -> key.hashcode -> hash(key.hashcode) ->indexFor(h&(length-1))->获得数组存储下标位置 -> 看是否有链表,遍历链表按顺序插入。h&(length-1)保证获取的index一定在数组范围内
    HashMap get值
  2. key -> key.hashcode -> hash(key.hashcode) ->indexFor(h&(length-1))->获得数组存储下标位置 -> 看是否有链表,遍历链表,e.hash == hash && equals 进行比较

扩容:
当发生哈希冲突并且size大于阈值的时候,需要进行数组扩容,扩容时,需要新建一个长度为之前数组2倍的新的数组,然后将当前的Entry数组中的元素全部传输过去,扩容后的新数组长度为之前的2倍,所以扩容相对来说是个耗资源的操作

  1. 扩容后 hash 值与高位进行与运算,如果0 ,位置不变
  2. 如1,新位置为 原始位置 + 扩容前的旧容量

相关扩展资料:
https://tech.meituan.com/2016/06/24/java-hashmap.html

三、为何HashMap的数组长度一定是2的次幂?
resize方法

  1. HashMap的数组长度一定保持2的次幂,比如16的二进制表示为 10000,那么length-1就是15,二进制为01111,同理扩容后的数组长度为32,二进制表示为100000,length-1为31,二进制表示为011111。从下图可以我们也能看到这样会保证低位全为1,而扩容后只有一位差异,也就是多出了最左位的1,这样在通过 h&(length-1)的时候,只要h对应的最左边的那一个差异位为0,就能保证得到的新的数组索引和老数组索引一致(大大减少了之前已经散列良好的老数组的数据位置重新调换)
  2. 数组长度保持2的次幂,length-1的低位都为1,会使得获得的数组索引index更加均匀
  3. 所以说当length = 2^n时,不同的hash值发生碰撞的概率比较小,这样就会使得数据在table数组中分布较均匀,查询速度也较快。
  4. hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap”,省去重新计算hash值的时间,而且同时,由于新增的1bit是0还是1可以认为是随机的,因此resize的过程,均匀的把之前的冲突的节点分散到新的bucket了。

四、重写equals方法需同时重写hashCode方法
同时还要保证通过equals判断相等的两个对象,调用hashCode方法要返回同样的整数值。而如果equals判断不相等的两个对象,其hashCode可以相同

五、JDK1.8中HashMap的性能优化
即当链表超过8时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能,其中会用到红黑树的插入、删除、查找等算法。
六、HashMap Key,Value 允许数据类型

key和Value 可以为null 存数组0位置

  1. HashMap 的 key 和 value 都可以是 null
  2. HashMap 的key只能是引用数据类型
  3. Map 的 key 和 value 都 不允许 是 基本数据类型,基本数据类型不能调用其hashcode()方法和equals()方法,进行比较
  4. 能为基本数据类型,可以使用基本数据类型的包装类,例如Integer Double等。
  5. HashMap 的 key 可以是 任意对象,但如果 对象的 hashCode 改变了,那么将找不到原来该 key 所对应的 value

七、HashMap为什么不是线程安全:
1. resize(扩容)方法.
2. 不同线程put时,冲突
八、JDK1.8 HashMap扩容从头插法改为尾插法:
JDK1.7 头插法,单链表延伸,1.8改为红黑树
则是为了避免出现逆序且链表死循环的问题(JDK1.7的HashMap扩容导致死循环了解哈)。
为什么在JDK1.7的时候是先进行扩容后进行插入,而在JDK1.8的时候则是先插入后进行扩容的呢?

二、ArrayList

扩容规则: 动态数组扩容规则:(原始容量*3)/2 + 1

  1. ArrayList 实际上是通过一个数组去保存数据的。当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10。
  2. 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”。
  3. ArrayList的克隆函数,即是将全部元素克隆到一个数组中。
  4. ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。

ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。

ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。 - 浅拷贝 内部元素指向内存地址同一个
浅拷贝:
基本类型
引用类型(内存地址)

ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

三、其他扩展容器类

JVM内存空间:
eg:Student stu = new Student
(1). Heap 堆空间:分配对象 new Student
(2). Stack 栈空间:临时变量 Student stu
(3). Code 代码区 :类的定义,静态资源 Student.class
上例实现步骤:
a.JVM加载Student.class 到Code区
b.new Student()在堆空间分配空间并创建一个Student实例
c.将此实例的地址赋值给引用stu, 栈空间

问题一:什么叫垃圾回收机制?
垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用,以免造成内存泄露。

问题二:java的垃圾回收有什么特点?
Java语言不允许程序员直接控制内存空间的使用。内存空间的分配和回收都是由JRE负责在后台自动进行的,尤其是无用内存空间的回收操作(garbagecollection,也称垃圾回收),只能由运行环境提供的一个超级线程进行监测和控制。

问题三:垃圾回收器什么时候会运行?
一般是在CPU空闲或空间不足时自动进行垃圾回收,而程序员无法精确控制垃圾回收的时机和顺序等。、

问题四:什么样的对象符合垃圾回收条件?
当没有任何获得线程能访问一个对象时,该对象就符合垃圾回收条件。

问题五:垃圾回收器是怎样工作的?
垃圾回收器如发现一个对象不能被任何活线程访问时,他将认为该对象符合删除条件,就将其加入回收队列,但不是立即销毁对象,何时销毁并释放内存是无法预知的。垃圾回收不能强制执行,然而java提供了一些方法(如:System.gc()方法),允许你请求JVM执行垃圾回收,而不是要求,虚拟机会尽其所能满足请求,但是不能保证JVM从内存中删除所有不用的对象。

问题六:一个java程序能够耗尽内存吗?
可以。垃圾收集系统尝试在对象不被使用时把他们从内存中删除。然而,如果保持太多活动对象,系统则可能会耗尽内存。垃圾回收器不能保证有足够的内存,只能保证可用内存尽可能的得到高效的管理。

问题七:程序中的数据类型不一样存储地方也不一样,原生数据类型存储在java栈中,方法执行结束就会消失;对象类型存储在Java堆中,可以被共享,不一定随着方法执行结束而消失。

问题八:如何检测垃圾?(垃圾检测机制)

 垃圾收集器的两个任务:正确检测出垃圾对象和释放垃圾对象占用的内存空间,而前者是关键所在。

 垃圾收集器有一个根对象集合,包含的元素:1)方法中局部变量的引用;2)Java操作栈中的对象引用;3)常量池中的对象引用;4)本地方法持有的对象引用;5)类的class对象。

 JVM在垃圾回收的时候会检查堆中的所有对象是否会被根对象直接或间接的引用,能够被根对象到达的叫做活动对象,否则叫做非活动对象可以被回收。

内存回收 - GC 原理
jvm内存回收采用的是基于分代的垃圾收集算法
把对象分为年青代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的算法。(基于对象生命周期分析)

常用的垃圾回收算法有三种,分别是标记-清除算法、复制算法、标记-整理算法
标记-清除算法:
标记阶段:首先,通过根节点,标记所有从根节点开始的可达对象。未被标记的对象就是未被引用的垃圾对象;

清除阶段:然后,清除所有未被标记的对象。

标记-清除算法的缺点:
首先,它的缺点就是效率比较低(递归与全堆对象遍历),暂停程序stop the world的时间比较长。(尤其对于交互式的应用程序来说简直是无法接受。试想一下,如果你玩一个网站,这个网站一个小时就挂五分钟,你还玩吗?)
第二则是这种方式清理出来的空闲内存不连续,这点不难理解,我们的死亡对象都是随即的出现在内存的各个角落的,现在把它们清除之后,内存的布局自然会乱七八糟。而为了应付
复制算法(适用于年轻代GC)
概念:内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。
与标记-清除算法相比,复制算法是一种相对高效的回收方法,且内存连续。
不适用于存活对象较多的场合,如老年代(复制算法适合做新生代的GC)
优点:实现简单,运行高效,内存连续。每次只要一动指针,就可联系分配内存存放复制过来的对象。

缺点:空间浪费,只用了一半内存,所以,要想用复制算法,最起码对象的存活率要非常低才行,而且最重要的是要克服50%内存的浪费。

MR原理(https://www.cnblogs.com/tieandxiao/p/8807475.html):
https://www.cnblogs.com/yx-zhang/p/9572221.html

Map阶段
Map端Shuffle
Reduce端Shuffle
Reduce阶段
Map任务处理

Reduce端:

1、Copy阶段:Reducer通过Http方式得到输出文件的分区。

reduce端可能从n个map的结果中获取数据,而这些map的执行速度不尽相同,当其中一个map运行结束时,reduce就会从JobTracker中获取该信息。map运行结束后TaskTracker会得到消息,进而将消息汇报给  JobTracker,reduce定时从JobTracker获取该信息,reduce端默认有5个数据复制线程从map端复制数据。

2、Merge阶段:如果形成多个磁盘文件会进行合并

从map端复制来的数据首先写到reduce端的缓存中,同样缓存占用到达一定阈值后会将数据写到磁盘中,同样会进行partition、combine、排序等过程。如果形成了多个磁盘文件还会进行合并,最后一次合并的结果作为reduce的输入而不是写入到磁盘中。

3、Reducer的参数:最后将合并后的结果作为输入传入Reduce任务中。(注意:当Reducer的输入文件确定后,整个Shuffle操作才最终结束。之后就是Reducer的执行了,最后Reducer会把结果存到HDFS上。)

/

2.2 对多个map的输出进行合并、排序。覆盖reduce函数,接收的是分组后的数据,实现自己的业务逻辑, <hello,2> <me,1> <you,1>

处理后,产生新的<k,v>输出。

2.3 对reduce输出的<k,v>写到HDFS中。

///追加

partition过程

1,计算(key,value)所属与的分区。

当map输出的时候,写入缓存之前,会调用partition函数,计算出数据所属的分区,并且把这个元数据存储起来。

2,把属与同一分区的数据合并在一起。

当数据达到溢出的条件时(即达到溢出比例,启动线程准备写入文件前),读取缓存中的数据和分区元数据,然后把属与同一分区的数据合并到一起。

yarn的三大调度策略

FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。

Capacity(容量)调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。

在Fair(公平)调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。

需要注意的是,在下图Fair调度器中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终的效果就是Fair调度器即得到了高的资源利用率又能保证小任务及时完成。

MapReduce

10.用mapreduce怎么处理数据倾斜问题

数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜。

(1)局部聚合加全局聚合。

第一次在 map 阶段对那些导致了数据倾斜的 key 加上 1 到 n 的随机前缀,这样本来相

同的 key 也会被分到多个 Reducer 中进行局部聚合,数量就会大大降低。

第二次 mapreduce,去掉 key 的随机前缀,进行全局聚合。

思想:二次 mr,第一次将 key 随机散列到不同 reducer 进行处理达到负载均衡目的。第

二次再根据去掉 key 的随机前缀,按原 key 进行 reduce 处理。

这个方法进行两次 mapreduce,性能稍差。

(2)增加 Reducer,提升并行度

JobConf.setNumReduceTasks(int)

(3)实现自定义分区

根据数据分布情况,自定义散列函数,将 key 均匀分配到不同 Reducer

11.shuffle 阶段,怎么理解的

shuffle: 洗牌、发牌——(核心机制:缓存,数据分区,排序,Merge进行局部value的合并);

具体来说:就是将maptask输出的处理结果数据,分发给reducetask,并在分发的过程中,对数据按key进行了分区和排序;

1)Map 方法之后 Reduce 方法之前这段处理过程叫 Shuffle

2)Map 方法之后,数据首先进入到分区方法,把数据标记好分区,然后把数据发送到 环形缓冲区;环形缓冲区默认大小 100m,环形缓冲区达到 80%时,进行溢写;溢写前对数 据进行排序,排序按照对 key 的索引进行字典顺序排序,排序的手段快排;溢写产生大量溢 写文件,需要对溢写文件进行归并排序;对溢写的文件也可以进行 Combiner 操作,前提是汇总操作,求平均值不行。最后将文件按照分区存储到磁盘,等待 Reduce 端拉取。

3)每个 Reduce 拉取 Map 端对应分区的数据。拉取数据后先存储到内存中,内存不够 了,再存储到磁盘。拉取完所有数据后,采用归并排序将内存和磁盘中的数据都进行排序。

在进入 Reduce 方法前,可以对数据进行分组操作。

12.Mapreduce 的 map 数量 和 reduce 数量是由什么决定的 ,怎么配置

map的数量由输入切片的数量决定,128M切分一个切片,只要是文件也分为一个切片,有多少个切片就有多少个map Task。

reduce数量自己配置。

Spark提交流程:
1、构建Spark Application的运行环境,启动SparkContext
2、SparkContext向资源管理器(可以是Standalone,Mesos,Yarn)申请运行Executor资源
3、启动StandaloneExecutorbackend
4、Executor向SparkContext申请Task
5、SparkContext将应用程序分发给Executor
6、SparkContext构建成DAG图,将DAG图分解成Stage、将Taskset发送给Task Scheduler
7、最后由Task Scheduler将Task发送给Executor运行
8、Task在Executor上运行,运行完释放所有资源

什么是DAG:
在 Spark 中, 使用 DAG 来描述我们的计算逻辑。

DAG 是一组顶点和边的组合。顶点代表了 RDD, 边代表了对 RDD 的一系列操作。

DAG Scheduler 会根据 RDD 的 transformation 动作,将 DAG 分为不同的 stage,每个 stage 中分为多个 task,这些 task 可以并行运行。

Docker专题:
什么Docker?

答:Docker是一个容器化平台,它以容器的形式将您的应用程序及其所有依赖项打包在一起,以确保您的应用程序在任何环境中无缝运行。
2、Docker与虚拟机的不同点在哪里?

答:Docker不是虚拟化方法。它依赖于实际实现基于容器的虚拟化或操作系统级虚拟化的其他工具。为此,Docker最初使用LXC驱动程序,然后移动到libcontainer现在重命名为runc。Docker主要专注于在应用程序容器内自动部署应用程序。应用程序容器旨在打包和运行单个服务,而系统容器则设计为运行多个进程,如虚拟机。因此,Docker被视为容器化系统上的容器管理或应用程序部署工具。

3、Docker容器有几种状态?

答:有四种状态:运行、已暂停、重新启动、已退出。

4、Dockerfile中最常见的指令是什么?

答:FROM:指定基础镜像;LABEL:功能是为镜像指定标签;RUN:运行指定的命令;CMD:容器启动时要运行的命令。

5、Dockerfile中的命令COPY和ADD命令有什么区别?

答:一般而言,虽然ADD并且COPY在功能上类似,但是首选COPY。

那是因为它比ADD更易懂。COPY仅支持将本地文件复制到容器中,而ADD具有一些功能(如仅限本地的tar提取和远程URL支持),这些功能并不是很明显。因此,ADD的最佳用途是将本地tar文件自动提取到镜像中,如ADD rootfs.tar.xz /。

6、什么是Docker镜像?

答:Docker镜像是Docker容器的源代码。换句话说,Docker镜像用于创建容器。使用build命令创建镜像,并且在使用run启动时它们将生成容器。镜像存储在Docker注册表中,registry.hub.docker.com因为它们可能变得非常大,镜像被设计为由其他镜像层组成,允许在通过网络传输镜像时发送最少量的数据。

7、解释基本的Docker使用工作流程是怎样的?

答:(1)从Dockerfile开始,Dockerfile是镜像的源代码;(2)创建Dockerfile后,可以构建它以创建容器的镜像。图像只是“源代码”的“编译版本”,即Dockerfile;(3)获得容器的镜像后,应使用注册表重新分发容器。注册表就像一个git存储库,可以推送和拉取镜像;接下来,可以使用该图像来运行容器。在许多方面,正在运行的容器与虚拟机(但没有虚拟机管理程序)非常相似。

Spark VS MapReduce:
Spark 基于内存迭代计算
Spark RDD失败可快速从父RDD恢复
Spark更优的任务调度,DAG

1 spark中count(distinct) 的原理是什么?
使用map算子把元素转为一个带有null的元组;使用reducebykey对具有相同key的元素进行统计;之后再使用map算子,取得元组中的单词元素,实现去重的效果。
map(x => (x, null)).reduceByKey((x, y) => x, numPartitions).map(_._1)

2.spark消费kafka中数据时使用的reciver模式与direct模式的区别?
reciver是一直有一个task监听着kafka的消息,是被动的消费消息,reciver模式kafka不自己管理消费的偏移量offset,而是由zookeeper管理,这样容易造成消费的错误(提交消费偏移量时出错,那么offset就没有及时更新),reciver下从kafka读来的数据一个一个batch,bacth里是一个一个block,最后到Rdd里,Rdd中的一个partition就对应一个block
direct模式是主动的去kafka拿取数据,且direct模式下,spark自己管理offset(存内存,也可以checkpoint到hdfs),spark读取kafka的partition与DStream中Rdd的partition对应一致

3.java中HashMap的key值是那种类型?对象可不可作为key值?
key 可以为Null
key只能是引用类型,不能是基本类型
对象是可以作为key的,如string就是对象,至于其他的对象需要实现里面方法 即是需要重写hashCode和equals方法
查找key的顺序:
1.调用hashCode()计算对象的HashCode,看是否存在表中
2.如果存在表中,则调用equals()判断对象是否相同

4.hbase是写的快还是读的快?
hbase是写的快,因为写直接就往memstore里写,不用考虑其他,即使要往HLog里写,也是先经过memstore再到HLog
对于读,一般是先从memstore里读取,如果没有,再根据meta表里记录的表所处的region信息再取查找对应的region上的数据,综合来看,是写的快
1. Hbase写入速度比读取速度要快,根本原因LSM存储引擎
2. 就是假定内存足够大,因此不需要每次有数据更新就必须将数据写入到磁盘中,而可以先将最新的数据驻留在内存中,等到积累到最后多之后,再使用归并排序的方式将内存内的数据合并追加到磁盘队尾
3. HBase读取首先会在缓存(BlockCache)中查找,它采用了LRU(最近最少使用算法),如果缓存中没找到,会从内存中的MemStore中查找,只有这两个地方都找不到时,才会加载HFile中的内容,而上文也提到了读取HFile速度也会很快,因为节省了寻道开销。

delta lake

spark sql 运行原理:

核心用到了Catalyst 框架

  1. 调用Parser 模块将 SQL 抽象转换为AST 语法树

  2. 调用Analysis 模块,及模式匹配 对树上每个节点进行绑定解析转换

  3. 调用Optimizer: 规则和 成本优化
    3.1 谓词下推
    3.2 列裁剪
    3.3 连接重排序
    3.4 常量累加
    3.5 成本优化 多个逻辑执行计划 结合数据分布选出最优解

  4. 转物理执行计划

flink-sql 解析过程:

  1. 用户使用对外提供Stream SQL的语法开发业务应用
  2. 用calcite对StreamSQL进行语法检验,语法检验通过后,转换成calcite的逻辑树节点;最终形成calcite的逻辑计划
  3. 采用Flink自定义的优化规则和calcite火山模型、启发式模型共同对逻辑树进行优化,生成最优的Flink物理计划
  4. 对物理计划采用janino codegen生成代码,生成用低阶API DataStream 描述的流应用,提交到Flink平台执行

flink waterMark

flink 延迟数据处理:

1. 直接将迟到的数据丢弃
2. 将迟到的数据输出到单独的数据流中,即使用sideOutputLateData(new OutputTag<>())实现侧输出
3. 根据迟到的事件更新并发出结果

Flink VS SparkStreaming

Flink 是标准的实时处理引擎,基于事件驱动。而 Spark Streaming 是微批(Micro-Batch)的模型。

  1. 架构模型
    Spark Streaming 在运行时的主要角色包括:Master、Worker、Driver、Executor,Flink 在运行时主要包含:Jobmanager、Taskmanager和Slot。
  2. 任务调度
    Spark Streaming 连续不断的生成微小的数据批次,构建有向无环图DAG,Spark Streaming 会依次创建 DStreamGraph、JobGenerator、JobScheduler。
    Flink 根据用户提交的代码生成 StreamGraph,经过优化生成 JobGraph,然后提交给 JobManager进行处理,JobManager 会根据 JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 调度最核心的数据结构,JobManager 根据 ExecutionGraph 对 Job 进行调度。
  3. 时间机制
    Spark Streaming 支持的时间机制有限,只支持处理时间。Flink 支持了流处理程序在时间上的三个定义:处理时间、事件时间、注入时间。同时也支持 watermark 机制来处理滞后数据。
  4. 容错机制
    对于 Spark Streaming 任务,我们可以设置 checkpoint,然后假如发生故障并重启,我们可以从上次 checkpoint 之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰一次处理语义。
    Flink 则使用两阶段提交协议来解决这个问题

slot和parallelism关系
1.slot是静态的概念,是指taskmanager具有的并发执行能力

2.parallelism是动态的概念,是指程序运行时实际使用的并发能力

3.设置合适的parallelism能提高运算效率,太多了和太少了都不行

4.设置parallelism有多中方式,优先级为api>env>p>file

工厂模式:
工厂是创建型模式,它的作用就是创建对象

策略模式:
策略是行为型模式,它的作用是让一个对象在许多行为中选择一种行为;
原则就是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为的变化独立于算法的使用者。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值