• 问题1:NameNode如何管理和存储元数据?

    计算机中存储数据两种:内存或者是磁盘。

    元数据存储磁盘:存储磁盘无法面对客户端对元数据信息的任意的快速低延迟的响应,但是安全性高。

    元数据存储内存:元数据存放内存,可以高效的查询以及快速响应客户端的查询请求,数据保存在内存,如果断点,内存中的数据全部丢失。

解决方案:内存+磁盘;NameNode内存+FsImage的文件(磁盘)。

  • 问题2:磁盘和内存中元数据如何划分?两个数据一模一样,还是两个数据合并到一起才是一份完整的数据呢?

    一模一样:client如果对元数据进行增删改操作,需要保证两个数据的一致性。FsImage文件操作起来效率也不高。

    两个合并=完整数据:NameNode引入了一个edits文件(日志文件:只能追加写入)edits文件记录的是client的增删改操作,不再选择让NameNode把数据dump出来形成FsImage文件(这种操作是比较消耗资源)。

HDFS元数据管理机制

  1. 第一阶段:NameNode启动

    • 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。

    • 客户端对元数据进行增删改的请求。

    • NameNode记录操作日志,更新滚动日志。

    • NameNode在内存中对数据进行增删改。

  2. 第二阶段: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。

Fsimage与Edits文件解析

NameNode在执行格式化之后,会在/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/current目录下产生如下文件


  • Fsimage文件:是namenode中关于元数据的镜像,一般称为检查点,这里包含了HDFS文件系统所有目录以及文件相关信息(Block数量,副本数量,权限等信息)。

  • Edits文件:存储了客户端对HDFS文件系统所有的更新操作记录,Client对HDFS文件系统所有的更新操作都会被记录到Edits文件中(不包括查询操作)。

  • seen_txid:该文件是保存了一个数字,数字对应着最后一个Edits文件名的数字。
  • VERSION:该文件记录namenode的一些版本号信息,比如:CusterId,namespaceID等。

Fsimage文件内容

  • 查看oiv命令

    1
    2
    3
    [root@linux121 current]$ hdfs
    oiv Offline Image Viewer View a Hadoop fsimage INPUTFILE using the specified
    PROCESSOR,saving the results in OUTPUTFILE.
  • 基本语法如下,详情可以查看官方文档

    1
    hdfs oiv -p 文件类型(xml) -i 镜像文件 -o 转换后文件输出路径
  • 案例实操

    1
    2
    3
    [root@linux121 current]$ cd /opt/lagou/servers/hadoop- 2.9.2/data/tmp/dfs/name/current
    [root@linux121 current]$ hdfs oiv -p XML -i fsimage_0000000000000000265 -o /opt/lagou/servers/fsimage.xml
    [root@linux121 current]$ cat /opt/lagou/servers/fsimage.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    <?xml version="1.0"?>
    <fsimage>
    <version>
    <layoutVersion>-63</layoutVersion>
    <onDiskVersion>1</onDiskVersion>
    <oivRevision>826afbeae31ca687bc2f8471dc841b66ed2c6704</oivRevision>
    </version>
    <NameSection>
    <namespaceId>1393381414</namespaceId>
    <genstampV1>1000</genstampV1>
    <genstampV2>1024</genstampV2>
    <genstampV1Limit>0</genstampV1Limit>
    <lastAllocatedBlockId>1073741848</lastAllocatedBlockId>
    <txid>265</txid>
    </NameSection>
    <INodeSection>
    <inode>
    <id>16398</id>
    <type>DIRECTORY</type>
    <name>history</name>
    <mtime>1592376391028</mtime>
    <permission>root:supergroup:0777</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16399</id>
    <type>DIRECTORY</type>
    <name>done_intermediate</name>
    <mtime>1592375256896</mtime>
    <permission>root:supergroup:1777</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16400</id>
    <type>DIRECTORY</type>
    <name>root</name>
    <mtime>1592378079208</mtime>
    <permission>root:supergroup:0777</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16413</id>
    <type>FILE</type>
    <name>job_1592375222804_0001-1592375231176-root-word+count- 1592375281926-1-1-SUCCEEDED-default-1592375261492.jhist</name>
    <replication>3</replication>
    <mtime>1592375282039</mtime>
    <atime>1592375281980</atime>
    <preferredBlockSize>134217728</preferredBlockSize>
    <permission>root:supergroup:0777</permission>
    <blocks>
    <block>
    <id>1073741834</id>
    <genstamp>1010</genstamp>
    <numBytes>33584</numBytes>
    </block>
    </blocks>
    <storagePolicyId>0</storagePolicyId>
    </inode>
    <inode>
    <id>16414</id>
    <type>FILE</type>
    <name>job_1592375222804_0001_conf.xml</name>
    <replication>3</replication>
    <mtime>1592375282121</mtime>
    <atime>1592375282053</atime> <preferredBlockSize>134217728</preferredBlockSize>
    <permission>root:supergroup:0777</permission>
    <blocks>
    <block>
    <id>1073741835</id>
    <genstamp>1011</genstamp>
    <numBytes>196027</numBytes>
    </block>
    </blocks>
    <storagePolicyId>0</storagePolicyId>
    </inode>
    <inode>
    <id>16415</id>
    <type>DIRECTORY</type>
    <name>done</name>
    <mtime>1592376776670</mtime>
    <permission>root:supergroup:0777</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16427</id>
    <type>DIRECTORY</type>
    <name>logs</name>
    <mtime>1592378009623</mtime>
    <permission>root:root:0770</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16428</id>
    <type>DIRECTORY</type>
    <name>application_1592376944601_0001</name>
    <mtime>1592378045481</mtime>
    <permission>root:root:0770</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16430</id>
    <type>DIRECTORY</type>
    <name>wcoutput</name>
    <mtime>1592378037463</mtime>
    <permission>root:supergroup:0755</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16436</id>
    <type>FILE</type>
    <name>part-r-00000</name>
    <replication>3</replication>
    <mtime>1592378037264</mtime>
    <atime>1592378037074</atime>
    <preferredBlockSize>134217728</preferredBlockSize>
    <permission>root:supergroup:0644</permission>
    <blocks>
    <block>
    <id>1073741842</id>
    <genstamp>1018</genstamp>
    <numBytes>43</numBytes>
    </block>
    </blocks>
    <storagePolicyId>0</storagePolicyId>
    </inode>
    <inode>
    <id>16445</id>
    <type>FILE</type>
    <name>linux123_39919</name>
    <replication>3</replication>
    <mtime>1592378045469</mtime>
    <atime>1592378045331</atime>
    <preferredBlockSize>134217728</preferredBlockSize>
    <permission>root:root:0640</permission>
    <blocks>
    <block>
    <id>1073741848</id>
    <genstamp>1024</genstamp>
    <numBytes>56910</numBytes>
    </block>
    </blocks>
    <storagePolicyId>0</storagePolicyId>
    </inode>
    <inode>
    <id>16446</id>
    <type>DIRECTORY</type>
    <name>0617</name>
    <mtime>1592387393490</mtime>
    <permission>root:supergroup:0755</permission>
    <nsquota>-1</nsquota>
    <dsquota>-1</dsquota>
    </inode>
    <inode>
    <id>16449</id>
    <type>FILE</type>
    <name>banzhang.txt</name>
    <replication>1</replication>
    <mtime>1592388309046</mtime>
    <atime>1592388309026</atime>
    <preferredBlockSize>134217728</preferredBlockSize>
    <permission>root:supergroup:0644</permission>
    <storagePolicyId>0</storagePolicyId>
    </inode>
    </INodeSection>
    </fsimage>

    问题:Fsimage中为什么没有记录块所对应DataNode?


在内存元数据中是有记录块所对应的dn信息,但是fsimage中就剔除了这个信息;HDFS集群在启动的时候会加载image以及edits文件,block对应的dn信息都没有记录,集群启动时会有一个安全模式(safemode),安全模式就是为了让dn汇报自己当前所持有的block信息给nn来补全元数据。后续每隔一段时间dn都要汇报自己持有的block信息。

Edits文件内容

  • 查看oev命令

    1
    2
    3
    [root@linux121 current]$ hdfs
    oev Offline edits viewer Parse a Hadoop edits log file INPUT_FILE and save results in
    OUTPUT_FILE
  • 基本语法如下

    1
    hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
  • 案例实操

    1
    2
    [root@linux121 current]$ hdfs oev -p XML -i edits_0000000000000000266- 0000000000000000267 -o /opt/lagou/servers/hadoop-2.9.2/edits.xml
    [root@linux121 current]$ cat /opt/lagou/servers/hadoop-2.9.2/edits.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    <?xml version="1.0" encoding="UTF-8"?>
    <EDITS>
    <EDITS_VERSION>-63</EDITS_VERSION>
    <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
    <TXID>113</TXID>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>114</TXID>
    <SRC>/wcoutput/_SUCCESS</SRC>
    <MODE>493</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>115</TXID>
    <SRC>/wcoutput/part-r-00000</SRC>
    <MODE>493</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>116</TXID>
    <SRC>/wcoutput</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>117</TXID>
    <SRC>/wcoutput/_SUCCESS</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>118</TXID>
    <SRC>/wcoutput/part-r-00000</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_DELETE</OPCODE>
    <DATA>
    <TXID>119</TXID>
    <LENGTH>0</LENGTH>
    <PATH>/wcoutput/part-r-00000</PATH>
    <TIMESTAMP>1592377324171</TIMESTAMP>
    <RPC_CLIENTID></RPC_CLIENTID>
    <RPC_CALLID>-2</RPC_CALLID>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>120</TXID>
    <SRC>/</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>121</TXID>
    <SRC>/tmp</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>122</TXID>
    <SRC>/tmp/hadoop-yarn</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>123</TXID>
    <SRC>/tmp/hadoop-yarn/staging</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>124</TXID>
    <SRC>/tmp/hadoop-yarn/staging/history</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>125</TXID>
    <SRC>/tmp/hadoop-yarn/staging/history/done</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
    <TXID>126</TXID>
    <SRC>/tmp/hadoop-yarn/staging/history/done/2020</SRC>
    <MODE>511</MODE>
    </DATA>
    </RECORD>
    </EDITS>

    备注:Edits中只记录了更新相关的操作,查询或者下载文件并不会记录在内!!

    问题:NameNode启动时如何确定加载哪些Edits文件呢?

    nn启动时需要加载fsimage文件以及那些没有被2nn进行合并的edits文件,nn如何判断哪些edits已经被合并了呢?

    可以通过fsimage文件自身的编号来确定哪些已经被合并。

checkpoint周期

查看hdfs-default.xml文件,默认配置周期。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 定时一小时 -->
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>

<!-- 一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次 -->
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作动作次数</description>
</property>

<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description> 1分钟检查一次操作次数</description>
</property >

NameNode故障处理

NameNode故障后,HDFS集群就无法正常工作,因为HDFS文件系统的元数据需要由NameNode来管理维护并与Client交互,如果元数据出现损坏和丢失同样会导致NameNode无法正常工作进而HDFS文件系统无法正常对外提供服务。

如果元数据出现丢失损坏如何恢复呢?

  1. 将2NN的元数据拷贝到NN的节点下此种方式会存在元数据的丢失。

  2. 搭建HDFS的HA(高可用)集群,解决NN的单点故障问题!!(借助Zookeeper实现HA,一个Active的NameNode,一个是Standby的NameNode)。