百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

什么是HDFS?算了,告诉你也不懂。

wxin55 2024-11-11 14:41 10 浏览 0 评论

一、HDFS介绍

上篇文章已经讲到了,随着数据量越来越大,在一台机器上已经无法存储所有的数据了,那我们会将这些数据分配到不同的机器来进行存储,但是这就带来一个问题:不方便管理和维护

所以,我们就希望有一个系统可以将这些分布在不同操作服务器上的数据进行统一管理,这就有了分布式文件系统

  • HDFS是分布式文件系统的其中一种(目前用得最广泛的一种)

在使用HDFS的时候是非常简单的:虽然HDFS是将文件存储到不同的机器上,但是我去使用的时候是把这些文件当做是存储在一台机器的方式去使用(背后却是多台机器在执行):

  • 好比:我调用了一个RPC接口,我给他参数,他返回一个response给我。RPC接口做了什么事其实我都不知道的(可能这个RPC接口又调了其他的RPC接口)-----屏蔽掉实现细节,对用户友好

明确一下:HDFS就是一个分布式文件系统,一个文件系统,我们用它来做什么?存数据呀

下面,我们来了解一下HDFS的一些知识,能够帮我们更好地去「使用」HDFS

二、HDFS学习

从上面我们已经提到了,HDFS作为一个分布式文件系统,那么它的数据是保存在多个系统上的。例如,下面的图:一个1GB的文件,会被切分成几个小的文件,每个服务器都会存放一部分。

那肯定会有人会问:那会切分多少个小文件呢?默认以128MB的大小来切分,每个128MB的文件,在HDFS叫做(block)

显然,这个128MB大小是可配的。如果设置为太小或者太大都不好。如果切分的文件太小,那一份数据可能分布到多台的机器上(寻址时间就很慢)。如果切分的文件太大,那数据传输时间的时间就很慢。

PS:老版本默认是64MB

一个用户发出了一个1GB的文件请求给HDFS客户端,HDFS客户端会根据配置(现在默认是128MB),对这个文件进行切分,所以HDFS客户端会切分为8个文件(也叫做block),然后每个服务器都会存储这些切分后的文件(block)。现在我们假设每个服务器都存储两份

这些存放真实数据的服务器,在HDFS领域叫做DataNode

现在问题来了,HDFS客户端按照配置切分完以后,怎么知道往哪个服务器(DataNode)放数据呢?这个时候,就需要另一个角色了,管理者(NameNode)。

NameNode实际上就是管理文件的各种信息(这种信息专业点我们叫做MetaData「元数据」),其中包括:文文件路径名,每个Block的ID和存放的位置等等。

所以,无论是读还是写,HDFS客户端都会先去找NameNode,通过NameNode得知相应的信息,再去找DataNode

  • 如果是写操作,HDFS切分完文件以后,会询问NameNode应该将这些切分好的block往哪几台DataNode上写。
  • 如果是读操作,HDFS拿到文件名,也会去询问NameNode应该往哪几台DataNode上读数据。

2.1 HDFS备份

作为一个分布式系统(把大文件切分为多个小文件,存储到不同的机器上),如果没有备份的话,只要有其中的一台机器挂了,那就会导致「数据」是不可用状态的。

写到这里,如果看过我的KafkaElasticSearch的文章可能就懂了。其实思想都是一样的。

Kafka对partition备份,ElasticSearch对分片进行备份,而到HDFS就是对Block进行备份。

尽可能将数据备份到不同的机器上,即便某台机器挂了,那就可以将备份数据拉出来用。

对Kafka和ElasticSearch不了解的同学,可以关注我的GitHub,搜索关键字即可查询(我觉得还算写得比较通俗易懂的)

注:这里的备份并不需要HDFS客户端去写,只要DataNode之间互相传递数据就好了。

2.2 NameNode的一些事

从上面我们可以看到,NameNode是需要处理hdfs客户端请求的。(因为它是存储元数据的地方,无论读写都需要经过它)。

现在问题就来了,NameNode是怎么存放元数据的呢?

  • 如果NameNode只是把元数据放到内存中,那如果NameNode这台机器重启了,那元数据就没了。
  • 如果NameNode将每次写入的数据都存储到硬盘中,那如果只针对磁盘查找和修改又会很慢(因为这个是纯IO的操作)

说到这里,又想起了Kafka。Kafka也是将partition写到磁盘里边的,但人家是怎么写的?顺序IO

NameNode同样也是做了这个事:修改内存中的元数据,然后把修改的信息append(追加)到一个名为editlog的文件上。

由于append是顺序IO,所以效率也不会低。现在我们增删改查都是走内存,只不过增删改的时候往磁盘文件editlog里边追加一条。这样我们即便重启了NameNode,还是可以通过editlog文件将元数据恢复。

现在也有个问题:如果NameNode一直长期运行的话,那editlog文件应该会越来越大(因为所有的修改元数据信息都需要在这追加一条)。重启的时候需要依赖editlog文件来恢复数据,如果文件特别大,那启动的时候不就特别慢了吗?

的确是如此的,那HDFS是怎么做的呢?为了防止editlog过大,导致在重启的时候需要较长的时间恢复数据,所以NameNode会有一个内存快照,叫做fsimage

说到快照,有没有想起Redis的RDB!!

这样一来,重启的时候只需要加载内存快照fsimage+部分的editlog就可以了。

想法很美好,现实还需要解决一些事:我什么时候生成一个内存快照fsimage?我怎么知道加载哪一部分的editlog?

问题看起来好像复杂,其实我们就只需要一个定时任务

如果让我自己做的话,我可能会想:我们加一份配置,设置个时间就OK了

如果editlog大到什么程度或者隔了多长时间,我们就把editlog文件的数据跟内存快照fsiamge给合并起来。然后生成一个新的fsimage,把editlog给清空,覆盖旧的fsimage内存快照这样一来,NameNode每次重启的时候,拿到的都是最新的fsimage文件,editlog里边的都是没合并到fsimage的。根据这两个文件就可以恢复最新的元数据信息了。

HDFS也是类似上面这样干的,只不过它不是在NameNode起个定时的任务跑,而是用了一个新的角色:SecondNameNode。至于为什么?可能HDFS觉得合并所耗费的资源太大了,不同的工作交由不同的服务器来完成,也符合分布式的理念。

现在问题还是来了,此时的架构NameNode是单机的。SecondNameNode的作用只是给NameNode合并editlog和fsimage文件,如果NameNode挂了,那client就请求不到了,而所有的请求都需要走NameNode,这导致整个HDFS集群都不可用了。

于是我们需要保证NameNode是高可用的。一般现在我们会通过Zookeeper来实现。架构图如下:

主NameNode和从NameNode需要保持元数据的信息一致(因为如果主NameNode挂了,那从NameNode需要顶上,这时从NameNode需要有主NameNode的信息)。

所以,引入了Shared Edits来实现主从NameNode之间的同步,Shared Edits也叫做JournalNode。实际上就是主NameNode如果有更新元数据的信息,它的editlog会写到JournalNode,然后从NameNode会在JournalNode读取到变化信息,然后同步。从NameNode也实现了上面所说的SecondNameNode功能(合并editlog和fsimage)

稍微总结一下:

  • NameNode需要处理client请求,它是存储元数据的地方
  • NameNode的元数据操作都在内存中,会把增删改以editlog持续化到硬盘中(因为是顺序io,所以不会太慢)
  • 由于editlog可能存在过大的问题,导致重新启动NameNode过慢(因为要依赖editlog来恢复数据),引出了fsimage内存快照。需要跑一个定时任务来合并fsimage和editlog,引出了SecondNameNode
  • 又因为NameNode是单机的,可能存在单机故障的问题。所以我们可以通过Zookeeper来维护主从NameNode,通过JournalNode(Share Edits)来实现主从NameNode元数据的一致性。最终实现NameNode的高可用。

2.3 学点DataNode

从上面我们就知道,我们的数据是存放在DataNode上的(还会备份)。

如果某个DataNode掉线了,那HDFS是怎么知道的呢?

DataNode启动的时候会去NameNode上注册,他俩会维持心跳,如果超过时间阈值没有收到DataNode的心跳,那HDFS就认为这个DataNode挂了。

还有一个问题就是:我们将Block存到DataNode上,那还是有可能这个DataNode的磁盘损坏了部分,而我们DataNode没有下线,但我们也不知道损坏了。

一个Block除了存放数据的本身,还会存放一份元数据(包括数据块的长度,块数据的校验和,以及时间戳)。DataNode还是会定期向NameNode上报所有当前所有Block的信息,通过元数据就可校验当前的Block是不是正常状态

最后

其实在学习HDFS的时候,你会发现很多的思想跟之前学过的都类似。就比如提到的Kafka、Elasticsearch这些常用的分布式组件。

相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: