dfs.datanode.failed.volumes.toleratedとdatanodeのdecommission

HDFSにはdfs.datanode.failed.volumes.toleratedという設定項目があります。defaultは0。

<property>
  <name>dfs.datanode.failed.volumes.tolerated</name>
  <value>0</value>
  <description>The number of volumes that are allowed to
  fail before a datanode stops offering service. By default
  any volume failure will cause a datanode to shutdown.
  </description>
</property>

内容は下記に詳しいです。

By default, the failure of a single dfs.data.dir will cause the HDFS DataNode process to shut down, which results in the NameNode scheduling additional replicas for each block that is present on the DataNode. This causes needless replications of blocks that reside on disks that have not failed.

To prevent this, you can configure DataNodes to tolerate the failure of dfs.data.dir directories; use the dfs.datanode.failed.volumes.tolerated parameter in hdfs-site.xml. For example, if the value for this parameter is 3, the DataNode will only shut down after four or more data directories have failed. This value is respected on DataNode startup; in this example the DataNode will start up as long as no more than three directories have failed.

https://ccp.cloudera.com/display/CDHDOC/CDH3+Deployment+on+a+Cluster#CDH3DeploymentonaCluster-ConfiguringToleranceforLocalStorageDirectoryFailureinHDFSandMapReduce

どういうことかっていうとdfs.data.dirに複数のディレクトリを指定することが多いと思います。各ディレクトリ毎にパーティションが切ってあって物理的なディスクに対応しているような状況があると思います。

例えば/data1〜/data10まであるとして/data1に障害が起きるとdefaultの挙動ではdatanodeは停止します。/data2〜/data10までは問題無いにも関わらずです。
しかしdfs.datanode.failed.volumes.toleratedに1以上の値を設定するとそれを回避できます。

例えばdfs.datanode.failed.volumes.toleratedに1を設定すると2つ以上のディレクトリに障害が発生しない限りはdatanodeは動き続けます。
つまりdfs.datanode.failed.volumes.toleratedで設定した値よりも大きい数分だけ障害が発生しない限りはdatanodeは動き続けるというわけです。

ちなみにdatanodeのログにはこんな感じの警告がでます。

WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Removing failed volume /data1/...
org.apache.hadoop.util.DiskChecker$DiskErrorException: directory is not writable: /data1/...
        at org.apache.hadoop.util.DiskChecker.checkDir(DiskChecker.java:98)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset$FSDir.checkDirTree(FSDataset.java:264)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset$FSVolume.checkDirs(FSDataset.java:502)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset$FSVolumeSet.checkDirs(FSDataset.java:745)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset.checkDataDir(FSDataset.java:1991)
        at org.apache.hadoop.hdfs.server.datanode.DataNode.checkDiskError(DataNode.java:828)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset.validateBlockFile(FSDataset.java:1832)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset.getBlockFile(FSDataset.java:1067)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset.getLength(FSDataset.java:1035)
        at org.apache.hadoop.hdfs.server.datanode.FSDataset.getVisibleLength(FSDataset.java:1045)
        at org.apache.hadoop.hdfs.server.datanode.BlockSender.<init>(BlockSender.java:94)
        at org.apache.hadoop.hdfs.server.datanode.BlockSender.<init>(BlockSender.java:81)
        at org.apache.hadoop.hdfs.server.datanode.DataXceiver.copyBlock(DataXceiver.java:529)
        at org.apache.hadoop.hdfs.server.datanode.DataXceiver.run(DataXceiver.java:120)
        at java.lang.Thread.run(Thread.java:662)

ただ障害が起きたディレクトリが復旧した場合に再度そこに書き込むようにするにはdatanodeを再起動しないとだめっぽいですね。


この辺のslave nodeに障害が起きた場合の対応ってみなさんどんな感じなんでしょうねえ。

例えばノードのdecommissionなら本来正しい手順は下記になると思います。
HDFSでMissing blocksが出た場合、DataNodeに問題があって外したい場合の対応メモ - たごもりすメモ

ただこれをやると時間がすごくかかります。

1ノードぐらいならdatanodeを停止して対応することが多い気がします。てか僕はそうでした。
この場合複製数が不足しているブロックが存在することになりますがまあ許容範囲な気がします。
ただ3ノード以上同時に障害が発生している状況で障害が起きたdatanodeをすべて停止してしまうとdfs.replicationが3だったらデータロストにつながるでしょう。

まあこの場合も1ノードのdatanodeを停止して復旧したらhadoop fsckで Under-replicated blocksが0になるまで待ってから
次の障害ノードのdatanodeを停止して、、、というように順番にやればexcludeファイルを用いたdecommissionをしなくてもいけると思います。てかさっきまでそういうことやってました。。。

というような個人的経験則からいうとexcludeファイルを用いたdecommissionする機会って実はそんなに無いような気がしていますがどうなんでしょう。
僕は過去1回だけやりましたね。このときは障害ではなくクラスター統合でしたね。