はじめに
Apache Hadoopにある構成プロパティの一部は、ApacheHBaseなどのクライアントに直接影響します。これらのプロパティの1つは「dfs.datanode.max.xcievers」と呼ばれ、HDFSサブプロジェクトに属します。これは、サーバー側のスレッドの数と、ある程度はデータ接続に使用されるソケットを定義します。この数値を低く設定しすぎると、クラスターの使用率を上げたり増やしたりするときに問題が発生する可能性があります。この投稿は、クライアントとサーバーの間で何が起こっているのか、そしてこのプロパティの妥当な数を決定する方法を理解するのに役立ちます。
問題
HBaseは必要なものすべてをHDFS内に保存しているため、「dfs.datanode.max.xcievers」構成プロパティによって課せられるハードな上限により、HBaseで使用できるリソースが少なすぎて、接続のいずれかの側でIOExceptionとして現れる可能性があります。これは、HBaseメーリングリスト[1]の例であり、次のメッセージが最初にRegionServer側でログに記録されました。
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient:Exception in createBlockOutputStream java.io.IOException:ストリームから読み取ることができませんでした
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient:Abandoning block blk_-5467014108758633036_595771
2008-11- 11 19:55:58,455警告org.apache.hadoop.dfs.DFSClient:DataStreamer例外:java.io.IOException:新しいブロックを作成できません。
2008-11-11 19:55:58,455警告org.apache .hadoop.dfs.DFSClient:ブロックblkのエラーリカバリ_-5467014108758633036_595771不正なデータノード[0]
2008-11-11 19:55:58,482致命的なorg.apache.hadoop.hbase.regionserver.Flusher:hlogの再生が必要です。サーバーの強制シャットダウン
これをHadoop DataNodeログと関連付けると、次のエントリが明らかになりました:
エラーorg.apache.hadoop.dfs.DataNode:DatanodeRegistration(10.10.10.53: 50010、storageID =DS-1570581820-10.10.10.53-50010-1224117842339、infoPort =50075、ipcPort =50020):DataXceiver:java.io.IOException:xceiverCount258が同時xcievers256の制限を超えています
この例では、DataNodeの「dfs.datanode.max.xcievers」の値が低いため、RegionServer全体がシャットダウンしました。これは本当に悪い状況です。残念ながら、必要な制限を計算する方法を説明する厳格なルールはありません。通常、数値をデフォルトの256から4096などに増やすことをお勧めします(参考のために[1]、[2]、[3]、[4]、[5]を参照)。これは、このプロパティをすべてのDataNodeのhdfs-site.xmlファイルに追加することによって行われます(スペルが間違っていることに注意してください):
注:構成ファイルにこの変更を加えた後、DataNodeを再起動する必要があります。
これは上記の問題に役立つはずですが、これがどのように連携して機能するか、およびHBaseがこれらのリソースで何を行っているかについてもっと知りたい場合があります。これについては、この投稿の残りの部分で説明します。ただし、その前に、この数値を単純に非常に高く設定できない理由、たとえば64Kを設定して、それで済ませることができない理由を明確にする必要があります。
上限には理由があり、それは2つあります。1つは、スレッドが独自のスタックを必要とすることです。つまり、スレッドはメモリを占有します。現在のサーバーの場合、これはデフォルトでスレッド[6]あたり1MBを意味します。つまり、4096個のDataXceiverスレッドをすべて使い切った場合、それらに対応するために約4GBのヒープが必要になります。これにより、memstoreとブロックキャッシュ、およびJVMの他のすべての可動部分に割り当てたスペースが削減されます。最悪のシナリオでは、OutOfMemoryExceptionが発生し、RegionServerプロセスがトーストされる可能性があります。このプロパティを適度に高い数値に設定しますが、高すぎないようにします。
次に、これらの多くのスレッドをアクティブにすると、CPUの負荷も増加します。すべての同時作業を処理するために発生する多くのコンテキストスイッチがあり、実際の作業のためのリソースが奪われます。メモリに関する懸念と同様に、スレッドの数が際限なく増えるのではなく、妥当な上限を提供する必要があります。これが「dfs.datanode.max.xcievers」の目的です。
Hadoopファイルシステムの詳細
クライアント側からは、HDFSライブラリがPathと呼ばれる抽象化を提供しています。このクラスは、FileSystemクラスで表される、Hadoopでサポートされるファイルシステム内のファイルを表します。抽象FileSystemクラスの具体的な実装がいくつかあります。そのうちの1つは、HDFSを表すDistributedFileSytemです。このクラスは、リモートサーバーとのすべての対話を処理する実際のDFSClientクラス、つまりNameNodeと多くのDataNodeをラップします。
HBaseなどのクライアントがファイルを開くときは、たとえば、FileSystemクラスのopen()メソッドまたはcreate()メソッドを呼び出します。ここでは最も単純なインカネーションです
public DFSInputStream open(String src)throws IOException
public FSDataOutputStream create(Path f)throws IOException
返されるストリームインスタンスは、データのブロックの読み取りと書き込みに使用されるサーバー側のソケットとスレッドを必要とするものです。これらは、クライアントとサーバー間でデータを交換するための契約の一部を形成します。さまざまなマシン間で使用されている他のRPCベースのプロトコルがありますが、この説明の目的上、それらは無視できることに注意してください。
返されるストリームインスタンスは、特殊なDFSOutputStreamまたはDFSInputStreamクラスであり、NameNodeとのすべての対話を処理して、ブロックのコピーが存在する場所と、DataNodeごとのブロックごとのデータ通信を把握します。
サーバー側では、DataNodeはDataXceiverServerのインスタンスをラップします。これは、上記の構成キーを読み取り、制限を超えると上記の例外をスローする実際のクラスです。
DataNodeが起動すると、スレッドグループが作成され、次のように前述のDataXceiverServerインスタンスが起動します。
this.threadGroup =new ThreadGroup( "dataXceiverServer");
this.dataXceiverServer =new Daemon( threadGroup、
new DataXceiverServer(ss、conf、this));
this.threadGroup.setDaemon(true); //空のときに自動破棄
DataXceiverServerスレッドはすでにスレッドグループの1つの場所を占めていることに注意してください。 DataNodeには、このグループで現在アクティブなスレッドの数を取得するためのこの内部クラスもあります。
/**ノードごとの同時受信者の数。 * /
int getXceiverCount(){
return threadGroup ==null? 0:threadGroup.activeCount();
}
クライアントによって開始されたブロックの読み取りと書き込みにより、接続が確立され、DataXceiverServerスレッドによってDataXceiverインスタンスにラップされます。このハンドオフ中に、スレッドが作成され、上記のスレッドグループに登録されます。したがって、アクティブな読み取りおよび書き込み操作ごとに、サーバー側で新しいスレッドが追跡されます。グループ内のスレッドの数が構成された最大数を超えると、上記の例外がスローされ、DataNodeのログに記録されます。
if(curXceiverCount> dataXceiverServer.maxXceiverCount){
throw new IOException( "xceiverCount" + curXceiverCount
+”は同時xcieversの制限を超えています”
+ dataXceiverServer.maxXceiverCount);
}
クライアントへの影響
ここで問題となるのは、クライアントの読み取りと書き込みがサーバー側のスレッドとどのように関連しているかということです。ただし、詳細に入る前に、DataXceiverクラスが作成されて閉じられたときにログに記録されるデバッグ情報を使用しましょう
LOG.debug( "アクティブな接続の数は次のとおりです:" + datanode.getXceiverCount());
…
LOG.debug(datanode.dnRegistration +“:アクティブな接続の数は:” + datanode.getXceiverCount());
HBaseの起動中に、DataNodeに何が記録されているかを監視します。簡単にするために、これは単一のDataNodeおよびRegionServerインスタンスを使用した疑似分散セットアップで実行されます。以下は、RegionServerのステータスページの上部を示しています。
重要な部分は「メトリクス」セクションにあり、「storefiles=22」と表示されています。したがって、HBaseに少なくとも処理するファイルがいくつもあり、先行書き込みログ用にいくつかの追加ファイルがあると仮定すると、上記のログメッセージに少なくとも22の「アクティブな接続」があることが示されます。 HBaseを起動して、DataNodeとRegionServerのログファイルを確認しましょう。
コマンドライン:
$ bin / start-hbase.sh
…
DataNodeログ:
2012-03-05 13:01:35,309DEBUGorg.apache.hadoop.hdfs.server.datanode。 DataNode:アクティブな接続の数は次のとおりです:1
2012-03-05 13:01:35,315 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS- 1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:2
12/03/05 13:01:35 INFO regionserver.MemStoreFlusher:globalMemStoreLimit =396.7m、 globalMemStoreLimitLowMark =347.1m、maxHeap =991.7m
12/03/05 13:01:39情報http.HttpServer:open()が-1になる前にwebServer.getConnectors()[0] .getLocalPort()によって返されたポート。 60030でリスナーを開く
2012-03-0513:01:40,003 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:1
12/03/05 13:01:40 INFO regionserver.HRegionServer:リージョンを開くリクエストを受信しました:-ROOT-,, 0.70236052
2012-03-05 13:01:40,882 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode :アクティブな接続の数は次のとおりです:3
2012-03-05 13:01:40,884 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448 -10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:4
2012-03-05 13:01:40,888DEBUGorg.apache.hadoop.hdfs.server。 datanode.DataNode:アクティブな接続の数は次のとおりです:3
…
12/03/0513:01:40 INFO regionserver.HRegion:Onlined -ROOT-,, 0.70236052; next sequenceid =63083
2012-03-05 13:01:40,982 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:3
2012-03-05 13 :01:40,983 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです。4
…
12/03/0513:01:41 INFO regionserver.HRegionServer:リージョンを開くためのリクエストを受信しました:.META。,, 1.1028785192
2012-03 -05 13:01:41,026 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:3
2012-03-05 13:01:41,027DEBUGorg.apache.hadoop。 hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:4
…
12/03/0513:01:41 INFO regionserver.HRegion:Onlined.META。,,1.1028785192; next sequenceid =63082
2012-03-05 13:01:41,109 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:3
2012-03-05 13 :01:41,114 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:4
2012-03-05 13:01:41,117 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:アクティブな接続の数は次のとおりです:5
12/03/05 13:01:41 INFO regionserver.HRegionServer:16のリージョンを開く要求を受信しました
12/03/05 13 :01:41 INFO regionserver.HRegionServer:リージョンを開くリクエストを受信しました:usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f。
12/03/0513:01:41 INFO regionserver.HRegionServer:リージョンを開くリクエストを受信しました:usertable、user1120311784、 1330944810191.90d287473fe223f0ddc137020efda25d。
…
2012-03-05 13:01:41,246DEBUGorg.apache.hadoop.hdfs.server.datanode。 DataNode:アクティブな接続の数は次のとおりです:6
2012-03-05 13:01:41,248 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:7
…
2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772 、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:10
2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0。 0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:9
…
12/03/0513: 01:41 INFO regionserver.HRegion:Onlined usertable、user1120311784,1330944810191.90d287473fe223f0ddc137020efda25d .; next sequenceid =62917
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable ,, 1330944810191.62a312d67981c86c42b6bc02e6ec7e3f .; next sequenceid =62916
…
12/03/0513:01:41 INFO regionserver.HRegion:Onlined usertable、user1361265841,1330944811370.80663fcf291e3ce00080599964f406ba .; next sequenceid =62919
2012-03-05 13:01:41,474 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:6
2012-03-05 13 :01:41,491 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:7
2012-03-05 13:01:41,495 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数:8
2012-03 -05 13:01:41,508 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:7
…
12/03/0513:01:41 INFO regionserver .HRegion:オンラインユーザーテーブル、user1964968041,1330944848231.dd89596e9129e1caa7e07f8a491c9734 .; next sequenceid =62920
2012-03-05 13:01:41,618 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:6
2012-03-05 13 :01:41,621 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです。7
…
2012-03-0513:01:41,829 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:7
12/03/05 13:01:41 INFO regionserver.HRegion:オンラインユーザーテーブル、user515290649,1330944849739.d23924dc9e9d5891f332c337977af83d .; next sequenceid =62926
2012-03-05 13:01:41,832 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:6
2012-03-05 13 :01:41,838 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです。7
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable、user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5d6c6c6b9f .; next sequenceid =62929
…
2012-03-0514:01:39,711 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:4
2012 -03-05 22:48:41,945 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、 ipcPort =50020):アクティブな接続の数は次のとおりです:4
12/03/05 22:48:41 INFO regionserver.HRegion:Onlined usertable、user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5d6c6c6b9f .; next sequenceid =62929
2012-03-05 22:48:41,963 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64 -50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:4
リージョンが次々に開かれる様子を見ることができますが、アクティブな接続の数が22に達することはなく、10に達することもほとんどありません。何故ですか?これをよりよく理解するには、HDFS内のファイルがサーバー側のDataXceiverのインスタンスにどのようにマッピングされるか、およびそれらが表す実際のスレッドを確認する必要があります。
Hadoop Deep Dive
前述のDFSInputStreamとDFSOutputStreamは、実際には通常のストリームの概念を取り巻くファサードです。これらは、クライアント/サーバー通信をこれらの標準Javaインターフェースにラップし、トラフィックを、現在のブロックのコピーを保持している選択されたDataNodeに内部的にルーティングします。必要に応じてこれらの接続を開いたり閉じたりする自由があります。クライアントがHDFSでファイルを読み取ると、クライアントライブラリクラスはブロック間、つまりDataNodeからDataNodeに透過的に切り替わるため、必要に応じて接続を開いたり閉じたりする必要があります。
DFSInputStreamには、DataNodeへの接続を開くDFSClient.BlockReaderクラスのインスタンスがあります。ストリームインスタンスは、read()を呼び出すたびにblockSeekTo()を呼び出します。これにより、接続がまだ存在しない場合は、接続が開かれます。ブロックが完全に読み取られると、接続が閉じられます。もちろん、ストリームを閉じると同じ効果があります。
DFSOutputStreamには、同様のヘルパークラスであるDataStreamerがあります。 nextBlockOutputStream()メソッドによって開始されるサーバーへの接続を追跡します。ブロックデータの書き込みに役立つ内部クラスがさらにありますが、簡潔にするためにここでは省略します。
ブロックの書き込みと読み取りの両方で、DataXceiverインスタンスにラップされた、サーバー側のソケットと中間データを保持するスレッドが必要です。クライアントが何をしているかに応じて、接続数はHDFSで現在アクセスされているファイルの数を中心に変動します。
上記のHBaseのなぞなぞに戻ります。開始時に最大22(およびそれ以上)の接続が表示されない理由は、リージョンが開いている間、必要なデータはHFileの情報ブロックのみであるためです。このブロックは、各ファイルに関する重要な詳細を取得するために読み取られますが、その後再び閉じられます。これは、サーバー側のリソースがすばやく連続して解放されることを意味します。残りの4つの接続を判別するのは困難です。 JStackを使用して、DataNode上のすべてのスレッドをダンプできます。この例では、次のエントリが表示されます。
「クライアント用DataXceiver / 127.0.0.1:64281[送信ブロックblk_5532741233443227208_4201]」デーモンprio=5 tid =7fb96481d000 nid =0x1178b4000 runnable [1178b3000]
java.lang.Thread.State:RUNNABLE
…
「クライアント用DataXceiver / 127.0.0.1:64172[受信ブロックblk_-2005512129579433420_4199client =DFSClient_hb_rs_10.0.0.29 、60020,1330984111693_1330984118810]”デーモンprio =5 tid =7fb966109000 nid =0x1169cb000 runnable [1169ca000]
java.lang.Thread.State:RUNNABLE
…
これらは(この例では)唯一のDataXceiverエントリであるため、スレッドグループのカウントは少し誤解を招く可能性があります。 DataXceiverServerデーモンスレッドはすでに1つの追加エントリを占めており、上記の2つと組み合わせると、3つのアクティブな接続(実際には3つのアクティブなスレッドを意味します)を考慮していることを思い出してください。ログに代わりに4が表示される理由は、終了しようとしているアクティブなスレッドからのカウントをログに記録するためです。したがって、4つのカウントがログに記録された直後は、実際には1つ少なくなります。つまり、3つになるため、アクティブなスレッドのヘッドカウントと一致します。
また、PacketResponderなどの内部ヘルパークラスは、アクティブな間、グループ内の別のスレッドを占有することに注意してください。 JStackの出力はその事実を示しており、スレッドをそのようにリストしています。
「PacketResponder0 forBlockblk_-2005512129579433420_4199」daemonprio=5 tid =7fb96384d000 nid =0x116ace000 in Object.wait ()[116acd000]
java.lang.Thread.State:TIMED_WAITING(オブジェクトモニター上)
java.lang.Object.wait(ネイティブメソッド)
org.apache.hadoop。 hdfs.server.datanode.BlockReceiver $ PacketResponder \
.lastDataNodeRun(BlockReceiver.java:779)
–ロック(org.apache.hadoop.hdfs.server.datanode.BlockReceiver $ PacketResponder)
org.apache.hadoop.hdfs.server.datanode.BlockReceiver $ PacketResponder.run(BlockReceiver.java:870)
at java.lang.Thread.run(Thread.java:680)
このスレッドは現在TIMED_WAITING状態であり、アクティブとは見なされません。そのため、DataXceiverログステートメントによって発行されるカウントには、これらの種類のスレッドは含まれていません。クライアントが送信データを送信したためにアクティブになると、アクティブなスレッド数が再び増加します。このスレッドは、クライアントとサーバーの間に個別の接続またはソケットを必要としないことに注意してください。 PacketResponderは、ブロックデータを受信し、書き込みパイプラインの次のDataNodeにストリーミングするためのサーバー側の単なるスレッドです。
Hadoop fsckコマンドには、現在書き込み用に開いているファイルを報告するオプションもあります。
$ hadoop fsck / hbase -openforwrite
FSCKはlarsgeorgeによってパス//10.0.0.29から開始されました。 hbase at Mon Mar 05 22:59:47 CET 2012
……/hbase/.logs/10.0.0.29,60020,1330984111693/10.0.0.29%3A60020.13309841188420バイト、1ブロック、OPENFORWRITE: ………………………………..ステータス:HEALTHY
合計サイズ:2088783626 B
合計dirs:54
合計ファイル数:45
…
これらはブロックIDによって割り当てられるため、これは占有されているサーバー側スレッドにすぐには関係しません。しかし、それから、書き込み用のオープンブロックが1つあることを知ることができます。 Hadoopコマンドには、実際のファイルとそれらが構成されているブロックIDを出力するための追加オプションがあります。
$ hadoop fsck / hbase -files -blocks
FSCKはlarsgeorgeによって/10.0.0.29から開始されましたパス/hbaseat Tue Mar 06 10:39:50 CET 2012
…
/hbase/.META./1028785192/.tmp
/hbase/.META./1028785192/info
/hbase/.META./1028785192/info/4027596949915293355 36517バイト、1ブロック:OK
0。 blk_5532741233443227208_4201 len =36517 repl =1
…
ステータス:HEALTHY
合計サイズ:2088788703 B
合計dirs :54
合計ファイル数:45(現在書き込まれているファイル数:1)
合計ブロック数(検証済み):64(平均ブロックサイズ32637323 B)(合計オープンファイルブロック数(検証されていません):1)
最小限に複製されたブロック:64(100.0%)
…
これにより、2つのことがわかります。まず、要約には、コマンドの実行時に開いているファイルブロックが1つあることが示されています。これは、上記の「-openforwrite」オプションによって報告されたカウントと一致します。次に、各ファイルの横にあるブロックのリストを使用すると、スレッド名を、アクセスされているブロックを含むファイルと照合できます。この例では、IDが「blk_5532741233443227208_4201」のブロックがサーバーからクライアント(ここではRegionServer)に送信されます。このブロックはHBase.METAに属しています。 Hadoopfsckコマンドの出力で示されるテーブル。 JStackとfsckの組み合わせは、lsof(「開いているファイルを一覧表示する」ためのLinuxコマンドライン上のツール)の貧弱な代替品として機能する可能性があります。
JStackは、ブロックID「blk_-2005512129579433420_4199」のDataXceiverスレッドとそれに付随するPacketResponderがあることも報告していますが、このIDはfsckによって報告されたブロックのリストにありません。これは、ブロックがまだ完成していないため、読者が利用できないためです。つまり、Hadoop fsckは、完全な(または、この機能をサポートするHadoopバージョンの場合はsynced [7] [8])ブロックについてのみレポートします。
HBaseに戻る
すべてのリージョンを開くには、サーバー上に予想したほど多くのリソースは必要ありません。ただし、HBaseテーブル全体をスキャンする場合は、HBaseにすべてのHFileのすべてのブロックを読み取るように強制します。
HBaseシェル:
hbase(main):003:0> scan'usertable'
…
1000000 1460.3120秒で行
DataNodeログ:
2012-03-05 14:42:20,580DEBUGorg.apache.hadoop.hdfs.server.datanode。 DataNode:アクティブな接続の数は次のとおりです:6
2012-03-05 14:43:23,293 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:7
2012 -03-05 14:43:23,299 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、 ipcPort =50020):アクティブな接続の数は次のとおりです:8
…
2012-03-0514:49:24,332 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0。 0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:11
2012-03-05 14:49:24,332 DEBUG org .apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:10
2012-03-05 14:49:59,987 DEBUG org.apache.hadoop.hdfs.server.datanod e.DataNode:アクティブな接続の数は次のとおりです:11
2012-03-05 14:51:12,603 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は次のとおりです:12
2012-03-05 14:51:12,605 DEBUG org.apache.hadoop.hdfs .server.datanode.DataNode:アクティブな接続の数は次のとおりです:11
2012-03-05 14:51:46,473 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:12
…
2012-03-0514:56:59,420 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数:15
2012-03-05 14:57:31,722 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:16
2012-03-05 14:58:24,909DEBUGorg.apache.hadoop.hdfs。 server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):動作数ive接続は次のとおりです:17
2012-03-05 14:58:24,910 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:16
…
2012-03-05 15:04:17,688 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:21
2012-03-05 15:04:17,689 DEBUG org.apache .hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数:22
2012-03-05 15:04:54,545 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は次のとおりです:21
2012-03-05 15:05:55,901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010、storageID =DS-1423642448-10.0.0.64-50010-1321352233772、infoPort =50075、ipcPort =50020):アクティブな接続の数は:22
2012-03-05 15:05:55,901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:アクティブな接続の数は:21
現在、アクティブな接続の数はとらえどころのない22に達しています。この数にはすでにサーバースレッドが含まれているため、HBaseが処理する必要のあるファイルの数に基づいて、理論上の最大値と見なすことができる数にはまだ少し足りないことに注意してください。
それはどういう意味ですか?
では、いくつの「xcievers(sic)」が必要ですか? HBaseのみを使用している場合は、上記の「storefiles」メトリック(GangliaまたはJMXからも取得)を監視し、中間ログファイルと先行書き込みログファイルに数パーセントを追加するだけで済みます。これは、動作中のシステムで機能するはずです。ただし、アイドル状態の完全にコンパクト化されたシステムでその数を決定し、それが最大であると想定した場合、通常のmemstoreフラッシュ中にストアファイルを追加し始めると、つまり、 HBaseテーブルにデータを追加します。または、同じクラスターでMapReduceを使用する場合、Flumeログ集約など。これらの余分なファイルを考慮する必要があり、さらに重要なことに、読み取りと書き込みのためにブロックを開く必要があります。
この投稿の例では、実際のクラスターにはない単一のDataNodeを使用していることに再度注意してください。そのためには、ストアファイルの総数(HBaseメトリックによる)を、使用しているDataNodeの数で割る必要があります。たとえば、ストアファイル数が1000で、クラスターに10個のDataNodeがある場合、DataNodeごとにデフォルトの256個のxceiverスレッドで問題ありません。
最悪のケースは、すべてのアクティブなリーダーとライター、つまり現在データを送信または受信しているものの数です。しかし、これを事前に決定するのは難しいので、まともな予備で構築することを検討することをお勧めします。また、書き込みプロセスには追加のスレッド(PacketResponder用)が必要になるため(PacketResponderの場合)、それも考慮する必要があります。したがって、合理的ですが、かなり単純な式は次のようになります。
この式は、アクティブなライター用に約2つのスレッドが必要であり、アクティブなリーダー用にもう1つのスレッドが必要であることを考慮に入れています。次に、DataNodeごとに「dfs.datanode.max.xcievers」を指定する必要があるため、これを合計してDataNodeの数で除算します。
上記のHBaseRegionServerのスクリーンショットにループバックすると、22個のストアファイルがあることがわかります。 These are immutable and will only be read, or in other words occupy one thread only. For all memstores that are flushed to disk you need two threads – but only until they are fully written. The files are finalized and closed for good, cleaning up any thread in the process. So these come and go based on your flush frequency. Same goes for compactions, they will read N files and write them into a single new one, then finalize the new file. As for the write-ahead logs, these will occupy a thread once you have started to add data to any table. There is a log file per server, meaning that you can only have twice as many active threads for these files as you have RegionServers.
For a pure HBase setup (HBase plus its own HDFS, with no other user), we can estimate the number of needed DataXceiver’s with the following formula:
Since you will be hard pressed to determine the active number of store files, flushes, and so on, it might be better to estimate the theoretical maximum instead. This maximum value takes into account that you can only have a single flush and compaction active per region at any time. The maximum number of logs you can have active matches the number of RegionServers, leading us to this formula:
Obviously, the number of store files will increase over time, and the number of regions typically as well. Same for the numbers of servers, so keep in mind to adjust this number over time. In practice, you can add a buffer of, for example, 20%, as shown in the formula below – in an attempt to not force you to change the value too often.
On the other hand, if you keep the number of regions fixed per server[9], and rather split them manually, while adding new servers as you grow, you should be able to keep this configuration property stable for each server.
Final Advice &TL;DR
Here is the final formula you want to use:
It computes the maximum number of threads needed, based on your current HBase vitals (no. of store files, regions, and region servers). It also adds a fudge factor of 20% to give you room for growth. Keep an eye on the numbers on a regular basis and adjust the value as needed. You might want to use Nagios with appropriate checks to warn you when any of the vitals goes over a certain percentage of change.
Note:Please make sure you also adjust the number of file handles your process is allowed to use accordingly[10]. This affects the number of sockets you can use, and if that number is too low (default is often 1024), you will get connection issues first.
Finally, the engineering devil on one of your shoulders should already have started to snicker about how horribly non-Erlang-y this is, and how you should use an event driven approach, possibly using Akka with Scala[11] – if you want to stay within the JVM world. Bear in mind though that the clever developers in the community share the same thoughts and have already started to discuss various approaches[12][13].
Links:
- [1] http://old.nabble.com/Re%3A-xceiverCount-257-exceeds-the-limit-of-concurrent-xcievers-256-p20469958.html
- [2] http://ccgtech.blogspot.com/2010/02/hadoop-hdfs-deceived-by-xciever.html
- [3] https://issues.apache.org/jira/browse/HDFS-1861 “Rename dfs.datanode.max.xcievers and bump its default value”
- [4] https://issues.apache.org/jira/browse/HDFS-1866 “Document dfs.datanode.max.transfer.threads in hdfs-default.xml”
- [5] http://hbase.apache.org/book.html#dfs.datanode.max.xcievers
- [6] http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom
- [7] https://issues.apache.org/jira/browse/HDFS-200 “In HDFS, sync() not yet guarantees data available to the new readers”
- [8] https://issues.apache.org/jira/browse/HDFS-265 “Revisit append”
- [9] http://search-hadoop.com/m/CBBoV3z24H1 “HBase, mail # user – region size/count per regionserver”
- [10] http://hbase.apache.org/book.html#ulimit “ulimit and nproc”
- [11] http://akka.io/ “Akka”
- [12] https://issues.apache.org/jira/browse/HDFS-223 “Asynchronous IO Handling in Hadoop and HDFS”
- [13] https://issues.apache.org/jira/browse/HDFS-918 “Use single Selector and small thread pool to replace many instances of BlockSender for reads”