hdfs
1.为什么HDFS系统的分块大小为64,128,256mb效率最高?
1.1 分块过小1.1.1 导致硬盘寻址时间长
1.1.2 消耗namenode的内存大,namenode的内存资源是宝贵的,减少分块信息内存消耗可以让namenode 去做更多其他的事情。
1.2 分块过大
1.2.1 发生监管时间问题,namenode无法估计datanode是否死亡
1.2.2 数据量越大,时间复杂度越大,计算一个块中的数据的时间越长,得不偿失。
2. 为什么分片的大小要等于分块的大小最合理,hadoop会为每一个分片创建一个map,增加了并行处理的能力
2.1 分片小于块大小 : 分片越小,管理分片和构建map的时间就会加长。
2.2 分片大于块大小 : 需要在多个分块上存储一个分片,计算时需要通过网络调数据,增加网络消耗。
3.map任务输出到本地磁盘,因为一旦把数据传输给reduce,map数据就会被删除所以不需要存储在hdfs上面浪费资源。
hflush: 语义是保证flush的数据被新的reader读到,但是不保证数据被datanode持久化.
hsync: 与hflush几乎一样,不同的是hsync保证数据被datanode持久化。
4.如何实现hdfs的容错性:每一个存有文件的块数据都会复制三份放在不同的datanode上。
5.关于hdfs高可用:
5.1 备份元数据所在的文件
5.2 增加namenode备用节点
6. hdfs提供了缓存池,对经常使用的块数据可以进行显示的缓存,并可以设置缓存时间。spark就是利用数据放入内存来提高运行的速度。这里解释下spark比mr快10-100倍的条件就是spark将文件缓存到内存中来快速的读取实现的。不通过缓存,spark的速度比mr快4-5倍左右。
7. 2.x版本的hdfs提供了 联邦HDFS 使用多台服务器形成多个namenode并且每一个namenode互不通信 各自管理不同的目录
8. 故障切换和规避:当namenode挂了的时候,备用namenode会在1分钟以内接管(为了确保namenode确实挂了),但是当因为网络情况等特殊原因,namenode没有挂掉,这个时候会采用 “一枪爆头” 将namenode挂掉,因为不能让两个namenode同时存在。
9.文件块在集群中均匀分布时,hdfs能达到最佳工作状态,当使用ditcp在集群中或者集群之间使用时,将map的数量多于集群的数量来达到分布均匀。但是想限制map来运行其他方法就应该使用balancer工具
YARN
1.ResourceManager是全局的,负责对于系统中的所有资源有最高的支配权 AM负责向ResourceManager索要NodeManager执行任务所需要的资源容器以及跟踪这些资源的使用情况以及任务进度的监控 NodeManager 是客户端框架负责 containers, 监控他们的资源使用 (cpu, 内存, 磁盘, 网络) 和上报AM 给 ResourceManager
2.yarn的三种调度模式:slot-based 公平调度算法:不考虑cpu只考虑内存。单一资源调度。
FIFO调度:按顺序调度任务,队列中先进先出。不适合共享集群使用
容量调度器:多个使用者分配多个队列,每个队列中按FIFO调度,当一个队列的资源不够时,容量调度器会把空闲的资源从其他队列调度给它,称为弹性队列 yarn.scheduler.capacity.<>.user-limit-factor大于1 默认为1。但是当没有空闲资源时,队列只能等待其他队列释放资源,降低了运行效率,解决方式:yarn.scheduler.<>.maximum-capacity为队列设置一个最大容量限制,这样队列就不会过多的侵占其他的资源。但是牺牲了弹性,需要不断的尝试找到一个合理的值。作业中制定队列只能使用最好的队列名 不能<>.<>
公平调度器:1.在一个队列占用所有的资源时,启动了另一个作业,公平调度器会在延时后为两个作业分配差不多的资源。可以自己在fair-scheduler.xml或者通过yarn.scheduler.fair.allocation.file来修改文件名,该文件中可以对每一个队列进行设置,设置权重,还可以为特定队列设置调度器。可以只是匹配规则<queuePlacementPolicy>
2.公平调度器提供了抢占的功能,可以强行终止那些占用超过半数的容器。但是会降低性能,因为容器需要重新启动。yarn.scheduler.fair.preemption设置为true全面开启抢占。注意:需要设定最小共享时间或者公平共享时间来允许抢占容易。在分配文件中设置
3.延迟调度:所以的调度器都以本地请求为重(提供集群带宽的效率),yarn不会简单的使用收到的第一个调度机会,而是会等待。直到设定值后,还是最大的容量允许,那么会放宽本地限制去同一机架上寻找其他容器运行。容量调度器:yarn.scheduler.capacity.node-locality-delay 设置为正整数。会让yarn错过正整数个调度机会。公平调度器:yarn.scheduler.fair.locality.threshold.node设为0.5表示调度器在接受同一个机架上的其他节点之前,将一直等待集群中超过一半的节点都已经给过调度机会。
4.主导资源公平性:RDF:针对不同的资源类型的调度算法。同时考虑内存和cpu。
Hadoop I/O
1.数据完整性:HDFS会对所有写入的数据计算校验和,并在读取数据是计算校验和。写入操作时管线中的最后一个datanode会验证校验和。每一个datanode会持久保存一个用于验证的校验和,每当客户读取数据是会更新校验和和时间,datanode自身会运行一个类来定期验证校验和并刷新时间。如果数据损坏,dn会报告给nn,nn会标记为损坏,并从其他的复本复制一个过来。如果想要检查一个损坏的文件 :hadoop fs -checksum
ChecksumFileSystem类提供校验和的方法。读取报错是会将出错的文件和校验和移到一个名为bad_files的文件夹中。定时检查。
2.文件压缩:
LZO速度最快但是压缩效果不好,BZIP2效果最好但是压缩速度太慢,均可支持切分。
源码:conf.setMapOutputCompressorClass(LzopCodec.class)map中使用压缩lzo
3.序列化:将结构性对象转化为字节流,方便传输和永久存储。Writable对象。
SPARK
1.RDD是一种弹性分布式数据集,弹性指的是 rdd是一种数据集的抽象,通过接口可以 放置数据在硬盘或者内存中,不需要在乎数据的格式。并且rdd之间有血统,任何一个出错的rdd可以通过重新计算他的父rdd来重建。
2.stage是通过聚合来划分的,stage的中间数据传递给下一个rdd后就失效了,要重新使用中间就要重新计算,浪费性能,所以stage提供了 两种机制(cache缓存)和 (checkpoint) 检查点 来缓存数据防止重新计算。
RDD 的主要属性 ,rdd name sparkcontext sparkconf parent storageLevel partitioner check point Iterator
SparkContext : sparkcontext 为spark job 的入口 ,由是sparkdrvie 创建在client 端 包括集群链接 ,RDDid 创建抽样 累加器 广播变量等
SparkConf Spark 参数配置信息
Parent 指向依赖上层RDD的partitioner id 利用dependencies 方法可以查找RDD所依赖的partition 的List 集合
StorageLevel 一个枚举类型 用来存储RDD 的 存储级别 ,内存 磁盘 堆外内存 ,另外还包括是否 序列化操作 以及 副本数量
Partitioner RDD 的分区方式 ,()Hash 和 Range 这两种的分区类型都是 Key vale ,如果是非 k-v 分区类型是None
Hash 是以key 作为分区条件的散列分布 ,分区数据不连续 ,可能会导致数据不均 引起 **********************
Range 按key 的排序平衡分布 ,分区内数据连续 大小相对一致
Check Point
spark 提供的一种缓存机制 ,当需要计算的RDD 过多时候 为了避免重新计算之前的RDD造成 资源浪费 ,可以对 RDD 做 checkpoint 操作 ,检查RDD是否被物化或计算 ,并将结果 持久化,与 spark 提供的另外一种 缓存机制相比 cache ,cache 的缓存数据有 executor 管理 ,所以 executor 如果消逝了 那么 缓存的数据也就没了 RDD 从而重新计算
Iterator 说真的 不是特明天 这个东西是干嘛的
迭代器 用来 查看当前RDD 跟 上层 RDD 的 依赖关系 并通过 storeageLevel 确定存储位置
迭代方式 氛围 checkpoint 和 RDD 迭代
如果StorageLevel 为None 则 执行 computeorReadcheckpoint 方法计算并获取数据 ,迭代checkpoint数据的存放位置 ;如果checkpoint 不为None 根据存储级别 进入相应的RDD 迭代器 继续迭代上层RDD 知道获取数据 位置 。而迭代器内部有本地优化策略 ,先从本地获取数据 ,如果没有则远程查找
关于Spark Streaming数据输出多次重写及其解决方案
a、为什么会有这个问题,因为Spark Streaming在计算的时候基于Spark Core,Spark Core天生会做以下事情导致Spark Streaming的结果(部分)重复输出:
Task重试;
慢任务推测
Stage重复;
Job重试;
b、具体解决方案:
设置spark.task.maxFailures次数为1;最大允许失败的次数,设为1就没有task、stage、job等的重试;
设置spark.speculation为关闭状态(因为慢任务推测其实非常消耗性能,所以关闭后可以显著提高Spark Streaming处理性能)
Spark Streaming on Kafka的话,Job失败会导致任务失败,Job失败后可以设置auto.offset.reset为“largest”的方式;
c、怎么保证数据零丢失?
必须要有可靠的数据来源和可靠的Receiver、整个应用程序的MetaData必须进行CheckPoint、通过WAL来保证数据安全(生产环境下Receiver接收Kafka的数据,默认情况下会在Executor中存在二份数据,且默认情况下必须二份数据备份后才进行计算;如果Receiver接收数据时崩溃,没有拷贝副本,此时会重新从Kafka中进行拷贝,拷贝的依据是zookeeper元数据)。
大家可以将Kafka看作是一个简单的文件存储系统,在Executor中Receiver确定受到Kafka的每一条记录后进行Replication到其他Executor成功后会通过ack向Kafka发送确认收到的信息并继续从Kafka中读取下一条信息。
性能补充:
a、通过WAL方式保证数据不丢失,但弊端是通过WAL方式会极大的损伤SparkStreaming中的Receiver接收数据的性能(现网生产环境通常会Kafka direct api直接处理)。
b、需要注意到是:如果通过Kafka作为数据来源的话,Kafka中有数据,然后Receiver接受数据的时候又会有数据副本,这个时候其实是存储资源的浪费。(重复读取数据解决办法,读取数据时可以将元数据信息放入内存数据库中,再次计算时检查元数据是否被计算过)。