ネームノードのヒープメモリのサイジング
このブログは「Sizing NameNode Heap Memory」ドキュメントの翻訳記事です。
各ワークロードには、ユニークにバイトを配分するプロファイルがあります。一部のワークロードではヒープメモリとガベージコレクションにデフォルトのJVMの設定を使用することができますが、他のワークロードではチューニングが必要です。このトピックでは、動的なヒープの設定によってボトルネックが発生した場合のNameNodeのJVMのサイジングに関する指針を提供します。
すべてのHadoopのプロセスは Java Virtual Machine(JVM)上で実行されます。JVMの数はデプロイモードによって異なります。
- ローカル (またはスタンドアロン)モード − デーモンは存在せず、すべてが単一のJVM上で実行されます。
- 疑似分散モード −(NameNodeデーモンなどの)各デーモンは、単一のホスト上の独自のJVM上で動作します。
- 分散モード − 各デーモンは、ホストのクラスタ全体で、独自のJVM上で動作します。
標準のNameNodeの設定では、名前空間全体に対して、1つのアクティブ(かつプライマリ)のNameNodeと、チェックポイントのための(しかしフェイルオーバーではない)Secondary NameNodeがあります。高可用性の構成では、単一障害点を防ぐため、Secondary NameNodeの代わりにスタンバイ NameNodeを使います。HDFS フェデレーションでは 、名前空間の独立した部分(またはボリューム)とパーティション化されていないブロックプールをそれぞれ管理する、複数のアクティブなNameNodeを利用可能になります。これらの構成では、各NameNodeは独自のJVMを使用します。
環境変数
HADOOP_HEAPSIZEは 、HDFS、YARN、MapReduceのような全てのHadoopプロジェクトサーバーのJVMのヒープサイズを設定します。HADOOP_HEAPSIZEは、最大のメモリ(Xmx)引数としてJVMに渡される整数です。例:
HADOOP_HEAPSIZE=1024
HADOOP_NAMENODE_OPTSはNameNodeに固有ですべてのJVMのフラグを設定します。この環境変数は指定必須です。HADOOP_NAMENODE_OPTSは、NameNodeのHADOOP_HEAPSIZEの Xmxの値を上書きします。例:
HADOOP_NAMENODE_OPTS=-Xms1024 -Xmx1024 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:+PrintTenuringDistribution -XX:OnOutOfMemoryError={{AGENT_COMMON_DIR}}/killparent.sh
HADOOP_NAMENODE_OPTSとHADOOP_HEAPSIZEは両方とも/etc/hadoop/conf/hadoop-env.shに格納されています。
ヒープメモリの使用状況の監視
ヒープメモリの使用状況は、いくつかの方法で監視することができます。
- ClouderaのManager: NameNodeのヒープメモリ使用量のチャートをご覧ください。チャートを最初から作成する必要がある場合は次のコマンドを実行します。
select jvm_max_memory_mb, jvm_heap_used_mb where roleType="NameNode"
- NameNodeのWeb UI:Summaryまでスクロールダウンして”Heap Memory Used”を探します。
- コマンドライン:ヒープダンプを生成します。
ファイルとブロック
HDFSでは、データとメタデータが分離されています。データファイルはブロックファイルに分割され、クラスタに渡ってDataNodeに複製されます。ファイルシステムの名前空間のツリーと関連するメタデータはNameNodeに格納されます。
名前空間のオブジェクトはファイルのinodeと、DataNodes上のブロックファイルを示すブロックです。これらの名前空間のオブジェクトはファイルシステムのイメージ(fsimage)として、NameNodeのメモリに格納、およびローカルにも保存されます。メタデータの更新は編集ログに書き込まれます。NameNodeの起動時またはチェックポイントが取得される際、編集ログが適用され、ログがクリアされて新しいfsimageが作成されます。
重要:NameNodeは名前空間のイメージ全体をメモリ内に保持します。独自のJVM上で動作するSecoundary NameNodeがイメージのチェックポイントを作成するときも同じです。
平均すると 、各ファイルは1.5ブロックのストレージを消費します。つまり、平均的なファイルは2つのブロックファイルに分割されます:1つは割り当てられたブロックサイズの全体を消費し、もう1つはその半分を消費します。NameNodeでは、この同じ平均的なファイルに3つの名前空間オブジェクトが必要です:ファイルのinodeが1つとブロックが2つです。
ディスクスペースと名前空間
CDHのデフォルトのブロックサイズ(dfs.blocksize)は 128 MBに設定されています。NameNode上の各名前空間のオブジェクトは約150バイトを消費します。
DataNodesでは、データファイルは消費されたディスク領域(実際のデータ長)によって測定され、必ずしも完全なブロックサイズではありません。例えば、192MBのファイルは192MBのディスク領域を使用し、ブロックサイズの整数倍は使用しません。デフォルトのブロックサイズの128 MBを使用すると、192 MBのファイルは2つのブロックファイルに分割されます:1つが128 MBのファイル、もう1つが64 MBのファイルです。NameNodeでは、名前空間のオブジェクトは、ファイルとブロックの数によって測定されます。同じ192 MBのファイルは、3つの名前空間のオブジェクト(1つのファイルinode + 2つのブロック)で表され、約450バイトのメモリを消費します。
少数のブロックに分割される大容量のファイルは、多数のブロックを生成する小さなファイル群よりも少ないメモリを消費します。128 MBの1つのデータファイルは、NameNode上で2つの名前空間オブジェクト(1つのファイルinode + 1ブロック)によって表され、約300バイトのメモリを消費します。これとは対照的に、それぞれ1 MBの128個のファイルは、256個の名前空間オブジェクト(128のファイルinode + 128ブロック)で表され、約38,400バイトを消費します。最適な分割サイズは、メモリ管理とデータローカリティの最適化のために、ブロックサイズの整数倍です 。
デフォルトでは、Cloudera Managerは 100万ブロックごとに1 GBの最大ヒープ領域を割り当てます。(ただし、1 GB未満になることは決してありません)。実際に必要とするメモリ量は、ワークロード、特に各名前空間で生成されるファイル、ディレクトリ、ブロックの数によって異なります。すべてのファイルがブロックサイズで分割されている場合は、100万ファイルごとにの1 GBを割り当てることができます。しかし、1ファイルあたり1.5ブロック(2ブロックオブジェクト)という過去の平均から考えると、100万ブロックごとに1GBのメモリになります。
重要:Clouderaは、名前空間オブジェクト、必要なブックキーピングのデータ構造、およびリモートプロシージャコール(RPC)のワークロードを考慮して、100万ブロックごとに1 GBのNameNodeののヒープ領域を推奨します。実際には、あなたのヒープ要件は、この控えめな見積もりよりも小さくなる可能性があります。
複製
デフォルトのブロック複製係数(dfs.replication)は 3です。レプリケーションはディスク領域に影響しますが、メモリ消費には影響しません。 レプリケーションは、各ブロックに必要なストレージの量を変更しますが、ブロックの数は変更しません。NameNode上の1つのブロックで表現されるDataNode上の1つのブロックファイルが3回複製されている場合は、ブロックファイルの数は3倍になりますが、ブロックの数は3倍にはなりません。
複製がオフだと、192 MBの1つのファイルは 192 MBのディスク領域と約450バイトのメモリを消費します。これらのファイルが100万件、または192 TBのデータがある場合、192 TBのディスク領域と(RPCのワークロードを考慮しない場合)450 MBのメモリが必要です:(100万inode + 200万ブロック)* 150バイト。デフォルトの複製をオンにすると、576 TBのディスク容量(192 TB * 3)が必要になりますが、メモリ使用量は同じ 450 MBのままです。ブックキーピングとRPCを考慮して、100万ブロックごとに1 GBのヒープメモリという推奨に従う場合、このシナリオでの推定値は 2GB のメモリです。(複製の有無にかかわらず)。
例
例1:使用されているNameNodeのヒープメモリの見積もり
Alice, Bob, Carlはそれぞれディスク上に1 GB (1024 MB)のデータを持っていますが、異なるサイズのファイルにスライスされています。AliceとBobはブロックサイズの積分で、最小限のメモリしか必要としないファイルを持っています。Carlはそうではなく、必要以上の名前空間オブジェクトでヒープを埋めます。
Alice:1 × 1024 MBのファイル
- 1 ファイル inode
- 8 ブロック (1024 MB / 128 MB)
合計= 9オブジェクト * 150バイト = 1350バイトのヒープメモリ
Bob:8 × 128 MBのファイル
- 8 ファイル inode
- 8 ブロック
合計 = 16オブジェクト* 150バイト = 2400バイトのヒープメモリ
Carl:1024 × 1 MBのファイル
- 1024 ファイル inode
- 1024 ブロック
合計 = 2048オブジェクト* 150バイト = 307,200バイトのヒープメモリ
例2:必要なNameNodeのヒープメモリの見積り
この例では、クラスタの容量を考慮してメモリを見積もります。値は丸められています。両方のクラスタには、物理的に4800 TB、つまり約3600万のブロックファイル(デフォルトのブロックサイズで)を保存します。複製は、これらのブロックファイルを表す名前空間のブロックの数を決定します。
Cluster A: それぞれ 24 TBの200台のホスト = 4800 TB
- ブロックサイズ = 128MB、 複製 = 1
- クラスタの容量 (MB):200 * 24,000,000 MB = 4,800,000,000 MB(4800 TB)
- ブロックごとに必要なディスク容量:ブロックあたり128 MB* 1 = ブロックごとに128 MB
- クラスタの容量(ブロック):4,800,000,000 MB / 128 MB = 36,000,000ブロック
容量は、100万のブロックあたり 1 GBのメモリを割り当てることを推奨します。Cluster A には最大 36 GB のヒープ領域が必要です。
Cluster B: それぞれ 24 TBの200台のホスト = 4800 TB
- ブロックサイズ = 128 MB、 複製 = 3
- クラスタの容量 (MB):200 * 24,000,000 MB = 4,800,000,000 MB(4800 TB)
- ブロックごとに必要なディスク容量:ブロックあたり128 MB * 3 = ブロックごとに384 MB
- クラスタの容量(ブロック):4,800,000,000 MB / 384 MB = 12,000,000ブロック
容量は、100万のブロックあたり 1 GBのメモリを割り当てることを推奨します。Cluster B には最大 12 GB のヒープ領域が必要です。
Cluster AとCluster Bの両方には同じ数のブロックファイルが保存されます。しかし、Cluster A では各ブロックは一意であり、NameNode上の1つのブロックで表されます。Cluster Bでは3分の1だけが一意で、3分の2はレプリカ(複製)です。