HDFSのデータ構造 | Hadoop Advent Calendar 2016 #03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、小澤です。 この記事はHadoop Advent Calendar 3日目のものとなります。

前回はMapReduce応用編ということで、MapとReduce以外の処理を制御する方法を紹介しました。
今回はHadoopを構成するコンポーネントであるHDFSについて記載させていただきます。

HDFSとは

HDFSとはHadoop Distributed File Systemの略で、Hadoop上で利用される分散ファイルシステムとなります。 Hadoopを特徴付ける一つの要素となっており、通常のファイルシステムとは異なる点がいくつかあるためその仕組みと注意点について書かせていただこうかと思います。

Data Locality

HDFSの一番大きな特徴としてはこのData Localityになります。 Hadoop上では、ジョブが実行された際にそれを処理するためのノードとデータを保持しておくためのノードに区別がありません。

これはどういうことかというと、分散された処理がHadoop上のどのノードで実行されるかについては利用者側からは意識しなくてもいい状態になっています。 実際に処理を実行する際にデータが蓄積されたノード群と処理を行うノード群が分かれている場合だと、必ずネットワークをまたいでのデータ転送を行わなければ実際の処理が実行できない状態になります。

HDFSではこの2つが分かれていないことによって、実際のデータを保持しているノードで処理を実行するということが可能になります。 これによって、データは自分自身のローカル環境にあるものから取り出せば良いことになり、ネットワーク転送が発生しないことになります。

ただし、実際にはデータを持っているノードがすでに他の処理を行っている最中でありそのノードが空くのを待つか他のノードにデータを転送して利用するかを選択しなければならない場合もあります。 その場合、データセンターの同じラックで処理を行うなどネットワーク上で近い位置にある場所を利用するといった仕組みも存在しています。

Replicationとデータサイズ

次にReplicationについて説明します。 これ自体はなんら難しいことはなく、単純に全く同じデータを複数箇所で保持する仕組みとなります。

デフォルトでのReplication数は3となっており、これは実際のデータサイズに対して3倍のディスク容量が必要となることを示しています。 HDFS上には大規模なデータが置かれることが想定されるため、この実際のデータの3倍となるということは意識しておかなければ「見積もっていたディスクサイズでは全然足りない」という事態が起こりかねないので注意してくださいい。

HDFSはReplicationされる全てのノードへの書き込みの完了をもってデータの書き込みが終了と判断されることと、それらが直列に行われるため、書き込みには時間がかかりますが読み込みの際の遅延などはあまり考慮しなくても大丈夫でしょう。

また、先ほどのData Localityと絡む話となりますが、 3箇所に同じデータを保持するということは最大で3箇所までData Localityを担保した処理を同時実行できる計算になります。 同様にReplication数を増やすと多くのジョブが同じデータにアクセスといった状況では対応しやすくなるかもしれません。 その場合、ディスクサイズはそれだけ余分に必要となる点には注意が必要です。

hdfs1

ブロックとブロックサイズ

HDFS上ではブクッロ呼ばれる単位でファイルを管理します。 この単位は64MBや128MBなどといった設定がなされており、このサイズがブロックサイズとなります。 特に何も指定しなければ、Hadoopの個々のノードで処理する対象の範囲はこのブロック単位で決定されるため、クラスタの個々のノードの処理能力なども含めながら検討するとよいかと思います。

このブロックサイズと実際のファイルには一つ注意点があります。 テキストファイルのように行単位で分割して分散処理可能なものであれば問題ないのですが、gzip圧縮されたファイルのようにファイル全体がないと復元できないものを考えてみます。 この場合、例えば10GBのファイルがあったとして、それが128MBのブロックごとに分割されているとすると復元するのに一度ネットワーク転送を挟んでファイル全体を1つのノードに集める必要性が生じるかもしれません。 その場合Data Localityはほぼ無いに等しい状態となってしまうため処理の開始までに非常に多くの時間がかかってしまいます。 場合によっては部分的に解答可能なインデックス付きのlzoなどを検討してもいいかもしれません。

また、最近ですとカラムナ形式のデータフォーマットをHadoop上で使うなどといった機会も増えています。 カラムナ形式だと、データの圧縮率をより高めることが可能となるため「解答してみたら想像以上に大きいデータを1つのノードで扱うことになった」といった可能性も考えられますのでその点にもご注意ください。

データのUPDATE/DELETE

HDFSは大規模にデータを蓄積するとこを主眼としています。 そのため、RDBのような行単位でのデータのUPDATEやDELETEといった操作を考慮していません。 擬似的にそれらを可能にするコマンドが存在していたり、Hiveで工夫を凝らしてACIDを実現するなどといった試みは存在していますが、基本的には"蓄積される大規模データに対するバッチ処理"がHadoopの始まりなのでそれが前提で頻繁に更新されるデータを利用する際にはそれなりの覚悟が必要と考えたほうがいいでしょう。

データを管理するNameNode

HadoopはHDFSという仕組みを利用して分散環境で効率良く処理を行うためにあちこちにデータを置いているということはご理解いただけたかと思います。 これらの分散して置かれているファイルの"どれがどこにあるか"を管理するのがNameNodeとなります。

ハードビートやブロックレポートといった仕組みでNameNodeと実際にファイルが置かれているDataNodeがやり取りすることで、 ファイルツリー全体の管理や個々のDataNodeの使用率などを管理しています。

また、Replication数が適切かの管理も行っています。 大量のコンピュータが稼働しているため、どうしてもどこかが故障している確率は高くなってしまいます。故障したノードに置いてあったファイルはReplication数が規定の数より減ってしまうため他のノードに複製する必要があります。また、逆に複製しすぎてしまう場合もあります。 そういった事態に対応するための仕組みも備わっています。 ただし、Replicationされている全てのデータが破損してしまった場合にはどうしても復元することはできませんのでその点はご注意ください。

NameNodeはファイルツリー全体の管理を行うマスターノードのため、Hadoop1系ではSPOFでした。 現在主流のHadoop2でも1つのノードが全体の管理をするという点では変わっていませんが、冗長化することが可能になっています。 ファイルやディレクトリの作成・削除といった操作をEdit Logとして出力し、Journal Nodeと呼ばれるノードがそれを受け取ると待機系のNameNodeにもそれが反映させる仕組みとなっています。

hdfs2

HDFS以外のストレージとの関係

クラウド上のでのHadoopの流れでは、AWS S3などHDFSの外にあるストレージを入力としてHadoopを利用するシーンも多くなっています。 これはHadoopの外でデータを管理するため、データ処理基盤としてのHadoopをバージョンアップさせやすい、データの一元管理がしやすい、ファイルにアクセスする権限などを設定しやすいなどのHDFSにはなかった利点が数多く存在します。 一方でData Localityは失われるため、処理を開始するまでにかかるオーバーヘッドが大きくなるという問題もあります。

ClouderaのKuduやHortonworksのOzoneなど、従来のHDFSとは違った考え方のものも出てきているため、今後どのように発展していくか非常に楽しみな領域となっています。

おわりに

今回はHDFSについて話しました。Hadoopは外から見ると1つの巨大なストレージになっているためこういったことはあまり意識しなくてもいいと考える方も多いかもしれません。 しかし、「ストレージの使い方が実は1つのパフォーマンスチューニングのポイントだった」なんてことも実際には起こりえます。 ファイルシステムのみで解決する問題ではありませんが、大規模なデータを扱い際は「いかにしてディスクIOを減らすか」が1つの大きなポイントとなるので今回のような点にも考慮してみるといいことがあるかもしれません。

明日はHDFSに関連して、Hadoop3.0からの新機能であるErasure Codingというものについて書かせていただく予定です。
ぜひ、お楽しみに!