このトピックでは、Lindorm でタイムスタンプに基づいてホットデータとコールドデータを個別に保存する方法について説明します。
背景情報
Lindorm は、タイムスタンプと指定されたホットデータとコールドデータの境界に基づいて、データをコールドストレージにアーカイブできます。タイムスタンプを指定しない場合、データがテーブルに書き込まれた時刻を使用して、データをコールドストレージにアーカイブするかどうかが決定されます。
前提条件
Lindorm インスタンスでコールドストレージが有効になっていること。詳細については、概要をご参照ください。
LindormTable のバージョンが 2.1.8 以降であること。 LindormTable のバージョンを表示またはアップグレードする方法の詳細については、LindormTable のリリースノートとLindorm インスタンスのマイナーエンジンバージョンをアップグレードするをご参照ください。
LindormTable に接続していること。
HBase Shell を使用して LindormTable に接続する方法の詳細については、Lindorm Shell を使用して LindormTable に接続するをご参照ください。
ApsaraDB for HBase API for Java を使用して LindormTable に接続する方法の詳細については、ApsaraDB for HBase API for Java を使用してアプリケーションを開発するをご参照ください。
Lindorm-cli を使用して LindormTable に接続する方法の詳細については、Lindorm-cli を使用して LindormTable に接続および使用するをご参照ください。
テーブルまたは列ファミリーの STORAGE_POLICY 属性は、
COLDではありません。これは、ホットデータとコールドデータの分離を有効にする対象のテーブルが、コールドストレージ内のテーブルではないことを示しています。列ファミリーの属性を変更する方法の詳細については、「コールドストレージの構成」をご参照ください。
手順
方法 1:Apache HBase Shell を使用してホットデータとコールドデータの分離を実装する
テーブルを作成し、テーブルのホットデータとコールドデータの境界を指定します。
HBase(main):002:0> create 'chsTable', {NAME=>'f', COLD_BOUNDARY=>'86400'}パラメーター
NAME: ホットデータとコールドデータの分離を実装する列ファミリーの名前。
COLD_BOUNDARY: ホットデータとコールドデータの分離を実行するための境界。このパラメーターの値の単位は秒です。たとえば、COLD_BOUNDARY パラメーターの値を 86400 に設定すると、データがホットストレージに保存されてから 86,400 秒(1 日に相当)後に、データはコールドストレージにアーカイブされます。
(オプション)ホットデータとコールドデータの境界を変更します。
HBase(main):005:0> alter 'chsTable', {NAME=>'f', COLD_BOUNDARY=>'42300'}(オプション)ホットデータとコールドデータの分離を無効にします。
HBase(main):004:0> alter 'chsTable', {NAME=>'f', COLD_BOUNDARY=>""}説明ホットデータとコールドデータの境界を変更するか、ホットデータとコールドデータの分離を無効にした後、Lindorm が
compaction操作を実行すると、データはコールドストレージからホットストレージに転送されます。データをコールドストレージからホットストレージにすぐに転送するには、major_compact コマンドを手動で実行します。
方法 2:ApsaraDB for HBase API for Java を使用してホットデータとコールドデータの分離を実装する
テーブルを作成し、テーブルのホットデータとコールドデータの境界を指定します。
Admin admin = connection.getAdmin(); TableName tableName = TableName.valueOf("chsTable"); HTableDescriptor descriptor = new HTableDescriptor(tableName); HColumnDescriptor cf = new HColumnDescriptor("f"); // ホットデータとコールドデータの境界を設定します。 cf.setValue(AliHBaseConstants.COLD_BOUNDARY, "86400"); descriptor.addFamily(cf); admin.createTable(descriptor);(オプション)ホットデータとコールドデータの境界を変更します。
HTableDescriptor descriptor = admin .getTableDescriptor(tableName); HColumnDescriptor cf = descriptor.getFamily("f".getBytes()); // ホットデータとコールドデータの境界を変更します。 cf.setValue(AliHBaseConstants.COLD_BOUNDARY, "86400"); admin.modifyTable(tableName, descriptor);(オプション)ホットデータとコールドデータの分離を無効にします。
HTableDescriptor descriptor = admin .getTableDescriptor(tableName); HColumnDescriptor cf = descriptor.getFamily("f".getBytes()); // ホットデータとコールドデータの分離を無効にします。 cf.setValue(AliHBaseConstants.COLD_BOUNDARY, null); admin.modifyTable(tableName, descriptor);説明ホットデータとコールドデータの境界を変更するか、ホットデータとコールドデータの分離を無効にした後、Lindorm が
compaction操作を実行すると、データはコールドストレージからホットストレージに転送されます。
方法 3:lindorm-cli を使用してホットデータとコールドデータの分離を実装する
テーブルを作成し、テーブルのホットデータとコールドデータの境界を指定します。
テーブルを作成するときに、ホットデータとコールドデータの分離を有効にし、ホットデータとコールドデータの境界を指定します。
CREATE TABLE dt ( p1 integer, p2 integer, c1 varchar, c2 bigint, constraint pk primary key(p1 desc)) WITH (COMPRESSION = 'ZSTD', CHS = '86400', CHS_L2 = 'storagetype=COLD');パラメーター
CHS: テーブルのホットデータとコールドデータの境界。テーブルに保存されている期間がこの期間よりも長いデータは、コールドストレージにアーカイブされます。このパラメーターの値の単位は秒です。たとえば、このパラメーターの値が 86400 の場合、データがテーブルに書き込まれてから 86,400 秒(1 日に相当)後に、データはコールドストレージにアーカイブされます。
COMPRESSION: データの圧縮に使用されるアルゴリズム。このパラメーターは、テーブル内のすべてのデータに適用されます。このパラメーターの値は大文字と小文字を区別しません。デフォルト値:NONE。
CHS_L2: レイヤー 2 属性。一般に、このパラメーターはストレージタイプを指定するために設定されます。このパラメーターを storagetype=COLD に設定します。
ALTER TABLE構文を使用して、既存のテーブルのホットデータとコールドデータの境界を指定します。-- この例では、サンプルテーブル dt が作成されるときに、ホットデータとコールドデータの分離は有効になっていません。 -- CREATE TABLE dt (p1 integer, p2 integer, c1 varchar, c2 bigint, constraint pk primary key(p1 desc)) WITH (COMPRESSION = 'ZSTD'); -- dt テーブルのホットデータとコールドデータの分離を有効にします。 ALTER TABLE dt SET 'CHS' ='86400', 'CHS_L2' = 'storagetype=COLD';
(オプション)ホットデータとコールドデータの境界を変更します。
ALTER TABLE dt SET 'CHS'='1000';(オプション)ホットデータとコールドデータの分離を無効にします。
ALTER TABLE dt SET 'CHS'='', 'CHS_L2' = '';説明ホットデータとコールドデータの境界を変更するか、ホットデータとコールドデータの分離を無効にした後、Lindorm が
compaction操作を実行すると、データはコールドストレージからホットストレージに転送されます。データをコールドストレージからホットストレージにすぐに転送するには、major_compactコマンドを手動で実行します。この操作の実行に使用される構文の詳細については、ALTER TABLEをご参照ください。
データの書き込み
ホットデータとコールドデータを個別に保存するワイドテーブルにデータを書き込む方法は、標準テーブルにデータを書き込む方法と同じです。デフォルトでは、データのタイムスタンプは、データが書き込まれたときの現在のシステム時刻です。 ApsaraDB for HBase API を使用してデータを書き込む場合、要件に基づいてカスタムタイムスタンプを指定できます。ホットデータとコールドデータを個別に保存するテーブルにデータが書き込まれると、データは最初に Standard タイプまたは Performance タイプのホットストレージに保存されます。データが COLD_BOUNDARY または CHS で指定された値よりも長い期間保存されると、Lindorm が compaction 操作を実行するときに、データはコールドストレージにアーカイブされます。
データのタイムスタンプは、Lindorm によってデータがコールドストレージにアーカイブされる必要があるかどうかを判断するために使用されます。 Lindorm は現在の時刻とデータのタイムスタンプを比較します。データのタイムスタンプが現在のシステム時刻の 3 日後の時点である場合、データはタイムスタンプが現在のシステム時刻であるデータよりも 3 日遅れてコールドストレージにアーカイブされます。データのタイムスタンプが現在のシステム時刻の 3 日前の時点であり、ホットデータとコールドデータの境界が 3 日に設定されている場合、データはテーブルに書き込まれた後に非同期的にコールドストレージにアーカイブされます。
データのクエリ
Lindorm は、ホットデータとコールドデータを保存するために同じテーブルを使用します。このようにして、1 つのテーブル内のすべてのデータをクエリできます。データをクエリするときに、TimeRange パラメーターを設定して、クエリの時間範囲を指定できます。 Lindorm は、指定した時間範囲に基づいて、ホットストレージのみをクエリするか、コールドストレージのみをクエリするか、ホットストレージとコールドストレージの両方をクエリするかを決定します。クエリで時間範囲を指定しない場合、コールドデータがクエリされる可能性があります。この場合、クエリの処理能力はコールドストレージの仕様によって制限されます。詳細については、概要をご参照ください。
ホットストレージ内のデータをクエリする場合、クエリで _l_hot_only_ ヒントを使用するか、HOT_ONLY パラメーターを設定して、ホットストレージ内のデータのみをクエリできます。
コールドストレージ内のデータはアーカイブ用であり、めったにアクセスされるべきではありません。コールドストレージ内のデータに多数のリクエストが頻繁にアクセスする場合、COLD_BOUNDARY で指定されたホットデータとコールドデータの境界が正しく設定されているかどうかを確認してください。頻繁にクエリする必要がある大量のデータが境界に基づいてコールドストレージにアーカイブされている場合、クエリの性能が低下する可能性があります。
コールドストレージに保存されているデータ行のフィールドが更新されると、更新されたフィールドはホットストレージに保存されます。 HOT_ONLY または TimeRange パラメーターを指定してホットストレージ内のデータのみをクエリする場合、更新されたフィールドのみが返されます。 LindormTable が行全体のデータを返すようにするには、HOT_ONLY または TimeRange パラメーターを指定せずにクエリを実行するか、TimeRange で指定された時間範囲が行が挿入された時点から行が最後に更新された時点までの期間をカバーしていることを確認する必要があります。したがって、コールドストレージに保存されているデータを更新しないことをお勧めします。
現在、GET メソッドと SCAN メソッドがデータのクエリをサポートしています。
GET メソッドを使用してデータをクエリする
方法 1:Apache HBase Shell を使用してデータをクエリする
HOT_ONLY パラメーターを指定せずにデータをクエリします。この場合、コールドストレージ内のデータがクエリされる可能性があります。
HBase(main):013:0> get 'chsTable', 'row1'HOT_ONLY パラメーターを指定してデータをクエリします。この場合、ホットストレージ内のデータのみがクエリされます。
HBase(main):015:0> get 'chsTable', 'row1', {HOT_ONLY=>true}TimeRange パラメーターを指定してデータをクエリします。 Lindorm は TimeRange と COLD_BOUNDARY の値を比較して、ホットストレージのみをクエリするか、コールドストレージのみをクエリするか、ホットストレージとコールドストレージの両方をクエリするかを決定します。
HBase(main):016:0> get 'chsTable', 'row1', {TIMERANGE => [0, 1568203111265]}パラメーター
TimeRange: クエリが実行される時間範囲。範囲内の時間は、エポックタイム 1970 年 1 月 1 日 00:00:00 UTC から経過したミリ秒数を表す UNIX タイムスタンプです。
方法 2:ApsaraDB for HBase API for Java を使用してデータをクエリする
HOT_ONLY パラメーターを指定せずにデータをクエリします。この場合、コールドストレージ内のデータがクエリされる可能性があります。
Get get = new Get("row1".getBytes()); System.out.println("result: " + table.get(get));HOT_ONLY パラメーターを指定してデータをクエリします。この場合、ホットストレージ内のデータのみがクエリされます。
get = new Get("row1".getBytes()); // ホットデータのみをクエリします。 get.setAttribute(AliHBaseConstants.HOT_ONLY, Bytes.toBytes(true));TimeRange パラメーターを指定してデータをクエリします。 Lindorm は TimeRange と COLD_BOUNDARY の値を比較して、ホットストレージのみをクエリするか、コールドストレージのみをクエリするか、ホットストレージとコールドストレージの両方をクエリするかを決定します。
get = new Get("row1".getBytes()); get.setTimeRange(0, 1568203111265)
方法 3:Lindorm SQL を使用してデータをクエリする
// ホットデータのみをクエリします。 SELECT /*+ _l_hot_only_ */ * FROM dt WHERE pk IN (1, 2, 3);
SCAN メソッドを使用して指定された範囲内のデータをクエリする
HOT_ONLY パラメーターと TimeRange パラメーターを設定しない場合、または TimeRange の値がコールドストレージ内のデータのタイムスタンプをカバーしている場合、Lindorm はコールドストレージとホットストレージの両方でデータをクエリし、クエリ結果をマージします。
Apache HBase Shell と ApsaraDB for HBase API for Java のみが、指定された範囲内のクエリをサポートしています。
方法 1:Apache HBase Shell を使用してデータをクエリする
HOT_ONLY パラメーターを指定せずにデータをクエリします。この場合、コールドストレージ内のデータがクエリされます。
Lindorm(main):017:0> scan 'chsTable', {STARTROW =>'row1', STOPROW=>'row9'}HOT_ONLY パラメーターを指定してデータをクエリします。この場合、ホットストレージ内のデータのみがクエリされます。
Lindorm(main):018:0> scan 'chsTable', {STARTROW =>'row1', STOPROW=>'row9', HOT_ONLY=>true}TimeRange パラメーターを指定してデータをクエリします。 Lindorm は TimeRange と COLD_BOUNDARY の値を比較して、ホットストレージのみをクエリするか、コールドストレージのみをクエリするか、ホットストレージとコールドストレージの両方をクエリするかを決定します。
Lindorm(main):019:0> scan 'chsTable', {STARTROW =>'row1', STOPROW=>'row9', TIMERANGE => [0, 1568203111265]}
方法 2:ApsaraDB for HBase API for Java を使用してデータをクエリする
TableName tableName = TableName.valueOf("chsTable"); Table table = connection.getTable(tableName); // この例では、HOT_ONLY パラメーターは設定されていません。コールドストレージ内のデータがクエリされます。 Scan scan = new Scan(); ResultScanner scanner = table.getScanner(scan); for (Result result : scanner) { System.out.println("scan result:" + result); } // この例では、HOT_ONLY パラメーターが設定されています。ホットストレージ内のデータのみがクエリされます。 scan = new Scan(); scan.setAttribute(AliLindormConstants.HOT_ONLY, Bytes.toBytes(true)); // この例では、TimeRange パラメーターが設定されています。 Lindorm は TimeRange と COLD_BOUNDARY の値を比較して、ホットストレージのみをクエリするか、コールドストレージのみをクエリするか、ホットストレージとコールドストレージの両方をクエリするかを決定します。 scan = new Scan(); scan.setTimeRange(0, 1568203111265);
優先的にホットデータをクエリする
顧客のすべての注文やチャット記録などの情報をクエリするために行われる SCAN クエリでは、LindormTable はホットストレージとコールドストレージの両方でデータをスキャンする可能性があります。クエリ結果は、データ行がテーブルに書き込まれたタイムスタンプに基づいて降順にページ分割されます。ほとんどの場合、ホットデータはコールドデータの前に表示されます。 SCAN クエリで HOT_ONLY パラメーターを設定しない場合、LindormTable はホットデータとコールドデータの両方をスキャンします。その結果、クエリ応答時間が長くなります。ホットデータ優先機能を有効にすると、LindormTable は優先的にホットストレージ内のデータをクエリします。コールドストレージ内のデータは、ホットストレージ内の行数がクエリするデータ行の最小数よりも少ない場合にのみクエリされます。このようにして、コールドストレージ内のデータへのアクセスが削減され、応答速度が向上します。
Apache HBase Shell または ApsaraDB for HBase API for Java のみを使用して、優先的にホットデータをクエリできます。
方法 1:Apache HBase Shell を使用してデータをクエリする
Lindorm(main):002:0> scan 'chsTable', {COLD_HOT_MERGE=>true}パラメーター
COLD_HOT_MERGE: ホットデータ優先機能を有効にするかどうかを指定します。
true: ホットデータ優先機能を有効にします。 COLD_HOT_MERGE パラメーターを true に設定すると、LindormTable は優先的にホットデータをスキャンします。 LindormTable は、ホットストレージ内のデータ行数がクエリする行数よりも少ない場合にのみ、コールドデータをスキャンします。
false: ホットデータ優先機能を無効にします。
方法 2:ApsaraDB for HBase API for Java を使用してデータをクエリする
scan = new Scan(); // ホットデータの優先スキャンを有効にします。 scan.setAttribute(AliHBaseConstants.COLD_HOT_MERGE, Bytes.toBytes(true)); scanner = table.getScanner(scan);
使用上の注意
行の特定のフィールドのデータが更新されるシナリオでは、行はホットデータとコールドデータを同時に保存します。ホットデータ優先機能を有効にすると、クエリ結果は 2 つのバッチで返されます。結果セットには、同じ行キーの 2 つの結果があります。
ホットデータ優先機能を有効にすると、ホットデータがコールドデータの前に返されます。したがって、LindormTable はホットデータをコールドデータの前に返すため、返されたコールドデータの特定の行の行キー値は、返されたホットデータの特定の行の行キー値よりも小さい場合があります。 SCAN クエリで返される結果は順番にソートされません。ホットデータの行とコールドデータの行は、行キー値に基づいて個別にソートされます。返された行のソート方法の詳細については、次のサンプル結果を参照してください。シナリオによっては、行キーを指定して、SCAN クエリの結果の順序を確保できます。たとえば、顧客が行った注文に関する情報を保存するためにテーブルを使用する場合、顧客 ID を保存する列と注文作成時刻を保存する列で構成される行キーを指定できます。このようにして、顧客が行った注文をクエリすると、返された注文は注文が作成された時点に基づいてソートされます。
// 次の例では、行キー値が coldRow の行はコールドデータを保存し、行キー値が hotRow の行はホットデータを保存します。 // ほとんどの場合、Lindorm の行は辞書順にソートされるため、coldRow 行は hotRow 行の前に返されます。 HBase(main):001:0> scan 'chsTable' ROW COLUMN+CELL coldRow column=f:value, timestamp=1560578400000, value=cold_value hotRow column=f:value, timestamp=1565848800000, value=hot_value 2 row(s) // COLD_HOT_MERGE パラメーターの値を true に設定すると、LindormTable は最初に hotRow の行キー値を持つ行をスキャンします。その結果、hotRow 行は coldRow 行の前に返されます。 HBase(main):002:0> scan 'chsTable', {COLD_HOT_MERGE=>true} ROW COLUMN+CELL hotRow column=f:value, timestamp=1565848800000, value=hot_value coldRow column=f:value, timestamp=1560578400000, value=cold_value 2 row(s)
FAQ
Q: コールドデータの行は、更新後もコールドデータのままですか?
A: いいえ。コールドデータの行が更新されると、この行のタイムスタンプが更新されます。したがって、コールドデータはホットデータになります。
Q: ホットデータのみをクエリしたいのに、なぜコールドデータが返されるのですか?
A: HOT_ONLY パラメーターまたは _l_hot_only_ ヒントを設定して、ホットデータのみをクエリできます。データはタイムスタンプに基づいて定期的にコールドストレージにアーカイブされます。したがって、データをクエリするときに、一部のコールドデータがまだコールドストレージにアーカイブされていない可能性があります。この場合、コールドデータが返されます。この問題を解決するには、クエリするホットデータの時間範囲を指定できます。次の例は、この関数の使用方法を示しています。
// _l_ts_min_ ヒントと _l_ts_max_ ヒントを使用して時間範囲を指定する必要があります。 _l_ts_min_ ヒントは、現在のシステム時刻とホットデータとコールドデータの境界の差を示します。 _l_ts_max_ ヒントは現在のシステム時刻を示します。ヒントの単位は同じである必要があります。 SELECT /*+ _l_hot_only_(true), _l_ts_min_(1000), _l_ts_max_(2001) */ * FROM test WHERE p1>1;Q: クエリで時間範囲を指定し、HOT_ONLY ヒントを使用しているのに、なぜクエリがタイムアウトするのですか?
A: この問題は、一般に、データをテーブルに移行した後、またはテーブルのホットデータとコールドデータの分離を有効にした後に発生します。この場合、コールドデータはコールドストレージに完全にアーカイブされておらず、大量のコールドデータがまだホットストレージに保存されています。したがって、クエリがタイムアウトする可能性があります。この問題を解決するには、テーブルで
major compaction操作を実行する必要があります。この操作の実行に使用される構文の詳細については、ALTER TABLEをご参照ください。