@R星校长
Hadoop一共六天课程:
第一天内容安排
1. Redis集群
2. Hadoop
3. Hbase
4. ElasticSearch
需求:
有一个非常大的文本文件,里面有非常多的行,只有两行内容一样,它们出现在未知的位置,需要查找到它们。硬件:单台机器,而且可用的内存很少,也就 500MB。
• 假如 IO 速度是 500MB/S
• 1T 文件读取一遍需要约 30 分钟
• 循环遍历需要 N 次 IO 时间
• 分治思想可以使时间降为 2 次 IO
• 思考:
• 如何让时间变为分钟、秒级别
• 假如 IO 速度是 500MB/S
• 1T 文件读取一遍需要约 30 分钟
• 如何对 1TB 文件进行排序
方式 1:外部有序,内部无序。
逐一读入内存排序
方式 2:逐一读取 500M 排序,内部有序, 外部无序 ,然后进行归并排序
需求:
• 有一个非常大的文本文件,里面有几百亿行,只有两行内容一样,它们出现在未知的位置,需要查找到它们。
• 分钟、秒级别完成
• 硬件:*台机器,而且可用的内存 500MB。
由于涉及到计算机之间文件传输,千兆带宽,100MB/s
拉取网卡 100MB/S
之前忽略了上传时间:1TB/100MB = 10000S /3600S = 3H
• 2000 台真的比一台快吗?
• 如果考虑分发上传文件的时间呢?
• 如果考虑每天都有 1TB 数据的产生呢?
• 如果增量了一年,最后一天计算数据呢?
• 1天 2*30=1H 3H1M2S
• 2天 2H 3H1M4S
• 3天 3H 3H1M6S
• 4天 4H 3H1M8S
问题:
100 台服务器,存储空间单个 100GB 10T
5T 文件如何存储?
128MB一块 128MB*8=1GB 128*8*1024=1TB
5T数据分成的128MB的块数8192 *5。
清单:
5TB文件分的块:
元数据:
文件名称:web.log
大小:5TB
创建时间:
权限:
文件所有者:
文件所属的用户组:
文件类型:
文件块列表信息:
0~128*1024*1024 -1:128MB:node1:path,node3:path,node8:path
128*1024*1024~2*128*1024*1024 -1:128MB:node2:path,...
2*128*1024*1024~3*128*1024*1024 -1:128MB:node3:path
0~128*1024*1024 -1:128MB:node1:
0~128*1024*1024 -1:128MB:node1:
0~128*1024*1024 -1:128MB:node1:
0~128*1024*1024 -1:128MB:node1:
0~128*1024*1024 -1:128MB:node1:
NameNode
管理文件系统的命名空间
文件和目录的元数据:(运行时,元数据放内存)
文件的 block 副本个数
修改和访问的时间
访问权限
block 大小以及组成文件的 block 列表信息
以两种方式在 NameNode 本地进行持久化:
命名空间镜像文件(fsimage)和编辑日志(edits log)。
fsimage 文件不记录每个 block 所在的 DataNode 信息,这些信息在每次系统启动的时候从 DataNode 重建。之后 DataNode 会周期性地通过心跳包向 NameNode 报告 block 信息。DataNode 向 NameNode 注册的时候 NameNode 请求 DataNode 发送 block 列表信息。
1、文件名称和路径
2、文件的大小
3、文件的所属关系
4、文件的block块大小 128MB
5、文件的副本个数 3 MR 10个副本
6、文件的修改时间
7、文件的访问时间
8、文件的权限
9、文件的block列表
blk1:0,134217728,node1,node13,node26:blockID
blk2:134217728,134217728,node7,node89,node1002
blk2:134217728*2,134217728,node7,node89,node1002
blk2:134217728*3,134217728,node7,node89,node1002
blk2:134217728*4,134217728,node7,node89,node1002
blk2:134217728*5,134217728,node7,node89,node1002
blk2:134217728,134217728,node7,node89,node1002
blk2:134217728,134217728,node7,node89,node1002
...
存储结构
一个运行的 NameNode 如下的目录结构,该目录结构在第一次格式化的时候创建
如果属性 dfs.namenode.name.dir 指定了多个路径,则每个路径中的内容是一样的,尤其是当其中一个是挂载的 NFS 的时候,这种机制为管理提供了一些弹性。备份数据
in_use.lock 文件用于 NameNode 锁定存储目录。这样就防止其他同时运行的 NameNode 实例使用相同的存储目录。
edits 表示 edits log 日志文件
fsimage 表示文件系统元数据镜像文件
NameNode 在 checkpoint 之前首先要切换新的 edits log 文件,在切换时更新 seen_txid 的值。上次合并 fsimage 和 editslog 之后的第一个操作编号
VERSION 文件是一个 Java 的属性文件
layoutVersion 是一个负数,定义了 HDFS 持久化数据结构的版本。这个版本数字跟 hadoop 发行的版本无关。当 layout 改变的时候,该数字减 1(比如从 -57 到 -58)。当对 HDFDS 进行了升级,就会发生 layoutVersion 的改变。
namespaceID 是该文件系统的唯一标志符,当 NameNode 第一次格式化的时候生成。
clusterID 是 HDFS 集群使用的一个唯一标志符,在 HDFS 联邦的情况下,就看出它的作用了,因为联邦情况下,集群有多个命名空间,不同的命名空间由不同的 NameNode 管理。
blockpoolID 是 block 池的唯一标志符,一个 NameNode 管理一个命名空间,该命名空间中的所有文件存储的 block 都在 block 池中。
cTime 标记着当前 NameNode 创建的时间。对于刚格式化的存储,该值永远是 0 ,但是当文件系统更新的时候,这个值就会更新为一个时间戳。
storageType 表示当前目录存储 NameNode 内容的数据结构。
当文件系统客户端进行了写操作(例如创建或移动了文件),这个事务首先在 edits log 中记录下来。NameNode 在内存中有文件系统的元数据,当 edits log 记录结束后,就更新内存中的元数据。内存中的元数据用于响应客户端的读请求。
edits log 在磁盘上表现为一定数量的文件。每个文件称为片段(Segment),前缀 “ edits ” ,后缀是其中包含的事务 ID(transaction IDs)。每个写操作事务都仅仅打开一个文件(比如:edits_inprogress_00000000000010),写完后冲刷缓冲区并同步到磁盘,然后返回客户端 success 状态码。如果 NameNode 的元数据需要写到多个目录中,则对于每个写事务需要所有的写操作都完成,并冲刷缓冲区同步到磁盘才返回 success 状态码。这样就可以保证在发生宕机的时候没有事务数据丢失。
用户的操作是一个事务,每个操作 NN 都要先将操作记录到 edits log 中,如果给 NN 指定了多个目录,则在多个目录中都存在 edits log 文件,用户的操作要在多个目录中都写完成,才让 NN 同步数据到内存中。当 NN 在内存中也同步了数据,就返回客户端 success。
每个fsimage文件都是系统元数据的一个完整的持久化检查点(checkpoint)(后缀表示镜像中的最后一个事务)。写操作不更新这个数据,因为镜像文件通常为GB数量级,写到磁盘很慢。如果NameNode宕机,可以将最新fsimage加载到内存,同时执行edits log对应于该fsimage之后的操作,就可以重建元数据的状态。而这正是每次启动NameNode的时候NameNode要做的工作。
存在的意义
edits log 会随着对文件系统的操作而无限制地增长,这对正在运行的 NameNode 而言没有任何影响,如果 NameNode 重启,则需要很长的时间执行 edits log 的记录以更新 fsimage(元数据镜像文件)。在此期间,整个系统不可用。
在系统启动期间,NameNode 合并 fsimage + edits log
fsimage=0
edist log=很大
内存
fsimage=GB
edits log
内存->执行 edits log ·条目
解决方案就是运行 SecondaryNameNode,它的作用就是为 NameNode 内存中的文件系统元数据生成检查点(checkpoint)。fsimage
工作流程
edits_inprogress_00000000018_0000000028 seen_txid=29
1、secondarynamenode 请求 namenode 生成新的 edits log 文件并向其中写日志。NameNode 会在所有的存储目录中更新 seen_txid 文件
2、SecondaryNameNode 通过 HTTP GET 的方式从 NameNode 下载 fsimage 和 edits 文件到本地。
3、SecondaryNameNode 将 fsimage 加载到自己的内存,并根据edits log更新内存中的 fsimage 信息,然后将更新完毕之后的 fsimage 写到磁盘上。
4、SecondaryNameNode 通过 HTTP PUT 将新的 fsimage 文件发送到 NameNode ,NameNode 将该文件保存为 .ckpt 的临时文件备用。
5、NameNode 重命名该临时文件并准备使用。此时 NameNode 拥有一个新的 fsimage 文件和一个新的很小的 edits log 文件(可能不是空的,因为在 SecondaryNameNode 合并期间可能对元数据进行了读写操作)。管理员也可以将 NameNode 置于 safemode ,通过 hdfs dfsadmin -saveNamespace 命令来进行 edits log 和 fsimage 的合并。
SecondaryNameNode 要和 NameNode 拥有相同的内存。对大的集群,SecondaryNameNode 运行于一台专用的物理主机。
对于创建检查点( checkpoint )的过程,有三个参数进行配置:
1、默认情况下,SecondaryNameNode 每个小时进行一次 checkpoint 合并
由 dfs.namenode.checkpoint.period 设置,单位秒
2、在不足一小时的情况下,如果 edits log 存储的事务达到了 1000000 个也进行一次 checkpoint 合并
由 dfs.namenode.checkpoint.txns 设置事务数量
3、事务数量检查默认每分钟进行一次
由 dfs.namenode.checkpoint.check.period 设置,单位秒。
总结:
namenode
管理文件元数据
文件名称、大小、所属关系、权限、副本大小、副本个数
文件块的列表信息:(块的ID,偏移量,块的大小,块所在的主机名称列表)
持久化文件
fsimage(内存快照),edits log
fsimage很大,GB级别;edits log只追加的文件
用户操作首先记录到edits log中,然后更新内存
fsimage不保存数据块位置信息
在系统启动的时候,datanode向namenode发送文件块列表信息(bid)
datanode通过心跳向namenode汇报列表信息。
namenode元数据正常工作时,元数据放内存,高并发。
secondarynamenode
在系统启动的时候,namenode首先加载fsimage,然后逐条执行edits log中的日志操作,如果edits log很大,则需要很长时间才能加载完毕,向磁盘写新的fsimage,之后才可以对外提供服务。
周期性地从namenode拷贝fsimage+edits log,在SNN中合并为新的fsimage,推送给namenode。
条件:1、每小时一次,2、不足一小时,则只要edits log中记录的事务数达到了1000000,则合并。
datanode
存储结构
1、SecondaryNameNode 中 checkpoint 目录布局(dfs.namenode.checkpoint.dir)和 NameNode 中的一样。
2、如果 NameNode 完全坏掉(没有备用机,也没有 NFS ),可以快速地从 SecondaryNameNode 恢复。有可能丢数据
3、如果 SecondaryNameNode 直接接手 NameNode 的工作,需要在启动 NameNode 进程的时候添加 -importCheckpoint 选项。该选项会让 NameNode 从由 dfs.namenode.checkpoint.dir 属性定义的路径中加载最新的 checkpoint 数据,但是为了防止元数据的覆盖,要求 dfs.namenode.name.dir 定义的目录中没有内容。
DataNode 不需要显式地格式化;关键文件和目录结构如下:
1、HDFS 块数据存储于 blk_前缀的文件中,包含了被存储文件原始字节数据的一部分。
2、每个 block 文件都有一个 .meta 后缀的元数据文件关联。该文件包含了一个版本和类型信息的头部,后接该 block 中每个部分的校验和。
3、每个 block 属于一个 block 池,每个 block 池有自己的存储目录,该目录名称就是该池子的 ID(跟 NameNode 的 VERSION 文件中记录的 block 池 ID 一样)。
当一个目录中的 block 达到 64 个(通过 dfs.datanode.numblocks 配置)的时候,DataNode 会创建一个新的子目录来存放新的 block 和它们的元数据。这样即使当系统中有大量的 block 的时候,目录树也不会太深。同时也保证了在每个目录中文件的数量是可管理的,避免了多数操作系统都会碰到的单个目录中的文件个数限制(几十几百上千个)。
如果 dfs.datanode.data.dir 指定了位于在不同的硬盘驱动器上的多个不同的目录,则会通过轮询的方式向目录中写 block 数据。需要注意的是 block 的副本不会在同一个 DataNode 上复制,而是在不同的 DataNode 节点之间复制。
存储数据模型(重点)
1、文件线性切割成块(Block)(按字节切割)
…
Hello world
2、Block 分散存储在集群节点中
3、单一文件 Block 大小一致,文件与文件可以不一致
hdfs dfs -D dfs.blocksize=1048576 -D dfs.replication=2 -put hello.txt /
4、Block 可以设置副本数,副本分散在不同节点中
a) 副本数不要超过节点数量
b) 承担计算
c) 容错
5、文件上传可以设置 Block 大小和副本数
6、已上传的文件 Block 副本数可以调整,大小不变
7、只支持一次写入多次读取,同一时刻只有一个写入者
对同一个文件,一个时刻只有一个写入者
8、可以 append 追加数据
优势(了解)
第一个副本:放置在上传文件的 DN;如果是集群外提交,则随机挑选一台磁盘不太满,CPU 不太忙的节点。
第二个副本:放置在于第一个副本不同的 机架的节点上。
第三个副本:与第二个副本相同机架的节点。
更多副本:随机节点
1、每个文件和目录都和一个拥有者和组相关联。
2、文件或者目录对与拥有者、同组用户和其他用户拥有独立的权限。
3、对于一个文件,r 表示读取的权限,w 表示写或者追加的权限。对于目录而言,r 表示列出目录内容的权限,w 表示创建或者删除文件和目录的权限,x 表示访问该目录子项目的权限。
4、默认情况下 hadoop 运行时安全措施处于停用模式。一个客户端可以在远程系统上通过创建和任意一个合法用户同名的账号来进行访问。 hadoop root
5、安全措施可以防止用户或自动工具及程序意外修改或删除文件系统的重要部分。(dfs.permissions.enabled 属性)。防止好人做错事。
6、超级用户是 namenode 进程的标识。对于超级用户,系统不会执行任何权限检查。
在 NameNode 安全模式(safemode)
通过命令查看 namenode 是否处于安全模式:
$ hdfs dfsadmin -safemode get
Safe mode is ON
HDFS 的前端 webUI 页面也可以查看 NameNode 是否处于安全模式。
有时候我们希望等待安全模式退出,之后进行文件的读写操作,尤其是在脚本中,此时:
$ hdfs dfsadmin -safemode wait
# your read or write command goes here
管理员有权在任何时间让 namenode 进入或退出安全模式。进入安全模式:
$ hdfs dfsadmin -safemode enter
Safe mode is ON
这样做可以让 namenode 一直处于安全模式,也可以设置 dfs.namenode.safemode.threshold-pct 为1做到这一点。
离开安全模式:
$ hdfs dfsadmin -safemode leave
Safe mode is OFF
64KB 数据包包含的头部信息
packet 接收者:
64KB 数据包格式:
namenode告知客户端每个block中最佳的datanode,并让客户端直接连到datanode检索数据。由于数据流分散在集群中的所有datanode,这样可以使HDFS可扩展到大量的并发客户端。同时,namenode只需要响应block位置的请求,无需响应数据请求,否则namenode会成为瓶颈。
hadoop 把网络看作是一棵树,两个节点间的距离是它们到最近共同祖先的距离和。通常可以设置等级:
hadoop 官网地址:
http://hadoop.apache.org
中文文档:
http://hadoop.apache.org/docs/r1.0.4/cn
apache老版本软件下载地址:
https://hadoop.apache.org/old/releases.html#Download
安装&部署:
node1: NN DN SNN
1)基础设施
GUN/Linux
jdk 1.7+
环境:JAVA_HOME -> /etc/profile ~/.bash_profile
ssh免密:
远程执行<-不需要用户交互,而是用户直接给出一个命令,直接在远程执行
不会加载 /etc/profile
远程登陆<-返回一个交互接口
返回接口/bash 会加载/etc/profile
ip
时间同步
hosts/hostname
2)应用的安装
a)绿色:开箱即用(配置/部署)
环境变量
应用自己的环境变量
JAVA_HOME -> hadoop-env.sh
b)操作:
format
start
使用
hadoop-2.6.5.tar.gz
jdkxxx.rpm
将文件上传到 /opt/apps 目录下
[root@node1 apps]# tar -zxvf hadoop-2.6.5.tar.gz -C /opt
[root@node1 apps]# rpm -ivh jdk-8u221-linux-x64.rpm
[root@node1 apps]# vim /etc/profile
export JAVA_HOME=/usr/java/default
export PATH=$PATH:$JAVA_HOME/bin
[root@node1 apps]# source /etc/profile 或者 . /etc/profile
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
cat ~/.ssh/id_dsa.pub > ~/.ssh/authorized_keys
tar -zxf hadoop-2.6.5.tar.gz -C /opt
将 HADOOP_HOME 以及 HADOOP_HOME/bin 和 HADOOP_HOME/sbin 添加到环境变量
export HADOOP_HOME=/opt/hadoop-2.6.5
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
$HADOOP_HOME/etc/hadoop
由于通过 SSH 远程启动进程的时候默认不会加载 /etc/profile 设置,JAVA_HOME 变量就加载不到,需要手动指定。
export JAVA_HOME=/usr/java/jdk1.8.0_221-amd64
<!-- 指定访问HDFS的时候路径的默认前缀 / hdfs://node1:9000/ -->
fs.defaultFS</name>
hdfs://node1:9000</value>
</property>
<!-- 指定hadoop的临时目录位置,它会给namenode、secondarynamenode以及datanode的存储目录指定前缀 -->
hadoop.tmp.dir</name>
/var/bjsxt/hadoop/pseudo</value>
</property>
</configuration>
配置文件拷贝后格式不美观,可以通过以下方式格式化:
<!-- 指定block副本数 -->
dfs.replication</name>
1</value>
</property>
<!-- 指定secondarynamenode所在的位置 -->
dfs.namenode.secondary.http-address</name>
node1:50090</value>
</property>
</configuration>
DataNode 所在的节点
[root@bk1 hadoop]# vim slaves
node1
hdfs namenode -format
start-dfs.sh
[root@node1 current]# jps
1943 SecondaryNameNode
1800 DataNode
1693 NameNode
2045 Jps
说明进程都正常启动了,然后网页访问:
http://node1:50070
查看文件系统
神马都没有:
生成本地文件:
for i in `seq 100000`; do echo "hello bjsxt $i" >> hh.txt; done
ll -h
hdfs dfs -D dfs.blocksize=1048576 -D dfs.replication=1 -put hh.txt /
cd /var/bjsxt/hadoop/pseudo/dfs/data/current/
cd current/BP-2057742434-192.168.20.91-1575827659318/current/finalized/subdir0/subdir0
ll -h
total 1.8M
-rw-r--r-- 1 root root 1.0M Dec 27 16:28 blk_1073741825
-rw-r--r-- 1 root root 8.1K Dec 27 16:28 blk_1073741825_1001.meta
-rw-r--r-- 1 root root 723K Dec 27 16:28 blk_1073741826
-rw-r--r-- 1 root root 5.7K Dec 27 16:28 blk_1073741826_1002.meta
[root@node1 ~]# stop-dfs.sh
总结-1
大文件如何存储?
单台服务器放不下,切块,将块打散放在各个datanode中
文件要放进去,还要取出来
文件分了多少块,每个块偏移量是多少,大小是多少
在哪些datanode上。
元数据:
一个文件的元数据放在NameNode的内存中
放内存中应付高并发
元数据很小,可以放内存
方便用户浏览
方便客户端操作