ラボの紹介HBaseは、LSMツリーを基盤として構築された分散型の列指向オープンソースデータベースです。シーケンシャル書き込み操作により、書き込みパフォーマンスを大幅に向上させます。ただし、読み取り時にはメモリ上のデータとディスク上のデータをマージする必要があるため、読み取りパフォーマンスが若干犠牲になります。書き込みが多く、読み取りが少ないシナリオに適しています。 パート01:読み書きのプロセスRegionServerはHBaseシステムの中核コンポーネントであり、主にユーザーデータの書き込みや読み取りといった基本的な操作を担います。その内部構造は以下の通りです。 写真 HBaseは、データの読み取りおよび書き込み操作のためにクライアントを介してRegionServerに接続します。テーブルは複数のRegionに水平分割され、各Regionは自身の領域内で読み取りおよび書き込みリクエストを処理します。Regionは複数のStoreで構成され、各Storeは対応する列ファミリーのデータを保存します。例えば、テーブルに2つの列ファミリーがある場合、そのテーブルのすべてのRegionには2つのStoreが含まれます。 HBaseバージョン0.96以降では、RegionServerからのHBaseデータの読み取りと書き込みの場所は、hbase:metaテーブルのみに依存します。hbase:metaテーブルには、すべてのユーザーHRegionの位置情報が格納されます。hbase:metaの1つの行キーは、1つのRegionに対応します。metaテーブルにはinfoという1つの列ファミリーのみがあり、各データ行は以下に示すように4つの列に分割されます。 写真 各メタデータエントリは約1KBです。HRegionを2GBに設定すると、2の21乗のリージョンをサポートし、最大4PBのデータを格納できます。これはほとんどのクラスターに十分な容量です。HBaseクラスター全体では、Metaテーブルは1つだけ存在し、分割されていません。このテーブルはZooKeeperの`/hbase/meta-region-server`ノード上に存在し、最初の読み取り後にクライアントにキャッシュされます。HBaseの読み取り/書き込み最適化には、RegionServer側とクライアント側の両方で同時に最適化を行う必要があり、読み取り/書き込みプロセス、リソース消費、パラメータチューニングを分析します。 パート02、書き込みパフォーマンスの最適化次の図に示すように、HBase のデータ書き込みプロセスを簡単に分析してみましょう。 写真 クライアントがPutリクエストを開始すると、まずhbase:metaテーブルから、最終的にPutデータの送信元となるHRegionServerを取得します。次に、クライアントは対応するHRegionServerにPutリクエストを送信します。HRegionServerはまずPut操作をWALログファイルに書き込みます(ディスクにフラッシュします)。 WALログファイルへの書き込み後、HRegionServerはPutステートメント内のTableNameとRowKeyに基づいて対応するHRegionを検索し、次に列ファミリに基づいて対応するHStoreを検索し、そのHStoreのMemStoreにPutステートメントを書き込みます。この時点で書き込みは成功し、クライアントに通知が返されます。 MemStoreのフラッシュ処理中、フラッシュ時のWALシーケンスの最大値など、いくつかのメタデータが末尾に追加されます。これにより、HBaseはこのStoreFileに書き込まれた最新のデータのシーケンスを把握し、リカバリ時にどこから開始すべきかを把握します。HRegionが起動すると、このシーケンスが読み込まれ、最大値が次回の更新の開始シーケンスとして使用されます。 HBaseデータの書き込み中に、書き込みパフォーマンスの低下やデータ書き込みエラーなどの問題が発生する場合があります。下図に示すアプローチを用いた最適化を検討してください。 写真 2.1 クライアント側書き込み最適化2.1.1 WAL書き込み最適化データ書き込みプロセスは、Write Ahead Log(WAL)と書き込みキャッシュへのシーケンシャル書き込みと捉えることができます。業務上、少量のデータ損失は許容され、書き込み速度を最大化する必要がある場合は、WALの無効化を検討できます。ただし、システムクラッシュ時に一部のデータが失われ、クラスタ間のレプリケーションが不可能になるというデメリットがあります。WALの永続性は4つのレベルに分かれています。 ● SKIP_WAL : キャッシュにのみ書き込み、HLog には書き込みません。これにより、データ損失のリスクが生じます。 ● ASYNC_WAL : HLog ログにデータを非同期に書き込みます。 ● SYNC_WAL : データをログ ファイルに同期的に書き込みますが、実際にはディスクに保存されません。 ● FSYNC_WAL : データをログファイルに同期的に書き込み、強制的にディスクに保存します。 デフォルトでは、ユーザーが永続性レベルを指定しない場合、HBaseはデータの永続性にSYNC_WALレベルを使用します。ユーザーは、ビジネスの優先度に応じて、WALメカニズムと書き込みスループットのどちらかを選択できます。WAL永続性戦略はクライアントから設定できます。テーブル作成時にWALストレージレベルを直接設定するだけでなく、クライアントからもWAL永続性レベルを設定できます: `put.setDurability(Durability.SYNC_WAL);` 2.1.2 PUTバッチ最適化HBaseは、単一行PUTとバッチPUTの両方のAPIインターフェースを提供しています。バッチPUTインターフェースを使用すると、クライアントとRegionServer間のRPC接続数を削減し、書き込みスループットを向上させることができます。データのリアルタイム性がそれほど厳しくない場合は、非同期バッチコミットを有効にできます。`setAutoFlush(false)`を設定すると、クライアントのキャッシュがしきい値(デフォルトは2MB)に達した時点で、RegionServerにデータをバッチコミットできます。 RPC 呼び出しの数を減らし、クライアントからサーバーにデータを送信するタスクを HBase に委任して処理することで、スループットを向上させることができます。ただし、欠点は、クライアントでエラーが発生した場合に、キャッシュされたデータが失われる可能性があることです。 2.1.3 大きなキー値の最適化KeyValueのサイズは書き込みパフォーマンスに大きな影響を与えます。サイズが大きすぎるとパフォーマンスに大きな影響を及ぼし、クラスターへの書き込み速度が急激に低下したり、データのバックログが発生したり、クラスター全体の業務に影響を及ぼしたりする可能性があります。 RowKeyの最大長は64KBに制限されていますが、実際のアプリケーションでは100KBを超えることはありません。これは、HBaseのRowKeyが、rowkey + columnFamily + qualifier + timestampで構成されるセルとして冗長的に複数回保存されるためです。RowKeyが大きくなるほど、メモリとディスクリソースの無駄が増えます。また、過度に大きな値はパフォーマンスとHBaseの応答速度に重大な影響を与えます。一般的に、解決策は2つあります。 ● 値が大きすぎる場合は、複数の列に分割して保存し、必要な値をその都度返すか、HDFS に値を保存して URL を HBase に保存することをお勧めします。 ● HBase 2.0 以降の MOB 機能を使用すると、メタデータと MOB データが別のファイルに分離されるため、ドキュメントや画像などのバイナリ データの保存に優れたパフォーマンスが得られます。 2.1.4 バルクロードインポートの最適化オフラインデータインポートを伴うビジネスシナリオでは、Bulkload を使用できます。Bulkload は、HFile ファイルを出力する MapReduce プログラムです。リアルタイム性は低いものの、スループットと効率性が高く、HBase サーバーへの負荷を軽減し、クラスター全体のパフォーマンスを向上させることができます。 2.2 サーバー側書き込み最適化2.2.1 不十分な領域数に対する最適化業務データの量に基づいてリージョンのパーティションを予測することで、テーブル作成時に事前パーティショニングを行い、複数サーバーの並列処理能力を最大限に活用できます。事前パーティショニング中に一部のリージョンで負荷とリクエスト量の不均衡が見つかった場合、一部のリクエストを負荷の高いリージョンにリダイレクトする必要があり、HBaseクラスターはロードバランシングを実行します。また、即時の解決策として、コマンドを使用して一部のリージョンを他のRegionServerノードに移行することで、サーバーリソースを最大限に活用し、ロードバランシングを実現できます。 2.2.2 書き込み要求のバランス最適化RowKeyの設計と事前パーティション戦略を検討し、書き込みリクエストのバランスを確保してください。主にGetクエリに使用するテーブルにはハッシュ事前パーティション戦略を使用し、主にScanクエリに使用するテーブルにはセグメント事前パーティション戦略を使用できます。 2.2.3 SSDストレージを使用してWALを最適化する書き込みパフォーマンスはWAL(Write-Ahead Log)書き込みの影響を受けます。SSDは応答時間を大幅に短縮できます。WALファイルをSSDに書き込むと、書き込みパフォーマンスが大幅に向上します。HDFSアーカイブストレージメカニズムを使用すると、HDFSのファイルディレクトリの一部をSSDに配置するように設定できます。`hbase.wal.storage.policy`のデフォルトは`none`ですが、ユーザーは`ONESSD`(1つのWALレプリカをSSDに書き込む)または`ALLSSD`(3つのWALレプリカすべてをSSDに書き込む)のいずれかを指定できます。 パート03、読み取りパフォーマンスの最適化HBaseのデータクエリプロセスは、書き込みプロセスよりも比較的複雑です。HBaseにデータを書き込む際、同じRowKey、ColumnFamily、またはColumnを持つセルが必ずしも同じ場所に配置されるとは限りません。セルを削除するには、新しいセルに書き込み、そのセルにDeleteマークを付け、BlockCache、MemStore、StoreFile(HFile)を順にスキャンするだけです。そして、その結果がマージされます(Merge Read)。このプロセスを次の図に示します。 写真 StoreFileのスキャンプロセスでは、まずブルームフィルタを使用して、基準を満たさないHFileを除外します。次に、ブロックインデックスを使用してセルを迅速に特定し、ブロックキャッシュにロードしてデータを読み取ります。HStoreには複数のStoreFile(HFile)が含まれる場合があり、複数のHFileのスキャンが必要になることがあります。HFileが多すぎるとパフォーマンスの問題が発生する可能性があります。HBaseデータのクエリ中にクエリ速度が低下することがありますが、これは下図に示すアプローチで最適化できます。 写真 3.1 クライアント側の読み取り最適化3.1.1 Get/Scan読み取り要求の最適化バッチリクエストを使用したGETリクエストの場合、HBaseは単一GETリクエストとバッチGETリクエストの両方に対応するAPIインターフェースを提供します。バッチGETインターフェースを使用すると、クライアントとRegionServer間のRPC接続数を削減でき、読み取りスループットが向上します。 スキャン クライアント キャッシュの場合、HBase RPC の合計数が適切なレベルに調整されていることを前提に、大規模なスキャン シナリオではスキャン キャッシュを 100 から 500 または 1000 に増やして RPC の数を減らすことを検討できます。 3.1.2 列ファミリーまたは列最適化を指定するクライアント側でクエリを実行するときは、正確なクエリのために列ファミリまたは列を指定し、不要な列ファミリまたは列を除外して、リージョン内でのデータクエリとネットワーク データ転送を削減するようにしてください。 3.1.3 オフライン読み取りキャッシュを無効にした最適化オフラインのバッチ読み取りリクエストでは、scan.setCacheBlocks(false) を設定することでキャッシュを無効化できます。これは、MapReduce などのオフラインのフルテーブルスキャンに適しています。この場合、キャッシュを使用してもパフォーマンスは向上しないだけでなく、逆効果になる可能性があります。 3.1.4 ブルームフィルタの使用の最適化ブルームフィルタは、すべての業務処理に対して設定する必要があります。これにより、処理スペースと時間を節約できます。デフォルトの設定は行です。ただし、業務のランダムクエリの種類が行+列であることが確実な場合は、ブルームフィルタを行列に設定する必要があります(これは、指定する列数が多いシナリオに適していますが、その場合はキャッシュメモリとディスク容量の使用量が増加します)。 3.2 サーバー側の読み取り最適化3.2.1 読み取り要求の負荷分散の最適化データスループットが高く、単一のクエリで大量のデータが返されるシナリオでは、Rowkeyをハッシュ化し、テーブルを事前にパーティション分割する必要があります。主にGetクエリで使用するテーブルの場合は、ハッシュによる事前パーティション分割戦略を使用してテーブルデータを均等に分散できます。主にScanクエリで使用するテーブルの場合は、セグメント化された事前パーティション分割戦略を使用できます。ビジネスシナリオを考慮しながら、Rowkeyはデータを可能な限り均等に分散し、クエリ要件を満たしながら負荷分散を実現するように設計する必要があります。 3.2.2 BlockCache キャッシュの最適化JVMメモリ構成が20GB未満の場合は、BlockCache戦略としてLRUBlockCacheを選択する必要があります。それ以外の場合は、オフヒープモードのBucketCache戦略を選択する必要があります。オフヒープモードでは、ビジネスシナリオの読み取り/書き込み比率に応じて、読み取りヒープ領域と書き込みヒープ領域の比率を設定できます。デフォルトでは、ヒープ内の読み取りキャッシュと書き込みキャッシュはどちらもヒープ領域の40%を占有し、読み取りと書き込みのバランスが取れています。 3.2.3 HFile量制御の最適化ストアには複数のHFileファイルが含まれます。ファイル数が多いほど、取得に必要なI/O操作が増え、読み取りレイテンシが長くなります。ファイル数は通常、マイナーコンパクション実行戦略によって決まり、一般的には2つの構成パラメータ「hbase.hstore.compactionThreshold」と「hbase.hstore.compaction.max.size」に関連しています。前者は、ストアのファイル数がしきい値を超え、マージする必要があることを示します。後者は、マージするファイルの最大サイズを示し、このサイズを超えるファイルはマージできません。RegionServerレベルとRegionレベルでHFileの数を確認することで、HFileファイルが多すぎないかどうかを確認できます。「hbase.hstore.compactionThreshold」の設定は高すぎないようにしてください。デフォルトは3です。 3.2.4 メジャーコンパクションの最適化MajorCompaction は、ストア内のすべてのファイルを 1 つにマージし、マージプロセス中に変更および削除されたデータを処理し、ディスクリソースを解放します。設定ファイル内のデフォルトの MajorCompaction はテーブルごとに実行され、多くのリソースを消費するため、システムパフォーマンスにも大きな影響を与えます。したがって、読み取りレイテンシやシステムパフォーマンスの変動に敏感な企業では、自動 MajorCompaction を有効にすることは一般的に推奨されません。代わりに、スクリプトを使用して定期的に実行するか、オフピーク時に手動で実行することをお勧めします。レイテンシの影響を受けない企業では、自動 MajorCompaction を有効にできますが、トラフィックを制限することをお勧めします。 3.2.5 データのローカリゼーションHBaseデータは書き込み時にローカライズされますが、リージョンが移行されると、コンパクションが完了するまでデータのローカリティが維持されなくなり、データのローカリティが回復される可能性があります。不要なリージョン移行は避けてください。ローカリティが低いノードでは、MajorCompactionをオフピーク時に実行できます。 パート04、要約HBase の読み取りおよび書き込み操作を最適化するには、ビジネス利用シナリオを考慮し、適切なクラスターサイズを事前に評価し、各読み取りおよび書き込みシナリオにおけるリソース消費量を定量的に分析する必要があります。これにより、RowKey 設計の改善、リージョンの事前パーティショニング、そして可能な限りリージョン間でのデータの分散が可能になり、読み取りおよび書き込みリクエストのバランスを確保し、コンパクションによるビジネスオペレーションへの影響を軽減し、データストレージ容量とネットワークリソース消費を削減できます。最後に、HBase の多数の設定パラメータから適切な設定の組み合わせを選択することが、最適な読み取りおよび書き込みパフォーマンスを実現するために不可欠です。 |