目录
一. General(概括)
1. Overview
2. Single Node Setup
3. Cluster Setup
4. Commands Reference
5. FileSystem Shell
6. Hadoop Compatibility
7. Interface Classification
8. FileSystem Specification
二. Common(共同)
1. CLI Mini Cluster
2. Native Libraries
3. Proxy User
4. Rack Awareness
5. Secure Mode
6. Service Level Authorization
7. HTTP Authentication
8. Credential Provider API
9. Hadoop KMS
10. Tracing
三. HDFS
1. Architecture
2. User Guide
3. Commands Reference
4. NameNode HA With QJM
5. NameNode HA With NFS
6. Federation
7. ViewFs
8. Snapshots
9. Edits Viewer
10. Image Viewer
11. Permissions and HDFS
12. Quotas and HDFS
13. HFTP
14. libhdfs (C API)
15. WebHDFS (REST API)
16. HttpFS
17. Short Circuit Local Reads
18. Centralized Cache Management
19. NFS Gateway
20. Rolling Upgrade
21. Extended Attributes
22. Transparent Encryption
23. Multihoming
24. Storage Policies
25. Memory Storage Support
26. Upgrade Domain
27. DataNode Admin
28. Router Federation
四. MapReduce
1. Tutorial
2. Commands Reference
3. Compatibility with 1.x
4. Encrypted Shuffle
5. Pluggable Shuffle/Sort
6. Distributed Cache Deploy
五. MapReduce REST APIs
1. MR Application Master
2. MR History Server
六. YARN
1. Architecture
2. Commands Reference
3. Capacity Scheduler
4. Fair Scheduler
5. ResourceManager Restart
6. ResourceManager HA
7. Node Labels
8. Web Application Proxy
9. Timeline Server
10. Timeline Service V.2
11. Writing YARN Applications
12. YARN Application Security
13. NodeManager
14. DockerContainerExecutor
15. Running Applications in Docker Containers
16. Using CGroups
17. Secure Containers
18. Registry
19. Reservation System
20. Graceful Decommission
21. Opportunistic Containers
22. YARN Federation
七. YARN REST APIs
1. Introduction
2. Resource Manager
3. Node Manager
4. Timeline Server
5. Timeline Service V.2
八. Hadoop compatible File Systems
1. Amazon S3
2. Azure Blob Storage
3. OpenStack Swift
九. Auth
1. Overview
2. Examples
3. Configuration
4. Building
十. Tools
1. Hadoop Streaming
2. Hadoop Archives
3. Hadoop Archive Logs
4. DistCp
5. GridMix
6. Rumen
7. Resource Estimator Service
8. Scheduler Load Simulator
9. Hadoop Benchmarking
十一. Reference
1. Changelog and Release Notes
2. API docs
3. Metrics
十二. Configuration
1. core-default.xml
2. hdfs-default.xml
3. mapred-default.xml
4. yarn-default.xml
5. Deprecated Properties
Apache Hadoop 2.9.2是2.x.y发行版中的一个点发行版,它建立在前一个稳定版2.9.1的基础上。
以下是主要特性和改进的简要概述:
* Common
> 阿里云OSS支持
> Hadoop资源估测器
* HDFS
> 基于HDFS路由器的联合
* YARN
> YARN 时间轴服务v.2
> YARN联合
> 随即容器
> YARN Web UI v.2
> 通过API(仅在容量调度器上支持)改变队列配置
> 更新已分配/正在运行的容器的资源和执行类型。(仅在容量调度器上支持)
Hadoop文档包括开始使用Hadoop所需要的信息。从单节点设置(Single Node Setup)开始,它向您展示了如何设置单节点Hadoop安装;然后转到集群设置(Cluster Setup),学习如何设置多节点Hadoop安装。
Purpose
本文档描述了如何设置和配置单节点Hadoop安装,以便您可以使用Hadoop MapReduce和Hadoop分布式文件系统(HDFS)快速执行简单操作。
Prerequisites(前提条件)
支持的平台
所需软件
对于Linux需要的软件包括:
1. 必须安装Java。在 HadoopJavaVersions上描述了推荐的Java版本。
2. 必须安装ssh,并运行sshd以使用 管理远程Hadoop守护进程的Hadoop脚本。
安装软件
如果你的集群没有必备的软件,您将需要安装它。
例如在Ubuntu Linux:
|
Download
要获得一个Hadoop发行版,请从Apache Download Mirrors之一下载最新的稳定版本。
Prepare to Start the Hadoop Cluster
解压下载的Hadoop发行版。在发行版中,编辑etc/hadoop/hadoop-env.sh文件来定义以下一些参数:
# set to the root of your Java installation
export JAVA_HOME=/usr/java/latest
尝试以命令:
$ bin/hadoop |
这将显示hadoop脚本的使用文档。
现在您将在三种支持的模式之一中启动Hadoop集群:
Standalone Operation
默认情况下,Hadoop被配置为在非分布式模式下运行,作为单个Java进程。这对调试很有用。
下面的示例复制解压后的conf目录用作输入,然后查找并显示给定的正则表达式的每个匹配项。输出被写入给定的输出目录。
$ mkdir input
$ cp etc/hadoop/*.xml input
$ bin/hadoop --config etc/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.9.2.jar grep input output 'dfs[a-z.]+'
$ cat output/*
摘抄:
默认的模式,无需运行任何守护进程(daemon),所有程序都在单个JVM上执行。由于在本机模式下测试和调试MapReduce程序较为方便,因此,这种模式适宜用在开发阶段。
使用本地文件系统,而不是分布式文件系统。
Hadoop不会启动NameNode、DataNode、JobTracker、TaskTracker等守护进程,Map()和Reduce()任务作为同一个进程的不同部分来执行的。
用于对MapReduce程序的逻辑进行调试,确保程序的正确。
所谓默认模式,及安装完jdk及hadoop,配置好相应的环境,及本地模式配置完成
Pseudo-Distributed Operation
Hadoop还可以在一个伪分布式模式的单个节点上运行,其中每个Hadoop守护进程在单独的Java进程中运行。
Configuration
使用如下:
etc/hadoop/core-site.xml:
fs.defaultFS
hdfs://localhost:9000
etc/hadoop/hdfs-site.xml:
dfs.replication
1
Setup passphraseless ssh(设置无密码ssh)
现在检查您在没有密码的情况下,是都能ssh到主机:
$ ssh localhost
如果在没密码的情况下无法ssh到主机,那么就执行下面的命令:
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys
Execution
以下说明用于在本地运行MapReduce作业。如果想在YARN上运行作业,请参见YARN on Single Node。
1. 格式化文件系统:
$ bin/hdfs namenode -format
2. 启动NameNode守护进程和DataNode守护进程:
$ sbin/start-dfs.sh
hadoop守护进程日志输出被写入$HADOOP_LOG_DIR目录(默认是$HADOOP_HOME/logs)
3.浏览NameNode的web页面;默认位于:
4.创建执行MapReduce作业所需的HDFS目录:
$ bin/hdfs dfs -mkdir /user
$ bin/hdfs dfs -mkdir /user/
5.将输入文件复制到分布式文件系统中:
$ bin/hdfs dfs -mkdir input
$ bin/hdfs dfs -put etc/hadoop/*.xml input
6.运行提供的一些示例:
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.9.2.jar grep input output 'dfs[a-z.]+'
7.检查输出文件:将输出文件从分布式文件系统复制到本地文件系统,然后查看它们:
$ bin/hdfs dfs -get output output
$ cat output/*
or
在分布式文件系统上查看文件:
$ bin/hdfs dfs -cat output/*
8.完成后,停止守护进程:
$ sbin/stop-dfs.sh
YARN on a Single Node
通过设置一些参数并运行ResourceManager守护进程和NodeManager守护进程,您可以在伪分布式模式的YARN上运行MapReduce作业。以下说明假定Execution中的前4步已经执行。
1.配置参数如下:
etc/hadoop/mapred-site.xml:
mapreduce.framework.name
yarn
etc/hadoop/yarn-site.xml:
yarn.nodemanger.aux-services
mapreduce_shuffle
2.启动ResourceManager守护进程和NodeManager守护进程
$ sbin/start-yarn.sh
3.浏览ResourceManager web页面;默认位于:
4. 运行MapReduce作业。
5.完成后,停止守护进程。
$ sbin/stop-yarn.sh
Fully-Distributed Operation
有关设置完全分布式、非普通集群的信息,请参阅Cluster Setup.
Pursose
本文描述了如何安装和配置Hadoop集群,从几个节点到具有数千个节点的超大集群。要使用Hadoop,您可能首先希望将其安装在一台机器上(请参阅单节点设置)
本文档不包括安全性或高可用性等高级主题。
Prerequisites(前提条件)
Installation(安装)
安装Hadoop集群通常需要在集群中的所有机器上解压软件,或者通过适合您的操作系统的打包系统安装软件。把硬件分成几个功能是很重要的。
通常集群中的一台机器被指定为Namenode,另一台机器被专门指定为ResourceManager。这些都是主机。其它服务(比如web应用代理服务器和MapReduce作业历史服务器)通常运行在专用硬件或共享基础设施上,这取决于负载。
集群中其它机器同时充当DataNode和NodeManager。这些都是slaves。
Configuring Hadoop in Non-Secure Mode(非安全模式下配置Hadoop)
Hadoop的Java配置是由两种重要的配置文件驱动的:
另外,你可以通过etc/hadoop/hadoop-env.sh和etc/hadoop/yarn-env.sh设置特定站点的值来控制分布的bin目录中的hadoop脚本。
要配置hadoop集群,你需要配置Hadoop守护进程执行的环境和Hadoop守护进程的配置参数。
HDFS守护进程是:NameNode,SecondaryNode,DataNode。YARN守护进程是:ResourceManager,NodeManager,WebAppProxy
。如果用到了MapReduce,那么MapReduce Job History服务器也将会运行。对于大型安装,它们通常安装在单独的主机上。
配置Hadoop守护进程环境
管理员应该使用etc/hadoop/hadoop-env.sh和可选的etc/hadoop/mapred-env.sh和etc/hadoop/yarn-env.sh脚本对Hadoop守护进程环境进行特定站点的自定义。
至少,必须定义JAVA_HOME,以便在每个远程节点上正确定义它。
管理员可以使用下表中显示的配置选项配置各个守护进程:
Daemon | Environment Variable |
NameNode | HADOOP_NAMENODE_OPTS |
DataNode | HADOOP_DATANODE_OPTS |
Secondary NameNode | HADOOP_SECONDARYNAMENODE_OPTS |
ResourceManager | YARN_RESOURCEMANAGER_OPTS |
NodeManager | YARN_NODEMANAGER_OPTS |
WebAppProxy | YARN_PROXY_SERVER_OPTS |
MapReduce Job History Server | HADOOP_JOB_HISTORYSERVER_OPTS |
例如,要将Namenode配置为使用parallelGC,应该在hadoop-env.sh中添加如下语句:
export HADOOP_NAMENODE_OPTS="-XX:+UseParallelGC" |
查看etc/hadoop/hadoop-env.sh文件中的其它示例。
可以自定义的其它有用配置参数包括:
大多情况下,应该指定HADOOP_PID_DIR和HADOOP_LOG_DIR目录,这样它们只能由运行hadoop守护进程的用户写入.否者可能会发生符号攻击.
在整个系统shell环境配置中配置HADOOP_PREFIX也是传统的做法.比如,目录profile.d中一个简单的脚本:
HADOOP_PREFIX=/path/to/hadoop export HADOOP_PREFIX |
Daemon | Environment Variable |
ResourceManager | YARN_RESOURCEMANAGER_HEAPSIZE |
NodeManager | YARN_NODEMANAGER_HEAPSIZE |
WebAppProxy | YARN_PROXYSERVER_HEAPSIZE |
Map Reduce Job History Server | HADOOP_JOB_HISTORYSERVER_HEAPSIZE |
配置Hadoop守护进程
本节处理在给定配置文件中要指定的重要参数:
Parameter | Value | Notes |
fs.defaultFS | NameNode URI | hdfs://host:port/ |
io.file.buffer.size | 131072 | 序列文件中使用的读/写缓冲区大小 |
Parameter | Value | Notes |
dfs.namenode.name.dir | NameNode持久存储名称空间和事务日志的本地文件系统上的路径 | 如果这是一个以逗号分隔的目录列表,那么那么将在所有目录中复制名称表,以实现冗余 |
dfs.hosts / dfs.hosts.exclude |
允许/排除的数据节点列表 | 如果必要,使用这些文件控制允许的数据节点列表 |
dfs.blocksize | 268435456 | 对于大型文件系统,HDFS块大小为256MB |
dfs.namenode.handler | 100 | 处理来自大量数据节点的PRCs的更多名称节点服务器线程数 |
Parameter | Value | Notes |
dfs.datanode.data.dir | 数据节点的本地文件系统上的以逗号分隔的路径列表,其中数据节点存储块 | 如果这是一个逗号分隔目录列表,那么数据将存储在所有命名分目录中,通常存储在不同的设备上 |
Parameter | Value | Notes |
yarn.acl.enable | true / false |
enable ACLs?默认为false |
yarn.admin.acl
|
Admin | 在集群上设置管理员的ACL.ACLs的形式:逗号分隔的用户+空格+逗号分隔的组.默认为特殊值*,表示所有人;仅仅是特殊值空格表示任何人都没权限. |
yarn.log-aggregation-enable | false | 启用或禁用日志聚合的配置 |
Parameter | Value | Notes |
yarn.resourcemanager.address | 供用户提交作业的ResourceManager的host:port
|
如果设置了host:port,将会覆盖设置在yarn.resourcemanager.hostname中的主机名. |
yarn.resourcemanager.scheduler.address | 供应用程序管理器与调度程序进行对话以获取资源的ResourceManager的host:port | 如果设置了host:port,将会覆盖设置在yarn.resourcemanager.hostname中的主机名. |
yarn.resourcemanager.resource-tracker.address | ResourceManager host:port for NodeManagers | 如果设置了host:port,将会覆盖设置在yarn.resourcemanager.hostname中的主机名. |
yarn.resourcemanager.admin.address | 用于管理命令的ResourceManager的host:port | 如果设置了host:port,将会覆盖设置在yarn.resourcemanager.hostname中的主机名. |
yarn.resourcemanager.webapp.address | ResourceManager web-ui host:port | 如果设置了host:port,将会覆盖设置在yarn.resourcemanager.hostname中的主机名. |
yarn.resourcemanager.hostname | ResourceManager host | host 可以替代所有yarn.resourcemanager*address资源的单一主机名.为ResourceManager组件生成默认端口. |
yarn.resourcemanager.scheduler.class | ResourceManager Scheduler class | CapacityScheduler(推荐),FairScheduler(也推荐),或者FiFoScheduler.使用完全限定的类名,比如:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler |
yarn.scheduler.minimum-allocation-mb | 在ResourceManager上分配给每个容器请求的最小内存限制 | 单位是MBs |
yarn.scheduler.maximum-allocation-mb | 在ResourceManager上分配给每个容器请求的最大内存限制 | 单位是MBs |
yarn.resourcemanager.nodes.include-path / yarn.resourcemanager.nodes.exclude-path |
允许/排除的NodeManagers列表 | 如果有必要,使用这些文件控制允许的NodeManagers列表 |
Parameter | Value | Notes |
yarn.nodemanager.resource.memory-mb | 资源,即给定的NodeManager的可用物理内存,单位是MB
|
定义NodeManager上可供运行容器使用的总可用资源 |
yarn.nodemanager.vmem-pmem-ratio | 任务的虚拟内存使用可能超出物理内存的最大比率 | 每个任务的虚拟内存使用率可能超出其物理内存限制的比率;NodeManager上的任务使用的虚拟内存总量超过其物理内存使用的比率. |
yarn.nodemanager.local-dirs | 写入中间数据的本地文件系统上以逗号分隔的路径列表。 | 多路径有助于扩展磁盘I/O. |
yarn.nodemanager.log-dirs | 写入日志的本地文件系统上以逗号分隔的路径列表。 | 多路径有助于扩展磁盘I/O |
yarn.nodemanager.log.retain-seconds | 10800 | NodeManager上日志保留的默认时间(以秒为单位),仅当log-aggregation禁用时适用. |
yarn.nodemanager.remote-app-log-dir | /logs | 应用程序完成时应用程序日志所要移动到的HDFS目录.需要设置适当的权限.仅当log-aggregation启用时适用. |
yarn.nodemanager.remote-app-log-dir-suffix | logs | 附加到远程日志目录的后缀.日志将聚集到${yarn.nodemanager.remote-app-log-dir}/${user}/${thisParam},仅当log-aggregation启用时适用. |
yarn.nodemanager.aux-services | mapreduce_shuffle | 需要为Map Reduce应用程序设置的洗牌服务 |
Parameter | Value | Notes |
yarn.log-aggregation.retain-seconds | -1
|
在删除聚合日志之前保留多长时间.-1表示禁止.注意,此参数值设置太小将会向NameNode发送垃圾邮件. |
yarn.log-aggregation.retain-check-internal-seconds
|
-1 | 检查聚合日志间隔之间的时间间隔.如果设置为零或负值,则该值将计算为聚合日志保留时间的十分之一.注意,此参数值设置太小将会向NameNode发送垃圾邮件. |
Parameter | Value | Notes |
mapreduce.framework.name | yarn
|
执行框架设置为YARN |
mapreduce.map.memory.mb | 1536 | maps更大的资源限制.描述:调度程序为每个map任务请求的内存量. |
mapreduce.map.java.opts | -Xmx1024M | |
mapreduce.reduce.memory.mb | 3072 | reduces更大的资源限制.描述:调度程序为每个reduce任务请求的内存量. |
mapreduce.reduce.java.opts | -Xm2560M | |
mapreduce.task.io.sort.mb | 512 | 有效排序数据时更大的内存限制.描述:排序文件时要使用的缓冲区内存总量,以兆字节为单位。默认情况下,为每个合并流提供1MB,这将使查找最小化。 |
mapreduce.task.io.sort.factor | 100 | 排序文件时同时合并的更多的流.描述:排序文件时要同时合并的流的数目。这将确定打开的文件句柄数。 |
mapreduce.reduce.shuffle.parallelcopyies | 50 | 用于从大量的maps获取输出后在reduces上运行的更多的并行副本数.描述:在复制(混排)阶段通过由reduce运行的默认并行传输数. |
Parameter | Value | Notes |
mapreduce.jobhistory.address | MapReduce JobHistroy Server host:port | 默认端口是10020.描述:MapReduce JobHistory Server IPC(进程间通信) host:port |
mapreduce.jobhistory.webapp.address | MapReduce JobHistory Server Web UI host:port | 默认端口是19888.描述:MapReduce JobHistory Server Web UI host:port |
mapreduce.jobhistory.intermediate-done-dir | /mr-history/tmp | MapReduce作业写入历史文件的目录. |
mapreduce.jobhistory.done-dir | /mr-history/done | MR JobHistory 服务器管理历史文件的目录 |
Monitoring Health of NodeManagers
Hadoop提供了一种机制,管理员可以通过该机制将节点管理器配置为定期运行管理员提供的脚本,以确定节点是否正常。
管理员可以通过在脚本中执行他们选择的任何检查来确定节点是否处于健康状态.如果脚本检测到节点处于不健康状态,它必须将一行以字符串ERROR开头的内容打印到标准输出中。NodeManager定期生成脚本并检查其输出。如果脚本的输出包含如上所述的字符串错误,则节点的状态报告为不健康,并且该节点被ResourceManager列入黑名单。不再向该节点分配任何其他任务。但是,NodeManager将继续运行该脚本,以便如果节点再次恢复健康,它将自动从ResourceManager上的黑名单节点中删除。节点的运行状况以及脚本的输出(如果不正常)可供管理员在ResourceManager Web界面中使用。自节点正常运行以来的时间也显示在Web界面上.
etc/hadoop/ yarns -site.xml中的下面的参数可以用来控制节点健康监控脚本.
Parameter | Value | Notes |
yarn.nodemanager.health-checker.script.path | Node health script | 用于检查节点运行状况的脚本. |
yarn.nodemanager.health-checker.script.opts | Node health script options | 用于检查节点运行状况的脚本选项.描述:传递给运行状况检查脚本的参数 |
yarn.nodemanager.health-checker.inter | Node health script interval | 运行health script的时间间隔.描述:运行磁盘运行状况检查程序代码的频率. |
yarn.nodemanager.health-checker.script.timeout-ms | Node health script timeout interval | health script 执行超时. |
如果只有部分本地磁盘损坏,则健康检查程序脚本不应该给出ERROR.NodeManager能够定期检查本地磁盘的运行状况(特别是检查nodemanager-local-dirs和nodemanager-log-dirs),并且在根据配置属性yarn.nodeManager.disk-health-checker.min-health-disks设置的值达到坏目录数阈值后,整个节点都被标记为不健康,而且这个信息也会发送给资源管理器。引导盘被攻击,或者健康检查程序脚本检测到引导盘中的故障.
Slaves File
在文件etc/hadoop/slaves中列出所有从属主机名或IP地址,每行一个.Helper scripts(如下所述)将使用etc/hadoop/slaves文件一次在很多主机上运行命令.它不用于任何基于Java的Hadoop配置.为了使用此功能,必须为用于运行Hadoop的帐户建立ssh信任(通过无密码ssh或其它方式,如Kerberos).
Hadoop Rack Awareness
许多Hadoop组建具有机架感知功能,并利用网络拓扑结构提高性能和安全性.Hadoop守护进程通过调用管理员配置的模块来获取集群中从机的机架信息.有关更多具体信息,请参阅 Rack Awareness文档.
强烈建议在启动HDFS之前配置机架感知.
Logging
Hadoop使用 Apache log4j.通过Apache Commons日志框架进行日志记录.编辑etc/hadoop/log4j.properties文件以自定义Hadoop守护进程的日志配置(日志格式等).
Operating the Hadoop Cluster(操作Hadoop集群)
完成所有必需的配置后,将文件分发到所有计算机上的HADOOP_CONF_DIR目录.这应该是所有机器上的同一个目录.一般来说,建议HDFS和YARN作为单独的用户来运行.在大多数安装中,HDFS进程作为hdfs执行,YARN通常使用yarn帐户.
Hadoop Starttup
要启动Hadoop集群,需要同时启动HDFS和YARN集群.
第一次打开HDFS时,必须要格式化.将一个新的分布式文件系统格式化为hdfs:
[hdfs]$ $HADOOP_PREFIX/bin/hdfs namenode -format |
在指定的节点上使用下面命令启动HDFS NameNode 作为hdfs:
[hdfs]$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode |
在每个指定的节点上使用下面命令启动一个DataNode 作为hdfs:
[hdfs]$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --confg $HADOOP_CONF_DIR --script hdfs start datanode |
如果配置了etc/hadoop/slaves和ssh可信访问(参阅Single Node Setup),那么所有的HDFS进程都可以用一个实用脚本启动.作为hdfs:
[hdfs]$ $HADOOP_PR EFIX/sbin/start-dfs.sh |
用下面的命令启动YARN,运行在指定的ResourceManager上,作为yarn:
[yarn]$ $HADOOP_YARN_HOME/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR start resourcemanager |
在每个指定的主机上运行一个脚本以启动一个NodeManager,作为 yarn:
[yarn]$ $HADOOP_YARN_HOME/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR start nodemanager |
启动一个独立的WebAppProxy服务器.作为 yarn 运行在WebAppProxy上.如果多个服务器用来平衡负载,则应该在每个服务器运行它们:
[yarn]$ $HADOOP_YARN_HOME/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR start proxyserver |
如果配置了etc/hadoop/slaves和ssh可信访问(参阅Single Node Setup),那么所有的YARN进程都可以用一个实用脚本启动.作为yarn:
[yarn]$ $HADOOP_YARN/HOME/sbin/start-yarn.sh |
用下面的命令启动MapReduce JobHistory服务器,运行在指定的服务器上,作为 mapred:
[mapred]$ $HDOOP_PREFIX/sbin/mr-jobhistory-daemon.sh --config $HADOOP_CONF_DIR start historyserver |
Hadoop Shutdown
使用以下命令停止NameNode,运行在指定的NameNode,作为 hdfs:
[hdfs]$ $HADOOP_PREFIX/sbin/hadopo-daemon.sh --config $HADOOP_CONF_DIR --script hdfs stop namenode |
运行一个脚本以停止一个DataNode,作为 hdfs:
[hdfs]$ $HADOOP_PREFIX/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs stop datanode |
如果配置了etc/hadoop/slaves和ssh可信访问(参阅 Single Node Setu),那么所有的HDFS进程都可以用一个实用的脚本来停止.作为 hdfs:
[hdfs]$ $HADOOP_PREFIX/sbin/stop-dfs.sh |
用下面的命令停止ResourceManager,运行在指定的ResourceManager,作为 yarn:
[yarn]$ $HADOOP_YARN_HOME/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR stop resourcemanager |
运行一个脚本以停止一个从属服务器器上NodeManager,作为 yarn:
[yarn]$ $HADOOP_YARN_HOME/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR stop nodemanager |
如果配置了etc/hadoop/slaves和ssh可信访问(参阅 Single Node Setu),那么就可以使用实用脚本程序停止所有yarn进程.作为 hdfs:
[yarn]$ $HADOOP_YARN_HOME/sbin/stop-yarn.sh |
停止WebAppProxy服务器.运行在WebAppProxy服务器上,作为 yarn. 如果多个服务器用于负载平衡,则应该在每个服务器上运行:
[yarn]$ $HADOOP_YARN_HOME/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR stop proxyserver |
用下面的命令停止MapReduce JobHistory服务器,运行在指定的服务器上,作为 mapred:
[mapred]$ $HADOOP_PREFIX/sbin/mr-jobhistory-daemon.sh --config $HADOOP_CONF_DIR stop historyserver |
Web Inerfaces
Hadoop集群启动并运行后,请按照以下说明检查组件的web-ui:
Daemon | Web Interface | Notes |
NameNode | http://nn_host:port/ | Default HTTP port is 50070. |
ResourceManager | http://rm_host:port/ | Default HTTP port is 8088. |
MapReduce JobHistory Server | http://jhs_host:port/ | Default HTTP port is 19888 |
概述
所有Hadoop命令都由bin/hadoop脚本调用.在没有任何参数的情况下运行hadoop脚本将打印所有命令的描述.
Usage: hadoop [--config confdir] [--loglevel loglevel] [COMMAND] [GENERIC_OPTIONS] [COMMAND_OPTIONS]
FIELD | Description |
--config confdir | 覆盖默认的配置目录.默认是${HADOOP_HOME}/conf |
--loglevel loglevel | 覆盖日志级别.有效的日志级别包括:FATAL(致命),ERROR(错误),WARN(警告),INFO(信息),DEBUG(调试)和TRACE(跟踪).默认是INFO(信息) |
GENERIC_OPTIONS | 有多个命令支持的公共选项集合 |
COMMAND_OPTIONS | 本文档中描述了Hadoop公共子项目的各种命令及其选项.HDFS和YARN包含在其它文档中. |
GENERIC_OPTIONS
许多子命令使用一组通用的配置选项来改变其行为:
GENERIC_OPTION | Description |
-archives |
指定要在计算机上不归档的逗号分隔的存档.仅适用于job. |
-conf |
指定应用程序配置文件 |
-D |
对给定属性使用值 |
-files |
指定要复制到map reduce 集群的逗号分隔的文件.仅适用于job. |
-fs |
指定要使用的默认文件系统URL.会覆盖配置中的fs.defaultFS属性 |
-jt |
指定ResourceManager.仅适用于job. |
-libjars |
指定要包含在classpath(类路径)中的逗号分隔的jar文件 |
所有这些命令都是从hadoop shell命令执行的.它们已经被分解成 User Commands 和 Administration Commands.
User Commands
对Hadoop集群用户有用的命令.
archive |
创建hadoop 备份.更多信息请参阅 Hadoop Archives Guide.
checknative |
Usage: hadoop checknative [-a] [-h]
COMMAND_OPTION | Description |
-a | 检查所有库是否可用 |
-h | 打印帮助 |
此命令检查Hadoop本机代码的可用性.参阅Native Libaries 以获取更多信息.默认情况下,此命令只检查libhadoop的可用性.
classpath |
Usage: hadoop classpath [--glob |--jar
COMMAND_OPTION | Description |
--glob | 扩展通配符 |
--jar path | 把路径作为清单写入名为 path 的jar中 |
-h, --help | 打印帮助 |
打印获取Hadoop jar和所需库的类路径.如果不带参数调用,则打印由命令脚本设置的类路径,很有可能在类路径条目中包含通配符.其它选项在通配符扩展后打印类路径,或将类路径写入JAR文件的清单中。后者在不能使用通配符且扩展类路径超过支持的最大命令行长度的环境中很有用。
credential |
Usage: hadoop credential
COMMAND_OPTION | Description |
create alias [-provider provider-path] [-strict] [-value credential-value] | 提示用户将凭据存储为给定别名.除非指定-provider,否则将使用core-site.xml文件中的hadoop.security.credential.provider.path .如果provider使用默认密码,-strict标志将导致命令失败.使用-value标志提供凭证值(也就是别名密码),而不是提示. |
delete alias [-provider provider-path] [-strict] [-f] | 使用提供的别名删除凭据.除非指定-provider,否则将使用core-site.xml文件中的hadoop.security.credential.provider.path .如果provider使用默认密码,-strict标志将导致命令失败. 除非指定了-f, 否则命令要求确认. |
list [-provider provider-path] [-strict] | 列出特定provider包含的所有credential别名,比如core-site.xml中配置的或通过-provider参数指定的.如果provider使用默认密码,-strict标志将导致命令失败. |
用于管理凭据provider中的凭据, 密码和机密的命令.
Hadoop中的CredentialProvider允许分离应用程序以及它们如何存储所需密码/机密.为了指示特定的provider类型和位置,用户必须在core-site.xml中提供hadoop.security.credential.provider.path配置元素, 或者在以下每个命令上使用命令行选项 -provider. provider path是一个逗号分隔的URLs列表,这些URLs指示应咨询的provider的列表的类型和位置. 例如,以下路径:
user:///,jceks://file/tmp/test.jceks,jceks://[email protected]/my/path/test.jceks
表示应该通过User Provider 咨询当前用户的凭据; 位于/tmp/test.jceks的本地文件是Java Keystore Provider; 位于HDFS中的nn1.example.com/my/path/test.jceks也是Java Keystore Provider的存储区.
当使用credential命令式,它通常用于向特定凭证存储提供程序提供密码或秘密. 为了指示使用哪个提供程序存储,应该使用-provider选项. 否则,给定多个提供程序的路径,将使用第一个非瞬时提供程序. 这可能是你想要的,也可能不是.
提供程序经常要求提供密码或其它机密.如果提供程序需要一个密码,但找到密码,它将使用默认密码,并发出警告信息,表明正在使用默认密码. 如果提供了-strict标志,警告信息将变为错误信息,命令将立即返回错误状态.
示例: hadoop credential list --provider jceks://file/tmp/test.jceks
distcp |
Usage: hadoop distcp
递归地复制文件或目录. 有关更多信息,请参阅 Hadoop DistCp Guide.
fs |
Usage: hadoop fs [generic options]
运行通用文件系统用户客户端. 此命令记录在 File System Shell Guide. 当使用HDFS时, 它是hdfs dfs 的同义词.
jar |
Usage: hadoop jar
运行一个jar文件.
注意:使用yarn jar 来启动YARN应用程序.
key |
Usage: hadoop key
COMMAND_OPTIONS | Description |
create keyname [-cipher cipher ] [-size size] [-description description] [-attr attribute=value] [-provider provider] [-strict] [-help] | 在-provider参数指定的提供程序中,为keyname参数指定的名称创建一个新密钥. 如果提供程序使用默认密码,-strict标志将导致命令失败。可以使用-cipher参数指定密码。默认密码当前为“AES/CTR/NoPadding”. 默认键大小是128. 可以用-size参数指定请求的密钥长度. 使用-attr参数可以指定任意attribute=value类型的属性. -attr可以指定多次,每次一个属性. |
roll keyname [-provider provider] [-strict] [-help] | 在使用-provider参数指示的提供程序中为指定密钥创建新版本. 如果提供程序使用默认密码,-strict标志将导致命令失败。 |
delete keyname [-provider provider] [-strict] [-f] [-help] | 在使用-provider参数指示的提供程序中删除keyname参数指定的密钥所有版本. 如果提供程序使用默认密码,-strict标志将导致命令失败。 该命令要求用户确认,除非指定了-f。 |
list [-provider provider] [-strict] [-metadata] [-help] | 显示正如core-site.xml配置的或由-provider参数指定的特定提供程序所包含的密钥名. 如果提供程序使用默认密码,-strict标志将导致命令失败。-metadata选项显示元数据 |
-help | 打印此命令的用法 |
通过密钥提供程序(KeyProvider)管理密钥. 有关密钥提供程序详情,请参阅 Transparent Encryption Guide.
提供程序经常要求提供密钥或其它机密. 如果提供程序需要密码,但找不到密码,它将使用默认密码并发出警告消息,说明正在使用默认密码。如果提供了-strict标志,则警告消息将变为错误消息,命令将立即返回错误状态。
注意: 某些 KeyProvider(比如:org.apache.hadoop.crypto.key.JavaKeyStoreProvider)不支持大写密钥名.
注意: 某些密钥提供程序不直接执行密钥删除(例如, 执行软删除,或延迟实际删除,以防出错). 在这种情况下,在删除密钥之后创建/删除具有相同名称的密钥时可能会遇到错误. 请检查基础密钥提供程序以获得详细信息。
trace |
查看和修改Hadoop tracing 设置. 请参阅Tracing Guide.
version |
Usage: hadoop version
CLASSNAME |
Usage: hadoop CLASSNAME
运行名为CLASSNAME的类.
envvars |
Usage: hadoop envvars
显示计算的Hadoop环境变量
Administration Commands
对Hadoop集群管理员有用的命令.
daemonlog |
Usage:
COMMAND_OPTION | Description |
-getlevel host:port classname [-protocol (http|https)] | 打印在host:port 运行的守护进程中由限定类名(classname)标识的日志等级. -protocol标志指定用于连接的协议 |
-setlevel host:port classname level [-protocol (http|https)] | 设置在host:port 运行的守护进程中由限定类名(classname)标识的日志等级. -protocol标志指定用于连接的协议 |
动态获取/设置守护进程中由限定类名标识的日志的日志级别. 默认情况下,该命令发送一个HTTP请求,但可以通过使用参数-protocol https发送一个HTTPS请求来覆盖它。
例如:
$ bin/hadoop daemonlog -setlevel 127.0.0.1:50070 org.apache.hadoop.hdfs.server.namenode.NameNode $ bin/hadoop daemonlog -getlevel 127.0.0.1:50074 org.apache.hadoop.hdfs.server.namenode.NameNode DEBUG -protocol https |
注意: 改设置不是永久性的, 重启守护进程时会重置. 此命令通过向守护进程内部的Jetty servlet发送HTTP/HTTPS请求来工作,因此它支持以下守护进程:
但是,该命令不支持KMS服务器,因为它的Web界面基于不支持servlet的Tomcat.
文件系统(FS)shell包含各种类似shell的命令,这些命令直接和分布式文件系统(HDFS)以及Hadoop支持的其它文件系统交互,例如,Local FS, HFTP FS, S3和其它。FS shell 这样来调用:
bin/hadoop fs |
所有FS shell都把path URIs当作参数。URI格式是:scheme://authority/path. 对于HDFS来说,scheme是hdfs;对于Local FS来说,scheme是file。scheme和authority是可选的,如果未指定,则使用配置中指定的默认scheme。HDFS文件或目录,如/parent/child,可以指定为hdfs://namenodehost/parent/child或仅指定为/parent/child(假定你的配置设置为指向hdfs://namenodehost)。
FS shell中大多数命令的行为类似于相应的Unix命令。每个命令都描述了不同之处。错误信息发送到stderr,输出发送到stdout.
如果使用了HDFS,则hdfs dfs是同义词。
可以使用相对路径。对于HDFS来说,当前工作目录是HDFS主目录/user/
参阅 Commands Manual知晓通用shell选项.
appendToFile
Usage: hadoop fs -appendToFile
将单个或多个src从本地文件系统追加到目标文件系统. 还从stdin读取输入并追加到目标文件系统.
退出代码:
成功时返回0,失败时返回1.
cat
Usage: hadoop fs -cat [-ignoreCrc] URI [URI ...]
将源路径复制到stdout.
Options
示例:
checksum
Usage: hadoop fs -checksum URI
返回一个文件的校验和信息.
示例:
chgrp
Usage: hadoop fs -chgrp [-R] GROUP URI [URI ...]
改变文件的组关联. 用户必须是文件属主(所有者),否则必须是超级用户. 其它信息在 Permissions Guide.
Options
chmod
Usage: hadoop fs -chmod [-R]
更改文件权限。使用-R,通过目录结构递归地进行更改。用户必须是文件属主(所有者),否则必须是超级用户. 其它信息在 Permissions Guide.
选项:
chown
Usage: hadoop fs -chown [-R] [OWNER][:[GROUP]] URI [URI ...]
改变文件所有者。用户必须是文件属主(所有者),否则必须是超级用户. 其它信息在 Permissions Guide.
Options
copyFromLocal
Usage: hadoop fs -copyFromLocal
类似于fs -put 命令,只是源文件仅限于本地文件引用。
选项:
copyToLocal
Usage: hadoop fs -copyToLocal [-ignoreCrc] [-crc] URI [localdst]
类似于get命令,只是目标仅限于本地文件引用。
count
Usage: hadoop fs -count [-q] [-h] [-v] [-x] [-t [
计算与指定文件模式匹配的路径下的目录、文件和字节数。获取配额和使用情况。此命令的各输出列分别是:目录数、文件数、内容大小和路径名。
-u和-q选项控制输出列包含哪些列。其中,-q表示显示配额;-u限制输出仅显示配额和使用情况。
使用-count -q的输出列为:配额、剩余配额、空间配额、剩余空间配额、目录计数、文件计数、内容大小、路径名。
使用-count -u的输出列为:配额、剩余配额、空间配额、剩余空间配额、路径名。
-t选项显示每种存储类型的配额和使用情况。如果为给定-u或-q选项,则忽略-t选项。可以在-t选项中使用的可能参数列表(不区分大小写,参数""除外):"", "all", "ram_disk", "ssd", "disk", "archive"。
-h选项以认类可读格式显示大小。
-v选项显示标题行。
-x选项从计算结果中排除快照。如果没有-x选项(默认),则始终从所有INodes,包括给定路径下的所有快照计算结果。如果给定了-u或-q选项,则忽略-x选项。
示例:
退出代码:
成功返回0,错误返回-1。
cp
Usage: hadoop fs -cp [-f] [-p | -p[topax]] URI [URI ...]
将文件从源复制到目标。此命令也允许多个源,在这种情况下,目标必须是一个文件夹。
如果(1)源文件系统和目标文件系统支持“raw.*”命名空间扩展属性(仅限HDFS),以及所有源路径名和目标路径名都在/.reserved/raw层级结构中,则保留这些属性。
选项:
示例:
退出代码:
成功返回0,错误返回-1.
createSnapshot
参阅HDFS Snapshots Guide。
deleteSnapshot
参阅HDFS Snapshots Guide。
df
Usage: hadoop fs -df [-h] URI [URI ...]
显示可用空间。
选项:
示例:
du
Usage: hadoop fs -du [-s] [-h] [-x] URI [URI ...]
显示给定目录中包含的文件和目录的大小,如果只是文件,则显示文件的长度。
选项:
du命令返回如下格式三列内容:
size disk_space_consumed_with_all_replicas full_path_name |
示例:
退出码:成功返回0,错误返回-1。
dus
Usage: hadoop fs -dus
显示文件长度的汇总。
注意:此命令已弃用,而是使用 hadoop fs -du -s
expunge
Usage: hadoop fs -expunge
从垃圾目录永久删除早于保留阈值的检查点中的文件,并创建新的检查点。
创建检查点时,垃圾桶中最近删除的文件将移动到检查点下。在下次调用-expunge命令时,将永久删除超出fs.trash.interval的检查点中的文件。
如果文件系统支持该功能,则用户可以配置为通过存储在fs.trash.checkpoint.interval(在core-site.xml中)的参数定期地创建和删除检查点。此值应小于等于fs.trash.interval。
有关HDFS的垃圾特性的更多信息,请参阅HDFS Architecture guide。
find
Usage: hadoop fs -find
查找与指定表达式匹配的所有文件,并把所选操作应用于这些文件。如果没有指定路径,则默认为当前工作目录。如果没有表达式,则默认为-print。
可识别以下主要表达式:
如果文件的基名与使用标准文件系统通配符模式匹配,则计算为true。如果使用-iname,则匹配不区分大小写。
总是计算为true。使当前路径名写入到标准输出。如果使用-print0表达式,则会附加一个ASCII空字符。
可以使用下面的操作符:
用于连接两个表达式的逻辑与运算符。如果两个子表达式都返回true则整体返回true。由两个表达式并置所决定,因此不需要显式指定。如果第一个表达式失败,则不应用第二个表达式。
示例:
hadoop fs -find / -name test -print
退出码:成功返回0,错误返回-1。
get
Usage: hadoop fs -get [-ignoreCrc] [-crc] [-p] [-f]
复制文件到本地文件系统。CRC检查失败的文件可以使用-ignoreCrc选项进行复制。使用-crc选项时文件和CRCs都会被复制。
示例:
退出码:成功返回0,错误返回-1。
选项:
getfacl
Usage: hadoop fs -getfacl [-R]
显示文件和目录的权限控制列表。如果一个目录有一个默认的ACL,那么getfacl也会显示默认的acl。
选项:
示例:
退出码:成功返回0,错误返回-1。
getfattr
Usage: hadoop fs -getfattr [-R] -n name | -d [-e en]
显示文件或目录的扩展属性名称和值(如果有)。
选项:
示例:
退出码:成功返回0,错误返回-1。
getmerge
Usage: hadoop fs -getmerge [-nl]
将源目录和目标文件作为输入,并将src中的文件连接到目标本地文件中。可以设置可选项-nl以允许在每个文件的末尾换行符(LF)。
-skip-empty-file可用于在文件为空时避免不必要的换行符。
示例:
退出码:成功返回0,错误返回-1。
help
Usage: hadoop fs -help
返回使用输出。
ls
Usage: hadoop fs -ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u]
选项:
对于文件,ls返回文件的stat,格式如下:
权限 副本数 用户ID 组ID 文件大小 修改日期 修改时间 文件名 |
就像在Unix中一样,对于一个文件夹,它返回其直接子目录的列表。目录如下:
权限 用户ID 组ID 修改日期 修改时间 文件名 |
默认情况下,目录中的文件按文件名排序。
示例:
退出码:成功返回0,错误返回-1。
lsr
Usage: hadoop fs -lsr
ls的递归版。
注意:此命令已经弃用,使用hadoop fs -ls -R替代。
mkdir
Usage: hadoop fs -mkdir [-p]
把路径uri作为参数并创建目录。
选项:
示例:
退出码:成功返回0,错误返回-1。
moveFromLocal
Usage: hadoop fs -moveFromLocal
类似于put命令,只是源localsrc在复制后回被删除。
moveToLocal
Usage: hadoop fs -moveToLocal [-crc]
显示一个‘尚未实现’的消息。
mv
Usage:hadoop fs -mv URI [URI ...]
把文件从源移动到目标。此命令也允许多个源,在这种情况下,目标需要是一个目录。不允许跨文件系统移动文件。
示例:
退出码:成功返回0,错误返回-1。
put
Usage: hadoop fs -put [-f] [-p] [-l] [-d] [ - |
从本地文件系统复制单src或多src到目标文件系统。如果源设置为“-”,则从stdin读取输入并写入目标文件系统。如果文件已经存在则复制失败,除非使用-f标识。
选项:
示例:
退出码:成功返回0,错误返回-1。
renameSnapshot
参阅HDFS Snapshots Guide。
rm
Usage: hadoop fs -rm [-f] [-r | -R] [-skipTrash] [-safely] URI [URI ...]
删除参数指定的文件。
如果提供了垃圾桶,则文件系统会把删除的文件移动到垃圾桶文件夹中( 由 FileSystem#getTrashRoot提供)。当前,默认情况下禁用垃圾桶。用户可以通过为core-site.xml中的fs.trash.interval参数设置大于零的值来启用垃圾桶。
请参阅删除有关删除垃圾桶中文件的说明。
选项:
示例:
退出码:成功返回0,错误返回-1。
rmdir
Usage: hadoop fs -rmdir [--ignore-fail-on-non-empty] URI [URI ...]
删除一个文件夹。
选项:
示例:
rmr
Usage: hadoop fs -rmr [-skipTrash] [URI] [URI ...]
删除的递归版。
注意:此命令已弃用,请使用hadoop fs -rm -r 替代。
setfacl
Usage :hadoop fs -setfacl [-R] [-b |-k -m |-x
设置文件和目录的访问控制列表。
选项:
示例:
退出码:成功返回0,错误返回-1。
setfattr
Usage: hadoop fs -setfattr -n name [-v value] | -x name
设置文件或目录的扩展属性名或值。
选项:
示例:
退出码:成功返回0,错误返回-1。
setrep
Usage: hadoop fs -setrep [-R] [-w]
更改文件的复制因子。如果 path 是个文件夹,那么该命令将递归地更改以 path 为根目录树下所有文件的复制因子。
选项:
示例:
退出码:成功返回0,错误返回-1。
stat
Usage: hadoop fs -stat [format]
以指定格式打印在path处文件/目录的统计信息。格式接受以八进制(%a)和符号(%A)表示的权限,以字节(%b)表示的文件大小,类型(%F),所有者组名(%g),文件/目录名(%n),块大小(%o),复制因子(%r),访问日期(%x,%X),修改日期(%y,%Y)。%x和%y将UTC日期显示为"yyyy-MM-dd HH:mm:ss",而%X和%Y显示自UTC1970年1月1日起的毫秒数。如果格式没有指定,默认使用%y。
示例:
退出码:成功返回0,错误返回-1。
tail
Usage: hadoop fs -tail [-f] URI
把文件的最后一千字节显示到stdout上。
选项:
示例:
退出码:成功返回0,错误返回-1。
test
Usage: hadoop fs -test [-defsz] URI
选项:
示例:
text
Usage: hadoop fs -text
获取源文件并以文本格式输出该文件。允许的格式是zip和TextRecordInputStream。
touchz
Usage: hadoop fs -touchz URI [URI ...]
创建零长度文件。如果文件以非零长度存在,则返回错误。
示例:
退出码:成功返回0,错误返回-1。
truncate
Usage: hadoop fs -truncate [-w]
将所有匹配指定文件模式的文件截断到指定长度。
选项:
示例:
usage
Usage: hadoop fs -usage command
返回单个命令的帮助。
Hadoop文件系统shell与对象存储(如Amzon S3、Azure WASB和OpenStack Swit)一起工作。
?????????????????????????????????????????
?????????????????????????????????????????
?????????????????????????????????????????
?????????????????????????????????????????
?????????????????????????????????????????
?????????????????????????????????????????
Purpose(目的)
本文件记录了Apache Hadoop项目的兼容性目标。列举了影响Hadoop开发人员、下游项目和最终用户的Hadoop版本之间的不同类型的兼容性。对于每种类型的兼容性,我们:
兼容性类型
Java API
将Hadoop接口和类注释以描述预期的设备和稳定性,以便保持与先前版本的兼容性。详见 Hadoop Interface Classification。
用例(Use Cases)
Policy
注意:由proto文件生成的APIs需要与滚动升级兼容。有关更多细节,请参见关于wire-compatibility的一节。APIs的兼容性策略和wire-communication需要携手解决这个问题。
Semantic compatibility(语义兼容)
Apache Hadoop 致力于确保APIs的行为在版本上保持一致,尽管对正确性的更改可能导致行为的更改。Tests和javadocs指定API的行为。社区正在更严格的指定一些APIs,并加强测试套件以验证是否符合规范,从而有效的为易于测试的行为子集创建正式的规范。
policy
API的行为可能会被更改以修正不正确的行为,这样的更改将伴随着更新现有bug的测试,或者在更改之前没有测试的情况下添加测试。
Wire compitibility
连接兼容性涉及Hadoop进程之间通过连接传输的数据。Hadoop使用协议缓冲区( Protocol Buffers)进行大多数RPC通信。保持兼容性需要禁止如下所述的修改。还应该考虑非rpc通信,例如,使用HTTP传输 HDFS镜像 作为 快照或传输MapTask输出 的一部分。潜在的通信可以分为以下几类:
用例
Policy
。以下更改是兼容的,可以在任何时候进行:
1. 添加一个可选字段,期望代码能够处理由于与旧版本代码通信而丢失的字段。
2. 向服务添加新的rpc/方法。
3. 向消息添加新的可选请求。
4. 重命名一个字段。
5. 重命名一个 .proto文件。
6. 更改影响代码生成的.proto注释(例如java包的名称)。
。以下更改是不兼容的,但只能在主版本中可以考虑:
1. 更改rpc/方法名字。
2. 更改rpc/方法参数类型或返回类型
3. 移除rpc/方法
4. 更改服务名称
5. 更改消息名称
6. 以不兼容的方式(按递归定义)修改字段类型
7. 将可选字段更改为required
8. 添加或删除必须字段
9. 只要可选字段具有允许删除的合理默认值,就删除可选字段
。以下更改是不兼容的,因此永远不允许:
1. 改变字段id
2. 重用以前删除的旧字段
3. 字段编号很便宜,更改和重用不是一个好主意。
Java Binary compatibility for end-user applications i.e. Apache Hadoop ABI(最终用户应用程序(即Apache Hadoop ABI)的Java二进制兼容性)
随着Apache Hadoop修订版的升级,最终用户合理地期望他们的应用程序在不做任何修改的情况下应该继续工作。这是由于支持API 兼容性、Semantic兼容性和Wire兼容性而实现的。
然而,Apache Hadoop是一个非常复杂的分布式系统,服务的用例非常广泛。尤其是,ApacheHadoopMapReduce是一个非常、非常广泛的API;从这个意义上说,最终用户可能会做出广泛的假设,比如在执行map/reduce任务时本地磁盘的布局、任务的环境变量等。在这种情况下,很难完全指定和支持绝对兼容性。
用例
policy
从hadoop-1.x跨到hadoop-2.x支持,APIs支持兼容性。更多详情请参阅 Compatibility for MapReduce applications between hadoop-1.x and hadoop-2.x。
REST APIs
REST API兼容性对应于请求(URLs)和对每个请求(内容,可能包含其他URLs)的响应。Hadoop REST APIs专门用于客户机跨版本(甚至是主版本)的稳定使用。以下是公开的REST APIs:
Policy
上面文本中注释稳定的API至少在一个主版本中保持兼容性,并且可能在一个主版本中被REST API的更新版本所弃。
Metrics/JMX
虽然度量标准API兼容性由Java API兼容性控制,但Hadoop公开的实际度量标准需要与之兼容,以便用户能够自动使用它们(脚本等)。添加额外的度量标准是兼容的。修改(例如更改单元或度量)或删除现有度量会破坏兼容性。类似地,对JMX MBean对象名称的更改也会破坏兼容性。
Policy
度量应该在主版本中保持兼容性。
File formats & Metadata
用户级和系统级数据(包括元数据)存储在不同格式的文件中。对元数据或用于存储数据/元数据的文件格式的更改可能导致版本之间不兼容。
User-level file formats
对最终用户用于存储其数据的格式所做的更改可能会阻止他们在以后的版本中访问数据,因此保持这些文件格式的兼容性非常重要。我们总是可以添加一个新格式,对现有格式加以改进。这些格式的示例包括har、war、SequenceFileFormat等。
Policy
System-internal file formats(系统内部文件格式)
Hadoop内部数据也存储在文件中,再次更改这些格式可能导致不兼容。虽然这种更改不像用户级文件格式那样具有破坏性,但是关于何时可以破坏兼容性的策略是很重要的。
MapReduce
MapReduce使用I-like这样的格式来存储MapReduce-specific数据。
Policy
对这些格式的更改可能会导致正在运行的作业失败,因此我们应该确保新客户机能够以兼容的方式从旧服务器获取shuffle-data。
HDFS Metadata
HDFS以特定的格式保存原数据(镜像和编辑日志)。对格式或元数据的不兼容更改会阻止后续版本读取旧的元数据。这种不兼容的更改可能需要HDFS “update”来转换元数据以使其可访问。一些更改可能需要多个这样的“updates”。根据变化中的不兼容程度,可能会出现以下潜在情况:
Policy
Command Line Interface(CLI)
Hadoop命令行程序可以直接通过系统shell使用,也可以通过shell脚本使用。更改命令的路径,删除或重命名命令行选项、参数的顺序或命令返回代码和输出会破环兼容性,并且可能会对用户产生不利影响。
Policy
在随后的主版本中删除或不兼容地修改CLI命令之前,必须对一个主版本弃用它们(使用时发出警告)。
Web UI
Web UI,尤其是Web页面的内容和布局,更改可能会干扰对Web页面进行筛选以获取信息的尝试。
Policy
Web页面并不是用来剪贴的,因此任何时候都允许对其进行不兼容的更改。用户应该使用REST APIs来获取任何信息。
Hadoop Configuration Files
用户使用(1)Hadoop定义的属性来配置Hadoop并向其提供提示;(2)自定义属性来将信息传递给作业。因此,配置属性的兼容性是双重的:
Policy
Directory Structure
源代码、工件(源代码和测试)、用户日志、配置文件、输出和作业历史记录都存储在磁盘上,可以是本地文件系统,也可以是HDFS。更改这些用户可访问文件的目录结构会破坏兼容性,即使在通过符号链接保留原始路径的情况下(例如,如果路径由配置为不遵循符号链接的servlet访问)。
Policy
Java Classpath
基于Hadoop构建的用户应用程序可能会将所有Hadoop jar(包括Hadoop的库依赖项)添加到应用程序的类路径中。添加新的依赖项或更新现有依赖项的版本可能会干扰应用程序类路径中的依赖项。
Policy
目前,还没有关于何时Hadoop的依赖关系可以更改的策略。
Environments variables
用户和相关项目经常使用导出的环境变量(例如HADOOP_CONF_DIR),因此,删除或重命名环境变量是不兼容的更改。
Policy
目前,没有关于环境变量何时可以更改的策略。开发人员试图限制对主版本的更改。
Build artifacts
Hadoop用内行(Maven)进行项目管理,更改工件可能会影响现有的用户工作流。
Policy
Hardware/Software Resquirements
为了跟上硬件、操作系统、JVMs和其它软件的最新进展,新的Hadoop版本或其某些功能可能需要相同的更高版本。对于特定的环境,升级Hadoop可能需要升级其它依赖的软件组件。
Policies
以下是一些与主题相关的JIRAs和页面:
Motivation
这里提供的接口分类是为了指导接口的开发人员和用户。分类指导开发人员声明接口的目标访问群体或用户以及其稳定性。
Interface Classification(接口分类)
Hadoop采用了以下接口分类,这个分类是从OpenSolaris分类法派生出来的,在某种程度上是从Yahoo内部使用的分类法派生出来的。接口有两个主要属性:访问量和稳定性。
Audience
Audience表示接口的潜在消费者。虽然许多接口是实现的内部/私有接口,但其它接口是公共/外部接口,用于应用程序和/或客户机更广泛的使用。例如,在posix中,libc是一个外部接口或公共接口,而内核的大部分是内部接口或私有接口。另外,一些接口针对其他特定的子系统。
识别接口的访问群体有助于定义破坏它的影响。例如,可以打破一个 访问对象是一小部分特定子系统的 接口 的兼容性。另一方面,破坏数百万互联网用户所依赖的协议接口可能是不好的。
Hadoop使用以下类型的受众以提高/扩大可见性:
Hadoop没有公司私有的分类,这是针对公司内其他项目使用的APIs的,因为它不适用于开源项目。此外,某些APIs被注释为@VisibleForTesting (from com.google.common .annotations.VisibleForTesting) - 它们被完全用于单元测试,并且应该被视为“Private” APIs。
Private
该接口用于项目内部(如HDF或MapReduce),不应被应用程序或其他项目使用。随时可更改,恕不另行通知。项目的大多数接口都是私有的(也称为project-private)。
LImited-Private
接口由指定的一组项目或系统(通常是紧密相关的项目)使用。其它接口的变更将与指定的项目进行沟通/协商。项目或系统不应使用接口。例如,在Hadoop项目中,一些接口是LimitedPrivate{HDFS, MapReduce},因为它们是HDFS和MapReduce项目的私有接口。
Public
接口供任何应用程序通用。
Stability
稳定性表示接口的稳定程度,如允许接口不兼容改变时一样。Hadoop APIs具有以下级别的稳定性。
Stable
可以在保持对次要版本边界的兼容性的同时进行改进;换句话说,标记为stable的APIs的不兼容更改只允许在主版本(即在m.0)中进行。
Evolving
正在发展,但允许次版本(即m.x)不兼容的更改。
Unstable
任何时候都允许对不稳定的API进行不兼容的更改。这通常只对私有接口有意义。
然而,对于一个假定的公共接口,我们可以调用它来强调它不应该被用作接口;对于公共接口,将其标记为非接口可能比"Ustable"更合适。
不稳定(即not-an-interface)的公开可见接口示例:GUI、输出格式将更改的CLIs.
Deprecated
将来可能会被删除而不应使用的APIs。
How are the Classifications Recorded?(如何记录分类?)
如何记录Hadoop APIs的分类?
FAQ(常见问题解答)
这是Hadoop文件系统APIs的规范,它将文件系统的内容建模为一组路径,这些路径可以是目录、符号链接或文件。
在这一领域几乎没有先例。Unix文件系统有多个规范作为索引节点树,但没有公共规范定义了“Unix文件系统作为数据存储访问的概念模型”。
本规范试图做到这一点;定义Hadoop文件系统模型和API,以便多个文件系统可以实现API,并向应用程序提供其数据的一致模型。它不试图正式地指定文件系统的任何并发行为,除了记录HDF显示的行为,因为这些行为通常是Hadoop客户机应用程序所期望的。
本文档为Hadoop文件系统的实现者和维护者以及Hadoop文件系统APIs的用户定义了Hadoop兼容文件系统所需的行为。
大多数Hadoop操作都是在Hadoop测试套件中针对HDF进行测试的,最初通过MiniDFSCluster进行测试,发布之前由特定供应商的“生产”测试,并由其上的Hadoop堆栈隐式地进行测试。
HDFS的操作是基于POSIX文件系统行为建模的,使用Unix文件系统操作的操作和返回代码作为参考。即使如此,也有一些HDF与POSIX文件系统的预期行为不同的地方。
其它Hadoop文件系统的行为没有经过严格测试。捆绑的S3N和S3A文件系统客户端使Amazon的S3对象存储(“blobstore”)可以通过文件系统API进行访问。Swift文件系统驱动程序为OpenStack Swift blobstore提供了类似的功能。Azure对象存储文件系统与微软的Azure等效程序进行对话。
“本地”文件系统提供对平台底层文件系统的访问。它的行为由操作系统定义,并且可以与HDF的行为不同。本地文件系统怪癖的例子包括区分大小写、尝试在另一个文件上重命名文件时的操作,以及是否可以在文件末尾查找()。
还有一些第三方实现的文件系统,它们声称与Apache Hadoop兼容。没有正式的兼容性套件,所以除了以自己的兼容性测试的形式之外,没有人可以声明兼容性。
这些文件并不试图提供兼容性的规范定义。通过关联的测试套件并不能保证应用程序的正确行为。
测试套件所定义的是预期的操作集——如果这些测试失败,将突出潜在的问题。通过使契约测试的每一个方面都可配置,就可以声明文件系统与标准契约的不同之处。这是可以传递给文件系统用户的信息。
Naming
下面的文档遵循关于 MUST, MUST NOT, MAY, and SHALL的使用规则。MUST NOT被视为规范性文件。
Hadoop文件系统APIs的隐式假设
原始的文件系统类及其用法基于一组隐含的假设。HDFS主要是底层文件系统,它提供POSIX文件系统行为的一个子集(或者至少是POSIX文件系统APIs的实现和Linux文件系统提供的模型)。
不管API如何,所有与Hadoop兼容的文件系统都会呈现在Unix中实现的文件系统模型:
Path Names
Security Assumptions(安全性假设)
除了在关于安全性的特殊部分,本文档假定客户机具有对文件系统的完全访问权。因此,列表中的大多数项目没有添加“假设用户有权使用提供的参数和路径执行操作”的限定条件。
未指定用户缺少安全权限时的故障模式。
Networking Assumptions(网络假设)
本文档假设所有网络操作都成功。所有语句都可以被假定为“假定操作不因网络可用性问题而失败”。
Core Expectations of a Hadoop Compatible FileSystem(Hadoop兼容文件系统的核心期望)
下面是Hadoop兼容文件系统的核心期望。一些文件系统不能满足所有这些期望;因此,一些程序可能无法按预期工作。
Atomicity(原子性)
有些操作必须是原子的。这是因为它们通常用于实现集群中进程之间的锁定/独占访问。
大多数其他操作都没有原子性的要求或保证。
Consistency(一致性)
Hadoop文件系统的一致性模型是一种拷贝更新语义( one-copy-update-semantics),即传统本地POSIX文件系统的一致性模型。注意,甚至NFS也放宽了关于更改传播速度的一些限制。
Concurrency(并发性)
不保证隔离访问数据:如果一个客户机与远程文件交互,而另一个客户机更改了该文件,则更改可能可见,也可能不可见。
Operations and failtures(操作和故障)
Undefined capacity limits(未定义的容量限制)
以下是一些从未明确定义的文件系统容量限制。
Undefined timeouts(未定义的超时)
操作超时完全没有定义,包括:
在HDFS中,阻塞操作超时实际上是可变的,因为站点和客户机可能会调优重试参数,以便将文件系统故障和故障转移转换为操作中的暂停。相反,人们普遍认为,FS操作“速度快,但不如本地FS操作快”,而且数据读写的延迟随数据量的增加而增加。
对于某些操作的开销也有一些隐含的假设。
Object Stores vs. Filesystems
此规范指的是对象存储在某些地方,通常使用术语Blobstore。这就是为什么,尽管Hadoop可以在对象存储中读取和写入数据,但Hadoop提供的两个直接支持(AmazonS3和OpenStack Swift)不能用作HDF的直接替代品。
什么是对象存储( Object Store)?
对象存储是一种数据存储服务,通常通过HTTP/HTTPS访问。对象存储是一种数据存储服务,通常通过HTTP/HTTPS访问。PUT请求上传一个对象/“Blob”;GET请求检索它;远程GET操作允许检索blob的某些部分。要删除该对象,将调用HTTP DELETE操作。
对象按名称存储:一个字符串,其中可能包含“/”符号。没有目录的概念;可以将任意名称分配给对象——这是在服务提供者强加的命名方案的限制范围内。
对象存储总是提供一个操作来检索具有给定前缀的对象;具有适当查询参数的服务根上的GET操作。
对象存储通常优先级可用性-没有与HDFS NameNode(s)等效的单点故障。他们还努力使用简单的非POSIX APIs:HTTP动词是允许的操作。
用于对象存储的Hadoop文件系统客户端试图让这些存储假装它们是一个文件系统,一个具有与HDFS相同的特性和操作的文件系统。。这最终是一种伪装:他们有不同的特点,偶尔幻想也会失败。
Timestamps
FileStatus条目有一个修改时间和一个访问时间。
HDFS文件系统在写入时不会更新修改时间。
明确地
其它文件系统可能有不同的行为。特别地,
对象存储对时间的看法更加模糊,可以概括为“它是变化的”。
最后,请注意,ApacheHadoop项目不能保证远程对象存储的时间戳行为是否会随着时间的推移保持一致:它们是第三方服务,通常通过第三方库访问。
这里最好的策略是“用你打算使用的确切终点进行实验”。此外,如果您打算使用任何缓存/一致性层,请启用该功能进行测试。更新Hadoop版本和端点对象存储更新后重新测试。
一个正式的符号(如Z符号)将是定义Hadoop文件系统行为的最严格的方法,甚至可以用来证明一些公理。
但是,它有许多实际缺陷:
由于该规范的目标受众是文件系统开发人员,因此不适合使用正式的符号。相反,广泛的可理解性、易于维护和易于派生测试优先于纯数学形式的符号。
Mathematics Symbols in this doucment(本文中的数学符号)
本文档在Z语法中使用了符号的子集,但使用的是ASCII格式,并使用Python列表符号来操作列表和集合。
Sets、LIsts、Maps、and Strings
python data structures被用作这种语法的基础,因为它是纯ASCII,而且众所周知。
Lists
Sets
集合是列表符号的扩展,添加了限制,即集合中不能有重复的条目,并且没有定义的顺序。
Maps
Maps(映射)类似于python字典;{“key”:value, “key2”,value2}
Strings
字符串是用双引号表示的字符列表。例如,"abc"
"abc"==['a','b','c'] |
State Immutability(状态不变性)
所有系统状态声明都是不可变的。
后缀“’”(单引号)作为约定,表示操作后系统的状态。
L' = L + ['d','e'] |
Function Specifications(函数说明)
函数被定义为一组先决条件和一组后置条件,其中后置条件定义系统的新状态和函数的返回值。
Exceptions(异常)
在经典的规范语言中,前置条件定义了必须满足的谓词,否则会引发一些失败条件。
在经典的规范语言中,前置条件定义了必须满足的谓词,否则会引发一些失败条件。
符号raise
如果不满足某个先决条件,可以在if-then-else序列中使用它来定义操作。
示例:
if not exists(FS, Path) : raise IOException |
如果实现可能引发一组异常中的任何一个,则通过提供一组异常来表示:
if not exists(FS, Path) : raise {FileNotFoundException, IOException} |
如果提供了一组异常,则该组的前面元素优先于后面的条目,因为它们有助于诊断问题。
我们还需要区分必须满足的断言和应该满足的断言。因此,函数规范可以在标记为“Should”的前置条件中包含一个部分:该部分中声明的所有断言都应该满足,如果该部分中有一个条目指定了更严格的结果,则应该首选它。这里有一个should-precondition的例子:
Should:
if not exists(FS, Path) : raise FileNotFoundException |
Conditions
在前置条件和后置条件声明中还使用了其他条件。
supported(instance, method)
这个条件声明了一个子类实现了命名方法——一些真正的文件系统类的子类不实现,而是引发UnsupportedOperation例如,FSDataInputStream.seek的一个前提条件是实现必须支持Seekable.seek:
supported(FDIS, Seekable.seek) : else raise UnsupportedOperation |
Paths and Path Elements
路径是表示文件、目录或符号链接路径的路径元素列表。
路径元素是非空字符串。有效字符串的确切集合可能仅限于特定的文件系统实现。
路径元素不能位于{“”,“.”,“…”,“/”}中。
径元素不能包含字符{'/'、':'}。
文件系统可能有其他在path元素中不允许的字符串。
验证路径元素时,当路径无效时,应引发异常InvalidPathException[HDFS]。
Predicates and Functions
valid-path-element(List[String]): bool
如果路径元素pe中的任何字符位于禁止字符集中,则该元素无效,或者该元素作为一个整体无效。
|
valid-path(List[PathElement]): bool
如果路径p中的所有路径元素都有效,则该路径p有效。
|
所有可能路径的集合是paths;这是所有有效路径元素列表的无限集合。
由空列表表示的路径,[]是根路径,并由字符串“/”表示。
parent(path:Path): Path
分部函数parent(path:Path):Path提供可以使用列表切片定义父路径。
|
前提条件:
path != [] |
filename(Path): PathElement
路径中的最后一个路径元素称为文件名。
def filename(p):p[-1] |
childElements(Path p, Path q): Path
部分函数childElements:(Path p, Path q):Path 是p中跟随路径q的路径元素的列表。
def childElements(p, q): p[len(q):] |
前提条件:
#路径‘q’必须位于路径'p'的头部 q=p[:len(q)] |
ancestors(Path): List[Path]
所有路径的列表,这些路径要么是路径p的直接父路径,要么是p的祖先路径的父路径。
Notes for relative paths(相对路径说明)
这个定义处理的是绝对路径,而不是相对路径;它需要重新编写,以便根元素是显式的,这可能是通过声明根(并且只有根)路径元素可以是['/']。
然后可以将相对路径与绝对路径区分开来,将其作为任何函数的输入,并在双参数函数(如rename)中的第二个条目时进行解析。
Defining the FileSystem
一个文件系统FS包含一组目录、一个路径字典和一个符号链接字典。
(Directories:Set[Path], Files:[Path:List[byte]], Symlinks:Set[Path]) |
访问器函数返回文件系统指定的元素。
def FS.Directories = FS.Directories def files(FS) = FS.Files def symlinks(FS) = FS.Symlinks def filenames(FS) = keys(FS.Files) |
所有可能路径的有限子集的整个路径集,以及解析数据路径、目录谓词或符号链接的函数:
def paths(FS) = FS.Directories + filenames(FS) + FS.Symlink |
如果路径在此聚合集中,则认为该路径存在:
def exists(FS, p) = p in paths(FS) |
根路径“/”是由路径[“/”]表示的目录,该路径必须始终存在于文件系统中。
def isRoot(p) = p ==["/"] forall FS in FileSystems : ["/"] in FS.Directories |
Directory references(目录引用)
路径可以引用文件系统中的目录:
isDir(FS, p) : p in FS.Directories |
目录可能有子目录,也就是说,文件系统中可能存在路径以目录开头的其他路径。只有目录可以有子目录。这可以通过说每个路径的父级都必须是一个目录来表示。
然后可以声明一个路径没有父目录,在这种情况下,它是根目录,或者它必须有一个父目录:
forall p in paths(FS) : isRoot(p) or isDir(FS, parent(p)) |
由于所有目录的父目录本身必须满足此条件,因此,隐式地说,只有叶子节点可以是文件或符号链接:
此外,因为每个文件系统都包含根路径,所以每个文件系统必须至少包含一个目录。
目录可以有子目录:
def chileren(FS, p) = {q for q in paths(FS) where parent(q) == p} |
子路径中没有重复的名称,因为所有路径都取自路径元素的列表集。集合中不能有重复的条目,因此没有具有重复名称的子项。
如果路径D是路径P的直接子级或祖先是路径P的直接子级,则路径D是路径P的后代:
def isDescendant(P, D) = parent(D) ==P where isDescendant(P, parent(D)) |
目录P的后代是文件系统中以路径P开头的所有路径——即它们的父路径是P,或者祖先路径是P
def descendants(FS, D) = {p for p in paths(FS) where isDescendant(D, p)} |
File references(文件引用)
路径可以引用文件系统中包含数据的文件;它的路径是数据字典中的一个键。
def isFile(FS, p) = p in FS.Files |
Symbolic references
路径可以引用符号链接:
def isSymlink(FS, p) = p in symlinks(FS) |
File Length(文件长度)
文件系统FS中路径p的长度是存储数据的长度,如果是目录,则为0:
def length(FS, p) = if isFile(p) : return length(data(FS, p)) else return 0 |
User home
用户的主目录是文件系统的隐式部分,由使用文件系统的进程的用户标识派生而来:
def getHomeDirectory(FS) : Path |
函数gethomedirectory返回文件系统和当前用户帐户的主目录。对于某些文件系统,路径是["/","users", System.getProperty("user-name")]. 但是,对于HDFS,用户名来自使用HDFS对客户机进行身份验证的凭据。This may differ from the local user account name。
Exclusivity
路径不能引用多个文件、目录或符号链接
FS.Directories ^ keys(data(FS)) =={} FS.Deirctories ^ symlinks(FS) =={} keys(data(FS))(FS) ^ symlink(FS) =={} |
这意味着只有文件可以有数据。
这个条件是不变的,并且是操作文件系统FS状态的所有操作的隐式后置条件。
Encryption Zone(加密区)
如果文件处于加密区域,则对数据进行加密。
def inEncryptionZone(FS, path) : bool |
加密的性质和创建加密区域的机制是本规范未涉及的实现细节。我们不保证加密的质量。元数据没有加密。
加密区域中目录下的所有文件和目录也在加密区域中。
forall d in directories(FS) : inEncryptionZone(FS, d) impies forall c in chileren(FS, d) where (isFile(FS, c) or isDir(FS, c)) : inEncryptionZone(FS, c) |
对于加密区域中的所有文件,数据都是加密的,但没有定义加密类型和规范。
|
NOTES
不包括:文件系统中的硬链接。如果文件系统支持Paths(FS)中的多个引用来指向同一数据,那么操作的结果是未定义的。
文件系统的这个模型足以描述除元数据和权限操作之外的所有文件系统查询和操作。Hadoop FileSystem和FileContext接口可以根据查询或更改文件系统状态的操作来指定。
抽象FileSystem类是访问Hadoop文件系统的原始类;所有hadoop支持的文件系统都有非抽象的子类。
所有采用此接口路径的操作都必须支持相对路径。在这种情况下,它们必须相对于setWorkingDirectory()定义的工作目录进行解析。
因此,对于所有客户机,我们还添加了状态组件PWD的概念:它表示客户机的当前工作目录。对此状态的更改不会反映在文件系统本身:它们对于客户机的实例是唯一的。
Implementation Note(实施说明):静态文件系统get(URI uri,Configuration conf)方法可能返回文件系统客户机类的一个预先存在的实例,该类也可能在其他线程中使用。ApacheHadoop附带的FIleSystem的实现(implementations)没有试图同步对工作目录字段的访问。
Invariants
有效文件系统的所有要求都被认为是隐含的前提条件和后置条件:有效文件系统上的所有操作都必须生成一个同样有效的新文件系统。
Predicates and other state access operations
boolean exists(Path p)
def exists(FS, p) = p in paths(FS) |
boolean isDirectory(Path p)
def isDirectory(FS, p) = p in directories(FS) |
boolean isFile(Path p)
def isFile(FS, p) = p in files(FS) |
FileStatus getFileStatus(Path p)
获取路径的状态
Preconditions
|
Postconditions
|
Path getHomeDirectory()
函数getHomeDirectory返回文件系统和当前用户帐户的主目录。
对于某些文件系统,路径是["/", "users", System.getProperty("user-name")]。
但是,对于HDFS,用户名来自使用HDFS对客户机进行身份验证的凭据。这可能与本地用户帐户名称不同。
文件系统的职责是确定调用者的实际主目录。
Preconditions
Postconditions
result = p where valid-path(FS, p) |
不要求在调用方法时存在路径,或者如果存在路径,则不要求路径指向目录。然而,代码倾向于假定not isFile(FS, getHomeDirectory())在某种程度上可以防止后续代码失败。
实施说明:
FileStatus[] listStatus(Path path, PathFilter filter)
列出路径path下的条目。如果路径引用一个文件,并且过滤器接受它,那么该文件的FileStatus条目将在一个单元素数组中返回。
如果路径引用一个目录,调用将返回一个列表,其中包含筛选器接受的所有直接子路径,并且不包括目录本身。
PathFilter filter是一个过滤器,当路劲path满足此过滤器的条件时,它的accept(path)方法返回true。
前提条件
路径path必须存在:
if not exists(FS, paht) : raise FileNotFoundException |
后置条件
if isFile(FS, path) and filter.accept(path) : result = [ getFileStatus(path) ]
elif isFile(FS, path) and not filter.accept(P) : result = []
elif isDir(FS, path) : result = [ getFileStatus(c) for c in children(FS, path) if filter.accepts(c) ] |
Implicit invariant(隐式不变量): 通过listStatus()检索的子文件状态的内容等于从getFileStatus()调用到相同路径的内容
forall fs in listStatus(path) : fs == getFileStatus(fs.path) |
Ordering of results(结果排序): 不保证对列出的条目进行排序。当HDFS当前返回一个字母数字排序的列表时,Posix readdir()和JavaFile.listFiles()API调用都不定义返回值的任何排序。对结果要求统一排序顺序的应用程序必须自己执行排序。
Atomicity and Consistency(原子性和一致性)
当listStatus()操作返回给调用方时,无法保证响应中包含的信息是最新的。详细信息可能过时,包括任何目录的内容、任何文件的属性以及提供的路径的存在。
在评估过程中,目录的状态可能会更改。
这不是理论上的可能性,当一个目录包含数千个文件时,可以在HDFS中观察到。
考虑目录“/d”,内容如下:
a part-0000001 part-0000002 ... part-9999999 |
如果文件的数量使得HDFS在每个响应中返回一个部分列表,那么,当列表listStatus("/d")和操作rename("/d/a", "/d/z")同时发生时,结果可能是下面其一:
|
虽然这种情况可能很少见,但也可能发生。在HDF中,这些不一致的视图只有在列出包含许多子目录的目录时才可能出现。其他文件系统可能具有更强的一致性保证,或者更容易返回不一致的数据。
FileStatus[] listStatus(Path path)
这完全等同于listStatus(Path, DEFATUL_FILTER),其中对于所有的路径DEFAULT_FILTER.accept(path) = True。
原子性和一致性约束与listStatus(Path, DEFAULT_FILTER)相同。
FileStatus[] listStatus(Path[] paths, PathFilter filter)
枚举在传入目录列表中找到的所有文件,对每个文件调用listStatus(path,filter)。
与listStatus(path, filter)一样,结果可能不一致。即:文件系统的状态在操作期间发生了更改。
对于路径是否按特定的顺序列出没有任何保证,只保证它们必须全部列出,并且在列出时存在。
前提条件
所有路径都必须存在。不需要唯一性。
forall p in paths : exists(fs, p) else raise FileNotFoundException |
后置条件
结果是一个数组,其条目包含在路径列表中找到的每个状态元素,而没有其他元素。
result = [listStatus(p, filter) for p in paths] |
实现可以合并重复条目;和/或通过重新编码重复路径和只列出一次条目来优化操作。
FileStatus[] listStatus(Path[] paths)
默认实现遍历列表;它不执行任何优化。
原子性和一致性约束与listStatus(Path, PathFilter)相同。
FileStatus[] listStatus(Path[] paths)
枚举在传入目录列表中找到的所有文件,对每个文件调用listStatus(path,DEFATUL_FILTER),其中DEFATUL_FILTER接受所有的路径名。
RemoteIterator[LocatedFileStatus] listLocatedStatus(Path path, PathFilter filter)
返回一个迭代器,枚举路径下的LocatedFileStatus条目。这类似于listStatus(Path),只是返回值是FileStatus的LocatedFileStatus子类的一个实例,并且不是返回整个列表,而是返回一个迭代器。
这实际上是一个受保护的方法,由listLocatedStatus(路径路径)直接调用。对它的调用可以通过分层文件系统(如FilterFileSystem)进行委托,因此必须将其实现视为强制的,即使listLocatedStatus(Path Path)是以不同的方式实现的。有公开的JIRAs提议将这一方法公之于众;这可能在未来发生。
迭代器不需要提供路径子条目的一致视图。默认实现确实使用listStatus(Path)列出其子级,并且已经记录了其一致性约束。其他实现可能更动态地执行枚举。例如,获取子条目的窗口子集,从而避免构建大型数据结构和传输大型消息。在这种情况下,对文件系统的更改更有可能变得可见。
调用方必须假定,如果在此调用返回和完全执行迭代之间对文件系统进行更改,迭代操作可能会失败。
前提条件
路径path必须存在:
exists(FS, path) : raise FileNotFoundException |
后置条件
该操作生成结果集resultset,等于listStatus(path, filter)的结果:
|
操作getLocatedFileStatus(FS, path: path): LocatedFileStatus定义为LocatedFileStatus实例ls的生成器,其中:
fileStatus = getFileStatus(FS, path) b1 = getFileBlockLocations(FS, path, 0, fileStatus.len) locatedFileStatus = new LocatedFileStatus(fileStatus, b1) |
迭代器中返回的结果集元素的顺序未定义。
原子性和一致性约束与listStatus(Path、PathFilter)相同。
RemoteIterator[LocatedFileStatus] listLocatedStatus(Path, path)
等于listlocatedStatus(path, DEFAULT_FILTER),其中DEFAULT_FILTER接受所有的路径名。
RemoteIterator[LocatedFileStatus] listFiles(Path path, boolean recursive)
在目录中/下的所有文件上创建一个迭代器,可能递归到子目录中。此操作的目标是通过减少在单个RPC调用中必须收集的数据量,允许文件系统更高效地处理大型递归目录扫描。
前提条件
exists(FS, path) else raise FileNotFoundException |
后置条件
结果是一个iterator,它的iterator.next()调用序列的输出可以定义为集合 iteratorset:
if not recursive: iteratorset == listStatus(path) else: iteratorset =[ getLocateFileStatus(FS, d) for d in descendants(FS, path) ] |
函数getLocatedFileStatus(FS, d)在listLocatedStatus(Path, PathFilter)中定义。
原子性和一致性约束与listStatus(Path、PathFilter)相同。
BlockLocation[] getFileBlockLocations(FileStatus f, int s, int l)
前提条件
if s<0 or l<0 : raise {HadoopIllegalArgumentException, InvalidArgumentException} |
后置条件
如果文件系统知道位置,它必须返回可以找到范围[s:s+l]中数据的块位置列表。
if f == null : result = null elif f.getLen() <= s: result = [] else result = [ locations(FS, b) for b in blocks(FS, p, s, s+l)] |
where
def locations(FS, b) = a list of all locations of a block in the filesystem (文件系统中一个块的所有位置列表) def blocks(FS, p, s, s + l) = a list of the blocks containing data(FS, path)[s:s+1] (包含数据data(FS, path)[s:s+1]的块列表) |
注意:由于如果isDir(FS, f)那么length(FS, f)定义为0,则目录上getFileBlockLocations()的结果是[]。
如果文件系统不知道位置,它应该返回
[ BlockLocation(["localhost:50010"], ["localhost"], ["/default/localhost"] 0, f.getLen())
]; |
*Hadoop 1.0.3中的bug意味着必须提供与集群拓扑相同数量元素的拓扑路径,因此文件系统应返回该“/default/localhost”路径。虽 然这已不再是一个问题,但约定一般仍予以保留。
BlockLocation[] getFileBlockLocations(Path P, int S, int L)
前提条件
if p == null : raise NullPointerException if not exists(FS, p) : raise FileNotFoundException |
后置条件
result = getFileBlockLocations(getFileStatus(FS, P), S, L) |
long getDefaultBlockSize()
获取文件系统的“默认”块大小。这通常在拆分计算期间用于在一组工作进程中以最佳方式划分工作。
前提条件
后置条件
result = interger > 0 |
虽然这个结果没有定义最小值,因为它用于在作业提交期间对工作进行分区,但是如果块大小过小,就会导致分区工作负载严重分区,甚至会导致JobSubmissionClient在计算分区时内存耗尽。
任何实际上没有将文件分割成块的文件系统都应该为此返回一个数字,从而实现有效的处理。文件系统可能会使这个用户可配置(S3和Swift文件系统客户机这样做)。
long getDefaultBlockSize(Path p)
获取路径的默认块大小,即即将对象写入文件系统中的路径时使用的块大小。
前提条件
后置条件
result = integer >=0 |
此操作的结果通常与getDefaultBlockSize()相同,不检查给定路径是否存在。
支持挂载点的文件系统对于不同的路径可能有不同的默认值,在这种情况下,应该返回目标路径的特定默认值。
如果路径不存在,则不是错误:必须返回文件系统该部分的默认值/建议值。
long getBlockSize(Path p)
这个方法完全等价于查询getFileStatus(p)中返回的FileStatus结构的块大小。为了鼓励用户对getFileStatus(p)进行一次调用,然后使用结果检查文件的多个属性(例如长度、类型、块大小),不推荐使用这种方法。如果查询多个属性,这将成为一项重要的性能优化—减少文件系统上的负载。
前提条件
if not exists(FS, ) : raise FileNotFoundException |
后置条件
if len(FS, P) > 0 : getFileStatus(P).getBlockSize > 0 result = getFileStatus(P).getBlockSize() |
1. 此操作的结果必须与getFileStatus(P). getblocksize()的值相同。
2. 通过推断,任何长度大于0的文件都必须大于0。
State Changing Operations(状态更改操作)
boolean mkdirs(Path p, FsPermission permission)
创建目录及其所有父目录
前置条件
if exists(FS, p) and not isDir(FS, p) : raise [ParentNotDirectoryException, FileAlreadyExistsException, IOException] |
后置条件
FS' where FS'.Directories = FS.Directories + [p] + ancestors(FS, p) result = True |
文件系统目录、文件和符号链接的条件独占性要求必须保持不变。
路径和目录创建的存在性和类型 的探测必须是原子性的。包括mkdirs(parent(F))在内的组合操作可以是原子性的。
即使没有创建新目录(这是在HDFS中定义的),返回值也始终为真。
实施说明:Local FileSystem
如果在存在且是文件的路径上调用mkdirs(p)),则本地文件系统不会引发异常。相反,该操作返回false。
if ifFile(FS, p) : FS' = FS result =False |
FSDataOutputStream create(Path, ...)
FSDataOutStream create( FsPermission permission, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable process) throws IOException; |
前提条件
不覆盖创建的文件不能存在:
if not overwrite and isFile(FS, p) : raise FileAlreadyExistsException |
写入或覆盖目录必须失败。
if isDir(FS, p) : raise {FileAlreadyExistsException, FileNotFoundException, IOException} |
文件系统可能会因为其他原因拒绝请求,比如FS是只读的(HDFS)、块大小低于允许的最小值(HDFS)、复制计数超出范围(HDFS)、超出名称空间或文件系统的配额、保留名称,等等。所有拒绝都应该是IOException或其子类,并且可以是RuntimeException或子类。例如,HDFS可能会引发InvalidPathException。
后置条件
FS' where : FS'.File'[p] == [] ancestors(p) is-subset-of FS'.Directories'
result = FSDataOutputStream |
更新(有效)的文件系统必须包含mkdirs(parent(p))创建的路径的所有父目录。
其结果是FSDataOutputStream,通过它的操作可以生成由FS.Files[p]的值更新的新文件系统状态。
实施说明
FSDataOutputStream append(Path p, int bufferSize, Progressable progress)
实现可能引发UnsupportedOperationException。
前提条件
if not exists(FS, p) : raise FileNotFoundException if not isFile(FS, p) : raise [FileNotFoundException, IOException] |
这是一个关键的前提条件。一些文件系统的实现(例如对象存储)可以通过将HTTP GET操作延迟到返回的FSDataInputStream上的第一个read()来缩短一次往返。然而,许多客户机代码确实依赖于open()操作时执行的生存检查。实现必须在创建时检查文件是否存在。这并不意味着该文件及其数据在以下read()或任何后续读取时仍然存在。
后置条件
result = FSDataInputStream(0, FS.Files[p]) |
结果提供对FS.Files[p]定义的字节数组的访问;在调用open()操作时,该访问是否是对内容的访问,或者它是否以及如何在FS的后续状态中获取对该数据的更改,这些都是实现细节。
对于操作的本地调用者和远程调用者,结果必须相同。
HDFS实施说明:
boolean delete(Path p, boolean rescursive)
删除路径,无论是文件、符号链接还是目录。递归标志指示是否应该进行递归删除——如果未设置,则无法删除非空目录。
除了根目录的特殊情况外,如果此API调用成功完成,则路径末尾没有任何内容。即:结果是期望的。返回标志只是告诉调用者是否对文件系统的状态进行了任何更改。
注意:此方法的许多使用都围绕着它,检查返回值是否为假,如果是,则引发异常。例如:
if (!fs.delete(path, true)) throw new IOException("Could not delete " + path ); |
不需要这种模式。代码应该只调用delete(path, recursive)并假设目标不再存在——除非在根目录的特殊情况下,根目录将始终存在(有关根目录的特殊覆盖,请参阅下面的内容)。
前提条件
不能删除由子目录且recursive == False的目录。
if isDir(FS, p) and not recursive and (children(FS, p) != {}) : raise IOException |
(HDFS在这里引发PathIsNotEmptyDirectoryException。)
后置条件
Nonexist path(不存在的路径)
如果文件不存在则文件状态不会修改
if not exists(FS, p) : FS' = FS result = False |
结果应该为False,表示没有删除任何文件。
简单文件
删除引用文件的路径,返回值:True
if isFile(FS, p) : FS' = (FS.Directories, FS.Files - [p], FS.Symlinks) result = True |
空根目录,recursive==false
删除空根不会更改文件系统状态,可能返回true或false。
if isDir(FS, p) and Root(p) and children(FS, p) == {} : FS' = FS result = (undetermined) |
删除根目录的尝试没有一致的返回代码。实现应该返回true;
这避免了检查错误返回值是否反应过度的代码。
空(非根)目录 recursive==false
删除非根目录的空目录将从FS中删除路径并返回true。
if isDir(FS, p) and not isRoot(p) and children(FS, p) == {} : FS' = (FS.Directories - [p], FS.Files, FS.Symlinks) result = True |
递归删除非空根目录
删除具有子目录且 recursive==True 的根路径可以做两件事之一。
if isDir(FS, p) and isRoot(p) and recursive : FS' = ({["/"]}, {}, {}, {}) result = True |
HDFS有保护目录的概念,在选项fs.protected.directories中声明。任何删除此类目录或其父目录的尝试都会引发AccessControlException。因此,如果存在受保护的目录,任何删除根目录的尝试都将导致引发此类异常。
本规范不建议采取任何具体措施。但是,请注意,POSIX模型假定存在权限模型,这样普通用户就没有删除该根目录的权限;只有系统管理员才能执行该操作。
任何与缺乏这种安全模型的远程文件系统交互的文件系统客户机,都可能拒绝删除(“/”,true)调用,因为它太容易丢失数据。
非根目录的递归删除
删除有子目录且recursive==true的非根路径将删除该路径和所有后代
if isDir(FS, p) and not isRoot(p) and rescursive : FS' where : not isDir(FS', p) and forall d in descendants(FS, p): not isDir(FS', d) not isFile(FS', d) not isSymlink(FS', d) result = True |
原子性
实施说明
boolean rename(Path src, Path d)
就其规范而言,rename()是文件系统中最复杂的操作之一。
就其实现而言,对于何时返回错误与引发异常,它是最模糊的。
重命名包括目标路径的计算。如果目标存在并且是目录,则重命名的最终目标将成为目标+源路径的文件名。
let dest = if (isDir(FS, src) and d != src) : d + [filename(src)] else : d |
前提条件
所有对目标路径的检查必须在最终dest路径计算完成之后进行。
源路径src必须存在:
exists(FS, src) else raise FileNotFoundException |
dest不能是src的后代:
if isDescendant(FS, src, dest) :raise IOException |
这隐式的涵盖了 isRoot(FS, src)的特殊情况。
dest必须是根目录,或具有存在的父目录:
isRoot(FS, dest) or exists(FS, parent(dest)) else raise IOException |
目标的父路径不能是文件:
if isFile(FS, parent(dest)) : raise IOException |
这隐式地涵盖了父代的所有祖先。
在目标路径的末端不能是一个存在的文件:
if isFile(FS, dest) : raise FileAlreadyExistsException, IOException |
后置条件
将目录重命名到其本身是无操作(no-op);没有指定返回值。
在POSIX中,结果为False;在HDFS中,结果为True。
if isDir(FS, src) and src == dest : FS' = FS result = (undefined) |
将文件重命名为自身
重命名文件本身是一种无操作(no-op);结果是真的。
if isFile(FS, src) and src == dest : FS' = FS result = True |
Renaming a file onto a nonexistent path(将文件重命名为不存在的路径 )
重命名目标为目录的文件会将文件作为目标目录的子级移动,并保留源路径的文件名元素。
if isFile(FS, src) and src != dest : FS' where : not exists(FS', src) and exists(FS', dest) and data(FS', dest) == data(FS, dest) result =True |
将目录重命名为目录
如果src是一个目录,那么它的所有子级都将存在于dest下,而路径src及其后代将不再存在。dest下的路径名称将与src下的路径名称相匹配,内容也一样:
|
重命名为父路径不存在的路径
not exists(FS, parent(dest)) |
这里没有一致的行为。
HDFS
结果不会更改文件系统状态,返回值为false。
FS' = FS ; result = False |
Local Filesystem, S3N
结果是一个普通的重命名,带有目标的父目录也存在的额外(隐式)特性。
exists(FS', parent(dest)) |
Other Filesystems (including Swift)
其他文件系统严格拒绝该操作,引发FileNotFoundException
并发性要求
实施说明
打开文件以供读取、写入或追加
没有指定在打开的文件上rename()的行为:无论是否允许,以后尝试读取或写入打开流时会发生什么。
将目录重命名为其自身
未指定将目录重命名为其自身的返回代码。
目标存在并且是一个文件
在现有文件上重命名文件被指定为失败,引发异常。
缺少源文件
如果源文件src不存在,应该抛出FileNotFoundException。
HDFS失败而不引发异常;rename()只返回false。
FS' = FS result = false |
这里不应该将HDFS的行为视为要复制的特性。FileContext显式地更改了行为以引发异常,并且将该操作重新安装到DFSFileSystem实现中是一个值得讨论的问题。
void concat(Path p, Path source[])
将多个块连接在一起以创建单个文件。这是一个很少使用的操作,目前仅由HDFS实现。
实现可能引发UnsupportedOperationException。
前提条件
if not exists(FS, p) : raise FileNotFoundException if source == [] : raise IllegalArgumentException |
所有源必须在同一目录中:
for s in sources : if parent(S) != parent(p) raise IllegalArgumentException |
所有块大小必须与目标块大小匹配:
for s in sources: getBlockSize(FS, S) == getBlockSize(FS, p) |
没有重复的路径:
not (exists p1, p2 in (sources + [p]) where p1 == p2) |
HDFS:除最后一个文件外,所有源文件都必须是完整的块:
for s in (sources[0:length(sources)-1] + [p]): (length(FS, s) mod getBlockSize(FS, p) ) == 0 |
后置条件
FS' where : (data(FS' , T) = data(FS, T) + data(FS, sources[0]) + ... + data(FS, srcs[length(srcs)-1])) and for s in srcs: not exists(FS', S) |
HDFS的限制可能是它如何通过更改inode引用将它们按顺序连接在一起来实现concat的实现细节。由于Hadoop核心代码库中没有其他文件系统实现此方法,因此无法区分实现细节和规范。
boolean truncate(Path p, longnewLength)
把文件p截断为指定的newlength。
实现可能会引发UnsupportedOperationException。
前提条件
if not exists(FS, p) : raise FileNotFoundException if isDir(FS, p) : raise [FileNotFoundException, IOException] if newLength < 0 || newLength > len(FS.FIles[p]) : raise HadoopIllegalArgumentException |
HDFS: 源文件必须关闭。无法对打开以进行写入或追加的文件执行截断。
后置条件
FS' where : len(FS.Files[p] = newLength) |
返回:如果截断完成,可以立即打开文件进行附加,则返回true,否则false。
HDFS:HDFS返回false,表示已经启动了调整最后一个块的长度的后台进程,客户机应该等待它完成后才能继续进行进一步的文件更新。
并发性
如果在truncate()发生时输入流是打开的,则与被截断的文件部分相关的读取操作的结果是未定义的。
interface RemoteIterator
RemoteIterator接口用作与java.util.Iterator等效的远程访问,允许调用者遍历远程数据元素的有限序列。
核心区别在于
public interface RemoteIterator boolean hasNext() throws IOException; E next() throws IOException; } |
该接口的基本观点是,hasNext()为true意味着next()将成功返回列表中的下一个条目:
while hasNext() : next() |
同样,成功调用next()意味着如果在调用next()之前调用hasNext(),那么它将是正确的。
boolean elementAvailable = hasNext(); try { next(); assert elementAvailable; } catch (NoSuchElementException e) { assert !elementAvailable } |
next()运算符必须遍历可用结果列表,即使没有调用hasNext()。
也就是说,可以通过仅在引发NoSuchElementException异常时终止的循环枚举结果。
try { while (true) { process(iterator.next()); } } catch (NoSuchElementException ignored) { // the end of list has been reached (已经到达列表末尾) } |
迭代的输出等价于循环
while (iterator.hasNext()) { process(iterator.next()); } |
由于引发异常在JVMs中是一项昂贵的操作,因此while(hasNext())循环选项更有效。(有关此主题的讨论,请参见 Concurrency and the Remote Iterator)。
接口的实现者必须支持两种形式的迭代;测试的作者应该验证两种迭代机制是否都有效。Hadoop代码库中接口的所有实现都满足这个要求;所有的使用者都认为它是有效的。
boolean hasNext()
当且仅当对next()的后续单个调用返回元素而不是引发异常时 返回true。
前提条件
后置条件
result = True ==> next() will succed. result =False ==> next() will raise an exception |
多个对hasNext()的调用(没有任何中间的next()调用)必须返回相同的值。
boolean has1 = iterator.hasNext(); boolean has2 = iterator.hasNext(); assert has1 == has2 |
E next()
返回迭代中的下一个元素。
前提条件
hasNext() else raise java.util.NoSuchElementException |
后置条件
result = the next element in the iteration |
重复调用next()返回序列中的后续元素,直到返回整个序列。
Concurrency and the Remote Iterator
在文件系统APIs中,RemoteIterator的主要用途是列出(可能是远程)文件系统上的文件。这些文件系统总是并发地访问;在hasNext()探测和调用next()调用之间,文件系统的状态可能会发生变化。
因此,通过RemoteIterator进行的健壮迭代将捕获并丢弃在进程中引发的NoSuchElementException异常,这可以通过上面的while(true)迭代示例完成,也可以通过具有外部try/catch子句的hasNext()/next()序列来捕获NoSuchElementException以及其它在失败期间引发(例如,一个FileNotFoundException)的异常。
try { while (iterator.hasNext()) { process(iterator.hasNext()); } } catch (NoSuchElementException ignored) { // the end of the list has been reached } |
值得注意的是,这不是在Hadoop代码库中完成的。这并不意味着不建议使用健壮的循环——更重要的是,在这些循环的实现过程中没有考虑并发性问题。
interface StreamCapabilities
StreamCapability提供了一种以编程方式查询 OutputStream、InputStream或其它文件系统类支持的 功能的方法。
public interface StreamCapabilities { boolean hasCapability(String capability); } |
boolean hasCapability(capability)
如果OutputStream、InputStream或其它文件系统类具有所需的功能,则返回true。
调用方可以使用字符串值查询流的功能。下面是一个可能的字符串值表:
String | Constant(常数) | Implements | Description |
hflush | HFLUSH | Syncable | 刷新客户端用户缓冲区中的数据。在此调用返回后,新读者将看到数据。 |
hsync | HSYNC | Syncable | 将客户机的用户缓冲区中的数据一直刷新到磁盘设备(但是磁盘的缓存中可能有它)。类似于POSIX fsync。 |
in:readahead | READAHEAD | CanSetReadahead | 在输入流上设置预读。 |
dropbehind | DROPBEHIND | CanSetDropBehind | 删除缓存。 |
in:unbuffer | UNBUFFER | CanUnbuffer | 减少输入流上的缓冲。 |
class FSDataInputStream extends DataInputStream
FSDataInputStream的核心行为是由java.io.DataInputStream定义的,带有向系统添加关键假设的扩展。
文件通过FileSystem.open(p)打开,如果成功,返回:
result = FSDataInputStream(0, FS.Files[p]) |
输入流可以建模为:
FSDIS = (pos, data[], isOpen) |
具有访问功能:
pos(FSDIS) data(FSDIS) isOpen(FSDIS) |
隐式不变量:数据流的大小等FfileSystem.getFileStatus(Path p)返回的文件大小。
forall p in dom(FS.Files) len(data(FSDIS)) == FS.getStatus(p).length |
Closeable.close()
java.io.Closeable的语义在JRE中的接口定义中定义。
操作必须是等幂的;以下序列不是错误:
FSDIS.close(); FSDIS.close(); |
实施说明
后置条件
FSDIS' = ((undefined), (undefined), False) |
Seekable.getPos()
返回当前位置。输入流关闭时的结果未定义。
前提条件
isOpen(FSDIS) |
后置条件
result = pos(FSDIS) |
InputStream.read()
返回当前位置的数据。
前提条件
isOpen(FSDIS) |
后置条件
if (pos < len(data)) : FSDIS' = (pos +1, data, True) result = data[pos] else result = -1 |
InputStream.read(buffer[], offset, length)
从偏移量offset开始,将length字节的数据读取到目标缓冲区。数据源是输入流的当前位置,正如在pos中隐式设置的那样。
前提条件
|
在前提条件失败时可能引发的异常是
|
并非所有文件系统都检查isOpen状态。
后置条件
|
java.io API声明,如果要读取的数据量(即length),那么调用必须阻塞,直到可用数据量大于零,也就是说,直到有一些数据为止。
当缓冲区已满时,不需要返回调用,或者直到流中没有剩余的数据时才真正阻塞调用。
也就是说,l不是简单地定义为min(length, len(data)-length),而是严格地定义为1范至min(length, len(data)-length)围内的整数。尽管调用者可能希望尽可能多地填充缓冲区,但在实现的规范中,总是返回一个较小的数字,可能只有一个字节。
关键是,除非目标缓冲区大小为0,否则调用必须阻塞,直到至少返回一个字节。因此,对于长度大于零的任何数据源,重复调用此read()操作将最终读取所有数据。
Seekable.seek(s)
前提条件
并非所有子类都实现查找(seek)操作:
|
如果支持该操作,则应打开该文件:
|
有些文件系统不执行此检查,而是依赖read()协议拒绝对关闭的流(例如RawLocalFileSystem)进行读取。
seek(0)必须始终成功,因为查找位置必须为正且小于流的长度:
|
如果不满足此条件,则某些文件系统不会引发异常。相反,它们在任何read()操作上返回-1,其中,在读取时,len(data(FSDIS)) < pos(FSDIS)。
后置条件
|
有一个隐式不变量:对当前位置的搜索是一个 非选项(no-op)。
|
实现可以识别此操作并绕过所有其他前提检查,从而保持输入流不变。
Seekable.seekToNewSource(offset)
只有当文件系统支持一个文件的多个副本,并且偏移量offset处有一个以上的数据副本时,这才相关。
前提条件
并非所有子类都实现了此操作,而是引发异常或返回False。
|
示例: CompressionInputStream (压缩输入流), HttpFSFileSystem
如果支持,文件必须打开:
|
后置条件
没有实现此操作的大多数子类都会失败。
|
示例:RawLocalFileSystem , HttpFSFileSystem
如果支持该操作,并且有新的数据位置:
|
新数据是原始数据(或其更新版本,如下面一致性部分所述),但包含offset处数据的块来自不同的副本。如果没有其他副本,则不会更新FSDIS;响应表明:
result = False |
在测试方法之外,此方法的主要用途是 {{FSInputChecker}}类中,它可以通过尝试从其他地方获取数据来响应读取中的校验和错误。如果可以找到新的源,它将尝试重新读取并重新检查文件的该部分。
interface PositionedReadable
PositionedReadable操作提供"positioned reads"("pread" --定位读取)。它们提供将数据从数据流中的指定位置读取到缓冲区中的能力;
定位读取等同于在指定偏移量处Seekable.seek ,然后是 InputStream.read(buffer[], offset, length),只有一个方法调用,而不是seek后read,并且两个定位读取可以选择性地在 FSDataInputStream流的单个实例上并发运行。
接口声明定位读取线程安全(一些实现不遵循此保证)。
与流操作并发的任何位置读取运行--Seekable.seek, Seekable.getPos() 和 InputStream.read() — 比如,必须单独运行;不能有相互干扰。
并发的位置读取和流操作必须是可序列化的;一个可以阻塞另一个,以便它们串联运行,但是为了获得更好的吞吐量和“活跃性(liveness)”,它们应该并发运行。
给定两个并行位置读取,一个在pos1处读取len1到buffer dest1,另一个在pos2处读取len2到buffer dest2,并给定一个在查找pos3后并发的流读取运行,即使结果缓冲区恰好在底层流上重叠,也必须按如下方式填充:
|
注意,实现不一定是原子的;操作的中间状态(getPos()值的变化)可能是可见的。
Implementation preconditions
并不是所有的FSDataInputStream实现都支持这些操作。这些没有实现Seekable.seek()的实现不实现PositionedReadable接口。
|
这可以被认为是显而易见的:如果流不能Seekable,则客户机无法查找位置。它也是使用Seekble.Seek()的基类实现的副作用。
隐式不变量:对于所有PositionedReadable操作,操作结束时pos值不变。
pos(FSDIS') ==pos(FSDIS) |
Failture states
对于任何失败的操作,目标buffer的内容都是未定义的。实现可能会在报告失败之前覆盖部分或全部缓冲区。
int PositionedReadable.read(position, buffer, offset, length)
将尽可能多的数据读取到分配给它的缓冲区空间中。
前提条件
|
后置条件
读取的数据量小于指定位置的可用数据的长度或量:
|
void PositionedReadable.readFully(position, buffer, offset, length)
将精确的length字节数据读取到缓冲区中,如果没有足够的可用数据,则会失败。
前提条件
|
如果在读取操作期间发生IO异常,则buffer的最终状态为未定义。
如果输入流中没有足够的数据来满足请求,则buffer的最终状态是未定义的。
后置条件
来自偏移量offset的缓冲区由从position开始的数据填充。
|
PositionedReadable.readFully(position, buffer)
它的语义完全等价于
|
也就是说,缓冲区完全由position处的输入源内容填充。
Consistency
At time t0
FSDIS0 = FS'read(p) = (0, data0[]) |
At time t1
FS' = FS' where FS'.Files[p] = data1 |
从时间 t >= t1 开始,FSDIS0的值未定义。
它可能是不变的
|
它可能会获取新的数据
|
它可能是不一致的,因此,对偏移量的读取会从任一数据集中返回数据。
|
也就是说,读取的每个值都可能来自原始或更新的文件。
在相同偏移量的重复读取时,也可能不一致,即t2>t1时:
|
当时间t3>t2时:
|
它可能是r3 != r2。(也就是说,一些数据可能是缓存的或复制的,并在后续读取时返回文件内容的不同版本)。 类似地,如果路径p上的数据被删除,那么在对FSDIS0执行读取操作期间,这个更改可能是可见的,也可能是不可见的。
Running the tests
正常的Hadoop测试运行将测试那些可以通过本地文件系统进行本地测试的文件系统。这通常意味着file://及其底层的本地文件系统,以及hdfs://通过HDFS MiniCluster。
除非提供文件系统的远程服务器有特定的配置,否则将跳过其他文件系统。
必须在一个XML配置文件中定义这些文件系统绑定,通常是hadoop-common-project/hadoop-common/src/test/resources/contract-test-option.xml。此文件被排除在外,不应签入。
ftp://
在contract-test-options.xml中,文件系统名必须在属性fs.contract.test.fs.ftp中定义。然后必须提供连接到FTP服务器的特定登录选项。选项fs.contract.test.ftp.testdir中还必须提供测试目录的路径。这是进行操作的目录。
示例:
fs.contract.test.fs.ftp
ftp://server1/
fs.ftp.user.server1
testuser
fs.contract.test.ftp.testdir
/home/testuser/test
fs.ftp.password.server1
secret-login
swift://
OpenStack Swift登录细节必须在文件 /hadoop-tools/hadoop-openstack/src/test/resources/contract-test-options.xml中定义。不能使用标准的hadoop-common contract-test-options.xml资源文件,因为该文件不包含在hadoop-common-test.jar中。
在/hadoop tools/hadoop-openstack/src/test/resources/contract-test-options.xml中,必须在fs.contract.test.fs.swift属性中定义swift bucket名称,以及在其中发布bucket的特定swift服务提供者的登录详细信息。
fs.contract.test.fs.swift
swift://swiftbucket.rackspace/
fs.swift.service.rackspace.auth.url
https://auth.api.rackspacecloud.com/v2.0/tokens
Rackspace US (multiregion)
fs.swift.service.rackspace.username
this-is-your-username
fs.swift.service.rackspace.region
DFW
fs.swift.service.rackspace.apikey
ab0bceyoursecretapikeyffef
Testing a new filesystem
向协议测试添加新文件系统的核心是添加一个新的协议类,然后为您希望测试的每个测试套件创建一个新的非抽象测试类。
例如,这里是本地文件系统的create()测试的测试实现。
package org.apache.hadoop.fs.contract.localfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.contract.AbstractCreateContractTest;
import org.apache.hadoop.fs.contract.AbstractFSContract;
public class TestLocalCreateContract extends AbstractCreateContractTest {
@Override
protected AbstractFSContract createContract(Configuration conf) {
return new LocalFSContract(conf);
}
}
AbstractfsContract子类的标准实现技术完全由存储在测试资源树中的一个Hadoop XML配置文件驱动。最好的做法是使用文件系统的名称将其存储在 /contract 下,例如 contract/localfs.xml。让XML文件定义所有文件系统选项,可以立即看到文件系统行为的列表。
LocalFSContract是一种特殊情况,因为它必须根据运行它的操作系统调整其区分大小写策略:对于Windows和OS/X,文件系统都不区分大小写,因此ContractOptions.IS_CASE_SENSITIVE选项必须设置为false。此外,Windows文件系统不支持Unix文件和目录权限,因此还必须设置相关的标志。这是在从资源树加载XML协议文件之后完成的,只需更新现在加载的配置选项:
getConf().setBoolean(getConfKey(ContractOptions.SUPPORTS_UNIX_PERMISSIONS), false);
Handling test failures
如果新的文件系统测试案例未能通过其中一个协议测试,您可以做什么?
这取决于问题的原因
如果由于不支持某个功能而需要跳过测试,请在ContractOptions类中查找现有的配置选项。如果没有方法,短期修复方法是重写该方法,并使用ContractTestUtils.skip()消息记录跳过测试的事实。使用此方法将消息打印到日志中,然后通知测试运行程序跳过了测试。这突出了问题。推荐的策略是调用超类,捕捉异常,并验证异常类和错误字符串的一部分与当前实现所引发的匹配。如果超类实际上成功了,那么它也应该fail()——即它以实现当前没有的方式失败了。这将确保测试路径仍然被执行,测试的任何其他失败—可能是回归—都会被发现。而且,如果这个特性真的实现了,那么改变就会被接受。
一个长期的解决方案是增强基本测试,以添加一个新的可选特性键。这将需要与hdfs-dev邮件列表上的开发人员协作。
'Lax vs Strict' exceptions
协议测试包括严格异常和松散异常的概念。严格的异常报告意味着:使用IOException的特定子类(如FileNotFoundException、EOFException等)报告失败。松散的报告意味着抛出IOException。
虽然文件系统应该引起更严格的异常,但是它们不能引起异常的原因可能是有的。仍然允许出现松散异常,这只会妨碍对用户应用程序故障的诊断。要声明文件系统不支持更严格的异常,请设置选项fs.contract.supports-strict-exceptions为false。
Supporting FileSystem with login and authentication parameters(支持带有登录和身份验证参数的文件系统)
针对远程文件系统的测试将需要指定文件系统的URL;针对需要登录细节的远程文件系统的测试需要用户名/ IDs和密码。所有这些详细信息都必须放在文件src/test/resources/contract-test-options.xml中,并且配置您的SCM工具为从不将此文件提交给subversion、git或等效工具。此外,必须将构建配置为从不将此文件捆绑到生成的任何-test工件中。Hadoop构建会这样做,从JAR文件中排除src/test/**/*.xml。此外,还需要创建src/test/resources/auth-keys.xml。它可以是contract-test-options.xml的副本。AbstractFSContract类会自动加载此资源文件(如果存在);可以添加特定测试用例的特定键。
作为一个例子,下面是S3N测试键的样子:
fs.contract.test.fs.s3n
s3n://tests3contract
fs.s3n.awsAccessKeyId
DONOTPCOMMITTHISKEYTOSCM
fs.s3n.awsSecretAccessKey
DONOTEVERSHARETHISSECRETKEY!
如果属性fs.contract.test.fs.%s中未定义文件系统URL,AbstractBondedFSContract将自动跳过测试套件,其中%s与文件系统的架构名称匹配。
运行测试时,需要关闭maven.test.skip,因为在这些测试中默认情况下它是真的。这可以通过诸如mvn test-Ptests on之类的命令来完成。
Important: passing the tests does not guarantee compatibility
通过所有文件系统协议测试并不意味着可以将文件系统描述为“与HDFS兼容”。测试试图查看每个操作的独立功能,并将重点放在每个操作的前提条件和后置条件上。未涉及的核心领域是跨分布式系统的并发性和故障方面。
Amazon S3和OpenStack Swift对象存储最终是具有非原子重命名和删除操作的一致对象存储,这证明了这一点。单线程测试用例不太可能看到一些并发问题,而一致性通常只在跨数据中心的测试中可见。
文件系统API的使用也有一些具体的方面:
当然,欢迎使用验证这些行为的测试。
Adding a new test suite
Root manipulation tests
有些测试直接针对根文件系统工作,尝试执行诸如重命名“/”和类似操作。根目录是“特殊的”,测试它非常重要,尤其是在non-POSIX文件系统(如对象存储)上。这些测试可能对本机文件系统造成非常大的破坏,因此谨慎使用。
skipIfUnsupported(TEST_ROOT_TESTS_ENABLED);
Scalability tests(可扩展性测试)
设计用于生成可伸缩负载的测试——其中包括大量小文件以及较少的大文件,应设计为可配置,以便测试套件的用户可以配置文件的数量和大小。
注意,在对象存储上,目录重命名操作通常是0(files)*0(data),然而删除操作是0(files)。后者意味着即使任何目录清理操作都可能需要时间,并且可能会超时。设计针对所有操作中可能存在延迟的远程文件系统的测试非常重要。
扩展规范
规范不完整。它没有对文件系统类进行完整的覆盖,并且可能有一些现有的指定类没有覆盖。
文件系统规范不完整。它不包括文件系统API中的所有操作甚至接口和类。它所涵盖的那些问题可能存在一些小问题,例如角点案例、故障模式和其它意外结果。也可能是标准文件系统与规范有显著的的差异,并且认为需要在测试中对其进行记录和处理。
最后,文件系统类和方法不是永久固定的。它们可以通过对现有类以及潜在的全新类和接口的新操作进行扩展。
因此,不要将此规范视为一个完整的静态文档,而应将其视为Hadoop代码的其余部分
How to update this specification
如果文件系统在新添加的测试中失败,那么可能是因为:
HDFS的行为必须是正确的。如果测试和规范与此行为不匹配,则需要更新规范。即便如此,仍可能有一些FS会改变的情况:
如果不匹配发生在本地文件系统中,那么可能无法纠正,因为这是通过Java IO APIs访问的本地文件系统。
对于其他文件系统,可以更新它们的行为以更准确地反映HDF和/或本地文件系统的行为。对于大多数操作来说,这是很简单的,尽管rename()的语义非常复杂,因此还不清楚HDFS是否是正确的引用。
如果测试失败,并且认为这是一个不可修复的文件系统特定问题,那么应该向ContractOptions接口、响应选项存在/不存在的已修改的测试和用于已更新的标准文件系统以指示何时出现功能/故障模式的XML协议文件添加一个允许对结果进行不同解释的新协议选项。
目的
使用CLI MiniCluster,用户只需使用一个命令启动和停止单节点Hadoop集群,无需设置任何环境变量或管理配置文件。CLI MiniCluster启动YARN/MapReduce和HDFS集群。
当用户希望快速试验真正的Hadoop集群或测试依赖于重要Hadoop功能的non-java程序时,这非常有用。
HadoopTarball
应该能够从发布版中获得Hadoop tarball。此外,还可以直接从源创建tarball:
$ mvn clean install -DskipTests
$ mvn package -Pdist -Dtar -DskipTests -Dmaven.javadoc.skip
注意:You will need protoc 2.5.0 installed.
tarball应该在hadoop dist/target/目录中可用。
运行MiniCluster
$ HADOOP_CLASSPATH=share/hadoop/yarn/test/hadoop-yarn-server-tests-2.9.2-tests.jar bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.9.2-tests.jar minicluster -rmport RM_PORT -jhsport JHS_PORT
在上面的示例命令中,应使用用户选择的这些端口号替换RM_PORT和JHS_PORT。如果未指定,将使用随机空闲端口。
用户可以使用许多命令行参数来控制要启动的服务,以及传递其他配置属性。可用的命令行参数:
-D Options to pass into configuration object (要传到配置对象的选项)
-datanodes How many datanodes to start (default 1) (要启动多少个数据节点(默认1)
-format Format the DFS (default false) (格式化DFS(默认false))
-help Prints option help.
-jhsport JobHistoryServer port (default 0--we choose)
-namenode URL of the namenode (default is either the DFS cluster or a temporary dir)(名称节点的URL(默认为DFS群集或临时目录))
-nnport NameNode port (default 0--we choose)
-nnhttpport NameNode HTTP port (default 0--we choose)
-nodemanagers How many nodemanagers to start (default 1)(要启动多少节点管理器(默认1))
-nodfs Don't start a mini DFS cluster
-nomr Don't start a mini MR cluster
-rmport ResourceManager port (default 0--we choose)
-writeConfig Save configuration to this XML file
-writeDetails Write basic information to this JSON file
要显示可用参数的完整列表,用户可以将-help参数传递给上面的命令。
概述
本指南介绍本地Hadoop库,并包括有关本地共享库的小讨论
注意:Depending on your environment, the term “native libraries” could refer to all *.so’s you need to compile; and, the term “native compression” could refer to all *.so’s you need to compile that are specifically related to compression. Currently, however, this document only addresses the native hadoop library (libhadoop.so). The document for libhdfs library (libhdfs.so) is here.
本地Hadoop库
由于性能原因和Java实现不可用,Hadoop拥有某些组件的本地实现。这些组件在一个名为本地hadoop库的动态链接的本地库中可用。在*nix平台上,库名为libhadoop.so。
用法
使用本机Hadoop库相当容易:
组件
本机hadoop库包含各种组件:
支持的平台
本机Hadoop库仅在*nix平台上受支持。该库不适用于Cygwin或Mac OS X平台。
本机Hadoop库主要用于GNU/Linus平台,并在以下分发版上进行了测试:
在所有上述发行版上,32/64位本机Hadoop库将与相应的32/64位JVM一起工作。
下载
预构建的32位i386-Linux本地hadoop库是hadoop发行版的一部分,位于lib/native目录中。您可以从hadoop公共发行版下载hadoop发行版。
请确保安装zlib和/或gzip开发包--无论您希望在部署中使用哪个压缩编解码器。
构建
本地hadoop库使用ANSI C编写,使用GNU autotools-chain (autoconf、autoheader、automake、autoscan、libtool)构建。这意味着在任何平台上使用符合标准的C编译器和GNU autotools-chain(请参阅受支持的平台)构建库都应该非常简单。
您需要在目标平台上安装的软件包包括:
一旦安装了前提条件包,就可以使用标准hadoop pom.xml文件并传递本机标志以构建本机hadoop库:
$ mvn package -Pdist,native -DskipTests -Dtar
您应该可以在以下位置看到新建的库:
$ hadoop-dist/target/hadoop-2.9.2/lib/native
请注意下面:
运行时
bin/hadoop脚本通过系统属性确保本机hadoop库位于库路径上:-Djava.library.path=
在运行时,检查MapReduce任务的hadoop日志文件。
检查
NativeLibraryChecker是一个检查本机库是否正确加载的工具。可以按如下方式启动NativeLibraryChecker:
$ hadoop checknative -a
14/12/06 01:30:45 WARN bzip2.Bzip2Factory: Failed to load/initialize native-bzip2 library system-native, will use pure-Java version
14/12/06 01:30:45 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop: true /home/ozawa/hadoop/lib/native/libhadoop.so.1.0.0
zlib: true /lib/x86_64-linux-gnu/libz.so.1
snappy: true /usr/lib/libsnappy.so.1
zstd: true /usr/lib/libzstd.so.1
lz4: true revision:99
bzip2: false
本地共享库
您可以使用DistributedCache加载任何本机共享库,以分发和符号链接库文件。
这个例子向您展示了如何分发共享库mylib.so,并从MapReduce任务中加载它。
注意:如果您下载或构建了本地hadoop库,则不需要使用DistibutedCache使该库对MapReduce任务可用。
介绍
本文档描述超级用户如何代表其他用户提交作业或访问HDF。
用例
下一节中描述的代码示例(code example)适用于以下用例。
用户名为“super”的超级用户希望代表用户joe提交作业并访问hdfs。超级用户有Kerberos凭据,但用户Joe没有任何凭据。任务需要以用户joe的身份运行,并且需要以用户joe的身份访问namenode上的任何文件。要求用户joe可以通过super的kerberos凭据进行身份验证的连接连接到namenode或job tracker。换句话说,super正在模仿用户joe。
一些产品,如Apache Oozie需要这个。
代码示例(Code example)
在本例中,super的凭证用于登录,并为joe创建代理用户ugi对象。这些操作在代理用户ugi对象的doAs方法中执行。
...
//create ugi for joe. The login user is 'super'.
UserGroupInformation ugi =
UserGroupInformation.createProxyUser("joe", UserGroupInformation.getLoginUser());
ugi.doAs(new PrivilegedExceptionAction){
public Void run() throws Exception {
//Submit a job
JobClient jc = new JobClient(conf);
jc.submitJob(conf);
//OR access hdfs
FileSystem fs = FileSystem.get(conf);
fs.mkdir(someFilePath);
}
}
配置
可以使用属性hadoop.proxy user.$superuser.hosts以及hadoop.proxy user.$superuser.groups和hadoop.proxy user.$superuser.users中的一个或两个来配置代理用户。
通过在core-site.xml中指定如下,名为super的超级用户只能从host1和host2连接,以模拟属于group1和group2的用户。
hadoop.proxyuser.super.hosts
host1,host2
hadoop.proxyuser.super.groups
group1,group2
如果不存在这些配置,则不允许模拟,连接将失败。如果更宽松的安全性是首选的,通配符*可用于允许从任何主机或任何用户进行模拟。例如,通过在core-site.xml中如下指定,名为oozie的用户从任何主机访问都可以模拟属于任何组的任何用户。
hadoop.proxyuser.oozie.hosts
*
hadoop.proxyuser.oozie.groups
*
hadoop.proxyuser.$superuser.hosts接受IP地址列表、CIDR格式的IP地址范围和/或主机名。例如,通过如下所示指定,名为super的用户从10.222.0.0-15范围内和10.113.221.221的主机访问可以模拟user1和user2。
hadoop.proxyuser.super.hosts
10.222.0.0/16,10.113.221.221
hadoop.proxyuser.super.users
user1,user2
警告
如果群集以Secure Mode(安全模式)运行,则超级用户必须具有Kerberos凭据才能模拟另一个用户。
它不能为此特性使用委托令牌。如果超级用户将自己的委托令牌添加到代理用户ugi中,则是错误的,因为它将允许代理用户使用超级用户的特权连接到服务。
但是,如果超级用户确实想给joe一个委派令牌,那么它必须首先模拟joe并为joe获取委派令牌,方法与上面的代码示例相同,并将其添加到joe的ugi中。这样,授权令牌将拥有joe的所有者。
Hadoop组件支持机架。例如,HDFS块放置将使用机架感知,通过将一个块副本放在不同的机架上来实现容错。这在集群中的网络交换机故障或分区时提供了数据可用性。
Hadoop主守护进程通过调用配置文件指定的外部脚本或java类来获得集群从属机器的机架id。使用java类或外部脚本进行拓扑,输出必须遵循java org.apache.hadoop.net.DNSToSwitchMapping接口。接口要求维护一对一的通信,拓扑信息格式为'/myrack/myhost',其中'/'是拓扑分隔符,'myrack'是机架标识符,'myhost'是单个主机。假设每个机架有一个/24子网,可以用'/192.168.100.0/192.168.100.5'格式作为唯一的 rack-host(机架主机)拓扑映射。
要使用Java类进行拓扑映射,类名由配置文件中的net.topology.node.switch.mapping.impl参数指定。示例,NetworkTopology.java包含在Hadoop发行版中,可以由Hadoop管理员自定义。使用Java类而不是外部脚本具有性能优势,因为Hadoop在新从节点注册自身时不需要派生外部进程。
如果实现外部脚本,将使用配置文件中的net.topology.script.file.name参数指定它。与java类不同,外部拓扑脚本不包含在Hadoop分发版中,由管理员提供。Hadoop在派生拓扑脚本时,会向ARGV发送多个IP地址。发送到拓扑脚本的IP地址的数量由net.topology.script.number.args控制,默认值为100。如果net.topology.script.number.args被更改为1,则DataNodes和/或NodeManagers提交的每个IP都会生成一个拓扑脚本。
如果未设置net.topology.script.file.name或net.topology.node.switch.mapping.impl,则会为任何传递的IP地址返回机架id '/default rack'。虽然这种行为看起来是可取的,但它会导致HDFS块复制的问题,因为默认行为是将一个复制的块从机架上写下来,但由于只有一个名为“/default-rack”的机架,所以无法这样做。
python Example
#!/usr/bin/python
# this script makes assumptions about the physical environment.
# 1) each rack is its own layer 3 network with a /24 subnet, which
# could be typical where each rack has its own
# switch with uplinks to a central core router.
#翻译:这个脚本对物理环境进行假设。
#1)每个机架都有自己的具有/24子网的3层网络,这可能是典型的,每个机架都有自己的交换机,通过上行链路连接到一个中央核心路由器。
#
# +-----------+
# |core router|
# +-----------+
# / \
# +-----------+ +-----------+
# |rack switch| |rack switch|
# +-----------+ +-----------+
# | data node | | data node |
# +-----------+ +-----------+
# | data node | | data node |
# +-----------+ +-----------+
#
# 2) topology script gets list of IP's as input, calculates network address, and prints '/network_address/ip'.
#2)拓扑脚本获取作为输入的IP列表,计算网络地址,并打印“/network_address/ip”
import netaddr
import sys
sys.argv.pop(0) # discard name of topology script from argv list as we just want IP addresses。丢弃argv列表中拓扑脚本的名称,因为我们只需要IP地址
netmask = '255.255.255.0' # set netmask to what's being used in your environment. The example uses a /24。将netmask设置为您的环境中正在使用的内容。示例使用a /24
for ip in sys.argv: # loop over list of datanode IP's。循环datanode IP的列表
address = '{0}/{1}'.format(ip, netmask) # format address string so it looks like 'ip/netmask' to make netaddr work。设置地址字符串的格式,使其看起来像“ip/netmask”以使netaddr工作
try:
network_address = netaddr.IPNetwork(address).network # calculate and print network address。计算并打印网络地址
print "/{0}".format(network_address)
except:
print "/rack-unknown" # print catch-all value if unable to calculate network address。如果无法计算网络地址,则打印catch-all值
bash Example
#!/bin/bash
# Here's a bash example to show just how simple these scripts can be
# Assuming we have flat network with everything on a single switch, we can fake a rack topology.
# This could occur in a lab environment where we have limited nodes,like 2-8 physical machines on a unmanaged switch.
# This may also apply to multiple virtual machines running on the same physical hardware.
# The number of machines isn't important, but that we are trying to fake a network topology when there isn't one.
#翻译:下面是一个bash示例,它展示了这些脚本是多么简单,假设我们有一个平面网络,所有东西都在一个交换机上,那么我们可以伪造一个机架拓扑。
#这可能发生在我们有有限节点的实验室环境中,比如非托管交换机上的2-8台物理机器。
#这也适用于在相同物理硬件上运行的多个虚拟机。
#机器的数量并不重要,但是我们试图在没有网络拓扑的情况下伪造网络拓扑。
#
# +----------+ +--------+
# |jobtracker| |datanode|
# +----------+ +--------+
# \ /
# +--------+ +--------+ +--------+
# |datanode|--| switch |--|datanode|
# +--------+ +--------+ +--------+
# / \
# +--------+ +--------+
# |datanode| |namenode|
# +--------+ +--------+
#
# With this network topology, we are treating each host as a rack. This is being done by taking the last octet
# in the datanode's IP and prepending it with the word '/rack-'. The advantage for doing this is so HDFS
# can create its 'off-rack' block copy.
# 1) 'echo $@' will echo all ARGV values to xargs.
# 2) 'xargs' will enforce that we print a single argv value per line
# 3) 'awk' will split fields on dots and append the last field to the string '/rack-'. If awk
# fails to split on four dots, it will still print '/rack-' last field value
#利用这种网络拓扑,我们将每个主机视为机架。这是通过获取数据节点IP中的最后一个八位字节并在其前面加上单词“/rack-”来完成的。这样做的好处是HDF可以创建它的“off-rack”块拷贝。
#1)“echo$@”将把所有argv值回送到xargs。
#2)“xargs”将强制我们每行打印一个argv值。
#3)“awk”将用点字段,并将最后一个字段附加到字符串“/rack-”。如果awk未能在四个点上拆分,它仍将打印'/rack-'最后一个字段值
echo $@ | xargs -n 1 | awk -F '.' '{print "/rack-"$NF}'
本文档全面描述了Hadoop MapReduce框架的所有面向用户的方面,并提供了一个教程。
确保Hadoop已安装、配置并正在运行。更多细节:
Hadoop Map/Reduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在由上千个商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上T级别的数据集。
一个Map/Reduce 作业(job) 通常会把输入的数据集切分为若干独立的数据块,由 map任务(task)以完全并行的方式处理它们。框架会对map的输出先进行排序, 然后把结果输入给reduce任务。通常作业的输入和输出都会被存储在文件系统中。 整个框架负责任务的调度和监控,以及重新执行已经失败的任务。
通常,Map/Reduce框架和分布式文件系统是运行在一组相同的节点上的,也就是说,计算节点和存储节点通常在一起。这种配置允许框架在那些已经存好数据的节点上高效地调度任务,这可以使整个集群的网络带宽被非常高效地利用。
MapReduce架构包含一个单独的master ResourceManager,每个集群节点一个slave NodeManager和每个应用的MRAppMaster组成。(参考 YARN Architecture Guide)。
应用程序至少应该指明输入/输出的位置(路径),并通过实现合适的接口或抽象类提供map和reduce函数。这些,和其他作业的参数,就构成了作业配置(job configuration)。
然后,Hadoop的 job client提交作业(jar包/可执行程序等)和配置信息给ResourceManager,后者负责分发这些软件和配置信息给slave、调度任务并监控它们的执行,同时提供状态和诊断信息给job-client。
虽然Hadoop框架是用JavaTM实现的,但Map/Reduce应用程序则不一定要用 Java来写 。
Map/Reduce框架运转在
框架需要对key和value的类(classes)进行序列化操作, 因此,这些类需要实现 Writable接口。 另外,为了方便框架执行排序操作,key类必须实现 WritableComparable接口。
一个Map/Reduce 作业的输入和输出类型如下所示:
(input)
在深入细节之前,让我们先看一个Map/Reduce的应用示例,以便对它们的工作方式有一个初步的认识。
WordCount是一个简单的应用,它可以计算出指定数据集中每一个单词出现的次数。
这个应用适用于 单机模式, 伪分布式模式 或 完全分布式模式 三种Hadoop安装方式。
源代码
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordCount {
public static class TokenizerMapper
extends Mapper
用法
假设环境变量设置如下:
export JAVA_HOME=/usr/java/default
export PATH=${JAVA_HOME}/bin:${PATH}
export HADOOP_CLASSPATH=${JAVA_HOME}/lib/tools.jar
编译wordcount.java并创建jar包:
$ bin/hadoop com.sun.tools.javac.Main WordCount.java
$ jar cf wc.jar WordCount*.class
假设:
作为输入的示例文本文件:
$ bin/hadoop fs -ls /user/joe/wordcount/input/
/user/joe/wordcount/input/file01
/user/joe/wordcount/input/file02
$ bin/hadoop fs -cat /user/joe/wordcount/input/file01
Hello World Bye World
$ bin/hadoop fs -cat /user/joe/wordcount/input/file02
Hello Hadoop Goodbye Hadoop
运行应用程序:
$ bin/hadoop jar wc.jar WordCount /user/joe/wordcount/input /user/joe/wordcount/output
输出:
$ bin/hadoop fs -cat /user/joe/wordcount/output/part-r-00000
Bye 1
Goodbye 1
Hadoop 2
Hello 2
World 2
应用程序能够使用-files选项来指定一个由逗号分隔的路径列表,这些路径是task的当前工作目录。使用选项-libjars可以向map和reduce的classpaths中添加jar包。使用-archives选项程序可以传递档案文件做为参数,这些归档文件是未归档的,并且在tasks的当前工作目录中创建了一个带有归档文件名称的链接。有关命令行选项的更多细节请参考 Commands manual。
Running wordcount example with -libjars, -files and -archives:
bin/hadoop jar hadoop-mapreduce-examples-.jar wordcount -files cachefile.txt -libjars mylib.jar -archives myarchive.zip input output
在这里,myarchive.zip将被放置并解压到一个名为“myarchive.zip”的目录中。
用户可以使用#通过-files和-archives选项为文件和归档文件指定不同的符号名。
bin/hadoop jar hadoop-mapreduce-examples-.jar wordcount -files dir1/dict.txt#dict1,dir2/dict.txt#dict2 -archives mytar.tgz#tgzdir input output
在这里,task可以分别使用符号名dict1和dict2访问dir1/dict.txt和dir2/dict.txt文件。归档文件mytar.tgz被置换,并解压到名为tgzdir的目录中。
解释
WordCount应用程序非常直截了当。
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
Mapper实现,通过map方法,由TextInputFormat指定的格式一次处理一行。然后,它通过StringTokenizer 以空格为分隔符将一行切分为若干tokens,之后,输出<
对于示例中的第一个输入,map输出是:
< Hello, 1>
< World, 1>
< Bye, 1>
< World, 1>
第二个输入,map输出是:
< Hello, 1>
< Hadoop, 1>
< Goodbye, 1>
< Hadoop, 1>
关于组成一个指定作业的map数目的确定,以及如何以更精细的方式去控制这些map,我们将在教程的后续部分学习到更多的内容。
job.setCombinerClass(IntSumReducer.class);
WordCount还指定了一个combiner 。因此,每次map运行之后,会对输出按照key进行排序,然后把输出传递给本地的combiner(按照作业的配置与Reducer一样),进行本地聚合。
第一个map的输出是:
< Bye, 1>
< Hello, 1>
< World, 2>
第二个map的输出是:
< Goodbye, 1>
< Hadoop, 2>
< Hello, 1>
public void reduce(Text key, Iterable values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
Reducer的实现,通过reduce方法仅仅是对每个键(比如本例中的Hello)出现的次数求和。
因此这个作业的输出就是:
< Bye, 1>
< Goodbye, 1>
< Hadoop, 2>
< Hello, 2>
< World, 2>
作业中的main方法中指定了作业的几个方面, 例如:通过命令行传递过来的输入/输出路径、key/value的类型、输入/输出的格式等等。其然后调用job.waitforcompletion提交作业并监视其进度。
我们将在本教程的后续部分学习更多的关于Job, InputFormat, OutputFormat和其他接口及类(class)。
这部分文档为用户将会面临的Map/Reduce框架中的各个环节提供了适当的细节。这将帮助用户以细粒度的方式实现、配置和优化他们的作业。然而,请注意每个类/接口的javadoc文档提供最全面的文档;本文只是想起到指南的作用。
我们会先看看Mapper和Reducer接口。应用程序通常会通过提供map和reduce方法来实现它们。
然后,我们会讨论其他的核心接口,其中包括:Job, Partitioner, InputFormat, OutputFormat和其它。
最后,我们将通过讨论框架中一些有用的功能点(例如:DistributedCache, IsolationRunner等等)来收尾。
核心功能描述
应用程序通常会通过提供map和reduce来实现 Mapper和Reducer接口,它们组成作业的核心。
Mapper
Mapper将输入键值对(key/value pair)映射到一组中间格式的键值对集合。
Map是一类将输入记录集转换为中间格式记录集的独立任务。 这种转换的中间格式记录集不需要与输入记录集的类型一致。一个给定的输入键值对可以映射成0个或多个输出键值对。
Hadoop MapReduce框架为 由该作业的InputFormat产生的 每一个InputSplit产生一个map任务。
总的来说,mapper实现是通过job.setMapperClass(class)方法传递给作业的。然后,框架为这个task的InputSplit中每个键值对调用一次 map(WritableComparable, Writable, Context)操作。然后,应用程序可以重写cleanup(Context)方法来执行任何必需的清理。
输出键值对不需要与输入键值对的类型一致。一个给定的输入键值对可以映射成0个或多个输出键值对。通过调用context.write(writableComparable,writable)收集输出键值对。
应用程序可以使用counter--计数器报告其统计信息。
框架随后会把与给定key关联的所有中间值(value)分组,并传递给reducer以确定最终输出。用户可以通过job.setGroupingComparatorClass(类)指定 Comparator--比较器 来控制分组。
Mapper的输出被排序后,就按每个Reducer分区。分区总数与作业的reduce任务数相同。用户可以通过实现自定义的 Partitioner来控制哪个key(以及记录)指向哪个 Reducer。
用户可选择通过 Job.setCombinerClass(Class)指定一个combiner,它负责对中间过程的输出进行本地的聚集,这会有助于降低从Mapper到 Reducer数据传输量。
这些被排好序的中间过程的输出结果保存的格式是(key-len, key, value-len, value),应用程序可以通过 Configuration 控制对这些中间结果是否进行压缩以及怎么压缩,使用哪种 CompressionCodec。
需要多少个Map?
Map的数目通常是由输入数据的大小决定的,一般就是所有输入文件的总块(block)数。
Map正常的并行规模大致是每个节点(node)大约10到100个map,对于CPU 消耗较小的map任务可以设到300个左右。由于每个任务初始化需要一定的时间,因此,比较合理的情况是map执行的时间至少超过1分钟。
这样,如果你输入10TB的数据,每个块(block)的大小是128MB,你将需要大约82,000个map来完成任务,除非使用 setNumMapTasks(int)(注意:这里仅仅是对框架进行了一个提示,实际决定因素见这里)将这个数值设置得更高。
Reducer
Redcuer把一个 共享key的中间值集合规约为 一个更小的值集合。
用户可以通过 JobConf.setNumReduceTasks(int)设定一个作业中reduce任务的数目。总的来说,reducer实现是通过job.setReducerClass(class)方法为作业传递的,并且可以重写此方法来初始化自己。然后,框架为成组的输入数据中的每个
Reducer有3个主要阶段:shuffle、sort和reduce。
Shuffle
Reducer的输入就是Mapper已经排好序的输出。在这个阶段,框架通过HTTP为每个Reducer获得所有Mapper输出中与之相关的分区。
Sort
这个阶段,框架将按照key的值对Reducer的输入进行分组 (因为不同mapper的输出中可能会有相同的key)。
Shuffle和Sort两个阶段是同时进行的;map的输出也是一边被取回一边被合并的。
Secondar Sort
如果要求 中间键分组的等价规则与reduce前键分组的等价规则不同,则可以通过job.setsortComparatorClass(class)指定一个比较器。由于job.setGroupingComparatorClass(Class)可用于控制如何对中间键进行分组,因此可以结合使用它们来模拟值的二级排序。
reduce
在这个阶段,框架为已分组的输入数据中的每个
应用程序可以使用counter报告状态信息。
Reducer的输出是没有排序的。
需要多少个Reduce?
Reduce的数目建议是0.95或1.75乘以 (<no. of nodes> * <no. of maximum containers per node>)。
用0.95,所有reduce可以在maps一完成时就立刻启动,开始传输map的输出结果。用1.75,速度快的节点可以在完成第一轮reduce任务后,可以开始第二轮,这样可以得到比较好的负载均衡的效果。
增加reduce的数目会增加整个框架的开销,但可以改善负载均衡,降低由于执行失败带来的负面影响。
上述比例因子比整体数目稍小一些是为了给框架中的推测性任务(speculative-tasks) 或失败的任务预留一些reduce的资源。
无Reducer
如果没有归约要进行,那么设置reduce任务的数目为零是合法的。
这种情况下,map任务的输出会直接被写入由 FileOutputFormat.setOutputPath(Job, Path)指定的输出路径。框架在把它们写入FileSystem之前没有对它们进行排序。
Partitioner
Partitioner用于划分键值空间(key space)。
Partitioner负责控制map输出结果key的分割。Key(或者一个key子集)被用于产生分区,通常使用的是Hash函数。分区的数目与一个作业的reduce任务的数目是一样的。因此,它控制将中间过程的key(也就是这条记录)应该发送给m个reduce任务中的哪一个来进行reduce操作。
HashPartitioner是默认的 Partitioner。
Counter
Counter是MapReduce应用程序报告其统计信息的工具。
Mapper和Reducer实现可以使用Counter来报告统计信息。
Hadoop MapReduce与一个通常有用的mapper、reducer和partitioner库捆绑在一起。
作业配置
Job代表一个MapReduce作业的配置。
Job是用户向Hadoop框架描述一个Map/Reduce作业如何执行的主要接口。框架会按照Job描述的信息忠实地去尝试完成这个作业,然而:
通常,Job会指明Mapper、Combiner(如果有的话)、 Partitioner、Reducer、InputFormat和 OutputFormat的具体实现。 FileInputFormat一组输入文件(FileInputFormat.setInputPaths(Job, Path…)/ FileInputFormat.addInputPath(Job, Path))和 (FileInputFormat.setInputPaths(Job, String…)/ FileInputFormat.addInputPaths(Job, String)) 以及输出文件应该写在哪儿 (FileOutputFormat.setOutputPath(Path))。
Job可选择地对作业设置一些高级选项,例如:设置Comparator; 放到DistributedCache上的文件;中间结果或者作业输出结果是否需要压缩以及怎么压缩;作业是否允许预防性(speculative)任务的执行 (setMapSpeculativeExecution(boolean))/ setReduceSpeculativeExecution(boolean)); 每个任务最大的尝试次数 (setMaxMapAttempts(int)/ setMaxReduceAttempts(int))等等。
当然,用户能使用 Contribution.set(String, String)/get(String, String) 来设置或者取得应用程序需要的任意参数。然而,DistributedCache的使用是面向大规模只读数据的。
任务的执行和环境
MRAppMaster 是在一个单独的jvm上以子进程的形式执行 Mapper/Reducer任务(Task)的。
子任务会继承父MRAppMaster的环境。用户可以通过Job中的 mapreduce.{map|reduce}.java.opts和配置参数来设定子jvm上的附加选项,例如: 通过-Djava.library.path=<> 将一个非标准路径设为运行时的链接用以搜索共享库,等等。如果 mapreduce.{map|reduce}.java.opts参数,包含一个符号@taskid@, 它会被替换成mapreduce的taskid的值。
下面是一个包含多个参数和替换的例子,其中包括:记录jvm GC日志; JVM JMX代理程序以无密码的方式启动,这样它就能连接到jconsole上,从而可以查看子进程的内存和线程,得到线程的dump;还把分别map和reduce子jvm的最大堆尺寸设置为512MB和1024MB,
并为子jvm的java.library.path添加了一个附加路径。
mapreduce.map.java.opts
-Xmx512M -Djava.library.path=/home/mycompany/lib -verbose:gc -Xloggc:/tmp/@[email protected]
-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
mapreduce.reduce.java.opts
-Xmx1024M -Djava.library.path=/home/mycompany/lib -verbose:gc -Xloggc:/tmp/@[email protected]
-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
内存管理
用户/管理员还可以使用mapreduce.{map|reduce}.memory.mb指定已启动子任务及其递归启动的任何子进程的最大虚拟内存。请注意,这里设置的值是每个进程的限制。mapreduce.{map|reduce}.memory.mb的值应以兆字节(MB)为单位指定。而且该值必须大于或等于传递给JavaVM的-Xmx,否则VM可能无法启动。
注意:mapreduce.{map|reduce}.java.opts仅用于配置从MRAppMaster启动的子任务。 配置守护进程的内存选项在Configuring the Environment of the Hadoop Daemons中有说明。
框架的某些部分可用的内存也是可配置的。在map和reduce任务中,调整 影响操作并发性的参数以及数据撞击磁盘的频率 可能会影响性能。监视某个作业的文件系统计数器——特别是相对于从map到reduce的字节计数——对于调优这些参数是非常宝贵的。
Map参数
从map输出的记录将被序列化到缓冲区中,元数据将存储到会计缓冲区中。如以下选项所述,当序列化缓冲区或元数据超过阈值时,缓冲区的内容将在后台排序并写入磁盘,而map将继续输出记录。如果其中任何一个缓冲区在溢出过程中被完全填满,map线程将阻塞。当map完成时,所有剩余的记录都写到磁盘上,所有磁盘上的段都合并到一个单一文件中。最小化磁盘溢出的数量可以减少map时间,但是更大的缓冲区也会减少mapper程序可用的内存。
Name | Type | Value | Description |
mapreduce.task.io.sort.mb | int | 100 (默认) |
(存储从map输出的记录 的 序列化和记帐 缓冲区的累积大小,以兆字节为单位。) 在对文件进行排序时要使用的缓冲内存总量,单位为兆字节。默认情况下,为每个合并流提供1MB的内存,这应该会使查找最小化。 |
mapredue.map.sort.spil.percent | float | 0.80 (默认) |
序列化缓冲区中的软限制。一旦到达,线程在后台将开始将内容溢出到磁盘。请注意,如果在溢出过程中超过此阈值,收集并不会阻塞,因此当溢出设置为小于0.5时,溢出可能大于此阈值。 |
其它说明:
Shuffle/Reduce参数
如前所述,每个reduce通过HTTP将分区器--Partitioner分配给它的输出提取到内存中,并定期将这些输出合并到磁盘。如果启用了map输出的中间压缩,则将每个输出解压缩到内存中。以下选项影响这些在reduce之前合并到磁盘的频率,以及在reduce期间分配到map输出的内存。
Name | Type | Value | Description |
mapreduce.task.io.soft.factor | int | 10 (默认) |
(排序文件时要同时合并的流的数目。这将确定打开的文件句柄数。) 它限制了合并过程中打开的文件数量和压缩编解码器数量。如果文件的数量超过这个限制,合并将进行多次。虽然这个限制也适用于map,但是大多数作业都应该进行配置,以使其不太可能达到这个限制。 |
mapreduce.reduce.merge.inmen.threholds | int | 1000 (默认) |
(以内存合并进程的文件数表示的阈值。当我们累积阈值文件数时,我们启动内存合并并溢出到磁盘。值为0或小于0表示我们不希望有任何阈值,而是只依赖ramfs的内存消耗来触发合并。) 在合并到磁盘之前,已拉取到内存中的已排序的map输出数。与前面注释中的溢出阈值一样,这不是定义分区单元,而是一个触发器。在实践中,这通常设置得非常高(1000)或禁用(0),因为从内存中合并段通常比从磁盘中合并要(请参阅下表中的注释)。这个阈值只影响洗牌期间内存中合并的频率。
|
mapreduce.reduce.shuffle.merge.percent | float | 0.66 (默认) |
(启动内存内合并的使用阈值,表示为分配给 存储 内存内map输出的总内存的百分比,由mapreduce.reduce.shuffle.input.buffer.percent定义。) 启动内存合并之前拉取map输出的内存阈值,表示为分配给内存中存储map输出的内存百分比。由于无法装入内存的map输出可能会暂停,因此设置此高值可能会降低获取和合并之间的并行性。相反,高达1.0的值对于输入完全可以在内存中容纳的reduces是有效的。这个参数只影响混排期间内存中合并的频率。 |
mapreduce.reduce.shuffle.input.buffer.percent | float | 0.70 (默认) |
(在混排期间相对于最大堆大小分配的用来存储map输出的内存百分比。) 内存的百分比——相对于通常在mapreduce.reduce.java.opts中指定的最大堆大小——可以在混排期间分配用于存储映射map输出。尽管应该为框架预留一些内存,但是通常将内存设置得足够高以存储大量的map输出是有利的。 |
mapreduce.reduce.input.buffer.percent | float | 0.0 (默认) |
(在reduce期间保留map输出的内存百分比(相对于最大堆大小)。当混排结束时,内存中任何剩余的map输出消耗必须小于此阈值,然后才能开始reduce。) 相对于最大堆大小的内存百分比,在reduce期间可以保留map输出。当reduce开始时,map输出将被合并到磁盘中,直到剩余的输出在这个定义的资源限制之下。默认情况下,在reduce开始将可用内存最大化之前,所有map输出都合并到磁盘。对于更少内存密集型的reduce,应该增加内存密集型,以避免磁盘访问。 |
其他说明:
配置的参数
以下属性在每个任务执行的作业配置中进行了本地化:
Name | Type | Value | Description |
mapreduce.job.id | String | The job id | |
mapreduce.job.jar | String | job.jar location in job directory(job.jar在job目录中的位置) | |
mapreduce.job.local.dir | String | The job specific shared scratch space(特定于作业的共享暂存空间) | |
mapreduce.task.id | String | The task id | |
mapreduce.task.attempt.id | String | The task attempt id(任务尝试id) | |
mapreduce.task.is.map | boolean | Is this a map task(这是一个map任务吗) | |
mapreduce.task.partition | int | The id of the task within the job(作业中任务的id) | |
mapreduce.map.input.file | String | The filename that the map is reading from(map正在读取的文件名) | |
mapreduce.map.input.start | long | The offset of the start of the map input split(map输入分片开始的偏移量) | |
mapreduce.map.input.length | long | The number of bytes in the map input split(map输入分片中的字节数) | |
mapreduce.task.output.dir | Sting | The task’s temporary output directory(任务的临时输出目录) |
备注:在执行流作业期间,将转换“mapreduce”参数的名称。点(.)变成下划线(_)。比如:mapreduce.job.id变为 mapreduce_job_id,以及mapreduce.job.jar变为 mapreduce_job_jar。要获取流作业的mapper/reducer中的值,请使用带下划线的参数名称。
任务日志
标准输出(stdout)和错误(stderr)流以及任务的系统日志由节点管理器--NodeManager读取并记录到${HADOOP_LOG_D}/userlog。
分发库
分布式缓存还可以用于分发jar和本机库,以用于map或reduce任务。子JVM总是将其当前工作目录添加到java.library.path和 LD_LIBRARY_PATH中,因此,可以通过 System.loadLibrary or System.load加载缓存的库。有关如何通过分布式缓存加载共享库的详细信息,请参见 Native Libraries。
作业的提交和监控
Job是用户作业--user-job与资源管理器--ResourceManager交互的主要界面。