截取知识星球的分享出来,也是对之前的HDFS进行一个补充,顺带让大家复习一下

HDFS的核心设计思想

分散存储,冗余存储

这两点我可以展开说明一下,首先我们要清楚,HDFS里面的数据,分为真实数据元数据两种,当然这里面元数据是在 Namenode 里面的,而真实数据是存储在 Datanode 里面的。

比如我们现在要存储一个大文件,分散存储的意思就是,会将这个文件拆分成一个个的数据块block,分别独立存放在某个 Datanode 中。那此时问题就来了,你怎么知道哪个文件是由哪些数据块组成呢?而且这些数据块又分别存在哪些 Datanode 上呢?这就是元数据所起到的作用。

元数据存储其实是在内存和磁盘都存储了一份的,存储在内存的考量主要就是提高响应速度,而存磁盘是为了保证元数据的安全。而这样导致的问题就是:如何保证内存和磁盘的数据一致性问题?这块可以去学习一下 Redis 的做法,既保证效率又保证安全。

而且为什么说HDFS不适合存储小文件,甚至说我们会有很多小文件的合并机制,那是因为元数据并不是一个文件一条元数据,而是每一个数据块都会对应有一个相关的元数据描述,而每个数据块的元数据大小将近150字节,这好比说我们往HDFS存一个100M的视频,对应一条150byte的元数据,如果存100张1M的图片,就会有对应100条150byte的元数据,所以这个资源的浪费是十分可怕的。

而冗余存储就是我们的block会有副本机制,这个副本的存储套路是机架存储策略

机架存储策略

实际机房中,会有机架,每个机架上会有若干台服务器。一般来说我们会把一个block的3个副本分别按照下述方法进行存储:

  1. 第一个副本就存储在一个机架A上 第二个副本存储在和这个block块不同机架(比如机架B)的一个服务器上
  2. 存储第2个副本时会优先把副本存储在不同的机架上,这是为了防止出现一个机架断电的情况,如果副本也存储在同机架上的不同服务器上,这时候数据就可能丢失了。
  3. 第三个副本存储在机架B的另外一个服务器上(注意副本2,3都存储在了机架B)

为什么会这么选择,因为如果我们把副本3也放在另外一个机架C上,副本2和副本3之间的通信就需要副本2通过它的交换机去联系总交换机,然后总交换机去联系机架C的交换机,需要走的路线非常长,而且机房中的带宽资源非常宝贵,如果处于高并发的情况,很容易就把机房的带宽打满,此时整一个集群的响应速度会急剧下降,这时候服务就会出现问题了。

当然我们的副本数也是可以手动通过命令增加的,在客户端访问量多的时候,可以适当分配一下压力
$ hadoop fs -setrep -R 4 path + FileName
setrep的意思其实就是set replication,设置副本数的缩写,上面命令就是将副本数设置成4份了,后面跟着文件路径和文件名即可

客户端的交互全部都是和 Namenode 打交道的,这点和 Kafka 一样,永远都是和 leader 打交道,而不是和 follower。但是你要知道,正常的实现数据的上传下载的功能确实是走的 Datanode。

HDFS 的架构

HDFS的架构:主从架构,三大角色

  1. Namenode作为集群的老大,掌管HDFS文件系统的元数据,处理客户端读写请求,HDFS的集群内部数据安全及负载均衡等
  2. Datanode存储整个集群的所有数据块,处理真正的数据读写
  3. SecondaryNamenode严格意义上来说并不属于namenode的备份节点,它主要起到的作用其实是替namenode分担压力,降低负载(元数据的编辑日志合并,也就是edits log)之用

心跳机制



hdfs元数据大小 hdfs的元数据_HDFS

心跳机制解决了HDFS集群间的通信问题,还是NameNode命令DataNode执行操作的途径

  1. master namenode启动之后,会开一个ipc server
  2. DataNode启动,连接NameNode,每隔3s向NameNode发送一个心跳,并携带状态信息
  3. NameNode通过对这个心跳的返回值来给DataNode传达任务指令
心跳机制的作用:

1.NameNode 全权管理数据块的复制,它周期性从集群中的每个 DataNode 接收心跳信号和 block 状态报告,接收到心跳信号意味着该 DataNode 节点工作正常,块状态报告包含了该 DataNode 上所有数据块的列表

2.DataNode启动时向 NameNode 注册,通过后周期性地向 NameNode 上报 block 报告,每3秒向 NameNode 发送一次心跳,NameNode 返回对该 DataNode 的指令,如将数据块复制到另一台机器,或删除某个数据块等···而当某一个 DataNode 超过10min还没向 NameNode 发送心跳,此时 NameNode 就会判定该 DataNode 不可用,此时客户端的读写操作就不会再传达到该 DataNode 上

安全模式

3.hadoop 集群刚开始启动时会进入安全模式(99.99%),就用到了心跳机制,其实就是在集群刚启动的时候,每一个 DataNode 都会向 NameNode 发送 block 报告,NameNode 会统计它们上报的总block数,除以一开始知道的总个数total,当 block/total < 99.99% 时,会触发安全模式,安全模式下客户端就没法向HDFS写数据,只能进行读数据。

而且补充一点,Namenode感知Datanode掉线死亡时间的计算公式为:

timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval

HDFS默认超时时间为630秒,因为默认的 heartbeat.recheck.interval 为5分钟,而 dfs.heartbeat.interval 默认为3秒,而这两个参数理解起来也很简单,一个是重新检查的时间间隔,而另一个是每n秒发送一次心跳的参数,等待10次,不行拉倒。

安全模式的补充

安全模式不仅仅是集群刚启动时等所有的Datanode汇报这一种情况会进入安全模式的,还有就是HDFS数据块丢失达到一个比例的时候,也会自动进入,当然我们也可以手动去进入安全模式。这个比例默认是0.1%,1000个块丢1个已经很严重的事件了。

可以通过 start-balancer.sh 来让HDFS做负载均衡,可是要注意,这个命令是存在一定的问题的,这和Java的垃圾回收机制中的System.gc()是一样的。我告诉你,现在要去进行垃圾回收了,可是JVM压根就不理咱们,为啥呢?它只会在自己有空,合适的时间去做垃圾回收,而 start-balancer.sh 就也是一样的套路,利用剩余的带宽去做这个事情。

而这个操作也有一定的标准,根据一个数值n规定。每一个节点都计算出一个磁盘的占用量,占用量最大-占用量最小 = 这个标准数值n即可。默认是10%,这样就很好理解了吧。而且这个负载均衡的操作是一定不能影响到客户端的读写业务的,所以HDFS默认会不允许balance操作占用太多的带宽。但是我们可以进行手动调整

hdfs dfs admin -setBalancerBandwidth newbandwidth

newbandwidth 的默认单位是字节,所以这个东西自己根据需求调整即可。默认是1M每秒的。

最近有在经营自己的知识星球,旨在帮助想要了解大数据的朋友们入门大数据的内容,且和已经从事大数据的开发人员一起进阶,免费但不代表你会没有收获,如果感兴趣的话可以加一下,基本都会更新的比较勤