前面的章节致力于设置集群,在本章我们将集中于使集群执行得更流畅。
HDFS
固定的数据结构
作为一个管理者,对HDFS的构件,比如在硬盘上组织持namenode、secondary namenode、datanode固定数据有个理解是非常重要的。弄清楚哪些文件能够帮助你分析问题或者分清哪些是没有用的。
namenode的目录结构
一种新的namenode形式创建了下面的目录结构:
${https://www.sodocs.net/doc/4c4394650.html,.dir}/current/VERSION
/edits
/fsimage
/fstime
回忆在第9章的https://www.sodocs.net/doc/4c4394650.html,.dir的属性是一个列表目录,列表的内容同样反映在每个目录。这种机制提供了弹性,尤其当你的目录是一个NFS,这种机制就更值得推荐。
VERSION文件是JAVA属性的文件,其包含有关的HDFS的运行,下面是一个典型文件:
#Tue Mar 10 19:21:36 GMT 2009
namespaceID=134368441
cTime=0
storageType=NAME_NODE
layoutVersion=-18
HDFS的固定数据结构的版本是由一个叫layoutVersion负整数定义的,这个版本号与Hadoop分布的发行号是不相干的。无论何时版本号都是减一(比如:版本-18过了就是-19)。当版本号变小时HDFS就需要升级,因此如果HDFS保存的layout是个旧的版本,那么新的namenode(datanode)就无法操作。升级被包含在296页的“Upgrades”中。
namespaceID能唯一被文件系统识别,当文件系统第一secondary格式化时它就被创建。namenode用他它识别新的datanode,因此它们将无法知道namespaceID直到已经注册了namenode。
cTime标记namenode存储的创建时间。新形式存储的值总是为0,但是无论何时文件系统升级它也会被升级。
storageType表明一个namenode存储目录包含的数据结构。
namenode的存储目录还包含其他文件比如:edits,fsimage,fstime。这些都是二进制文件,它们利用Hadoop的Writable作为其序列格式(见86页“Serialization”)。为了更深入理解这些文件具体干什么,你需要进一步挖掘namenode的工作原理。
文件系统镜像和操作日志
当一个文件系统的客服端进行写操作时(例如创建或者移动文件)就会被第一次记录在操作日志。namenode在内存中也有代表文件系统的元数据,当操作日志被修改后它也会更新。内存中的元数据被用作响应读请求。
在每次写后,在代码执行成功返回客户端之前,操作日志会被同步清除。为了使namenode 能写入多重目录,在成功返回之前写必须清除并每一个复本执行相同操作。这样才能保证不会因
为机器错误发生数据丢失。
fsimage文件是文件系统的固定检查点。然而,并不是每次写操作都会升级,因为在fsimage 文件外部执行写操作量会达到数十亿万位,这就导致写非常慢。这要有弹性,然而,因为如果namenode失败,最新元数据的状态将会通过从硬盘装载fsimage到内存被重构,接着应用到操作日志中。实际上,当它启动时就精确地定位namenode要干什么。
通过描述,edits文件将会无限的变大。但在namenode正在运行时这种缺陷对系统没有影响,如果namenode被重启,将花费很长一段时间应用每个操作到操作日志。在这段时间内文件系统将会挂机,这是不希望发生的。
这种解决方法是运行secondary namenode,目的是产生基本的内存文件系统元数据的断点。检查点进程的步骤如下:
1.s econdary namenode需要基本
2.s econdar ynamenode从原namenode检索fsimag和edits
3.s econdary namenode装载fsimag到存储器,应用edits的每一个操作,接着创建一个新的
统一的fsimag文件
4.s econdarynamenode发送新的fsimag到原namenode
5.原namenode通过从secondarynamenode获得的新的fsimag替换掉旧的,旧的edits文件将
安步骤一进行操作,它将更新fstime来记录断点发生的时间。
步骤的最后,原namenode有一个最新的fsimag文件和edits文件。当namenode在安全模式下使用
hadoop dfsadmin-saveNamespace命令可以使管理者手动运行这个进程。
这个过程可以清楚的解释为什么secondary namenode对存储器的要求会同原namenode的一样,这也是secondary namenode在云集上需要一个专门的服务器的原因。
检查点的调度由两个结构指针控制。secondary namenode的检查点每小时一次或者如果操作日志达到64MB,将会每5分钟检查一secondary。
secondary namenode的目录结构
一个有用的副作用被调度的过程是secondary要有一个检查点在最后的过程,这在一个叫previous.checkpoint子目录里可以被看到。这可以被用作为源namenode的元数据反馈的资源:${fs.checkpoint.dir}/current/VERSION
/edits
/fsimage
/fstime
/previous.checkpoint/VERSION
/edits
/fsimage
/fstime
这种目录布局和secondarynamenode的current目录同namenode是相同的。防止所有的namenode 都宕机, 这种设计允许通过复制相关的存储目录到一个新的namenode或者当启动守护进程时使用-importCheckpoint选项从secondarynamenode中恢复。-importCheckpoint将装载namenode的元数据到定义为fs.checkpoint.dir最新的检查点,但这些都发生在只有不存在元数据在
https://www.sodocs.net/doc/4c4394650.html,.dir目录下时,因此就不存在覆盖以前的元数据。
datanode目录结构
与namenode不同,datanode不需要清晰的格式,因为它们在启动时就创建自动自己保存目
录。下面给出关键的文件和目录:
${dfs.data.dir}/current/VERSION
/blk_
/blk_
/blk_
/blk_
/...
/blk_
/blk_
/subdir0/
/subdir1/
/...
/subdir63/
datanode的VERSION文件和namenode的非常相似:
#Tue Mar 10 21:32:31 GMT 2009
namespaceID=134368441
storageID=DS-547717739-172.16.85.1-50010-1236720751627
cTime=0
storageType=DATA_NODE
layoutVersion=-18
namespaceID,cTime和layoutVersion与namenode的都非常相似。storageID 是datanode特有的,它被用区分datanode。storageType识别这目录作为datanode的存储目录。
验证登录信息
HDFS能够记录所有文件系统的登录信息,这是一些审计目的的特征。将调试日志语句执行审计登录信息是利用日志在信息水平,在默认的配置是不可用的,为日志阈值log4j.properties 将书面警告:
https://www.sodocs.net/doc/4c4394650.html,.apache.hadoop.fs.FSNamesystem.audit=WARN
你可以通过信息代替警告打开验证登录信息,这样会导致日志栏被写入namenode的日志中。下面给出一个在/user/tom的列子:
2009-03-13 07:11:22,982 INFO
https://www.sodocs.net/doc/4c4394650.html,node.FSNamesystem.audit:
ugi=tom,staff,admin ip=/127.0.0.1 cmd=listStatus src=/user/tom
dst=null perm=null
设置log4j是个好方法以至于验证信息会被写入独立的文件而不会与namenode的其他日志混淆。
工具
dfsadmin
dfsadmin工具是个为了查询HDFS状态信息的多用途的工具,管理者也可以用其来操作HDFS。其被称为hadoop dfsadmin。要使用这个命令改变HDFS的状态需要以超级用户的身份使用。
下面是这个命令的具体描述。(281页)
检测文件系统
hadoop提供多功能的fsck检查HDFS文件的状态。该工具用来找寻元数据丢失的块,也没
有成功复制的块。下面是一个云集检查所有文件系统的例子:
......................Status: HEALTHY
Total size: 511799225 B
Total dirs: 10
Total files: 22
Total blocks (validated): 22 (avg. block size 23263601 B)
Minimally replicated blocks: 22 (100.0 %)
Over-replicated blocks: 0 (0.0 %)
Under-replicated blocks: 0 (0.0 %)
Mis-replicated blocks: 0 (0.0 %)
Default replication factor: 3
Average block replication: 3.0
Corrupt blocks: 0
Missing replicas: 0 (0.0 %)
Number of data-nodes: 4
Number of racks: 1
The filesystem under path '/' is HEALTHY
fsck从已经给出的路径开始递归的在文件系统中检查要找的文件,并为每个已检查的文件打点。为了检查一个文件,fsck检索文件块的元数据和寻找问题与异常情况。注意fsck从namenode检索所有的信息;它并不同任何元数据通信实际上能检索任何块数据。
绝大多数fsck的输出是显而易见的,但是也要有一定条件才能查询:
Over-replicated块
他们所属的文件块超过自己的目标复制。复制是不正常的问题,HDFS会自动删除多余的副本
Under-replicated块
这些都是不符合他们属于自己的目标复制文件块的。HDFS中会自动创建新的副本复制块,直到他们满足目标复制。您可以得到有关块的信息复制(或等待复制)使用的hadoop dfsadmin metasave
Misreplicated块
这些块不符合块的副本放置策略(见“副本第67页上的位置“)。例如,对于在一个multirack三个复制水平集群,如果同一机架上的所有三个副本块,块错误复制,因为副本应跨越至少两个韧性架蔓延。misreplicated块没有自动修复的HDFS(这时写操作)。作为一种变通方法,可以解决这个问题通过手动增加属于其的文件块复制(使用Hadoop的FS - setrep),等到块被复制,然后减少文件复制回其原始价值
Corrupt块
这些块的副本都是损坏。块至少有一个没有损坏副本就不报告不可用;namenode将复制的可用的直到满足目标复制副本。
缺失副本
这些集群中的任何地方没有副本的块。
损坏或缺失块是关注的最大原因,因为它意味着数据已丢失。默认情况下,fsck将遗弃损坏或者缺失的块的文件,但是,你可以通过一下方式阻止:
移动受影响的文件HDFS的名为/lost+found目录下,使用-move选项。文件被分解成连续的块链,以帮助你任何打捞工作可以尝试。
删除受影响的文件,使用删除选项。文件将无法恢复后被删除
为文件寻找块
f sck工具提供了一种简便的方式找出哪些块在任何特定的文件,例如:
% hadoop fsck /user/tom/part-00007 -files -blocks -racks
/user/tom/part-00007 25582428 bytes, 1 block(s): OK
0. blk_-3724870485760122836_1035 len=25582428 repl=3[/default-rack/10.251.43.2:50010,
/default-rack/10.251.27.178:50010, /default-rack/10.251.123.163:50010]
这表示该文件/ user/tom/part-00007是一个块,并显示区块位于的datanode。fsck选项如下:-files该文件选项显示文件名,大小,块的数量,和它的状态
-blocks该选项显示块有关文件中的每个块,一条线每信息块
-racks选项显示每个机架的位置和datanode的地址块
datanode块扫描
每个datanode都有块扫描,它定期的核实存储在datanode上的所有块,这样已损坏在用户使用之前能被检测和修补。DataBlockScanner维护一个块的扫描表,并按照表的顺序一个一个的检查错误。扫描在datanode上采用节流控制器机制限制硬盘的带宽。
块每隔3星期会被扫描以防止超期的硬盘错误出现(dfs.datanode.scan.hours控制,默认时间为504小时)。损坏的块将会报告给namenode修复。
你从datanode的官网上可以得到块核实的报告http://datanode:50075/blockScannerReport 下面给出一个例子:
Total Blocks : 21131
Verified in last hour : 70
Verified in last day : 1767
Verified in last week : 7360
Verified in last four weeks : 20057
Verified in SCAN_PERIOD : 20057
Not yet verified : 1074
Verified since restart : 35912
Scans since restart : 6541
Scan errors since restart : 0
Transient scan errors : 0
Current scan rate limit KBps : 1024
Progress this period : 109%
Time left in cur period : 53.08%
通过具体的listblocks指针http://datanode:50075/blockScannerReport? listblocks,报告连同前面的datanode上的所有块列表以及其最新的验证状态。
blk_6035596358209321442 : status : ok type : none scan time : 0
not yet verified
blk_3065580480714947643 : status : ok type : remote scan time :
1215755306400
2008-07-11 05:48:26,400
blk_8729669677359108508 : status : ok type : local scan time :
1215755727345
2008-07-11 05:55:27,345
第一列是块ID,其secondary是一些键- 值对。状态可以一个“失败”或“确定”按块
的最后
个扫描是否发现了一个校验错误。如果它是由后台线程执行的扫描类型是本地的,如果它是一个客户端或远程datanode的扫描类型为远程,或如果这个块扫描尚未作出。最后一条信息是扫描时间,这被看作是显示自1970年1月1日起午夜,也作为一个更可读的毫秒数值。
平衡器
随着时间的推移datanodes之间的分配块可以变得不平衡。不平衡的云集会影响MapReduce的位置,在充分利用datanode会很有压力,因此最好避免。
平衡器程序是一个Hadoop守护进程,其将重新分配块移动从过度利用datanodes还可利用datanodes,同时坚持以块副本的置换方针,将块复本放在不同的机架上,不可能有数据丢失(见第67页上的“副本放置”)。一直移动块知道云集被认为平衡,这就意味着利用每一个datanode不同于利用云集,而不再是一个给定的临界值。又可以这样启动平衡器:% start-balancer.sh
阈值参数指定的阈值的百分比定义表示集群是否平衡的。此标志是可选的,在这种情况下,阈值是10%。在任何时候,只有一个平衡器可在群集上运行。
平衡器一直运行直到云集平衡,这时就不能移动任何一个块,或者它将与namedata失去通信。它在标准的日志目录下产生一个日志文件,在日志文件里以行的形式将重新分布的情况表示出来。下面给出例子:
Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved
Mar 18, 2009 5:23:42 PM 0 0 KB 219.21 MB
150.29 MB
Mar 18, 2009 5:27:14 PM 1 195.24 MB 22.45 MB
150.29 MB
The cluster is balanced. Exiting...
Balancing took 6.072933333333333 minutes
平衡器通常是在后台运行不会加重云集的负担,或者打扰其他使用该云集的用户。它用一个块复制到另一个复制块来限制带宽。默认1MB/s,但是这可以在hdfs-site.xml下以字节方式设置dfs.balance.widthPerSec的属性改变。
监测
监测是系统管理的一个重要部分。在这部分,我们可以看到Hadoop中的监测设备系统,和他们是怎样连接到其他的监测系统的。
监测的目的是检测当集群不提供预期服务水平。主守护程序是最重要的监察的:在namenodes(初级和中级),和jobtracker。datanodes 和的TaskTracker的失败可以预料的,特别是对较大的群集,所以你应该提供额外的容量,使集群可以容忍在任何时候有一个很小的比例死节点。
除了描述未来的设施,有些管理员在运行测试作业在PEriodic集群的健康测试的基础上。
有大量的工作,添加更多的监视功能的Hadoop,这这里不讨论。例如,Chukwa?是一个数据采集和监控系统内置的HDFS和MapReduce,并擅长寻找大型采矿日志数据趋势。另一个例子是定义服务生命周期的Hadoop守护进程的工作,其中包括增加一个“ping”的方法,得到一个守护进程的健康简要介绍
记录
所有的Hadoop守护进程产生的日志文件对于找出系统发生了什么是非常有用的。第256页的“系统日志文件”上,介绍了如何配置这些文件。
设置记录级别
当调试一个问题,这是非常方便的能够改变日志级别暂时在系统中的特定组件。Hadoop守护进程有能更改日志级别的任何Log4j的网页,可以日志级别发现在守护进程的Web UI。按照惯例,日志名称Hadoop的对应做日志记录的类名,但这个规则也有例外,所以你应该咨询的源代码,找到日志名称。
例如,调试jobtracker类日志,我们浏览jobtracker的web UIhttp://jobtracker-host:50030/和设置日志名字org.apache.hadoop.mapred.JobTracker
同样的也可以通过命令行的形式:
% hadoop daemonlog -setlevel jobtracker-host:50030 \
org.apache.hadoop.mapred.JobTracker DEBUG
当守护进程重新启动时,以这种方式将更改日志级别被重置,这通常是你想要的。然而,要作出永久性更改日志级别,只需更改在配置目录中的log4j.properties文件。在这种情况下,该行补充的是:
https://www.sodocs.net/doc/4c4394650.html,.apache.hadoop.mapred.JobTracker=DEBUG
得到栈迹
Hadoop守护进程面临的一个网页(Web UI中的栈),产生一个线程在守护进程的JVM所有正在运行的线程转储。例如,你可以得到一个线程从http://jobtracker-host:50030/stacks jobtracker 转储。
指标
HDFS和MapReduce的守护进程收集有关事件的信息和测量,这些统称为指标。例如datanodes收集以下指标(多):写入的字节数,块数复制,和读取从客户端的请求(包括本地和远程)的数量。
度量属于一个背景下,Hadoop的目前使用“DFS”,“mapred”,“RPC”,和“JVM”上下文。Hadoop守护进程通常收集在若干情况的指标。例如,datanodes收集“DFS”,“RPC”,和“JVM”上下文的指标。
一个上下文定义的出版单位,您可以选择发布“DFS”的背景下,但不是“JVM”的背景下,例如。在度量配置conf/hadoop-metrics.properties文件,默认情况下,所有的上下文配置,所以他们不公布他们的指标。这是默认的配置文件的内容(减去注释):dfs.class=org.apache.hadoop.metrics.spi.NullContext
mapred.class=org.apache.hadoop.metrics.spi.NullContext
jvm.class=org.apache.hadoop.metrics.spi.NullContext
rpc.class=org.apache.hadoop.metrics.spi.NullContext
在这个文件中的每一行配置不同的上下文,并指定类来处理这方面的指标。该类必须执行MetricsCon文本界面,顾名思义,NullContext类既不公布,也不更新指标。
其他MetricsCon的执行将在下面部分讲述。
文件上下文
FileContext写入指标到本地文件。该指标暴露了两个配置属性:文件名,指定文件的绝对名写信给,和期间,为文件更新之间的时间间隔(以秒计)。这两个属性是可选的;如果没有设置,的指标将被写入到标准输出每五秒钟。配置属性适用于上下文的名称,并通过追加指定上下文名称的属性的名称(由点号分隔)。例如,转储“JVM”到文件的背景下,我们改变它的配置为以下:
jvm.class=org.apache.hadoop.metrics.file.FileContext
jvm.fileName=/tmp/jvm_metrics.log
在第一行我们用FileContext改变“JVM”的上下文,第二行,我们已成立一个临时文件“JVM”背景下的文件名属性。这里两行输出的日志文件,几行分裂,以适合页面:
jvm.metrics: hostName=ip-10-250-59-159, processName=NameNode, sessionId=, gcCount=46, ?gcTimeMillis=394, logError=0, logFatal=0, logInfo=59, logWarn=1, ?memHeapCommittedM=4.9375, memHeapUsedM=2.5322647, memNonHeapCommittedM=18.25, ?
memNonHeapUsedM=11.330269, threadsBlocked=0, threadsNew=0, threadsRunnable=6, ?threadsTerminated=0, threadsTimedWaiting=8, threadsWaiting=13
jvm.metrics: hostName=ip-10-250-59-159, processName=SecondaryNameNode, sessionId=, ?gcCount=36, gcTimeMillis=261, logError=0, logFatal=0, logInfo=18, logWarn=4, ?memHeapCommittedM=5.4414062, memHeapUsedM=4.46756, memNonHeapCommittedM=18.25, ?
memNonHeapUsedM=10.624519, threadsBlocked=0, threadsNew=0, threadsRunnable=5, ?threadsTerminated=0, threadsTimedWaiting=4, threadsWaiting=2
为了调试FileContext在本地系统非常有用,但是在大的并且输出文件遍布的云集就不适用了,如果还这样分析就变得很困难。
GangliaContext
GangliaContext(https://www.sodocs.net/doc/4c4394650.html,/)是一个开源的分布式监控系统非常大型集群。它的目的是在每个节点上施加在非常低的资源开销集群。使用Ganglia本身收集的指标,如CPU 和内存使用;通过使用GangliaContext,你可以注入Hadoop的指标到Ganglia。GangliaContext 有一个必需的属性,服务器,这需要一个空格和/或Ganglia的服务器主机端口对逗号分隔的列表。有关配置的一步细节可以找到这方面的Hadoop wiki的。有关的信息种类,你可以得到神经节的味道,见图10-2,这显示jobtracker的队列中任务的数量如何随着时间的推移而变化。
NullContextWithUpdateThread
FileContext和GangliaContext都将指标推到外部系统。然而,一些监测系统,特别是JMX 的需要得到Hadoop的指标。NullContextWithUpdateThread是专门为此设计的。同NullContext 一样,它并没有公布任何的指标,但除了它运行一个计时器,定期更新存储在度量内存。当他们是由另一系统获取时是确保指标是最新的。
MetricsContext实现NullContext以外的所有执行此更新功能(和他们都暴露一段时间,默认为五秒),所以你需要的属性使用NullContextWithUpdateThread只有你是不是使用其他收集度量输出。例如,如果您使用GangliaContext,然后它会确保指标更新,所以你就可以使用除了没有进一步的配置JMX指标体系。JMX是在接下来会有更详细讨论。
复合环境
CompositeContext允许你输出相同的多个上下文设置,比如一个FileContext和GangliaContext等。配置需要一点技巧,并最好通过一个例子所示:
jvm.class=https://www.sodocs.net/doc/4c4394650.html,positeContext
jvm.arity=2
jvm.sub1.class=org.apache.hadoop.metrics.file.FileContext
jvm.fileName=/tmp/jvm_metrics.log
jvm.sub2.class=org.apache.hadoop.metrics.ganglia.GangliaContext
jvm.servers=ip-10-250-59-159.ec2.internal:8649
arity属性是用来指定子上下文的数量,在这种例子,有两个。每个子上下文属性名称修改,有部分指定子上下文的数量,因此jvm.sub1.class和jvm.sub2.class。
JA V A管理拓展
Java管理扩展(JMX)是一个标准的Java API,用于监测和管理应用。Hadoop包括几个
管beans(MBean),其中公开Hadoop的度量知道JMX的应用程序。有公开度量的MBean在“DFS”和“RPC”的背景下,但没有“mapred”的背景下(在这段时间写),或“JVM”的背景下(如JVM本身的公开组更加丰富的JVM度量)。MBean在表10-3中列出:
JDK有一个叫JConsole工具可以用来观测MBean在JVM中的运行。浏览Hadoop指标非常有用,如表10-3.
许多第三方监控和报警系统(比如Nagios或Hyperic公司)可以查询的MBean,JMX自然的方式来从现有的监测系统监控您的Hadoop集群。然而,您需要启用远程访问JMX,选择适合您的群集的安全级别。这里的选项包括密码验证,SSL连接和SSL客户端认证。参见官方的Java配置这些选项的深入指导文件。
启用远程访问JMX的所有选项包括设置Java系统属性,我们的Hadoop通过编辑conf
/hadoop- env.sh文件完成的。以下配置设置显示如何启用密码验证的远程访问JMX的NameNode的(使用SSL禁用)。这个过程是非常类似Hadoop守护进程:
export HADOOP_NAMENODE_OPTS="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.password.file=$HADOOP_CONF_DIR/jmxremote.pass word
-Dcom.sun.management.jmxremote.port=8004 $HADOOP_NAMENODE_OPTS"
在纯文本jmxremote.password文件列出了的用户名和密码;JMX文档已经对这个文件的格式
更严格。有了这个配置,我们可以使用JConsole浏览遥控器上的MBean的名称,节点。另外,我们可以使用许多JMX工具之一来检索MBean属性值。这里是一个使用“jmxquery”命令行工具(和Nagios的例子插件,从https://www.sodocs.net/doc/4c4394650.html,/p/jmxquery/)检索的数量复制块:% ./check_jmx -U service:jmx:rmi:///jndi/rmi://namenode-host:8004/jmxrmi -O \
hadoop:service=NameNode,name=FSNamesystemState -A UnderReplicatedBlocks \
-w 100 -c 1000 -username monitorRole -password secret
JMX OK - UnderReplicatedBlocks is 0
这个命令在端口8004建立一个NameNode-host的JMX RMI和验证使用给定的用户名和密码。读取对象名Hadoop:service=NameNode,name=FSNamesystemState的UnderReplicatedBlocks的属性,并打印出其值在控制台上。#- w和- c选项指定警告和临界值水平:这些相应的值通常取决于经营一段时间后一个集群。像Nagios的预警系统,共同使用Ganglia的结合监测Hadoop集群。Ganglia是为有效地收集了大量的好指标和图形,而Nagios和类似的系统在发的送警报时,在任何一个较小的指标达到临界值。
维护
常规管理过程
元数据备份
如果NameNode的固定元数据丢失或损坏,整个文件系统呈现无法使用,所以这些文件备份是至关重要的。您应该保留不同年龄段的(一小时,一天,一个星期,一个月的时间,说的)的多个副本防止崩溃,无论是在NameNode复制上副本本身或运行现场文件。一个简单的方法来进行备份是编写一个脚本来定期归档二级Namenode会previous.checkpoint子目(目录下的定fs.checkpoint.dir财产)到异地的位置。脚本应该额外测试副本的完整性。这可以通过启动本地的NameNode守护和验证,它已成功读取的fsimage和编辑文件到NameNode
的日志,例如,扫描相应的成功消息)*
数据备份
虽然HDFS是设计可靠地存储数据,数据可能会丢失,就像在任何存储系统,从而备份策略是至关重要的。随着大数据量Hadoop数据要存储,决定什么样的数据要备份,以及在哪里存储,是一个挑战。存储的关键是要优先考虑你的数据。最高优先级的数据是那些不能再生的和关键的业务数据;然而有些数据再生很简单,或基本上是一次性的,因为它是有限的商业价值,是最低的优先级,你也可以选择不作这一类的数据的备份。
在HDFS中对用户目录有个规定是很常见的。例如,他们可以拥有的空间配额,每晚进行备份。无论什么政策,确保你的用户知道它是什么,让他们知道会发生什么。
distcp是理想备份到其他HDFS集群(最好运行由于不同版本的软件,以防止损失在HDFS 中的错误)或者其他的Hadoop文件系统(如S3或KFS)的工具,因为它可以并行复制文件。或者你可以聘请一个完全不同的存储系统,用于备份,使用一从HDFS中导出数据的方式描述在第47页上“Hadoop的文件系统”。
调试和解除节点
作为一个Hadoop集群的管理员,您不定时的将需要添加或删除节点。例如,要成长到群集存储,新的委员会节点。相反,有时你可能想收缩集群,这样做,你退役节点。如果是,它有时可能要取消节点行为不端的,也许是因为它没有比它应该更经常或表现明显减慢。
节点正常运行的datanode和tasktracker,都是典型委托或串联退役。
调试新节点
虽然调试一个新的节点可以作为简单配置hdfssite.xml文件指向Namenode和mapred site.xml文件指向作业跟踪和启动datanode和jobtracker守护进程,它通常最好能有授权节点列表。
允许任何机器连接到Namenode和行为作为datanode,这是一个潜在的安全风险,因为机器可能会获得对数据的访问,这是未经允许的。此外,因为这样的机器不是一个真正的datanode,它不受你的控制,可能随时停止,造成潜在的数据丢失。(想像一下发生,如果大量的这些节点连接,一个数据块仅在“外星人”的节点出现?)通过不配置,这种情况即使在防火墙内也是有风险,因此datanodes应当在产生集群中清晰的管理。
Datanodes被允许连接到在一个文件中指定的Namenode,这个文件的名称由dfs.hosts属性决定。该文件驻留在NameNode的本地文件系统,它包含每个datanode的路线,指定的网络地址(如报告datanode,你可以看到的NameNode的Web用户界面)。如果您需要指定一个datanode多个网络地址,把他们放在一个线上,由空格分隔。
同样,TaskTracker可能会连接到在一个文件中指定的jobtracker,这个文件的名称由mapred.hosts属性定义。在大多数情况下,有一个共享文件,与include file相关,与dfs.hosts 和mapred.hosts也相关,因为节点在集群中运行datanode和tasktracker守护进程。
新节点添加到群集:
1 添加新节点的网络地址包含文件。
2 更新的Namenode会使用这个新的设置允许datanodes命令:
% hadoop dfsadmin- refreshNodes
3 更新与新节点的奴隶文件,使他们在未来包括operations执行Hadoop的控制脚本。
4 开始新的datanodes。
5 重新启动的MapReduce集群。?
6 检查新datanodes的TaskTracker出现在Web UI。HDFS上不会移动块从老datanodes
新datanodes平衡群集。
要做到这一点,你应该运行284页上的“平衡器”的平衡器。
解除旧节点
虽然HDFS是用来解决datanode失败的,这并不意味着可以仅仅终止datanodes而不对系统产生不良的影响。例如,一个3层复制,如果同时关闭上下三层的datanodes且它们在不同的机架上,你失去的数据机会是非常高的。解除datanodes是告知你想重复利用的节点的Namenode,这样在datanodes关闭之前它可以复制到其他datanodes块。同TaskTracker 相比,Hadoop是更多的宽容。如果关闭的tasktracker是一个正在运行的任务,rjobtracke
通知失败并重新安排的其他任务的TaskTracker。
解除进程控制由排除文件控制,他的HDFS由dfs.hosts.exclude属性设置的,他的MapReduce由mapred.hosts.exclude 的属性指定的。通常情况下,这些属性是指到同一个文件。排除文件列出了不允许连接到群集的节点。一个tasktracker是否可以连接到jobtracker的规很简单:一个任务跟踪只有它出现在包含文件中,并且没有出现在排除文件中才连接。未指定的或空的包含文件是意味着所有的节点都在包含文件。
对于HDFS规则略有不同。如果出现一个datanode和同时包含排除文件,那么它可以连接,但只将解除。表10-4总结marizes datanodes的不同组合。至于的TaskTracker,未指定或空的包含文件中的所有节点都包括在内。
要从群集删除节点:
1 添加节点的网络地址,将退役,以排除文件。不要在这一点上,包括文件更新。
2 重新启动的MapReduce集群停止正在节点上的T askTracke解除。
3更新新设置允许datanodes NameNode的,这命令:
%hadoop dfsadmin- refreshNodes
4 转到Web UI和检查管理状态是否已经改变“解除中”。他们会开始复制他们到集群
中的其他datanodes的块..
5 当所有的datanodes报告其状态为“解除”,那么所有的块已复制。关闭解除的节点。
6 从包含文件中删除节点,并运行:
%hadoop dfsadmin- refreshNodes
7 从奴隶文件中删除节点。
升级
升级HDFS和MapReduce集群,需要认真规划。最重要的考虑是HDFS的升级。
如果文件系统的布局版本改变,那么升级将自动迁移文件系统的数据和元数据与新版本兼容的格式。至于涉及的任何程序数据迁移,会有数据丢失的风险,所以你应该确保你的数据和元数据的备份(见292页的“日常管理办法”)。
规划过程的一部分应包括,重复的用你的可遗失的数据在集群上做小的测试,这将让您熟悉的过程,自定义您的特定的群集配置和工具,也可以在生产集群上升级之前找到漏洞。测试群集也有可用来测试客户端升级的好处。
升级文件系统的布局并没有改变的集群是相当简单:安装新版本的HDFS和MapReduce集群(和客户在同一时间),关闭旧的进程,更新配置文件,然后启动新的守护程序和切换客户端使用的新数据库。这个过程是可逆的,因此回滚升级也很简单。
在升级之后,你需要执行最后两步清除工作:
?从集群中删除旧的安装配置文件
?修正代码和配置的任何过时的警告
HDFS数据和元数据升级
如果您使用刚才所描述的程序升级到新版本的HDFS预计不同的布局版本,那么
Namenode会拒绝运行。像信息下面将出现在其日志中:
File system image contains an old layout version -16.
An upgrade to version -18 is required.
Please restart NameNode with -upgrade option.
找出是否需要升级的文件系统的最可靠的方法是通过执行测试群集上进行试验。HDFS 的升级,做了一个以前版本的元数据和数据的副本。这样做升级不双群集的存储要求,作datanodes使用硬链接保持相同的两个引用(为当前和以前的版本)的数据块。这种设计使得如果您需要它可以直接回滚到以前的版本文件系统。你应该明白,在升级系统上所做的任何更改回滚完成后,都将丢失。
您可以只保留以前版本的文件系统:你不能回滚几个版本。因此,要开展另一个升级到HDFS的数据和元数据,你会需要删除以前的版本,这一过程称为完成升级。一旦升级定稿,就没有回滚到以前的版本的程序。
在一般情况下,你可以跳过版本升级时(例如,你可以升级发布0.18.30.20.0,而无需升级到一个0.19.x发行第一),但在一些情况下,您可能必须要经过中间的版本。发行说明清楚这是必需的。
您应该只尝试升级一个健康档案系统。在运行升级之前做一个完整的fsck(见第281页上的“文件系统检查(fsck)”)。作为额外的预防措施,可以保持fsck的输出,其中列出了系统中的所有文件和块的副本,所以你可以比较它与运行升级后的fsck的输出。
在升级之前清楚临时文件是非常有必要的,包括HDFS上的MapReduce文件目录和本地临时问件。
初级的已经介绍过了,当文件系统布局需要迁移时就要下面是高层次的程序升级群集:
1.确保以往任何升级完成后再执行另一升级
2.在tasktrackers关闭MapReduce并杀死任何孤进程。
3.关闭HDFS和namedata的目录备份
4.在客户端和集群安装新版本的Hadoop HDFS和MapReduce
5.启动HDFS的-upgrade选项
6.等待知道升级完成
7.检查HDFS
8.启动MapReduce
9.回滚或者完成升级
在运行升级程序,最好删除了Hadoop脚本从你的PA TH环境变量。这将迫使你要明确您正在运行的是脚本是哪个版本的。它可以方便新为新安装目录地定义两个环境变量;在下面的结构中我们定义了OLD_HADOOP_INSTALL和NEW_HADOOP_INSTALL.
开始升级执行升级运行命令:
% $NEW_HADOOP_INSTALL/bin/start-dfs.sh –upgrade
这使namenode升级它的元数据,并将以前的版本放在叫previous新目录里
${https://www.sodocs.net/doc/4c4394650.html,.dir}/current/VERSION
/edits
/fsimage
/fstime
/previous/VERSION
/edits
/fsimage
/fstime
类似的,datanodes升级它的存储目录,privious目录中保存旧的副本。
等待升级完成升级过程不是瞬间完成的,但是你可以用dfsadmin查看升级过程% $NEW_HADOOP_INSTALL/bin/hadoop dfsadmin -upgradeProgress status
Upgrade for version -18 has been completed.
Upgrade is not finalized.
检查升级这表明升级完成。在这个阶段,在文件系统你应该运行一些完整性检查(步骤7)(使用fsck检查文件和块,基本文件操作)。当你在运行,您可以选择进入安全模式的HDFS 其中一些检查(只读),以防止他人改变。
回滚升级(可选)如果您发现新版本无法正常工作,你可以选择回滚到以前的版本(步骤9)。如果你还没有最终确定了升级,这是唯一的可能。
首先,关闭新守护进程:
% $NEW_HADOOP_INSTALL/bin/stop-dfs.sh
其次,通过-rollback选项启动HDFS的新版本:
% $OLD_HADOOP_INSTALL/bin/start-dfs.sh –rollback
完成升级如果你对新版本的HDFS很满意,就可以删除以前的目录存储完成升级。这步需要在其他升级之前完成:
% $NEW_HADOOP_INSTALL/bin/hadoop dfsadmin -finalizeUpgrade
% $NEW_HADOOP_INSTALL/bin/hadoop dfsadmin -upgradeProgress status
There are no upgrades in progress.
HDFS完全升级到新版本了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define _POSIX_SOURCE 1 //POSIX 兼容源码
#define FALSE 0
#define TRUE 1
#define MAX_DEVICES 64
#define MAX_IDS 64
#define LINE_LENGTH 1128
FILE *output;
char input_fname[80]; //打印机的文件名称
FILE *input_file;
mode_t mode;
char Char; //用于单个char的处理
int display; //"-D" 项: 0-ASC,1-ASC/HEX, 2-Hex 3-dec 4-dec/asc 5-DOS text 6-UNIX text 7- strip all non-asc
int out_length; //-L 选项
int display_col; //显示列计数
int char_len;
int asc_char; //0-non-asc, 1-asc, 2-CR, 3-LF
int nospace;
int last_char; //最后一个char的类型
int get_linestring(char *file_line, char *label_name, int qty_statements, int strno);
int freadln(FILE *handle,char *outputline); //从一个文件读一行
void Process_Bufchar(); //一次处理一个在缓存中的Char
main(int Parm_Count, char *Parms[])
{
char message[90];
int start_options, in_source, done;
char *lastslash; //最后一个slash 的字符串地址
char dirname[80]; //目录名称
DIR *current_directory;
int i;
char In1, Key;
char buf[255]; //数据缓存
out_length = 80;
display = 1; //缺省值HEX/ASC 显示, 在CR, CR/LF, LF后断开
start_options=0;
in_source = 0; //缺省值,便准输出
if (Parm_Count>1) //在程序名后面如果有参数
{
start_options = 1;
strcpy(message,Parms[1]);
if (message[0]!='-') //如果是一个输入文件的名称
{
if ((input_file = fopen(Parms[1], "rb")) == NULL)
{
fprintf(stderr,"%s: Unable to open the input file %sn",Parms[0],Parms[1]);
exit(1); //发生错误退出
}
else
{
in_source = 1; //file
}
} //end 如果是一个输入文件
} //end在程序名后面如果有参数
//获得参数
if (start_options { for (i=1; i { strcpy(message, Parms[i]); if (message[0]=='-') { if ((message[1]=='D') || (message[1]=='d')) //if display option { if (message[2]=='0') display=0; if (message[2]=='1') display=1; if (message[2]=='2') display=2; if (message[2]=='3') display=3; if (message[2]=='4') display=4; if (message[2]=='5') display=5; if (message[2]=='6') display=6; if (message[2]=='7') display=7; } if ((message[1]=='L') || (message[1]=='l')) //如果有length 选项 { out_length=atoi(&message[2]); } } } } //end如果开始选项存在 done = 0; display_col=0; nospace = 1; //我们不需要space last_char=4; while (!done) { if (in_source==1) //从文件读一个字符 { if ((Char=fgetc(input_file))==EOF) { done = 1; } } else //从标准输入读一个字符 { Char=getchar(); if (Char==EOF) { done = 1; } } if (done==0) //输出这个字符到标准输出 { asc_char=0; //假设不是asc 字符 if ((Char>31) && (Char < 127)) asc_char = 1; if (Char==13) asc_char = 2; if (Char==10) asc_char = 3; switch (display) { case 0: //ASC if (asc_char < 2) char_len=1; else char_len=0; if (display_col+char_len>out_length) { putchar(10); //如果此行太长滚动 display_col=0; } putchar(Char); display_col++; if (asc_char==3) display_col=0; break; case 1: //ASC/HEX default: if (asc_char==1) char_len=1; else char_len=2; if ((display_col==0) || (last_char==4) || ((last_char==1) && (asc_char==1))) nospace=1; //dont need space else nospace=0; if (nospace==0) char_len++; //如果我们需要一个space if (display_col+char_len>out_length) { putchar(10); //如果此行太长滚动 display_col=0; if (nospace==0) { nospace=1; char_len--; } } if (nospace==0) //加一个space { putchar(' '); display_col++; } if (asc_char==1) { putchar(Char); display_col++; } else { sprintf(message,"%2x",Char); fputs(message,stdout); display_col +=2; if (asc_char==3) { putchar(10); display_col=0; } } if ((last_char==2) && (asc_char!=3)) //如果有CR 没有LF { putchar(10); display_col=0; } last_char=asc_char; break; case 2: //hex char_len=2; if (display_col==0) nospace = 1; else nospace = 0; if (nospace == 0) char_len++; //如果我们需要一个space if (display_col+char_len>out_length) { putchar(10); //如果此行太长滚动 display_col=0; if (nospace==0) { nospace=1; char_len--; } } if (nospace==0) //添加space { putchar(' '); display_col++; } sprintf(message,"%2x",Char); fputs(message,stdout); display_col +=2; break; case 5: //unix 文本–调整dos文本,在所有LF加CR if (Char==10) putchar(13); putchar(Char); break; case 6: //dos 文本–到unix, 跳过所有CR if ((last_char==2) && (asc_char !=3)) putchar(10); //if this char is not a LF and the last one was CR, need a line feed for unix if (Char!=13) putchar(Char); last_char=asc_char; break; case 3: //decimal char_len=3; if (display_col==0) nospace = 1; else nospace = 0; if (nospace == 0) char_len++; //如果我们需要一个space if (display_col+char_len>out_length) { putchar(10); //如果此行太长滚动 display_col=0; if (nospace==0) { nospace=1; char_len--; } } if (nospace==0) //添加一个space { putchar(' '); display_col++; } sprintf(message,"%3d",Char); fputs(message,stdout); display_col +=2; break; case 4: //decimal asc if (asc_char==1) char_len=1; else char_len=3; if ((display_col==0) || (last_char==4) || ((last_char==1) && (asc_char==1))) nospace=1; //dont need space else nospace=0; if (nospace==0) char_len++; //如果我们需要一个space if (display_col+char_len>out_length) { putchar(10); //如果此行太长滚动 display_col=0; if (nospace==0) { nospace=1; char_len--; } } if (nospace==0) //add a space { putchar(' '); display_col++; } if (asc_char==1) { putchar(Char); display_col++; } else { sprintf(message,"%3d",Char); fputs(message,stdout); display_col +=2; if (asc_char==3) { putchar(10); display_col=0; } } if ((last_char==2) && (asc_char!=3)) //如果有CR 没有 LF { putchar(10); display_col=0; } last_char=asc_char; break; case 7: //跳过所有得non-asc 字符转到Unix 文件(除了ASC 和LF) if ((asc_char==1) || (asc_char==3)) putchar(Char); break; } //end of switch display } //end of if not done } //end of while not done } //end of main