0

私のアプリケーションには、クライアント、Web 層 (負荷分散)、アプリケーション層 (負荷分散)、およびデータベース層が含まれています。Web 層はサービスをクライアントに公開し、呼び出しをアプリケーション層に転送します。次に、アプリケーション層はデータベースに対して (NHibernate を使用して) クエリを実行し、結果を返します。

データはほとんどが読み取られますが、特に新しいデータがシステムに入力されると、書き込みがかなり頻繁に発生します。多くの場合、データは集約され、元のデータではなく、それらの集約がクライアントに返されます。

通常、ユーザーは最近のデータ (たとえば、過去 1 週間) の集計に関心があります。したがって、過去 7 日間のすべてのデータを含むキャッシュを導入することは理にかなっています。ある範囲のエンティティを集約する必要があり、その範囲はフィルタなどの他の複雑さとともにクライアントによって決定されるため、エンティティがロードされたときにエンティティをキャッシュすることはできません。特定の時間範囲で、その範囲内のすべてのデータがキャッシュにあるかどうかを知る必要があります。

私の理想的なファンタジーの世界では、サービスをまったく変更する必要はありません。

public AggregationResults DoIt(DateTime starting, DateTime ending, Filter filter)
{
    // execute HQL/criteria call and have it automatically use the cache where possible
}

NHibernate にフックし、キャッシュに対して HQL/基準クエリを実行できるかどうかをインテリジェントかつ透過的に判断し、必要な場合にのみデータベースにアクセスする別のフィルタリング レイヤーが存在します。すべてのデータがキャッシュにある場合は、インメモリ データベースのように、キャッシュされたデータ自体にクエリを実行します。

しかし、最初の調査では、NHibernate の 2 番目のレベルのキャッシュ メカニズムは私のニーズに適していないようです。私ができるようにしたいのは:

  1. 過去 7 日間分のデータが常にキャッシュにあるように構成します。例えば。「このテーブルでは、このフィールドが 7 日前から現在までの間にあるすべてのレコードをキャッシュします。」
  2. キャッシュを手動で維持する機能があります。新しいデータがシステムに入ると、キャッシュが無効になるまで待つのではなく、直接キャッシュに入れることができればいいのにと思います。同様に、データが期間外になると、キャッシュからプルできるようにしたいと考えています。
  3. NHibernate に、データベースにまったくアクセスするのではなく、キャッシュから直接クエリを提供できるタイミングをインテリジェントに理解させます。例えば。ユーザーが過去 3 日間のデータの集計を要求した場合、その集計は DB にアクセスするのではなく、キャッシュから直接計算する必要があります。

今、私は #3 があまりにも多くを求めていると確信しています。キャッシュに必要なすべてのデータを取り込むことができたとしても、NHibernate はそのデータを効率的にクエリする方法を知りません。クエリに関連するものを区別するために、文字通りすべてのエンティティをループする必要があります (正直なところ、これで問題ないかもしれません)。また、データベースではなくオブジェクトに対して実行する NHibernate のクエリ エンジンの実装が必要になります。しかし、私は夢を見ることができますよね?

#3 の要求が多すぎると仮定すると、サービスに次のようなロジックが必要になります。

public AggregationResults DoIt(DateTime starting, DateTime ending, Filter filter)
{
    if (CanBeServicedFromCache(starting, ending, filter))
    {
        // execute some LINQ to object code or whatever to determine the aggregation results
    }
    else
    {
        // execute HQL/criteria call to determine the aggregation results
    }
}

これは理想的ではありません。これは、各サービスがキャッシュを認識する必要があり、集計ロジックを複製する必要があるためです。1 回は NHibernate を介してデータベースをクエリするため、もう 1 回はキャッシュをクエリするためです。

とはいえ、少なくとも関連データを NHibernate の第 2 レベルのキャッシュに格納できればいいのですが。そうすることで、(集約を行わない) 他のサービスが透過的にキャッシュの恩恵を受けることができます。また、システムの他の場所で第 2 レベルのキャッシュが必要であると判断した場合に、キャッシュされたエンティティ (第 2 レベルのキャッシュに 1 回、自分の別のキャッシュに 1 回) を 2 倍にしないようにします。

実行時に の実装を把握できればICache、メソッドを呼び出しPut()てデータをキャッシュに入れるだけでよいのではないかと思います。しかし、これは危険な地面を踏んでいる可能性があります...

私の要件のいずれかが NHibernate の第 2 レベルのキャッシュ メカニズムによって満たされるかどうかについて、誰か洞察を提供できますか? それとも、独自のソリューションをロールバックして、NHibernate の第 2 レベルのキャッシュを完全に放棄する必要がありますか?

ありがとう

PS。キューブを使用して集計計算をより迅速に行うことを既に検討しましたが、それでもデータベースがボトルネックとして残ります。キャッシュに加えてキューブを使用することもできますが、キャッシュがないことが今の私の主な関心事です。

4

3 に答える 3

2

トランザクション ( OLTP ) データソースを分析 ( OLAP ) クエリに使用するのをやめれば、問題は解決します。

ドメインに重要なイベントが発生すると (たとえば、新しいエンティティがシステムに入る、または更新される)、イベントが発生します (ドメイン イベントのように)。作成または更新されたエンティティの詳細を取得し、必要な集計のレポートを許可するように特別に設計された非正規化されたレポート ストアにデータを格納するイベントのハンドラーを接続します (ほとんどの場合、データをスター スキーマにプッシュします)。これで、レポートは単純な選択といくつかの結合だけを必要とする事前定義された軸に沿った集計 (事前に計算されている場合もあります) のクエリになります。クエリは、L2SQL などを使用して実行することも、単純なパラメーター化されたクエリとデータリーダーを使用して実行することもできます。

ID による高速ルックアップのために書き込み側を最適化し、書き込み時のインデックス負荷を軽減しながら、多くの基準にわたる高速ルックアップのために読み取り側を最適化できるため、パフォーマンスが大幅に向上するはずです。

このアプローチに移行すると、読み取りストアと書き込みストアを物理的に分離して、書き込みストアごとに n 読み取りストアを実行できるため、パフォーマンスとスケーラビリティも向上します。これにより、ソリューションをスケールアウトして、読み取り需要の増加に対応できます。一方、書き込み要求はより低い割合で増加します。

于 2010-03-02T19:36:57.773 に答える
1

2 つのキャッシュ領域「aggregation」と「aggregation.today」を長い有効期限で定義します。これらは、それぞれ前日と今日の集計クエリに使用します。

ではDoIt()、キャッシュ可能なクエリを使用して、要求された範囲で 1 日あたり 1 つの NH クエリを作成します。クエリ結果を C# で結合します。

DoIt()キャッシュする必要がある日付範囲で定期的に呼び出すバックグラウンド プロセスでキャッシュを準備します。このプロセスの頻度は、集約キャッシュ領域の有効期限よりも低くする必要があります。

今日のデータが変化したら、キャッシュ領域「aggregation.today」をクリアします。このキャッシュ リージョンをすばやくリロードする場合は、すぐにリロードするか、別のより頻繁なバックグラウンド プロセスをDoIt()今日呼び出す必要があります。

クエリ キャッシングを有効にすると、NHibernate は可能であればキャッシュから結果を取得します。これは、クエリとパラメーターの値に基づいています。

于 2010-03-01T16:14:13.657 に答える
0

NHibernate キャッシュの詳細を分析するときに、そこにあるキャッシュについて中継してはならないことを読んだことを覚えています。魔女は良い提案のようです。

O/R マッパーでアプリケーションのニーズをカバーしようとする代わりに、独自のデータ/キャッシュ管理戦略を展開する方が合理的であると思います。

また、あなたが話している 7 日間のキャッシュ ルールは、ビジネスに関連するもののように聞こえますが、魔女は O/R マッパーが知っておくべきことではありません。

結論として、プロファイラー (またはそれ以上 - .net,sql,nhibernate プロファイラー) を使用してボトルネックがどこにあるかを確認し、最終的にキャッシングまたはその他の最適化を追加して「赤い」部分の改善を開始するよりも、アプリをまったくキャッシュなしで動作させます。 .

PS: 一般的なキャッシングについて - 私の経験では、1 つのキャッシング ポイントで問題ありません。

それが役に立てば幸い

于 2010-03-01T21:34:37.937 に答える