在Hadoop2.0之前,只有一个NameNode,虽然有SecondaryNameNode(不能迅速切换,需要花费一定时间恢复),还是存在单点问题。NameNode在Hadoop中就好比是人的心脏,不能停止工作。如果NameNode数据丢失或者不能工作,那整个集群就不能恢复了。
【Hadoop学习】Hadoop 1.0 & Hadoop 2.0
Hadoop 1.0
Hadoop 1.0即第一代Hadoop,由分布式存储系统HDFS和分布式和分布式计算框架MapReduce组成。其中HDFS由一个NameNode和多个DataNode组成MapReduce由一个JobTracker和多个TaskTracker组成,对应的Hadoop版本为Apache Hadoop 0.20.x、1.x、0.21.x、0.22.x和CDH3。
Hadoop 2.0
Hadoop 2.0即第二代Hadoop,为了克服Hadooop 1.0中HDFS和MapReduce存在的各种问题而提出的。针对Hadoop 1.0中的单NameNode制约HDFS的扩展性问题,提出了HDFS Federation,它让多个NameNode分管不同的目录进而实现访问隔离和横向扩展,同时解决了NameNode的单点故障问题。针对Hadoop 1.0中的MapReduce在扩展性和多框架支持等方面的不足,它将JobTracker中的资源管理和作业控制功能分开,分别由组件ResourceManager和ApplicationMaster实现,其中,ResourceManager负责所有应用程序的资源分配,ApplicationMaster仅负责管理一个应用程序,着便是全新的通用的资源管理框架YARN。Hadoop 2.0对应的Hadoop的版本为Apache Hadoop 0.23.x、2.x和CDH4。
MRv1
MapReduce 1.0计算框架主要由三部分组成,分别是编程模型,数据处理引擎和运行时环境。它的编程模型是将问题抽象成Map和Reduce两个阶段,其中Map阶段将输入数据解析成key/value,迭代调用map()函数处理后,再以key/value的形式输出到本地目录,而Reduce阶段则是将Map阶段输出的数据按照key相同的value进行归约处理,并将最终结果写到HDFS上。它的数据处理引擎由MapTask和ReduceTask组成,分别负责Map阶段逻辑和Reduce阶段逻辑的处理。运行时的环境由一个JobTracker和若干个TaskTracker组成,JobTracker负责资源管理和所有作业的控制,TaskTracker负责接收来自JobTracker的命令并执行它。
MRv2
MRv2具有与MRv1相同的编程模型和数据处理引擎,唯一不同的是运行时环境。MRv2是在MRv1基础上经加工之后,运行于资源管理框架YARN之上的计算框架。它由资源管理系统YARN和作业控制进程ApplicationMaster组成,其中YARN负责资源管理和调度,而ApplicationMaster仅负责一个作业的管理。MRv1仅是一个独立的离线计算框架,而MRv2则是运行于YARN之上的MapReduce。
YARN
YARN是Hadoop 2.0中的资源管理系统,它是一个通用的资源管理模块,可以为各类应用横须进行资源管理和调度。YARN不仅限于MapReduce一种框架使用,也可以供其他框架使用,比如Spark,Storm等。
HDFS Federation
在Hadoop 2.0中,对HDFS进行改进,是的NameNode可以横向扩展成多个,每个NameNode分管一部分目录,进而产生了HDFS Federation,该机制的引入不仅增强了HDFS的扩展性,也使HDFS具备了隔离性。
【Hadoop学习】Secondary NameNode解读
Secondary NameNode从它的名字上来看,给人的感觉是NameNode的备份。但实际上不是这样。那到底Secondary NameNode在HDFS中扮演的是什么角色呢?
【Hadoop学习】Hadoop的序列化
对象的序列化用于将对象编码成一个字节流,以及从字节流中重新构建对象。
将一个对象编码成一个字节流叫做序列化改对象(Serializing)
相反的处理过程称为反序列化(Deserializing)
JVM垃圾回收
JVM堆内存被分为两部分年轻代(Young Generation)和老年代(Old Generation)。
新生代(Young Generation)
新生代是所有新对象产生的地方。当年轻代的内存空间被用完时,就会触发垃圾回收。这个垃圾回收叫做Minor GC。新生代分为3个部分Eden区和Survivor区(FromSpace和ToSpace,两个区域大小相同),新生代的大小可以通过-Xmn
来控制,也可以用-XX:SurvivorRatio
来控制Eden和Survivor的比例。
新生代的特点
- 大多数新建的对象都在Eden区
- 当Eden区域被填满时,就会执行Minor GC。并把所有存活下来的对象转移到其中一个survivor区
- Minor GC同样会检查存活下来的对象,并把他们转移到另一个survivor区。这样在一段时间内,总会有一个空的survivor区
- 经过多次GC周期后,仍然存活下来的对象会被转移到老年代内存空间。通常这是在新生代有资格提升到老年代前通过设定年龄阈值来完成的。
老年代(Old Generation)
老年代内存里包含了长期存活的对象和经过多次Minor GC后依然存活下来的对象。通常会在老年代内存被占满时进行垃圾回收。老年代的垃圾收集叫做Major GC。Major GC会花费更多的时间。旧生带占用大小为-Xmx
值减去-Xmn
对应的值
永久代(Permanent Generation)
永久代包含了JVM需要的应用元数据,这些元数据描述了在应用里使用的类和方法。注意,永久代不是Java堆内存的一部分,有一些JVM没有这一代,主要存放敞亮及类的一些信息,默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize
及-XX:MaxPermSize
来设置最小值和最大值。
永久代存放JVM运行时使用的类。永久代同样包含了Java SE库的类和方法。永久代的对象在full GC时进行垃圾收集。
方法区
方法区是永久代空间的一部分,并用来存储类型信息(运行时常量和静态变量)和方法代码和构造函数代码。
内存池
如果JVM实现支持,JVM内存管理会为创建内存池,用来为不变对象创建对象池。字符串池就是内存池类型的一个很好的例子。内存池可以属于堆或者永久代,这取决于JVM内存管理的实现。
运行时常量池
运行时常量池是每个类常量池的运行时代表。它包含了类的运行时常量和静态方法。运行时常量池是方法区的一部分。
Java栈内存
Java栈内存用于运行线程。它们包含了方法里的临时数据、堆里其它对象引用的特定数据。你可以阅读栈内存和堆内存的区别。
Java 堆内存开关
VM设置 | 描述 |
---|---|
-Xms | 设置JVM启动时堆的初始化大小。 |
-Xmx | 设置堆最大值。 |
-Xmn | 设置年轻代的空间大小,剩下的为老年代的空间大小。 |
-XX:PermGen | 设置永久代内存的初始化大小。 |
-XX:MaxPermGen | 设置永久代的最大值。 |
-XX:SurvivorRatio | 提供Eden区和survivor区的空间比例。比如,如果年轻代的大小为10m并且VM开关是-XX:SurvivorRatio=2,那么将会保留5m内存给Eden区和每个Survivor区分配2.5m内存。默认比例是8。 |
-XX:NewRatio | 提供年老代和年轻代的比例大小。默认值是2。 |
大多数时候,上面的选项已经足够使用了。但是如果你还想了解其他的选项,那么请查看JVM选项官方网页。
Java垃圾回收
JVM堆内存主要被分为三块,新生代、老年代、持久代。三代的特点不同,造就了他们所用的GC算法不同,新生代适合那些生命周期较短,频繁创建及销毁的对象,老年代适合生命周期相对较长的对象,持久代在Sun HotSpot中就是指方法区(有些JVM中根本就没有持久代这中说法)。
Java垃圾回收会找出没用的对象,把它从内存中移除并释放出内存给以后创建的对象使用。Java程序语言中的一个最大优点是自动垃圾回收,不像其他的程序语言那样需要手动分配和释放内存,比如C语言。
垃圾收集器是一个后台运行程序。它管理着内存中的所有对象并找出没被引用的对象。所有的这些未引用的对象都会被删除,回收它们的空间并分配给其他对象。
一个基本的垃圾回收过程涉及三个步骤:
- 标记:这是第一步。在这一步,垃圾收集器会找出哪些对象正在使用和哪些对象不在使用。
- 正常清除:垃圾收集器清会除不在使用的对象,回收它们的空间分配给其他对象。
- 压缩清除:为了提升性能,压缩清除会在删除没用的对象后,把所有存活的对象移到一起。这样可以提高分配新对象的效率。
简单标记和清除方法存在两个问题:
- 效率很低。因为大多数新建对象都会成为“没用对象”。
- 经过多次垃圾回收周期的对象很有可能在以后的周期也会存活下来。
上面简单清除方法的问题在于Java垃圾收集的分代回收的,而且在堆内存里有年轻代和年老代两个区域。我已经在上面解释了Minor GC和Major GC是怎样扫描对象,以及如何把对象从一个分代空间移到另外一个分代空间。
Java垃圾回收类型
这里有五种可以在应用里使用的垃圾回收类型。仅需要使用JVM开关就可以在我们的应用里启用垃圾回收策略。让我们一起来逐一了解:
- Serial GC(-XX:+UseSerialGC):Serial GC使用简单的标记、清除、压缩方法对年轻代和年老代进行垃圾回收,即Minor GC和Major GC。Serial GC在client模式(客户端模式)很有用,比如在简单的独立应用和CPU配置较低的机器。这个模式对占有内存较少的应用很管用。
- Parallel GC(-XX:+UseParallelGC):除了会产生N个线程来进行年轻代的垃圾收集外,Parallel GC和Serial GC几乎一样。这里的N是系统CPU的核数。我们可以使用 -XX:ParallelGCThreads=n 这个JVM选项来控制线程数量。并行垃圾收集器也叫throughput收集器。因为它使用了多CPU加快垃圾回收性能。Parallel GC在进行年老代垃圾收集时使用单线程。
- Parallel Old GC(-XX:+UseParallelOldGC):和Parallel GC一样。不同之处,Parallel Old GC在年轻代垃圾收集和年老代垃圾回收时都使用多线程收集。
- 并发标记清除(CMS)收集器(-XX:+UseConcMarkSweepGC):CMS收集器也被称为短暂停顿并发收集器。它是对年老代进行垃圾收集的。CMS收集器通过多线程并发进行垃圾回收,尽量减少垃圾收集造成的停顿。CMS收集器对年轻代进行垃圾回收使用的算法和Parallel收集器一样。这个垃圾收集器适用于不能忍受长时间停顿要求快速响应的应用。可使用 -XX:ParallelCMSThreads=n JVM选项来限制CMS收集器的线程数量。
- G1垃圾收集器(-XX:+UseG1GC) G1(Garbage First):垃圾收集器是在Java 7后才可以使用的特性,它的长远目标时代替CMS收集器。G1收集器是一个并行的、并发的和增量式压缩短暂停顿的垃圾收集器。G1收集器和其他的收集器运行方式不一样,不区分年轻代和年老代空间。它把堆空间划分为多个大小相等的区域。当进行垃圾收集时,它会优先收集存活对象较少的区域,因此叫“Garbage First”。你可以在Oracle Garbage-FIrst收集器文档找到更多详细信息。