私のアプリケーションには、クライアント、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 番目のレベルのキャッシュ メカニズムは私のニーズに適していないようです。私ができるようにしたいのは:
- 過去 7 日間分のデータが常にキャッシュにあるように構成します。例えば。「このテーブルでは、このフィールドが 7 日前から現在までの間にあるすべてのレコードをキャッシュします。」
- キャッシュを手動で維持する機能があります。新しいデータがシステムに入ると、キャッシュが無効になるまで待つのではなく、直接キャッシュに入れることができればいいのにと思います。同様に、データが期間外になると、キャッシュからプルできるようにしたいと考えています。
- 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。キューブを使用して集計計算をより迅速に行うことを既に検討しましたが、それでもデータベースがボトルネックとして残ります。キャッシュに加えてキューブを使用することもできますが、キャッシュがないことが今の私の主な関心事です。