アプリケーションサーバーに割り当てられたメモリ | クエリエンジンは永続ストレージから必要な情報を取得するため、Java 仮想マシンに割り当てられるメモリ (通常は -Xmx パラメータで指定) を低く抑えることができます。この数値は、OS で使用可能な合計メモリの 1/3 未満に設定することをお勧めします。また、32 GB 未満に抑えることをお勧めします。これは、すべての合理的なユースケースに適合し、圧縮された通常のオブジェクトポインター機能を利用できるようにする必要があります。 |
オペレーティングシステムに割り当てられたメモリ | アプリケーションサーバーを実行している OS では、OS キャッシュに十分なスペースを残して、永続的な Lucene インデックスへのアクセスを最適化できるようにすることが重要です。実際、これらがファイルシステムからロードされると、OS はメモリキャッシュを使用して、この同じデータへの後続のアクセスを高速化し、ディスクから毎回リロードすることを回避します。これは、この目的のために十分な RAM が残っている場合にのみ可能です。 また、JVM プロセスが多数のメモリマップトファイルに必要なリソースを予約できるように OS を構成する必要があります (詳細については、この記事を参照してください)。Linux OS では、これは次のコマンドを発行することで実行できます。 ulimit -n 512000 sysctl vm.max_map_count=262144 |
メモリ監視 | EBX® ロードアクティビティの兆候は、基盤となるデータベースを監視することによって、また「監視」ログカテゴリによって提供されます。 cleared および built オブジェクトの数が長期間高いままである場合、これは EBX® がアプリケーションサーバーでスワップしていることを示しています。その場合、アプリケーションサーバーに割り当てるメモリを増やす必要があります。 |
ガベージコレクター | ガベージコレクターを調整すると、全体的なパフォーマンスにもメリットがあります。このチューニングは、使用するユースケースと特定の Java ランタイム環境に適合させる必要があります。 |
EBX® リポジトリデータは Lucene インデックスにインデックス付けされ、ルートディレクトリの下のディスクに保存されます。
ディスク容量:ディスクサイズの経験則では、リレーショナルデータベースのテーブル G_BLK
が占める容量の 10 倍を計画します。
ディスク遅延:全体的なパフォーマンスを良好に維持するには、Lucene インデックスを格納するディスクの遅延時間を短くすることが重要です。
アプリケーションサーバーで使用可能な CPU の数は、処理される同時 HTTP 要求の数、暗黙のタスクの複雑さ (CPU コスト)、および Java ガベージコレクションを含むバックグラウンドアクティビティを考慮して定義する必要があります。
サーバーの負荷と使用可能なプロセッサの数の違いにより、トランザクション内でインデックス作成を効率的に並行して実行できる場合、大規模なインポート、およびより一般的には多くの作成、更新、削除を伴う大規模なトランザクションがより速く完了します。永続性
ログカテゴリには、次のエントリが含まれます。
「強制同期インデックスを false に設定 (...)」は、インデックスが同時に実行されることを示します。
「強制同期インデックスを true に設定 (...)」は、インデックスが同時に実行されないことを示します。
上記の違いは 10 秒ごとに評価され、Java クラス java.lang.management.OperatingSystemMXBean
のメソッド getSystemLoadAverage()
および getAvailableProcessors()
を使用して計算されます。両方の数値は、上記のログエントリの最後に書き込まれます。
LZ4 ライブラリは、データベースへのデータの保存とデータベースからのデータの取得に使用されます。データアクセスを高速化するには、ebx-lz4.jar
ネイティブインストールを実行する必要があります。
詳細については、データ圧縮ライブラリを参照してください。
Web アプリケーションサーバーの起動を高速化するには、JAR ファイルスキャナーを構成する必要があります。
他のデータベースと同様に、大量のデータを挿入および削除すると、データが断片化され、時間の経過とともにパフォーマンスが低下する可能性があります。この問題を解決するには、影響を受けるデータベーステーブルを再編成する必要があります。リレーショナルデータベースの監視とクリーンアップを参照してください。
EBX® の特徴は、データスペースとスナップショットを作成すると、テーブル GRS_DTR
と GRS_SHR
に新しいエントリが追加されることです。パフォーマンスが低下した場合、多くのデータスペースが作成および削除される大規模なリポジトリでは、これらのテーブルの再編成をスケジュールする必要がある場合があります。
データモデルでは、エレメントのカーディナリティ制約 maxOccurs
が 1 より大きく、このエレメントで osd:table
が宣言されていない場合、Java リスト
として実装されます。このタイプのエレメントは、テーブルではなく、集約リストと呼ばれます。
反復、ユーザーインターフェイスの表示などの観点から、集約リストにアクセスする際に特定の最適化がないことを考慮することが重要です。パフォーマンスの問題に加えて、集約リストは、テーブルでサポートされる多くの機能に関して制限されます。これらの機能のリストについては、テーブルの概要を参照してください。
上記の理由により、集約リストは、小規模な単純データ (1 ダースまたは 2 ダースのレコード) にのみ使用する必要があり、識別、ルックアップ、アクセス許可などの高度な要件はありません。大規模なデータ (またはより高度な機能) の場合、osd:table
宣言を使用することをお勧めします。
内部検証フレームワークは、データセットまたはテーブルの検証レポートを更新するための連続したリクエスト中に必要な作業を最適化します。インクリメンタル検証プロセスは次のように動作します。
データセットまたはテーブル検証レポートへの最初の呼び出しは、データセットまたはテーブルの完全な検証を実行します。
検証レポートへの次の呼び出しは、最後の検証以降に実行された変更を計算します。検証レポートは、これらの変更に応じて更新されます。
検証レポートは、TIBCO EBX® リポジトリに永続的に保存されます。これにより、データセットに大量の検証メッセージがある場合に、検証レポート専用のメモリの量が削減されます。また、アプリケーションサーバーの再起動時に検証レポートが失われることはありません。
検証レポートは、管理者ユーザーがユーザーインターフェイスで手動でリセットできます (このオプションは、EBX® の検証レポートセクションから利用できます)。結果として、関連付けられたデータセットまたはテーブルは、次回の検証レポートの呼び出し時に完全に再検証されるため、検証レポートのリセットは注意して使用する必要があります。
詳細については、Adaptation.resetValidationReport
を参照してください。
最後の検証以降に更新が発生していなくても、特定の制約は体系的に再検証されます。これらは、不明な依存関係の制約です。次の場合、エレメントには不明な依存関係があります。
デフォルトの不明な依存関係モードでプログラムによる制約を指定します。
これは継承されたフィールドであるか、それ自体が継承されたフィールドであるノードに依存する動的ファセットを宣言します。
したがって、大規模なテーブルでは、次のことをお勧めします。
依存関係が不明な制約は避けてください (または少なくともそのような制約の数を最小限に抑えるため)。プログラムによる制約の場合、開発者は、増分検証コストを大幅に削減する 2 つの代替モードを指定できます。ローカル依存関係モードと明示的依存関係です。詳細については、依存関係と検証を参照してください。
フィールド レベルで定義されたプログラムによる制約の代わりに、テーブルの制約を使用します。実際、テーブルがフィールドレベルで制約を定義している場合、検証プロセスはすべてのレコードに対して繰り返され、関連付けられたフィールドの値が制約に準拠しているかどうかを確認します。テーブルの制約を使用すると、テーブル全体で最適化されたクエリを実行できます。このようなクエリを最適化する方法に関する推奨事項については、下記を参照してください。ただし、トレードオフがあります。テーブルの制約は増分検証の恩恵を受けず、常に完全に検証されます。通常、検証の間に作成または削除されるレコードがわずかしかない場合は、プログラムによる制約の方がパフォーマンスが向上する可能性があります。ベンチマークまたはサンプリングプロファイラーは、決定を下すのに役立ちます。
ファセットパターンのチェックは大規模なテーブルでは最適化されていないため、使用を避けてください。つまり、フィールドがこのファセットを定義している場合、検証プロセスはすべてのレコードを繰り返し処理して、関連付けられたフィールドの値が指定されたパターンに準拠しているかどうかを確認します。
次のプロパティを使用して、検証レポートをログに記録するときのパフォーマンスへの影響を最小限に抑えることができます。
ebx.validation.report.logContent
プロパティを false
に設定して、個々の検証メッセージをログに記録しないようにします。メッセージ数を含む検証レポートの概要は引き続きログに記録されます。Java API によって開始された検証のログを完全に回避することもできます。詳細については、ValidationSpec.setResultLogged
を参照してください。
ebx.validation.report.maxItemDisplayed
プロパティをデフォルトの 100 よりも低い値に設定すると、前の推奨事項よりも効果が低くなりますが、ログに記録する検証メッセージの量が減るため、関連する計算作業が軽減されます。
テーブルには通常、EBX® UI、データサービス、リクエスト
、クエリ
API を介してアクセスされます。このアクセスには、動的解決プロセスを含む独自の機能セットが含まれます。このプロセスは次のように動作します。
継承:データセットツリーの継承では、再帰的なプロセスを使用して、親データセットで定義されているレコードと値が考慮されます。また、ルートデータセットでは、レコードは、xs:default
属性で定義されたデータモデルのデフォルト値からその値の一部を継承できます。
値の計算:osd:function
として宣言されたノードは、値にアクセスすると常にオンザフライで計算されます。ValueFunction.getValue
を参照してください。
フィルター:XPath 述語、プログラムフィルター、またはレコードレベルの権限ルールでは、レコードを選択する必要があります。
並べ替え:結果レコードの並べ替えを実行できます。
テーブルの操作速度を向上させるために、永続的な Lucene インデックスは EBX® エンジンによって管理されます。
インデックスの準備ができて OS メモリキャッシュに保持されている場合は、テーブルへのより高速なアクセスが保証されます。上記で述べたように、OS には十分なスペースが割り当てられていることが重要です。
クエリオプティマイザーは、リクエスト結果を計算するときにインデックスの使用を優先します。クエリがインデックスを利用できない場合、Java メモリで解決され、大容量でパフォーマンスが低下します。次のガイドラインが適用されます。
インデックスの最適化の恩恵を受けることができるのは、XPath 述語と SQL クエリだけです。
制限事項のセクションで説明されているように、一部のフィールドと一部のデータセットはインデックスに登録できません。
osd:label
関数を使用する XPath 述語は、インデックスの最適化の恩恵を受けることができません。
インデックスがまだ作成されていない場合は、テーブルへの最初のアクセス時に、インデックスを作成して永続化するために追加の時間が必要です。
テーブルデータブロックへのアクセスは、クエリをインデックスに対して計算できない場合 (ルールの解決、フィルター、または並べ替えのいずれの場合でも)、およびインデックスの構築に必要です。テーブルブロックがメモリに存在しない場合、データベースからそれらを取得するために追加の時間が必要です。
それとは別に、リクエスト/クエリのパフォーマンスに影響を与える可能性があるその他の考慮事項があります。
フィルター値のバリエーションだけで同じリクエスト/クエリが複数回実行される場合は、上記のフィルターでパラメーターを使用することをお勧めします。
request.setXPathFilter("./field=$param");
SELECT * FROM myTable WHERE field=?
可能であれば、RequestResult.getSize
ではなく RequestResult.isSizeGreaterOrEqual
を使用してください。
可能であれば、RequestResult
サイズ関連の呼び出しは避けてください。特に、RequestResult
で不要なコード パターン「走査する前に isEmpty をチェックする」を避けてください。
try (RequestResult result = ...) { if (result.isEmpty()) return; // unnecessary and inefficient! for (Adaptation record : result) { ... } } // simply do: try (RequestResult result = ...) { for (Adaptation record : result) { ... } }
メモリ監視を介して情報を取得し、ログカテゴリを要求することができます。
次のアクセスはパフォーマンスの低下につながるため、回避する必要があります。
いくつかの変更を繰り返した後、テーブルにアクセスします。これは、変更のたびにインデックスの状態が更新されることを意味します。更新のコストにより、このパターンは無効になります。代わりに、単一のクエリを実行し、結果を参照するときに変更を適用します。
前のケースと同時に、同じテーブルへの継続的なアクセスがある場合、古いインデックスファイルが削除されるのを防ぎます。その結果、ディスク上のインデックスのサイズが大きくなり、極端な場合にはサーバーのディスク容量が不足する可能性があります。同時アクセスが閉じられると、インデックスサイズは通常に戻ります。これは通常、リクエストまたはクエリが適切に閉じられていないことを示しています。
新しいレコードの作成またはレコードの挿入は、主キーインデックスによって異なります。したがって、このインデックスがすでにロードされている場合、作成はほぼ即時になります。
履歴テーブル (merge_info
フィールド) のマージ情報は、アクセスコストが高くなる可能性があります。パフォーマンスを向上させるために、クライアントコードがこのフィールドを必要としない場合は、includeMergeInfo
パラメーターを false
に設定する必要があります。
詳細については、履歴を参照してください。
パフォーマンスを向上させるには、テーブルに対するリクエストの結果の予想サイズに応じてフェッチサイズを設定する必要があります。フェッチサイズが設定されていない場合は、デフォルト値が使用されます。
履歴テーブルでは、デフォルト値が JDBC ドライバーによって割り当てられます。Oracle の場合は 10、PostgreSQL の場合は 0 です。
PostgreSQL では、デフォルト値の 0 は、結果セット全体を一度にフェッチするように JDBC ドライバーに指示します。これにより、大量のデータを取得するときに OutOfMemoryError
が発生する可能性があります。一方、PostgreSQL で fetchSize を使用すると、トランザクションの最後にサーバー側のカーソルが無効になります。同じスレッドで、最初に fetchsize を使用して結果セットをフェッチし、次にトランザクションをコミットするプロシージャを実行すると、次の結果にアクセスすると例外が発生します。
TIBCO EBX® は大量のデータをサポートするように設計されていますが、いくつかの一般的な要因によりパフォーマンスが低下する可能性があります。このセクションで説明する重要なポイントに対処することで、通常のパフォーマンスのボトルネックを解決できます。
参考までに、次の表に、実装できるプログラム拡張機能の詳細を示します。
ユースケース | 関与する可能性のあるプログラム拡張機能 |
---|---|
検証 | |
テーブルアクセス | |
EBX® コンテンツ表示 | |
データの更新 |
大量のデータの場合、計算が非常に複雑なアルゴリズムを使用すると、パフォーマンスに深刻な影響を及ぼします。たとえば、制約のアルゴリズムの複雑さは O (n 2) です。データサイズが 100 の場合、結果のコストは 10000 に比例します (これにより、通常、すぐに結果が得られます)。ただし、データサイズが 10000 の場合、結果のコストは 10000000 に比例します。
パフォーマンスが低下するもう 1 つの理由は、外部リソースの呼び出しです。ローカルキャッシングは通常、このタイプの問題を解決します。
上記のユースケースの 1 つでパフォーマンスが低下する場合は、コード分析または Java プロファイリングツールを使用して問題を追跡することをお勧めします。
Lucene インデックスの更新には時間がかかります。可能な限り避ける必要があります。
更新のタイミング | トランザクションのコンテキストでは、テーブルが変更され、次のいずれかの条件が発生すると、インデックスの更新が発生します。
|
コーディングの推奨事項 |
|
通常、トランザクション内のアトミック更新の数が 10 5 のオーダーを超える場合は、単一のトランザクションを使用することはお勧めしません。大規模なトランザクションには、EBX® および基盤となるデータベースからの多くのリソース、特にメモリが必要です。
トランザクションサイズを減らすために、次のことが可能です。
プロパティ ebx.manager.import.commit.threshold を指定します。ただし、このプロパティは、EBX® ユーザーインターフェイスから実行されるインタラクティブなアーカイブのインポートにのみ使用されます。
バッチプロシージャ内でコミットしきい値を明示的に指定します。
タスクの一部にプロシージャ
を実装し、必要な回数だけ実行することで、トランザクションの範囲を構造的に制限します。
一方、非常に小さいトランザクションサイズを指定すると、コミットごとに実行する必要のある永続的なタスクが原因で、パフォーマンスが低下する可能性もあります。
トランザクションのアトミック性が保証されなくなったために中間コミットが問題になる場合は、専用のデータスペース内で一括更新を実行することをお勧めします。このデータスペースは、一括更新の直前に作成されます。更新が正常に完了しない場合は、データスペースを閉じて、最初の失敗の理由を修正した後、更新を再試行する必要があります。成功すると、データスペースを元のデータスペースに安全にマージできます。
必要に応じて、メソッド ProcedureContext.setTriggerActivation
を使用してトリガーを非アクティブ化できます。
認証と権限の管理には、ユーザーとロールのディレクトリが含まれます。
特定のディレクトリ実装が展開され、外部ディレクトリにアクセスする場合、ローカルキャッシュが確実に実行されるようにすると便利です。特に、最も頻繁に呼び出されるメソッドの 1 つは、Directory.isUserInRole
です。