Spark
./spark-submit --class com.kgc.myspark01.WordCount --master yarn --deploy-mode cluster /opt/myspark01-1.0-SNAPSHOT.jar
1.Client向YARN的ResourceManager申请启动Application Master。Client中创建SparkContext同时初始化中将创建DAGScheduler和TASKScheduler等。
2.ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster
与YARN-Cluster区别的是在该ApplicationMaster不运行SparkContext,只与SparkContext进行联系进行资源的分派;
3.Client中的SparkContext初始化完毕后,与ApplicationMaster建立通讯,向ResourceManager注册,申请资源(Container)。一旦ApplicationMaster申请到Container后,便与对应的NodeManager通信,开辟Container或者直接在某个Container上启动Executor,向Client中的SparkContext注册并申请Task。
4.SparkContext将任务进行分解,先分解成Stage,然后进一步分解出task,发送到Executor中执行;Executor创建线程池,来运行这些任务,并及时向SC汇报执行情况;
5.应用程序运行完成后,Client的SparkContext向ResourceManager申请注销并关闭自己。
Spark Yarn Cluster模式
跟上面差不多 就是SparkContext的位置不一样 这边是在Application Master中
spark的Driver端就是在ApplicationMaster中
sparkcore编程步骤:启动 最好先开hadoop 然后在sbin下start-all 再在bin下./spark.shell
rdd分布式和partition详解:
说白了就是一个RDD它的分区是极有可能存储在不同结点上的
RDD上定义的函数分两种:转化函数和行动函数。
所有对rdd自身的操作都是在driver上执行的。
但比如foreach、foreachPartition都是针对rdd内部数据进行处理的
RDD弹性主要是下面123点
RDD两种创建方式:
1.读取内存数据创建RDD,Spark主要提供了两个方法:parallelize和makeRDD。
2.读取文件创建RDD,Spark提供了textFile和wholeTextFiles方法:
面试:描述一下spark的shuffle?分区?
1.可以举个例子:repartition默认调用的是coalesce(分区数,true)true是默认shuffle的 如果直接调用coalesce 那可以将参数改为false 就可以不发生shuffle 一次shuffle基本就是一次stage
2.分区数据重新分区时会出现1个分区数据分配到其他多个分区的情况,也就形成了「宽依赖」
减小分区的根本是将1个分区完整归类到另一个分区中,属于1对1的情况,也就形成「窄依赖
宽依赖窄依赖主要就是看 父分区的被多少子分区使用 大于1就是宽依赖 反之窄依赖
rdd.glom().collect() 将每一个分区的数据放到一个数组中然后收集
面试假如问makeRDD和paralleize的区别 区别就是paralleize底层就是makeRDD
当调用parallelize()方法的时候,不指定分区数的时候,使用系统给出的分区数,而调用makeRDD()方法的时候,会为每个集合对象创建最佳分区,就是自动分配一个合理的数
算子的血统 主要作用是可以通过Lineage获取足够的信息来重新运算和恢复丢失的数据分区
相比于宽依赖,窄依赖对优化很有利 ,主要基于以下两点:
1.宽依赖往往对应着shuffle操作,需要在运行过程中将同一个父RDD的分区传入到不同的子RDD分区中,中间可能涉及多个节点之间的数据传输;而窄依赖的每个父RDD的分区只会传入到一个子RDD分区中,通常可以在一个节点内完成转换。
2.当RDD分区丢失时(某个节点故障),spark会对数据进行重算。
容错性:
检查点需要你手动指定目录 落盘 即使程序都关闭 他还在
刚刚的缓存的落盘其实只是临时文件 sparkContext关闭后就会自动销毁
scala闭包的意思:大概就是你一个函数里面有两个参数 一个是你入参x 叫绑定变量 还有一个是more自由变量
这里需要注意的是,闭包捕获的是变量本身,即是对变量本身的引用,这意味着:闭包外部对自由变量的修改,在闭包内部是可见的;闭包内部对自由变量的修改,在闭包外部也是可见的。
spark闭包的意思:
在实际计算时,Spark 会将对 RDD 操作分解为 Task,Task 运行在 Worker Node 上。在执行之前,Spark 会对任务进行闭包,如果闭包内涉及到自由变量,则程序会进行拷贝,并将副本变量放在闭包中,之后闭包被序列化并发送给每个执行者。因此,当在 foreach 函数中引用 counter 时,它将不再是 Driver 节点上的 counter,而是闭包中的副本 counter,默认情况下,副本 counter 更新后的值不会回传到 Driver,所以 counter 的最终值仍然为零。
需要注意的是:在 Local 模式下,有可能执行 foreach 的 Worker Node 与 Diver 处在相同的 JVM,并引用相同的原始 counter,这时候更新可能是正确的,但是在集群模式下一定不正确。所以在遇到此类问题时应优先使用累加器。
累加器的原理实际上很简单:就是将每个副本变量的最终值传回 Driver,由 Driver 聚合后得到最终值,并更新原始变量。
Redis:
五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
redis天生16个库
查看所有的键:keys *
登录和切换库:redis-cli -h ip地址
set、get用于String类型 一个key对应一个字符串
再set就会覆盖之前的
Hash hset、hget 多个就加个m hmset hmget
拿多个hmget ddd name1 name3 name4 这么拿的
List(我们发现他是个栈!先进后出!下标是反过来的)
用的是lpush lrange
Set sadd不会覆盖 没有的话就创建set
SparkStreaming
KafkaUtils:
createDirectStream的四个参数 StreamingContext, LocationStrategy, ConsumerStrategy, PerPartitionConfig
LocationStrategies的是三个可选项
解决序列化的两个办法 脱壳或者包装
每次获取的一批数据生成一个RDD 一个离散流就是这些连续的rdd组成的 也就是RDDs
SparkStreaming中的foreachRDD方法就是处理每一个时间段内的RDD数据,直接操作的话就是处理所有的数据。
那么rdd在经过算子过后也会生成新的rdd 但是是和之前的rdd有血缘关系的
大部分的算子 进来处理的都是每行数据 就比如map 那就是每行执行一次map算子 然后最后是一个总的rdd
有状态操作:
进来的是单词的形式 然后把它先变成(单词,1)说白了就是你要先自动把它变成一个元组 然后才能updateStateByKey才能根据key把相同的key的分到一组变成一个seq序列
currval就是你这次处理的这个key的所有数的序列 histval是上次计算的历史值(状态值)
Flume:大数据面试题flume篇_后季暖的博客-CSDN博客
Kafka:
生产端数据丢失解决方案 ack1或-1
然后会产生数据重复 没有完美解决方案 除非幂等性+事务
消费端自动提交就是拿到数据游标offset就立即向前推
所以改成手动提交解决这个问题 但又会出现重复消费
这时就需要将异步提交改为同步提交
如果不在kafka中解决消费端重复 外面可以用
生产环境中比较常见的是 我们要将order表的所有数据都发送到kafka的一个分区 这时我们就可以指定分区key为表名 key一样的说明hashcode也一样 就会都到一个分区
自定义分区:
原理架构:
RecordAccumulator是用来缓存这些数据的 一个分区对应一个DQuene(双端队列) 一个DQuene存放batch batch一旦满足你设定的16K或者到达linger时间 则会sender线程把他们发送到kafka集群中
对应的参数:
数据重复:所有数据都同步了 都已经存储好了 但是就是应答的一瞬间leader挂了 就会发生重复问题(选新的leader会再发一遍)
假如发送失败收到异常会重发(一般leader有资格抛异常) isr机制是follower那边纯得不到回应 然后把该结点踢掉
数据乱序问题:
上图:因为开启了幂等性 所以每个请求(requst)都有序列号 这个序列号是单调递增的 比如你先收到request1、2直接落盘 然后这时收到request4 不是3 所以会自动缓存(最多缓存5个)一直直到收到request3 然后会把此时的3、5、4排个序 5、4、3 所以可以保证数据有序
这就是开启了事务 每波来的数据 也就是每次请求 在分区内是有序的 因为序列号不对 可以缓存 然后等下一个序列号的请求来
上面的requests.per.connection就是缓存的数量的意思 也就意味着你没开幂等性 所以无法缓存>1 就是每次只能存一个 然后一个一个放入kafka
32_尚硅谷_Kafka_Broker_Follower故障_哔哩哔哩_bilibili
Consumer不用push 因为每个消费者的消费速率不一样 你在kafka中直接把如图1、2、3等数据按照50m/s速度推到Consumer肯定不行
消费的时候 肯定要记录到消费到哪里了 就有了offset 防止消费到一半Consumer挂了 然后重启 再从offset开始消费 所以offset肯定不和consumer在一起 那为什么不放zookeeper呢?因为这样的话 你不断消费 也会不断更新offset到zoo 这样发生大量的交互 所以我们放到一个系统主题 也是一个topic:_consumer_offsets
初始化流程 说白了就是每个consumer先把申请加入组的请求发给coordinator(cd),然后cd选个consumer当leader,再把消费情况发给leader,leader制定消费方案(就是哪个consumer消费哪个分区)返回cd,cd再把方案发给每个consumer,然后每个consumer和cd保持心跳
说白了就是先提交过去消费 再提交offset(其实是offset每隔多少秒提交一次)所以有些数据已经消费了但还没来得及提交offset 这样下次会重复消费 但还有一种情况 就是你已经提交过去消费了 但没消费完 而此时offset提交完了 此时消费者挂了 这样下次就会造成数据丢失
kafka面试题:20道常见的kafka面试题以及答案_Happy编程的博客-CSDN博客_kafka面试题
【2021最新版】Kafka面试题总结(25道题含答案解析)_Java小叮当的博客-CSDN博客_kafka面试题
kafka和zookeepr关系:
1、存储元数据信息:包括consumerGroup/consumer、broker、Topic等;
2、0.8版本kafka支partition级别的replication,所以Kafka负责选出一个Broker节点作为controller来在一个partiiton内副本间进行Leader选举,维护出一个ISR;
3、目前,没了zk,kafka启动都启不起来。