Apache Hadoop2.0之HDFS均衡操做分析

1 HDFS均衡操做原理

HDFS默认的块的副本存放策略是在发起请求的客户端存放一个副本,若是这个客户端在集群之外,那就选择一个不是太忙,存储不是太满的节点来存放,第二个副本放在与第一个副本相同的机架可是不一样节点上,第三个放在与第二个和第一个副本不一样的机架上,原则是尽可能避免在相同的机架上放太多的副本。java

随着时间的推移,在各个DataNode节点上的数据块会分布的愈来愈不均衡。若是集群不均衡的程度很严重,会下降Mapreduce的使用性能,致使部分DataNode节点相对而言变得更加繁忙。因此,应该尽可能的避免出现这种状况。node

HDFS的 Balancer 类,是为了实现HDFS的负载调整而存在的。Balancer类是以一个独立的进程存在的,能够独立的运行和配置。它NameNode节点进行通讯,获取各个DataNode节点的负载情况,从而进行调整DataNode上的Block的分布。主要的调整其实就是一个操做,将一个数据块从一个服务器搬迁到另外一个服务器上。Balancer会向相关的目标 DataNode 节点  发出一个DataTransferProtocol.OP_REPLACE_BLOCK  消息,接收到这个消息的DataNode节点,会将从源DataNode节点传输来的数据块写入本地,写成功后,通知NameNode,删除源DataNode上的同一个数据块,直到集群达到均衡为止,即每一个DataNode的使用率(该节点已使用的空间和空间容量之间的百分比值)和集群的使用率(集群中已使用的空间和集群的空间容量之间的百分比值)很是接近,差距不超过均衡时给定的阈值。linux

其中,一个块是否能够被移动,要知足三个条件:web

(1)正在被移动或者已经被移动的块,不会重复移动apache

(2)一个块若是在源节点和目标节点上都有其副本,则此块不会被移动;缓存

(3)移动不会减小一个块所在的机架的数目;服务器

可见,因为上述等条件的限制,均衡操做并不能使得HDFS达到真正意义上的均衡,它只能是尽可能的减小不均衡。网络

均衡操做依靠一个均衡操做服务器、NameNode的代理和DataNode来实现,其逻辑流程以下:并发

其中,socket

Step1:Rebalance Server从Name Node中获取全部的Data Node状况,即每个Data Node磁盘使用状况;

Step2: Rebalance Server计算哪些Dataode节点须要将数据移动,哪些Dataode节点能够接受移动的块数据,而且从NameNode中获取须要移动的数据分布状况;

Step3: Rebalance Server计算出来能够将哪一台Dataode节点的block移动到另外一台机器中去;

Step四、五、6:须要移动block的Dataode节点将数据移动到目标DataNode节点上去,同时删除本身节点上的block数据;

Step7: Rebalance Server获取到本次数据移动的执行结果,并继续执行这个过程,一直到没有数据能够移动或者HDFS集群以及达到了平衡的标准为止;

在step2中,HDFS会把当前的DataNode节点根据阈值的设定状况划分到四个链表中:

(1)over组:此组中的DataNode的均知足

DataNode_usedSpace_percent  > Cluster_usedSpace_percent + threshold;

(2)above组:此组中的DataNode的均知足

Cluster_usedSpace_percent + threshold > DataNode_ usedSpace _percent  > Cluster_usedSpace_percent;

 (3)below组:此组中的DataNode的均知足

Cluster_usedSpace_percent > DataNode_ usedSpace_percent  > Cluster_ usedSpace_percent – threshold;

 (4)under组:此组中的DataNode的均知足

Cluster_usedSpace_percent – threshold > DataNode_usedSpace_percent;

    用一个示例图表示:

在移动块的时候,会把over组和above组中的块向below组和under组移动,直到均衡状态或者达到均衡退出的条件为止。

总得来讲,均衡操做的步骤能够分为4步:

(1)从namenode获取datanode磁盘使用状况;

(2)计算哪些节点须要把哪些数据移动到哪里;

(3)分别移动,完成后删除旧的block信息;

(4)循环执行,直到达到平衡标准;

2 HDFS均衡操做的启动

使用HDFS的balancer命令,能够配置一个Threshold来平衡每个DataNode磁盘利用率。命令以下:

start-balancer.sh -threshold 8

运行以后,会有Balancer进程出现:

 

上述命令设置了Threshold为8%,那么执行balancer命令的时候,首先统计全部DataNode的磁盘利用率的均值,而后判断若是某一个DataNode的磁盘利用率超过这个均值Threshold,那么将会把这个DataNode的block转移到磁盘利用率低的DataNode,这对于新节点的加入来讲十分有用。Threshold的值为1到100之间,不显示的进行参数设置的话,默认是10。

范围超出以后,会有异常抛出:

java.lang.IllegalArgumentException: Number out of range: threshold = 0.07

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Cli.parse(Balancer.java:1535)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Cli.run(Balancer.java:1510)

        at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)

        at org.apache.hadoop.hdfs.server.balancer.Balancer.main(Balancer.java:1582)

2012-12-19 16:28:33,299 ERROR org.apache.hadoop.hdfs.server.balancer.Balancer: Exiting balancer due an exception

java.lang.IllegalArgumentException: Number out of range: threshold = 110.0

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Cli.parse(Balancer.java:1535)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Cli.run(Balancer.java:1510)

        at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)

        at org.apache.hadoop.hdfs.server.balancer.Balancer.main(Balancer.java:1582)

若是参数值设置的越小,花费的时间就越长。使用此命令时,会反复的从磁盘使用率高的节点上,把块转移到磁盘使用率低的磁盘上,每次移动不超过10G大小,每次移动不超过20分钟。

在作均衡的时候,会对网络带宽有影响,可在配置文件中对均衡操做的带宽作限制:

<property>

    <name>dfs.balance.bandwidthPerSec</name>

    <value>1048576</value>

<description>

Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second.

    </description>

</property>

若不设置,则balance操做时,速度默认为1M/S大小。参数重启时生效。不容许在集群中使用多个均衡同时操做。

3 HDFS均衡操做的退出

除了在命令行直接使用stop-balancer.sh脚原本执行退出均衡操做以外,当发生如下几种状况时,当前执行的均衡操做也会退出:

(1)集群已经达到均衡状态;

(2)没有块能够再被移动;

(3)连续五次迭代操做时没有块移动;

(4)和NameNode通讯时出现IOException;

(5)另一个均衡操做启动;

4 实例分析

均衡操做以前DataNode节点块分布状况:

 

在sbin目录下执行命令./start-balancer.sh -threshold 5

均衡过程当中:

开始作均衡操做时,会有以下日志打印出:

2012-12-28 10:08:55,667 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Using a threshold of 5.0

2012-12-28 10:08:55,668 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: namenodes = [hdfs://goon]

2012-12-28 10:08:55,669 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: p         = Balancer.Parameters[BalancingPolicy.Node, threshold=5.0]

其中会标明对哪些nameservice进行均衡,同时对输入的参数进行说明,默认的策略是BalancingPolicy.Node,表示均衡的对象是DataNode,不然是对块池作均衡。

以后,会计算须要移动的块,移动的字节数,块的源地址和目标地址:

2012-12-28 10:08:57,200 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: 1 over-utilized: [Source[10.28.169.126:50010, utilization=25.807874799394025]]

2012-12-28 10:08:57,200 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: 1 underutilized: [BalancerDatanode[10.28.169.122:50010, utilization=9.395091359283992]]

2012-12-28 10:08:57,201 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Need to move 2.75 GB to make the cluster balanced.

2012-12-28 10:08:57,202 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Decided to move 2.46 GB bytes from 10.28.169.126:50010 to 10.28.169.122:50010

2012-12-28 10:08:57,203 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Will move 2.46 GB in this iteration

此时:

 

刚开始均衡操做时,其进程所占资源:

 

同时,能够观察到会有块的移动,从datanode0移动到sdc2和Tdatanode0,在NN会有以下日志(hadoop-hdfs-balancer-Tdatanode0.log):

2012-12-28 10:08:57,724 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Moving block 365766470964968392 from 10.28.169.126:50010 to 10.28.169.122:50010 through 10.28.169.225:50010 is succeeded.

2012-12-28 10:08:57,724 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Moving block 7346867188539736438 from 10.28.169.126:50010 to 10.28.169.122:50010 through 10.28.169.225:50010 is succeeded.

2012-12-28 10:08:57,724 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: Moving block -6882244909405313690 from 10.28.169.126:50010 to 10.28.169.122:50010 through 10.28.169.225:50010 is succeeded.

因为在Balancer类中对线程池作了限制,

final static private int MOVER_THREAD_POOL_SIZE = 1000;

因此最多能够有1000个线程并发块移动操做,可是向一个DN进行移动块时,最多5个块并发移动。

因为机器资源的限制,当均衡操做建立的线程数量达到900多的时候,就没法再建立线程,并有以下错误:

2012-12-28 10:19:32,905 WARN org.apache.hadoop.hdfs.server.balancer.Balancer: Dispatcher thread failed

java.lang.OutOfMemoryError: unable to create new native thread

        at java.lang.Thread.start0(Native Method)

        at java.lang.Thread.start(Thread.java:640)

        at java.util.concurrent.ThreadPoolExecutor.addIfUnderCorePoolSize(ThreadPoolExecutor.java:703)

        at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:652)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$PendingBlockMove.scheduleBlockMove(Balancer.java:402)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$PendingBlockMove.access$3500(Balancer.java:236)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Source.dispatchBlocks(Balancer.java:746)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Source.access$2000(Balancer.java:591)

        at org.apache.hadoop.hdfs.server.balancer.Balancer$Source$BlockMoveDispatcher.run(Balancer.java:598)

        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)

        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

        at java.util.concurrent.FutureTask.run(FutureTask.java:138)

        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

        at java.lang.Thread.run(Thread.java:662)

查看均衡操做所产生的线程会被阻塞:

Thread 15688: (state = BLOCKED)

 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Interpreted frame)

 - java.util.concurrent.locks.LockSupport.park(java.lang.Object) @bci=14, line=156 (Interpreted frame)

 - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await() @bci=42, line=1987 (Interpreted frame)

 - java.util.concurrent.LinkedBlockingQueue.take() @bci=29, line=399 (Interpreted frame)

 - java.util.concurrent.ThreadPoolExecutor.getTask() @bci=78, line=947 (Interpreted frame)

 - java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=18, line=907 (Interpreted frame)

 - java.lang.Thread.run() @bci=11, line=662 (Interpreted frame)

Thread 15687: (state = BLOCKED)

 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Interpreted frame)

 - java.util.concurrent.locks.LockSupport.park(java.lang.Object) @bci=14, line=156 (Interpreted frame)

 - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await() @bci=42, line=1987 (Interpreted frame)

 - java.util.concurrent.LinkedBlockingQueue.take() @bci=29, line=399 (Interpreted frame)

 - java.util.concurrent.ThreadPoolExecutor.getTask() @bci=78, line=947 (Interpreted frame)

 - java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=18, line=907 (Interpreted frame)

 - java.lang.Thread.run() @bci=11, line=662 (Interpreted frame)

同时,因为没法建立线程,RPC通讯也会阻塞,

2012-12-28 10:37:28,710 WARN org.apache.hadoop.io.retry.RetryInvocationHandler: Exception while invoking renewLease of class ClientNamenodeProtocolTranslatorPB. Trying to fail over immediately.

2012-12-28 10:37:28,716 WARN org.apache.hadoop.io.retry.RetryInvocationHandler: Exception while invoking renewLease of class ClientNamenodeProtocolTranslatorPB after 1 fail over attempts. Trying to fail over immediately.

2012-12-28 10:37:28,721 WARN org.apache.hadoop.io.retry.RetryInvocationHandler: Exception while invoking renewLease of class ClientNamenodeProtocolTranslatorPB after 2 fail over attempts. Trying to fail over immediately.

。。。

。。。

2012-12-28 10:37:28,795 WARN org.apache.hadoop.io.retry.RetryInvocationHandler: Exception while invoking renewLease of class ClientNamenodeProtocolTranslatorPB after 14 fail over attempts. Trying to fail over immediately.

2012-12-28 10:37:28,802 WARN org.apache.hadoop.io.retry.RetryInvocationHandler: Exception while invoking class org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.renewLease. Not retrying because failovers (15) exceeded maximum allowed (15)

java.io.IOException: Failed on local exception: java.io.IOException: Couldn’t set up IO streams; Host Details : local host is: “Tdatanode0/10.28.169.126″; destination host is: “sdc1″:9000;

        at org.apache.hadoop.net.NetUtils.wrapException(NetUtils.java:760)

        at org.apache.hadoop.ipc.Client.call(Client.java:1168)

        at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:202)

        at $Proxy11.renewLease(Unknown Source)

        at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.renewLease(ClientNamenodeProtocolTranslatorPB.java:452)

        at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)

        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

        at java.lang.reflect.Method.invoke(Method.java:597)

        at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:164)

        at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:83)

        at $Proxy12.renewLease(Unknown Source)

        at org.apache.hadoop.hdfs.DFSClient.renewLease(DFSClient.java:613)

        at org.apache.hadoop.hdfs.LeaseRenewer.renew(LeaseRenewer.java:411)

        at org.apache.hadoop.hdfs.LeaseRenewer.run(LeaseRenewer.java:436)

        at org.apache.hadoop.hdfs.LeaseRenewer.access$700(LeaseRenewer.java:70)

        at org.apache.hadoop.hdfs.LeaseRenewer$1.run(LeaseRenewer.java:297)

        at java.lang.Thread.run(Thread.java:662)

Caused by: java.io.IOException: Couldn’t set up IO streams

at org.apache.hadoop.ipc.Client$Connection.setupIOstreams(Client.java:640)

        at org.apache.hadoop.ipc.Client$Connection.access$1700(Client.java:220)

        at org.apache.hadoop.ipc.Client.getConnection(Client.java:1217)

        at org.apache.hadoop.ipc.Client.call(Client.java:1144)

        … 15 more

Caused by: java.lang.OutOfMemoryError: unable to create new native thread

        at java.lang.Thread.start0(Native Method)

        at java.lang.Thread.start(Thread.java:640)

        at org.apache.hadoop.ipc.Client$Connection.setupIOstreams(Client.java:633)

        … 18 more

对每一个NameNode都会尝试两次链接 set up IO streams,周期性的进行链接请求,即NN1链接不成功(尝试链接2次),而后就去尝试链接NN2(若尝试链接2次,不成功,就再去链接NN1),每次尝试链接NN后,都会有15次的更新租约尝试,固然,链接不上NN,租约更新也是失效的。

同时,因为此均衡是在NN上操做的,此NN节点会出现僵死状态(在NN上进行均衡仅为测试用,真正使用时不会在NN上),经过web不能访问,由于操做不能再建立新的线程。而且,若是当前是在active节点上进行的操做,并且在配置文件中配置了容许HA自动切换,那么此时会发生HA自动切换,即当前的standby节点变为active节点。

能够在linux下更改参数进行扩大线程建立的数量:

更改以前:

 

经过命令ulimit -u 65535临时修改,或者经过修改配置文件永久修改:/etc/security/limits.conf

 

同时也能够修改栈空间所占的大小,默认是10240字节,能够经过ulimit -s 1024修改成1024字节,减小每一个堆栈的使用空间,也能够增长线程的数量。

另外,在均衡过程当中,Balancer的内存使用状况以下:

 

所占内存大概是140M左右。在运行过程当中,会产生一些垃圾文件,由于节点硬件的限制,因此必须对缓存进行清理:

 

若出现socket链接异常,则块移动失败,则会提示:

2012-12-21 13:10:42,915 WARN org.apache.hadoop.hdfs.server.balancer.Balancer: Error moving block -5503762968190078708 from 10.28.169.225:50010 to 10.28.169.122:50010 through 10.28.169.225:50010: Connection reset

均衡以后:

当出现日志:

2012-12-28 12:20:00,430 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/10.28.169.122:50010

2012-12-28 12:20:00,431 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/10.28.169.225:50010

2012-12-28 12:20:00,431 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/10.28.169.126:50010

2012-12-28 12:20:00,431 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: 0 over-utilized: []

2012-12-28 12:20:00,431 INFO org.apache.hadoop.hdfs.server.balancer.Balancer: 0 underutilized: []

均衡操做结束,由于Over组没有DataNode,Under组也没有DataNode,此时:

 

在均衡操做以前:        clusterAvg1

               =集群dfs已使用空间/集群总空间

               =(12.7+12.19+4.62)/(49.22+49.22+49.22)

               =19.99%

咱们在作均衡时所设定的阈值为5,即百分之5,clusterAvg1-5%=14.99%,clusterAvg1+5%=24.99%,而Tdatanode0的空间使用率是25.81%,超过 24.99% ,属于over节点,sdc2的空间使用率是9.4%,低于14.99%,属于under节点,datanode0的空间使用率是24.76%,高于14.99%可是低于24.99%,属于above节点,符合均衡操做的发生条件。

集群的空间平均使用率为:   clusterAvg2

               =集群dfs已使用空间/集群总空间

               =(12.7+11.46+8.91)/(49.22+49.22+49.22)

               =22.41%

咱们在作均衡时所设定的阈值为5,即百分之5,clusterAvg2-5%=17.41%,clusterAvg2+5%=27.41%,全部的DN的空间使用率都在17.41%–27.41%中间,说明集群已经达到均衡状态。

 

转载:http://www.tuicool.com/articles/uaaEve

相关文章
相关标签/搜索