深度剖析HadoopHDFS.html.pdf

上传人:紫竹语嫣 文档编号:5518664 上传时间:2020-05-28 格式:PDF 页数:164 大小:6.78MB
返回 下载 相关 举报
深度剖析HadoopHDFS.html.pdf_第1页
第1页 / 共164页
深度剖析HadoopHDFS.html.pdf_第2页
第2页 / 共164页
深度剖析HadoopHDFS.html.pdf_第3页
第3页 / 共164页
深度剖析HadoopHDFS.html.pdf_第4页
第4页 / 共164页
深度剖析HadoopHDFS.html.pdf_第5页
第5页 / 共164页
点击查看更多>>
资源描述

《深度剖析HadoopHDFS.html.pdf》由会员分享,可在线阅读,更多相关《深度剖析HadoopHDFS.html.pdf(164页珍藏版)》请在三一文库上搜索。

1、前言 我上大学时,就开始在CSDN上写技术博客,目的在于记录平时遇到的一些问题以及研究的技术细节,好在将来可以进行查阅。随着时间的增长,我开始专注于某个技术模块,因为这样可以让我对具 体某项技术有更深入的研究,写出的内容也会更加系统化,而HDFS就是其中一个我持续研究的技术模块。同时作为一名Hadoop社区的活跃贡献者,我也会将社区上一些比较有意思的东西分享到博客上, 许多博友给了不少反馈,描述他们在工作中碰到的一些实际问题。在这样不断的写作、交流过程中,我得到了快速成长。目前大数据领域相关的书籍并不是很多,而专门讲解其中一个模块的书则更少,所 以我将我过去一年多时间内关于HDFS的博客文章进

2、行了整理、改进,同时也加入了一些新的内容。可以这么说,本书的内容源自博客,但是超越博客。 本书不会是纯源码分析的书籍。首先,我把工作实践中遇到的许多经验写入了书中,第7章便属于纯实践型的经验总结。其次,本书会是一个比较“新”的书,这里的“新”并不是指所分析的代码版本 新,而是包含了HDFS未来的一些比较棒的功能特性,以及Hadoop社区目前在做的一些事情。在这本书中,你会看到许多与社区相关的JIRA,了解如何从社区上找到问题的解决办法。期待本书能给你带来 更多的启发。 本书适合具有一定Java语言基础的同学,尤其适合以下读者朋友: 大数据架构师、开发者、运维工程师。 高年级本科生或研究生。 热

3、衷于分布式存储技术的爱好者。 本书分为三大部分,“核心设计篇”介绍HDFS的基本原理、数据管理与策略等,“细节实现篇”介绍HDFS的块处理、流量处理、结构分析等,“解决方案篇”介绍数据管理技术与方案、数据读写技 术、异常处理等。 第一部分“核心设计篇”包括内容如下: 第1章介绍HDFS现有的数据存储方式,主要介绍其中的内存存储和异构存储两个方面。 第2章介绍HDFS目前内部几种主要的功能机制,包括缓存管理、快照管理等。 第3章介绍HDFS比较新颖的一些功能,以及目前较少被人用到的功能特性。 第二部分“细节实现篇”包括内容如下: 第4章介绍HDFS的块处理相关操作,主要处理场景包括块如何组织、上

4、报处理的过程以及多余块的清除。 第5章介绍HDFS的流量处理过程,包括HDFS目前流量处理的场景以及Balancer工具的数据平衡原理和优化。 第6章介绍HDFS一些特殊的结构对象类,包括这些类的作用、原理以及运用场景。 第三部分“解决方案篇”包括内容如下: 第7章介绍与HDFS相关的多套运维管理的操作方案,包括数据迁移、数据监控等方面。 第8章介绍HDFS写磁盘时的一些优化策略和改造方案。 第9章介绍HDFS的一些异常场景,并给出了相应的解决方案。 由于笔者水平有限,本书难免会有出错或者介绍不明确的地方,恳请读者批评指正,可以发送关于本书的意见和建议到我的个人邮箱:yqtinapache.o

5、rg。本书所涉及的源码,大家可以从Hadoop的 Git地址上进行下载:https:/ Git地址:https:/ CSDN地址:http:/ 感谢机械工业出版社的吴怡编辑,在我写作的过程中,不断指出其中的不足之处,督促和引导我完成本书的编写。 感谢蘑菇街数据平台部的同事们,在工作中不断地给予我帮助和支持,协助我解决各种各样的问题,于是才有了本书中所展现的精彩内容。 林意群 2017年2月 第一部分 核心设计篇 第1章 HDFS的数据存储 本章将从HDFS的数据存储开始说起,因为正是先有了数据的存储,才有后续的写入和管理等操作。HDFS的数据存储包括两块:一块是HDFS内存存储,另一块是HDF

6、S异构存储。HDFS内存存储是一 种十分特殊的存储方式,将会对集群数据的读写带来不小的性能提升,而HDFS异构存储则能帮助我们更加合理地把数据存到应该存的地方。 第一部分 核心设计篇 第1章 HDFS的数据存储 本章将从HDFS的数据存储开始说起,因为正是先有了数据的存储,才有后续的写入和管理等操作。HDFS的数据存储包括两块:一块是HDFS内存存储,另一块是HDFS异构存储。HDFS内存存储是一 种十分特殊的存储方式,将会对集群数据的读写带来不小的性能提升,而HDFS异构存储则能帮助我们更加合理地把数据存到应该存的地方。 1.1 HDFS内存存储 HDFS的内存存储是HDFS所有数据存储方式

7、中比较特殊的一种,与之后将会提到的HDFS缓存有一些相同之处:都用机器的内存作为存储数据的载体。不同之处在于:HDFS缓存需要用户主动设置目标 待缓存的文件、目录,其间需要使用HDFS缓存管理命令。而HDFS内存存储策略:LAZY_PERSIST则直接将内存作为数据存放的载体,可以这么理解,此时节点的内存也充当了一块“磁盘”。只要将文件 设置为内存存储方式,最终会将其存储在节点的内存中。综合地看,HDFS缓存更像是改进用户使用的一种功能,而HDFS内存存储则是从底层扩展了HDFS的数据存储方式。本节将对HDFS内存存储策略进 行更细致的分析。 1.1.1 HDFS内存存储原理 对于内存存储的存

8、储策略,可能很多人会存有这么几种看法: 数据临时维持在内存中,服务一停止,数据全部丢失。 数据存在于内存中,在服务停止时做持久化处理,最终将数据全部写入到磁盘。 仔细来看以上这2种观点,其实都有不小的瑕疵: 第一个观点,服务一旦停止,内存数据全部丢失,这是无法接受的,我们只能容忍内存中少量的数据丢失。这个观点的另一个问题是,内存的存储空间是有限的,在服务运行过程中如果不及时处理 一部分数据,内存空间迟早会被耗尽。 第二个观点,在服务停止退出的时候做持久化操作,同样会面临上面提到的内存空间的限制问题。如果机器的内存足够大,数据可能会很多,那么最后写入磁盘的阶段速度会很慢。 所以一般情况下,通用的

9、、比较好的做法是异步持久化,什么意思呢?在内存存储新数据的同时,持久化距离当前时刻最远(存储时间最早)的数据。换一个通俗的解释,好比有个内存数据块队列, 在队列头部不断有新增的数据块插入,就是待存储的块,因为资源有限,需要把队列尾部的块,也就是更早些时间点的块持久化到磁盘中,这样才有空间存储新的块。然后形成这样的一个循环,新的块加 入,老的块移除,保证了整体数据的更新。 HDFS的LAZY_PERSIST内存存储策略用的就是这套方法,原理如图1-1。 图1-1 LAZY_PERSIST策略原理图 上面描述的原理在图中的表示是第4个步骤和第6个步骤。第4步写数据到内存中,第6步异步地将数据写到磁

10、盘。前面几个步骤是如何设置StorageType的操作,在下文中会具体提到。所以异步存储的 大体步骤可以归纳如下: 1)对目标文件目录设置StoragePolicy为LAZY_PERSIST的内存存储策略。 2)客户端进程向NameNode发起创建/写文件的请求。 3)客户端请求到具体的DataNode后DataNode会把这些数据块写入RAM内存中,同时启动异步线程服务将内存数据持久化写到磁盘上。 内存的异步持久化存储是内存存储与其他介质存储不同的地方。这也是LAZY_PERSIST名称的源由,数据不是马上落盘,而是懒惰的、延时地进行处理。 1.1.2 Linux虚拟内存盘 这里需要了解一个

11、额外的知识点:Linux虚拟内存盘。之前笔者也一直有个疑惑,内存也可以当作一个块盘使用?内存不就是临时存数据用的吗?于是在学习此模块知识之前,特意查了相关的资料。其 实在Linux中,的确有将内存模拟为一个块盘的技术,叫虚拟内存盘(RAM disk)。这是一种模拟的盘,实际数据都是存放在内存中的。虚拟内存盘可以在某些特定的内存式存储文件系统下结合使用,比 如tmpfs、ramfs。关于tmpfs的具体内容,大家可以查阅维基百科等资料。通过此项技术,我们就可以将机器内存利用起来,作为一块独立的虚拟盘供DataNode使用了。 1.1.3 HDFS的内存存储流程分析 下面讲述本章的核心内容:HDF

12、S内存存储的主要流程。不要小看这个存储策略,里面的过程可并不简单,在下面的内容中,笔者会给出比较多的过程图,帮助大家理解。 1.HDFS文件内存存储策略设置 要想让文件数据存储到内存中,一开始要做的操作是设置此文件的存储策略,即上面提到的LAZY_PERSIST,而不是使用默认的存储策略:StoragePolicy.DEFAULT,默认策略的存储介质是DISK类型 的。设置存储策略的方法目前有以下3种: 第一种方法,通过命令行的方式,调用如下命令: hdfs storagepolicies -setStoragePolicy -path -policy LAZY_PERSIST 这种方式比较方

13、便、快速。 第二种方法,调用对应的程序方法,比如调用暴露在外部的create文件方法,但是得带上参数CreateFlag.LAZY_PERSIST。如下所示: FSDataOutputStream fos = fs.create( path, FsPermission.getFileDefault(), EnumSet.of(CreateFlag.CREATE, CreateFlag.LAZY_PERSIST), bufferLength, replicationFactor, blockSize, null); 上述方式最终调用的是DFSClient的create同名方法,如下所示: / D

14、FSClient创建文件方法 public DFSOutputStream create(String src, FsPermission permission, EnumSet flag, short replication, long blockSize, Progressable progress, int buffersize, ChecksumOpt checksumOpt) throws IOException return create(src, permission, flag, true, replication, blockSize, progress, buffersiz

15、e, checksumOpt, null); 方法经过RPC层层调用,经过FSNamesystem,最终会到FSDirWriteFileOp的startFile方法,在此方法内部,会有设置存储策略的动作: static HdfsFileStatus startFile( FSNamesystem fsn, FSPermissionChecker pc, String src, PermissionStatus permissions, String holder, String clientMachine, EnumSet flag, boolean createParent, short r

16、eplication, long blockSize, EncryptionKeyInfo ezInfo, INode.BlocksMapUpdateInfo toRemoveBlocks, boolean logRetryEntry) throws IOException assert fsn.hasWriteLock(); boolean create = flag.contains(CreateFlag.CREATE); boolean overwrite = flag.contains(CreateFlag.OVERWRITE); / 判断CreateFlag是否带有LAZY_PERS

17、IST标识,来判断是否是内存存储策略 boolean isLazyPersist = flag.contains(CreateFlag.LAZY_PERSIST); http:/ / 在此设置策略 setNewINodeStoragePolicy(fsd.getBlockManager(), newNode, iip, isLazyPersist); fsd.getEditLog().logOpenFile(src, newNode, overwrite, logRetryEntry); if (NameNode.stateChangeLog.isDebugEnabled() NameNode

18、.stateChangeLog.debug(“DIR* NameSystem.startFile: added “ + src + “ inode “ + newNode.getId() + “ “ + holder); return FSDirStatAndListingOp.getFileInfo(fsd, src, false, isRawPath); 这部分的过程调用见图1-2。 图1-2 LAZY_PERSIST策略设置流程图 还有一种方法是通过FileSystem的setStoragePolicy方法,不过此方法在还未发布的2.8版本中提供,如下所示: fs.setStorageP

19、olicy(path, “LAZY_PERSIST“); 这种方式的优点在于可以用程序动态地设置目标路径的存储方式。 以上就是存储策略的设置过程,这一部分还是非常直接明了的。 2.LAZY_PERSIST内存存储 当我们为文件设置了LAZY_PERSIST的存储方式之后,DataNode如何进行内存式的存储呢?笔者在下面会分模块、分角色进行介绍。 首先要介绍的是LAZY_PERSIST相关结构。在之前的内容中已经提到过,在数据存储的同时会有另外一批数据被异步地持久化,所以这里一定会涉及多个服务对象的合作。这些服务对象的指挥者是 FsDatasetImpl,它是一个管理DataNode所有磁盘读

20、写的管家。 在FsDatasetImpl中,与内存存储相关的服务对象有3个,如图1-3所示。 图1-3 LAZY_PERSIST相关服务对象 说明如下: RamDiskAsyncLazyPersistService:此对象是异步持久化线程服务,针对每一个磁盘块设置一个对应的线程池,需要持久化到给定磁盘的数据块会被提交到对应的线程池中去。每个线程池的最大线程数 为1。 LazyWriter:这是一个线程服务,此线程会不断地从数据块列表中取出数据块,将数据块加入到异步持久化线程池RamDiskAsyncLazyPersistService中去执行。 RamDiskReplicaLruTracker

21、:是副本块跟踪类,此类中维护了所有已持久化、未持久化的副本以及总副本数据信息。所以当一个副本被最终存储到内存中后,相应地会有副本所属队列信息的变更。当 节点内存不足时,会将最近最少被访问的副本块移除。 以上3者的紧密合作,最终实现HDFS的内存存储。下面是具体的角色介绍。 (1)RamDiskReplicaLruTracker RamDiskReplicaLruTracker起到了一个中间人的角色,它内部维护了多个关系的数据块信息,主要是以下3类: public class RamDiskReplicaLruTracker extends RamDiskReplicaTracker http:

22、/ / blockpool Id对副本信息的映射图 Map replicaMaps; / 待写入磁盘的副本队列 Queue replicasNotPersisted; / 已持久化写入磁盘的映射图 TreeMultimap replicasPersisted; http:/ 这里的Queue就是待存入内存存储队列。以上3个变量之间的关系见图1-4。 图1-4 RamDisk副本块结构关系图 RamDiskReplicaLruTracker中的方法操作绝大多数与这3个变量的增删改动相关,所以逻辑并不复杂,我们只需要了解这些方法有什么作用即可。笔者将方法分成了以下两类: 第一类,异步持久化操作相关

23、方法。如图1-5所示。 图1-5 异步持久化操作相关流程图 当节点重启或者有新的文件设置了LAZY_PERSIST策略后,就会有新的副本块存储到内存中,同时会加入到replicaNotPersisted队列中。经过中间的dequeueNextReplicaToPersist方法,取出下一个 将被持久化的副本块,进行写磁盘的操作。在持久化的过程中将调用recordStartLazyPersist、recordEndLazyPersist这两个方法,标志着持久化状态的变更。 第二类,异步持久化操作无直接关联方法。方法如下: 1)discardReplica:当检测到不再需要某副本的时候(包括副本已

24、被删除,或已损坏的情况),可以从内存中移除、撤销副本。 2)touch:恰好与Linux中的touch命令同名,此方法意味着访问了一次某特定的副本块,并会更新此副本块的lastUesdTime(最近一次使用时间)。lastUesdTime会在后面提到的LRU算法中起到关 键的作用。 3)getNextCandidateForEviction:此方法在DataNode内存空间不足,需要内存额外预留出空间给新的副本块时被调用。此方法会根据所设置的eviction scheme模式,选择需要被移除的块,默认 的策略模式是LRU策略。 这里反复提到一个名词LRU,LRU的全称是Least Recent

25、ly Used,意为最近最少使用算法。getNextCandidateForEviction方法采用此算法的好处是保证了现有副本块的一个活跃度,把最近很久没有 访问过的块给移除掉。对于这个操作,我们有必要了解其中的细节。 首先touch方法会更新副本块最近访问的时间: synchronized void touch(final String bpid, final long blockId) Map map = replicaMaps.get(bpid); RamDiskReplicaLru ramDiskReplicaLru = map.get(blockId); http:/ / 更新最近

26、访问时间戳,并重新插入数据 if (replicasPersisted.remove(ramDiskReplicaLru.lastUsedTime, ramDiskReplicaLru) ramDiskReplicaLru.lastUsedTime = Time.monotonicNow(); replicasPersisted.put(ramDiskReplicaLru.lastUsedTime, ramDiskReplicaLru); / 第二步获取候选移除块 synchronized RamDiskReplicaLru getNextCandidateForEviction() / 获取

27、replicasPersisted迭代器进行遍历 final Iterator it = replicasPersisted.values().iterator(); while (it.hasNext() / 因为replicasPersisted已经根据时间排好序了,所以取出当前的块进行移除即可 final RamDiskReplicaLru ramDiskReplicaLru = it.next(); it.remove(); Map replicaMap = replicaMaps.get(ramDiskReplicaLru.getBlockPoolId(); if (replicaM

28、ap != null / 如果副本不存在,则继续下一个副本 return null; 这里比较有意思的是,根据已持久化块的访问时间来进行筛选移除,而不是直接在内存块对象中记录访问时间,然后进行排序和移除。最后在内存中移除与候选块属于同一副本信息的块并释放内存空 间: / 从内存中移除副本块信息直到满足需要字节数的大小 public void evictBlocks(long bytesNeeded) throws IOException int iterations = 0; final long cacheCapacity = cacheManager.getCacheCapacity();

29、 / 当检测到内存空间不满足外界需要的大小时 while (iterations+ = ramDiskReplicaTracker.numReplicas NotPersisted() Thread.sleep(checkpointerInterval * 1000); numSuccessiveFailures = 0; catch (InterruptedException e) LOG.info(“LazyWriter was interrupted, exiting“); break; catch (Exception e) LOG.warn(“Ignoring exception i

30、n LazyWriter:“, e); 之后,进入saveNextReplica方法的处理: private boolean saveNextReplica() RamDiskReplica block = null; FsVolumeReference targetReference; FsVolumeImpl targetVolume; ReplicaInfo replicaInfo; boolean succeeded = false; try / 从队列中取出新的待持久化的块 block = ramDiskReplicaTracker.dequeueNextReplicaToPersi

31、st(); if (block != null) synchronized (FsDatasetImpl.this) http:/ / 提交到异步服务中去 asyncLazyPersistService.submitLazyPersistTask( block.getBlockPoolId(), block.getBlockId(), replicaInfo.getGenerationStamp(), block.getCreationTime(), replicaInfo.getMetaFile(), replicaInfo.getBlockFile(), targetReference);

32、 succeeded = true; catch(IOException ioe) LOG.warn(“Exception saving replica “ + block, ioe); finally if (!succeeded / 进行副本块提交失败处理,此副本块将会再次提交到待持久化队列中 onFailLazyPersist(block.getBlockPoolId(), block.getBlockId(); return succeeded; LazyWriter线程服务的流程图可以归纳为图1-6。 图1-6 LazyWriter服务流程图 我们结合LazyWriter和RamDi

33、skReplicaTracker跟踪服务,就可以得到下面一个完整的流程(暂且不考虑RamDiskAsyncLazyPersistService的内部执行),如图1-7所示。 (3)RamDiskAsyncLazyPersistService 最后一部分异步服务的内容相对就比较简单了,主要围绕着Volume磁盘和Executor线程池这两部分的内容,秉持着下面一个原则: 一个磁盘服务对应一个线程池,并且一个线程池的最大线程数也只有1个。 线程池列表定义如下: 图1-7 异步持久化流程图 class RamDiskAsyncLazyPersistService http:/ private Map

34、 executors = new HashMap(); http:/ 这里的File代表一个磁盘上的目录,个人认为这里完全可以用String字符串替代。既可以减少存储空间,又直观明了。从这里可以看出磁盘服务与线程池一对一的关系了。 当服务启动的时候,就会有新的磁盘目录加入,如下代码所示: synchronized void addVolume(File volume) if (executors = null) throw new RuntimeException(“AsyncLazyPersistService is already shutdown“); ThreadPoolExecuto

35、r executor = executors.get(volume); / 如果当前已存在此磁盘目录对应的线程池,则抛异常 if (executor != null) throw new RuntimeException(“Volume “ + volume + “ is already existed.“); / 否则进行添加 addExecutorForVolume(volume); 之后,进入addExecutorForVolume方法: private void addExecutorForVolume(final File volume) http:/ / 新建线程池,最大线程执行数

36、为1 ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_THREADS_PER_VOLUME, MAXIMUM_THREADS_PER_VOLUME, THREADS_KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, new LinkedBlockingQueue(), threadFactory); executor.allowCoreThreadTimeOut(true); / 加入到executors中,以volume作为key executors.put(volume, executor);

37、还有一个需要注意的地方是提交执行方法submitLazyPersistTask,如下所示: void submitLazyPersistTask(String bpId, long blockId, long genStamp, long creationTime, File metaFile, File blockFile, FsVolumeReference target) throws IOException if (LOG.isDebugEnabled() LOG.debug(“LazyWriter schedule async task to persist RamDisk bloc

38、k pool id: “ + bpId + “ block id: “ + blockId); / 获取需要持久化的目标磁盘实例 FsVolumeImpl volume = (FsVolumeImpl)target.getVolume(); File lazyPersistDir = volume.getLazyPersistDir(bpId); if (!lazyPersistDir.exists() throw new IOException(“LazyWriter fail to find or create lazy persist dir: “ + lazyPersistDir.to

39、String(); / 新建此服务Task ReplicaLazyPersistTask lazyPersistTask = new ReplicaLazyPersistTask( bpId, blockId, genStamp, creationTime, blockFile, metaFile, target, lazyPersistDir); / 提交到对应volume的线程池中执行 execute(volume.getCurrentDir(), lazyPersistTask); 如果在上述执行的过程中发生失败,会调用失败处理的方法,并会重新将此副本块插入到replicateNotPe

40、rsisted队列中,等待下一次的持久化: public void onFailLazyPersist(String bpId, long blockId) RamDiskReplica block = null; block = ramDiskReplicaTracker.getReplica(bpId, blockId); if (block != null) LOG.warn(“Failed to save replica “ + block + “. re-enqueueing it.“); / 重新插入队列操作 ramDiskReplicaTracker.reenqueueRepli

41、caNotPersisted(block); 其他如removeVolume等方法实现比较简单,这里不做过多介绍。图1-8是RamDisk-AsyncLazyPersistService总的结构图。 以上3部分描述了LAZT_PERSIST下的队列式内存数据块持久化服务、异步持久化服务的内部运行逻辑和LRU预留内存空间算法策略。 图1-8 RamDiskAsyncLazyPersistService相关结构图 1.1.4 LAZY_PERSIST内存存储的使用 介绍完原理部分之后,下面介绍具体的配置使用。 第一步,要使用LAZY_PERSIST内存存储策略,需要有对应的存储介质,内存存储介质对

42、应的类型是RAM_DISK。 在使用RAM_DISK之前,需要完成虚拟内存盘的配置工作,这里以tmpfs文件系统为例进行介绍。在默认情况下,tmpfs是被挂载到/dev/shm,并且大小是32GB。也就是说,在此目录下的数据实质上 是存在于内存中的。但是有的时候,我们可能会想挂载到自己想要挂载的目录下,而且我们也想对内存的使用大小进行有效的控制,可以使用下面的命令进行这2方面的设置: sudo mount -t tmpfs -o size=16g tmpfs /mnt/dn-tmpfs/ 以上操作的意思是将tmpfs挂载到目录/mnt/dn-tmpfs,并且限制内存使用大小为16GB。最后,建

43、议在/etc/fstab文件中将这层挂载关系写入,这可以让机器在重启之后自动创建好挂载关系。 首先需要将机器中已经完成好的虚拟内存盘配置到dfs.datanode.data.dir中,其次还要带上RAM_DISK标签,以此表明此目录对应的存储介质为RAM_DISK,配置样例如下: dfs.datanode.data.dir /grid/0,/grid/1,/grid/2,RAM_DISK/mnt/dn-tmpfs 注意,这个标签是必须要打上的,否则HDFS默认的都是DISK。 第二步就是设置具体的文件策略类型。 注意 确保HDFS异构存储策略没有被关闭,默认是开启的,配置项是dfs.stora

44、ge.policy.enabled。 确认dfs.datanode.max.locked.memory是否设置了足够大的内存值,是否已是DataNode能承受的最大内存大小。内存值过小会导致内存中的总的可存储的数据块变少,但如果超过DataNode能承受的最大 内存大小的话,部分内存块会被直接移出。 FsDatasetAsyncDiskService 在FsDatasetImpl类中,还有一个与内存存储异步持久化相类似的服务FsDataset-AsyncDiskService。在类的实现逻辑上,该服务与RamDiskAsyncLazyPersistService有许多相似之处,同样包含许多 执

45、行线程池,并且每个线程池对应一个存储目录。不过在具体的执行内容上,它主要做两类异步任务: 文件目录的异步删除。 异步执行SyncFileRange请求操作。SyncFileRange的全称是sync a file segment with disk,它的作用在于数据做多次更新后,对其进行一次性的写出,提高IO的效率。 FsDatasetAsyncDiskService类位于包org.apache.hadoop.hdfs.server.datanode.fsdataset.impl下,感兴趣的读者可以自行研究。 在HDFS异构存储方式中,除了内存存储之外,其实还有另外一类存储方式也尤为重要,就是

46、HDFS的Archival Storage。Archival Storage指的是一种高密度的存储方式,以此解决集群数据规模增长 带来的存储空间不足的问题。通常用于Archival Storage的节点不需要很好的计算性能,一般用于冷数据的存储。HDFS的Archival Storage的具体设计与实现,可以参阅相关JIRA,HDFS-6584(Support Archival Storage)。 1.2 HDFS异构存储 Hadoop在2.6.0版本中引入了一个新特性:异构存储。异构存储关键在于“异构”两个字。异构存储可以根据各个存储介质读写特性的不同发挥各自的优势。一个很适用的场景就是上节提到的冷热数 据的存储。针对冷数据,采用容量大的、读写性能不高的存储介质存储,比如最普通的磁盘。而对于热数据而言,可以采用SSD的方式进行存储,这样就能保证高效的读性能,在速率上甚至能做到十倍或 百倍于普通磁盘的读写速度。换句话说,HDFS异构

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/环境 > 建筑资料


经营许可证编号:宁ICP备18001539号-1