Hadoop学习笔记
Hadoop
分布式计算平台,同时也是一个生态圈
- hadoop 1.X HDFS+MapReducer+Common
- hadoop 2.X HDFS+MAP+Reducer+Common
- hadoop 3.X java7->java8,引入纠删码,重写shell脚本,支持超过两个NameNode,默认端口改变
HDFS
分布式文件存储系统(可靠,高吞吐),利用目录树定位文件
- 可靠性-维护多个副本
- 扩展性-随时增减服务器
- 高效性-task并行
- 容错性-失败的任务重新分配执行
- 适合一次写入多次读出
- 支持数据的追加写入,不支持随机修改
- 采用Master/Slave架构,除去HA的两个NN节点外都是用一个NN节点+多个DN节点组成
- 数据存储采用block机制,在2.X版本中默认为128MB
- 命名空间:NN负责维护文件系统的名字空间,
HDFS组件
NameNode(主)
- NameNode 存储文件的元数据,位置信息
- 配置副本策略
- 管理数据块映射信息
- 处理读写请求
DataNode(从)
- DataNode 存储文件的真实数据,并做数据校验
- 一个数据块在DN中会存储数据本身,数据长度,检验和以及时间戳。同时DN启动后会向NN进行注册,后续每隔一小时向NN汇报数据块信息,同时每三秒进行一次NN心跳并带回NN指令,如果10分钟没有心跳信号,NN会认为该节点宕机。
- 在数据节点退役过程中推荐使用黑名单进行退役,辞职后会进行HDFS数据转移。
SecondaryNameNode
- SecondaryNameNode 对NameNode做备份,但不能顶替NN提供服务
- 监控HDFS状态,定期获取快照
- 定期合并镜像文件,编辑日志,推送给NN
- 可以恢复NN的数据(可能不完整)
Client
- Client切分上传的文件
- 告知NN文件的位置信息,交互DN的读写数据
- 通过命令管理HDFS
HDFS文件的上传与下载
- 上传:客户端通过HDFS对象向NameNode提交上传请求,NN确定文件状态以及父目录是否存在,返回许可。随后用户上传文件的第一个数据块,请求NN返回DataNode,NN根据请求返回三个DN节点,用户通过输出流请求在一个DN上上传数据(上传的DN根据网络拓扑计算决定),然后该DN会调用其他的DN节点将这个通信信道建立完成。三个节点逐级应答客户端,客户端向第一个DN节点上传一个数据块,以packet为单位,DN收到后先进行落盘处理,同时将该packet传送给第二个DN节点然后再传给第三个DN节点。当第一个块传输完成后,第二个数据块重复上面的动作,传递完成后关闭传输流,传输过程中,第一个DN节点会将packet放入一个应答队列,待所有节点相应完成后表示上传成功。
- 下载: 客户端访问HDFS对象,向NameNode请求下载某文件,NameNode返回文件的元数据信息,以及数据块坐在的位置。客户端得到信息后获取文件输入流,根据就近原则随机原则随机挑选一个DN节点获取packet,客户端收到后现在本地缓存,然后写入目标文件。
NameNode与SecondaryNameNode的机制
- NN在启动后会将fsimage和edits加载到内存里,格式化后则是创建。客户端对HDFS进行操作后,NN先将操作记录到日志中,然后再内存中进行操作,2NN向NN询问是否CheckPoint,带回指令。如果CheckPoint,NN会生成一个滚动的日志文件,一个磁盘中编辑日志的复制文件,将磁盘中的镜像文件和复制好的编辑日志文件复制到2NN中,加载到2NN内存中合并成一个合并文件,返回到NN中,NN用重命名的方式覆盖原文件。
- fsimage是HDFS文件系统中元数据的一个永久性检查点
- edits存放HDFS文件系统中所有的更新操作
- CheckPoint触发点为1小时或者edits执行了一百万次操作。2NN在一分钟内确认三次NN的操作次数
Yarn组件
- ResourceManager 处理客户端请求,监控NodeManager,启动ApplicationMaster,调度资源
- NodeManager 管理单个节点上的资源,处理ResourceManager的命令,处理ApplicationMaster的命令
- Contianer 封装单个节点上的资源
- ApplicationMaster 负责数据切分,为应用申请资源,监控任务
HDFS读写流程
HDFS读数据流程
- 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据, 找到文件块所在的DataNode地址。
- 挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
- DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
- 客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
HDFS写数据流程
- 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件 是否已存在,父目录是否存在。
- NameNode返回是否可以上传。
- 客户端请求第一个 Block上传到哪几个DataNode服务器上。
- NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
- 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后
dn2调用dn3,将这个通信管道建立完成。- dn1、dn2、dn3逐级应答客户端。
- 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单
位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个确认队列
等待确认。- 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行
3-7步)。
NN与2NN
NN的元数据管理
NameNode采用内存+磁盘方式存储数据,使用FsImage备份文件+Edits增量日志存储完整数据。数据的保存涉及到一个CheckPoint机制。
> 第一阶段:NameNode启动:第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
>
> - 客户端对元数据进行增删改的请求。
> - NameNode记录操作日志,更新滚动日志。
> - NameNode在内存中对数据进行增删改。
第二阶段:Secondary NameNode工作
- Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否执 行检查点操作结果。
- Secondary NameNode请求执行CheckPoint。
- NameNode滚动正在写的Edits日志。
- 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。 Secondary NameNode加载编辑日志和镜像文件到内存,并合并。 生成新的镜像文件fsimage.chkpoint。 拷贝fsimage.chkpoint到NameNode。 NameNode将fsimage.chkpoint重新命名成fsimage。
可以通过命令OIV OEV转换成另一种文件格式
hdfs oiv -p 文件类型(xml) -i 镜像文件 -o 转换后文件输出路径
hdfs oev -p 文件类型(xml) -i 镜像文件 -o 转换后文件输出路径
MapReduce
MapReduce框架⭐
- 常用的数据序列化类型 String-》Text | Map-》MapWritable | Array-》ArrayWritable
- 一个运算程序一般是一个map阶段和一个reduce阶段,MapTask并发执行,互不相干。ReduceTask并发执行,依赖MapTask的数据结果。
- 关于进程,mrAppMaster负责过程调度和状态协调,MapTask负责map阶段的数据处理。ReduceTask负责reduce阶段的数据处理。
Hadoop序列化
- Hadoop要选择建立自己的序列化格式而不使用java自带serializable的原因:
- 在Hadoop中,集群中多个节点的进程间的通信是通过RPC(远程过程调用:Remote Procedure Call)实现;RPC将消息序列化成二进制流发送到远程节点,远程节点再将接收到的二进制数据反序列化为原始的消息,RPC有紧凑(数据更紧凑,能充分利用网络带宽资源)和快速(序列化和反序列化的性能开销更低)的特点。
- Hadoop的序列化格式Writable比java的序列化serialization更紧凑速度更快。一 个对象使用Serializable序列化后,会携带很多额外信息比如校验信息,Header,继承体系等。
Mapper与Reducer的继承
- 继承自Mapper并重写map方法,读取文件中内容并格式化输出到Reduce中处理。
- 继承自Reducer并重写reduce方法,将map输出的KV对接收处理后提交到job中执行。
Writable序列化接口
- Writable序列化接口是一个javaBean对象,其中封装了需要系列化的参数。其中重写的序列化与反序列化方法中的值顺序必须一致。提供空参构造函数来实现反射调用。另外还需要重写toString方法,令输出数据可观。
MapTask的工作机制(分而治之思想)
- 通过TextInputFormat组件(可自定义)将文件进行逻辑切片(HDFS是物理切块),后续有多少个切片就会启动多少个MapTask。其中每个切片大小与blok大小对应为128M。
- 文件切分完成后交给LineRecordReader按照换行符依次读取数据交给定义的map方法。
- map方法输出的KV对会进入一个环形缓冲区(内存区域),按照Key的HashCode值%NumReduceTask数量进行分区,环形缓冲区的默认大小是100M,达到80M后会进行溢写,同时会进行分区内按照key执行快速排序,在最后一次溢写结束后,会进行分区内的归并排序,最后输出一个文件给MapTask,文件中会有多个分区的索引来记录偏移量。
- 在Hadoop中,执行MR任务的角色有两个,一个是负责任务调度的JobTasker,一个是负责执行任务的TaskerTracker。并且一个Hadoop集群中只有一个JobTasker。
MapTask的并行度
- 移动计算比移动数据划算、即写满blok大小防止出现数据的移动(数据本地化-HDFS的短路读取)
- 单个数据切片大小为blok大小128M,最大超限10%,即129M也会分为一个切片。MapTask的并行度取决于split的数量。
ReduceTask的工作机制
copy阶段包含一个eventFetcher来获取已完成的map列表,由Fetcher线程去copy数据,在此过程中会启动两个merge线程,分别为inMemoryMerger和onDiskMerger,分别将内存中的数据merge到磁盘和将磁盘中的数据 进行merge。待数据copy完成之后,开始进行sort阶段,sort阶段主要是执行 finalMerge操作,纯粹的sort阶段,之后就是reduce阶段,调用用户定义的reduce函数进行处理。
对于同一个分区的数据,一定会进入同一个ReduceTask。Copy阶段:Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求 maptask复制Map端输出的一个分区的一片数据。
Copy阶段:Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求 maptask复制Map端输出的一个分区的一片数据。
Merge阶段:这里的merge如map端的merge动作,只是数组中存放的是不同map端copy来的数值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活。merge有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。与map端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种 merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge 方式生成最终的文件。
合并排序。把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。
对排序后的键值对调用reduce方法,键相等的键值对调用一次reduce方法,每次调用会产生零个 或者多个键值对,最后把这些输出的键值对写入到HDFS文件中。
ReduceTask的并行度
- ReduceTask的并行度通过job.setNumReduceTasks() 设置。0是与MapTask保持一致,不设置默认为一个。如果数据分配不均会产生数据倾斜的问题,即某个ReduceTask处理的数据量远远大于其他处理的数据量
Shuffle机制⭐
- Map阶段处理后的数据传给Reduce阶段被称为Shuffle,是MapReduce框架中最关键的一个流程,主要分为数据分区,排序,分组,预聚合(combine),合并四个过程。
- 这时数据会按照key进行分区,默认的分区规则是key的hashcode%numberducetasks
- 溢写文件进行合并会保留原本分区,同时进行归并排序。
- combiner使用的前提是不影响最终业务的逻辑。combiner是map方法后的执行流程,所以输入输出要和map保持一致
Copy阶段根据分区编号拉取相同编号的map数据
可以直接使用Reducer作为Combiner组件
MR中的排序
- 部分排序:Hadoop的默认行为,MapReduce根据key排序,保证输出文件内部有序。
- 全排序:丧失了MapReduce的并行功能,由一台机器处理全部文件,处理大型文件时效率极低,通过设置一个ReduceTask实现。
- 辅助排序:在Reduce端对接受的Key进行分组。
- 二次排序:自定义排序过程。
MR中文件的输入和输出
输入
- TextInputFormat (普通文本文件,MR框架默认的读取实现类型)
- KeyValueTextInputFormat(读取一行文本数据按照指定分隔符,把数据封装为kv类型)
- NLineInputF ormat(读取数据按照行数进行划分分片)
- CombineTextInputFormat(合并小文件,避免启动过多MapTask任务)
- CombineTextInputFormat切片原理
切片生成过程分为两部分:虚拟存储过程和切片过程
虚拟存储过程:把输入目录下所有文件大小,依次和设置的setMaxInputSplitSize值进行比 较,如果不大于设置的最大值,逻辑上划分一个块。如果输入文件大于设置的最大值且大于 两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值2倍,此时 将文件均分成2个虚拟存储块(防止出现太小切片)
切片过程:判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个 切片。如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。
例如四个小文件:1.txt -->2M ;2.txt-->7M;3.txt-->0.3M;4.txt--->8.2M,// 如果不设置InputFormat,它默认用的是TextInputFormat.class job.setInputFormatClass(CombineTextInputFormat.class); //虚拟存储切片最大值设置4m CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);
输出
- 默认的输出格式是TextOutputFormat,它把每条记录写为文本行。它的键和值可以是任意类型,
因为TextOutputFormat调用toString()方法把它们转换为字符串。- 将SequenceFileOutputFormat输出作为后续MapReduce任务的输入,这是一种好的输出格式,因为它的格式紧凑,很容易被压缩。
Yarn资源调度
Yarn架构
ResourceManager(rm):处理客户端请求、启动/监控ApplicationMaster、监控NodeManager、资 源分配与调度;
NodeManager(nm):单个节点上的资源管理、处理来自ResourceManager的命令、处理来自 ApplicationMaster的命令;
ApplicationMaster(am):数据切分、为应用程序申请资源,并分配给内部任务、任务监控与容错。
Container:对任务运行环境的抽象,封装了CPU、内存等多维资源以及环境变量、启动命令等任务运
行相关的信息。
Yarn的任务提交流程⭐
Yarn作业提交流程:
- 作业提交
- Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业
- Client向RM申请一个作业id
- RM给Client返回该job资源的提交路径和作业id
- Client提交jar包、切片信息和配置文件到指定的资源提交路径
- Client提交资源后,向RM申请运行MrAppMaster
- 作业初始化
- 当RM收到Client的请求后,将该job添加到容量调度器中
- 某一个空闲的NM领取到该Job
- 该NM创建Container,并产生MRAppmaster
- 下载Client提交的资源到本地
- 任务分配
- MrAppMaster向RM申请运行多个MapTask任务资源
- RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器
- 任务运行
- MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager 分别启动MapTask,MapTask对数据分区排序
- MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask
- ReduceTask向MapTask获取相应分区的数据
- 程序运行完毕后,MR会向RM申请注销自己
- 进度和状态更新
- YARN中的任务将其进度和状态返回给应用管理器, 客户端每秒(通过 mapreduce.client.progressmonitor.pollinterval设置)向应用管理器请求进度更新, 展示给用户
- 作业完成
- 除了向应用管理器请求作业进度外, 客户端每5秒都会通过调用waitForCompletion()来检查作 业是否完成。时间间隔可以通过mapreduce.client.completion.pollinterval来设置。作业完 成之后, 应用管理器和Container会清理工作状态。作业的信息会被作业历史服务器存储以备 之后用户核查
Yarn调度策略
作业调度器主要有三种:FIFO、Capacity Scheduler和Fair Scheduler
Hadoop2.9.2默认的资源调度器是Capacity Scheduler
- FIFO(先进先出调度器)
FIFO的缺点是只简单按照时间进行排序,没有考虑更多条件
- 容量调度器(Capacity Scheduler 默认的调度器)
Capacity 调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,集群通过设置多个队列的方式给组织提供服务。在一个队列内部使用FIFO策略。
-
Fair Scheduler(公平调度器,CDH版本的hadoop默认使用的调度器)
Fair调度器的设计目标是为所有的应用分配公平的资源(对公平的定义可以通过参数来设置)。公 平调度在也可以在多个队列间工作
调优
- Job执行三原则:1.充分利用集群资源 2.reduce阶段尽量放在一轮 3.每个task的执行时间要合理
- 充分利用集群资源:通过调整处理的数据量大小,以及调整map和reduce个数来实现
- ReduceTask并发调整:避免一轮任务只剩下少数ReduceTask刚开始运行,或者在MapTask结束后只有部分节点的ReduceTask进行工作
- Task执行时间调整:如果每个tak处理时间都很短,要考虑加大task处理的数据量,避免浪费过多时间在task的调度上
Shuffle调优
Map阶段调优
- 判断Map阶段内存使用情况
- 判断Map分配的内存是否够用,可以查看运行完成的job的Counters中(历史服务器),对应的task是 否发生过多次GC,以及GC时间占总task运行时间之比。通常,GC时间不应超过task运行时间的10%, 即GC time elapsed (ms)/CPU time spent (ms)<10%。
- Map需要的内存还需要随着环形缓冲区的调大而对应调整(mapreduce.map.memory.mb)
- 需要的CPU核数(mapreduce.map.cpu.vcores)默认是1
- 环形缓冲区
- 调整mapreduce.task.io.sort.mb=512M
- 调整文件溢写完后对这些文件进行合并的个数,减少对磁盘的使用(mapreduce.task.io.sort.factor=64)
- Combiner
Copy阶段
- 对Map的中间结果进行压缩,当数据量大时会显著减少网络传输的数据量
- 当任务属于网络瓶颈类型时,压缩Map中间结果
Reduce阶段
- 设置Reduce资源(mapreduce.reduce.memory.mb=5G mapreduce.reduce.cpu.vcores=1)
- ReduceTask在copy的过程中默认使用5并行度进行复制数据(mapreduce.reduce.shuffle.parallelcopies)服务器上调整为50-100
- 溢写归并
- Copy过来的数据会先放入内存缓冲区中,然后当使用内存达到一定量的时候spill磁盘。这里的缓冲区 大小要比map端的更为灵活,它基于JVM的heap size设置。这个内存大小的控制是通过 mapreduce.reduce.shuffle.input.buffer.percent(default 0.7)控制的
- shuffile在reduce内存中的数据最多使用内存量为:0.7 × maxHeap of reduce task,内存到磁盘 merge的启动可以通过mapreduce.reduce.shuffle.merge.percent(default0.66)配置
- copy完成后,reduce进入归并排序阶段,合并因子默认为10(mapreduce.task.io.sort.factor参数 控制),如果map输出很多,则需要合并多次,可以提高此参数来减少合并次数
Job执行阶段
推测执行 (mapreduce.map.speculative =true;mapreduce.map.speculative=true)大集群建议开启
Slow Start 通过设置mapreduce.job.reduce.slowstart.completedmaps来延后申请reduce的资源,达到先执行完大部分Map再执行Reduce的目的
小文件优化
- 通过运行MR程序合并HDFS上已经存在的小文件
- 尽量在HDFS上不存储小文件,数据上传HDFS的时候就合并小文件
- MR计算的时候可以使用CombineTextInputFormat来降低MapTask并行度
数据倾斜
- 默认的是hash算法进行分区,尝试自定义分区,修改分区实现逻辑,结合业务特点,使得每个分区数据基本平衡
- 可以尝试修改分区的键,让其符合hash分区,并且使得最后的分区平衡,比如在key前加随机数n- key
- 抽取导致倾斜的key对应的数据单独处理
如果不是数据倾斜带来的问题,而是节点服务有问题造成某些map和reduce执行缓慢则使用推测执行以空间换时间进行优化
Yarn调优
- NM配置可用内存(yarn.nodemanager.resource.memory-mb 8192)默认情况下,Map或Reduce container会使用1个虚拟CPU内核和1024MB内存, ApplicationMaster使用1536MB内存
- CPU虚拟核数:将此配置设定在逻辑核数的1.5~2倍之间(yarn.nodemanager.resource.cpu-vcores)
- Container的启动模式(yarn.nodemanager.container-executor.class)
- YARN默认为每一个Container启动一个JVM,JVM进程间不能实现资源共享。设置为org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor ,则每次启动container将会启动一个线程来实现资源本地化。提升启动时间但是无法做到资源隔离。
- 设置为 org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor ,每次启动container都会启动一个JVM进程来实现资源本地化。
- ApplicationMaster调优:增大内存(yarn.app.mapreduce.am.resource.mb)
Namenode Full GC
JVM内存划分为堆内存和非堆内存,堆内存分为年轻代(Young Generation)、老年代(Old Generation),非堆内存只有永久代(Permanent Generation)
年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量, Survivor两个区占小容量,默认比例是8:1:1
堆内存用途:存放的是对象,垃圾收集器就是收集这些对象,然后根据GC算法回收
非堆内存用途:永久代,也称为方法区,存储程序运行时长期存活的对象,比如类的元数据、方 法、常量、属性等
对象分代
- 新生成的对象首先放到年轻代Eden区,当Eden空间满了,触发Minor GC,存活下来的对象移动到Survivor0区,Survivor0区满后触发执行Minor GC,Survivor0区存活对象移动到Suvivor1区,这样保证了一段时间内总有一个survivor区为空
- 经过多次Minor GC仍然存活的对象移动到老年代,老年代存储长期存活的对象,占满时会触发Major GC(Full GC),GC期间会停止所有线程等待GC完成,所以对响应要求高的应用尽量减少发生Major GC,避免响应超时
- Minor GC : 清理年轻代
- Major GC(Full GC) : 清理老年代,清理整个堆空间,会停止应用所有线程
Jstat
#C即Capacity 总容量,U即Used 已使用的容量 S0C: 当前survivor0区容量(kB)。
S1C: 当前survivor1区容量(kB)。
S0U: survivor0区已使用的容量(KB)
S1U: survivor1区已使用的容量(KB)
EC: Eden区的总容量(KB)
EU: 当前Eden区已使用的容量(KB) OC: Old空间容量(kB)。
OU: Old区已使用的容量(KB)
MC: Metaspace空间容量(KB) MU: Metacspace使用量(KB) CCSC: 压缩类空间容量(kB)。 CCSU: 压缩类空间使用(kB)。 YGC: 新生代垃圾回收次数
YGCT: 新生代垃圾回收时间
FGC: 老年代 full GC垃圾回收次数 FGCT: 老年代垃圾回收时间
GCT: 垃圾回收总消耗时间
开启HDFS GC详细日志输出
编辑hadoop-env.sh
export HADOOP_LOG_DIR=/hadoop/logs/
增加JMX配置打印详细GC信息,增加新的打印配置
#JMX配置
export HADOOP_JMX_OPTS="-Dcom.sun.management.jmxremote.authenticate=false - Dcom.sun.management.jmxremote.ssl=false"
export HADOOP_NAMENODE_OPTS="-Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:- INFO,RFAS} -Dhdfs.audit.logger=${HDFS_AUDIT_LOGGER:-INFO,NullAppender} $HADOOP_NAMENODE_OPTS"
export HADOOP_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS $HADOOP_DATANODE_OPTS"
#
export NAMENODE_OPTS="-verbose:gc -XX:+PrintGCDetails -
Xloggc:${HADOOP_LOG_DIR}/logs/hadoop-gc.log \
-XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -
XX:+PrintGCApplicationStoppedTime \
-server -Xms150g -Xmx150g -Xmn20g -XX:SurvivorRatio=8 -
XX:MaxTenuringThreshold=15 \
-XX:ParallelGCThreads=18 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -
XX:+UseCMSCompactAtFullCollection -XX:+DisableExplicitGC -
XX:+CMSParallelRemarkEnabled \
-XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=70 -
XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -
XX:CMSMaxAbortablePrecleanTime=5000 \
-XX:+UseGCLogFileRotation -XX:GCLogFileSize=20m -
XX:ErrorFile=${HADOOP_LOG_DIR}/logs/hs_err.log.%p -
XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${HADOOP_LOG_DIR}/logs/%p.hprof
\
"
#
export DATENODE_OPTS="-verbose:gc -XX:+PrintGCDetails -
Xloggc:${HADOOP_LOG_DIR}/hadoop-gc.log \
-XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -
XX:+PrintGCApplicationStoppedTime \
-server -Xms15g -Xmx15g -Xmn4g -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15
\
-XX:ParallelGCThreads=18 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -
XX:+UseCMSCompactAtFullCollection -XX:+DisableExplicitGC -
XX:+CMSParallelRemarkEnabled \
-XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=70 -
XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -
XX:CMSMaxAbortablePrecleanTime=5000 \
-XX:+UseGCLogFileRotation -XX:GCLogFileSize=20m -
XX:ErrorFile=${HADOOP_LOG_DIR}/logs/hs_err.log.%p -
XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${HADOOP_LOG_DIR}/logs/%p.hprof
\
"
#
export HADOOP_NAMENODE_OPTS="$NAMENODE_OPTS $HADOOP_NAMENODE_OPTS"
export HADOOP_DATANODE_OPTS="$DATENODE_OPTS $HADOOP_DATANODE_OPTS"
- -Xms150g -Xmx150g:堆内存大小最大和最小都是150g
- -Xmn20g :新生代大小为20g,等于eden+2*survivor,意味着老年代为150-20=130g
- -XX:SurvivorRatio=8 :Eden和Survivor的大小比值为8,意味着两个Survivor区和一个Eden区的比值为2:8,一个Survivor占整个年轻代的十分之一
- -XX:ParallelGCThreads=10 :设置ParNew GC的线程并行数,默认为8+(Runtime.availableprocessors -8)* 5/8
- -XX:MaxTenuringThreshold=15 :设置对象在年轻代的最大年龄,超过这个年龄则会晋升到老年代
- -XX:+UseParNewGC :设置新生代使用Parallel New GC
- -XX:+UseConcMarkSweepGC :设置老年代使用CMS GC当此项设置时候自动设置新生代为
ParNew GC- -XX:CMSInitiatingOccupancyFraction=70 :老年代第一次占用达到该百分比时候,就会引发CMS的第一次垃圾回收周期。后继CMS GC由 HotSpot自动优化计算得到
jstat命令输出后查看GC日志输出,检查ParNew(GC前的新生代占用量->GC后的新生代占用量(Eden+一 个被占用Survivor的总和))
在HDFS Namenode内存中的对象大都是文件,目录和blocks,这些数据只要不被程序或者数据的拥 有者人为的删除,就会在Namenode的运 行生命期内一直存在,所以这些对象通常是存在在old区中, 所以,如果整个hdfs文件和目录数多,blocks数也多,内存数据也会很大,通过以下方法减少Full GC的影响
计算NN所需的内存大小,合理配置JVM
使用低卡顿G1收集器
并发、并行和CMS垃圾收集器都有2个共同的问题
- 老年代收集器大部分操作都必须扫描整个老年代空间(标记,清除和压缩)。这就导致了GC随着 Java堆空间而线性增加或减少
- 年轻代和老年代是独立的连续内存块,所以要先决定年轻代和年老代放在虚拟地址空间的位置
G1垃圾收集器利用分而治之的思想将堆进行分区,划分为一个个的区域。 将堆拆成一系列的分区,这样的话,大部分的垃圾收集操作就只在一个分区内执行,从而避免很多GC操作在整个Java堆或者整个年轻代进行。

浙公网安备 33010602011771号