プラットフォームキャッシュのベストプラクティス
パフォーマンスへの影響を評価する
プラットフォームキャッシュによってアプリケーションのパフォーマンスが向上するかどうかをテストするには、キャッシュを使用した場合と使用しない場合の経過時間を計算します。実行時間については Apex デバッグログのタイムスタンプを使用しないでください。代わりに System.currentTimeMillis() メソッドを使用します。たとえば、最初に System.currentTimeMillis() をコールして開始時刻を取得します。アプリケーションロジックを実行し、キャッシュまたは別のデータソースからデータを取得します。その後で経過時間を計算します。
1long startTime = System.currentTimeMillis();
2// Your code here
3long elapsedTime = System.currentTimeMillis() - startTime;
4System.debug(elapsedTime);キャッシュの欠落を適切に処理する
null を返すキャッシュ要求をテストして、コードでキャッシュの欠落が処理されることを確認します。デバッグに役立てるために、キャッシュ操作に関する情報のログ記録を追加します。
または、キャッシュの欠落をチェックする Cache.CacheBuilder インターフェースを使用します。
1public class CacheManager {
2 private Boolean cacheEnabled;
3
4 public void CacheManager() {
5 cacheEnabled = true;
6 }
7
8 public Boolean toggleEnabled() { // Use for testing misses
9 cacheEnabled = !cacheEnabled;
10 return cacheEnabled;
11 }
12
13 public Object get(String key) {
14 if (!cacheEnabled) return null;
15 Object value = Cache.Session.get(key);
16 if (value != null) System.debug(LoggingLevel.DEBUG, 'Hit for key ' + key);
17 return value;
18 }
19
20 public void put(String key, Object value, Integer ttl) {
21 if (!cacheEnabled) return;
22 Cache.Session.put(key, value, ttl);
23 // for redundancy, save to DB
24 System.debug(LoggingLevel.DEBUG, 'put() for key ' + key);
25 }
26
27 public Boolean remove(String key) {
28 if (!cacheEnabled) return false;
29 Boolean removed = Cache.Session.remove(key);
30 if (removed) {
31 System.debug(LoggingLevel.DEBUG, 'Removed key ' + key);
32 return true;
33 } else return false;
34 }
35
36}キャッシュ要求をまとめる
可能ならばキャッシュ要求をまとめます。ただし、キャッシュ制限には注意してください。パフォーマンスが向上するように、個々のキーではなくキーのリストに対してキャッシュ操作を実行します。たとえば、Visualforce ページを呼び出したり、Apex でタスクを実行したりするのに必要なキーがわかっている場合は、一度にすべてのキーを取得します。複数のキーを取得するには、初期化メソッドで get(keys) をコールします。
キャッシュする項目を大きくする
多くの小さな項目を別々にキャッシュするよりも、少しの大きな項目をキャッシュする方が効率的です。多くの小さな項目をキャッシュすると、パフォーマンスが低下し、合計シリアライゼーションサイズ、シリアライゼーション時間、キャッシュコミット時間、キャッシュ容量の使用率など、オーバーヘッドが増加します。
1 回の要求でプラットフォームキャッシュに多くの小さな項目を追加しないでください。代わりに、リストなど、データをより大きな項目でラップします。リストが大きい場合、複数の項目に分割することを検討します。次に、避けるべき例を示します。
1// Don't do this!
2
3public class MyController {
4
5 public void initCache() {
6 List<Account> accts = [SELECT Id, Name, Phone, Industry, Description FROM
7 Account limit 1000];
8 for (Integer i=0; i<accts.size(); i++) {
9 Cache.Org.put('acct' + i, accts.get(i));
10 }
11 }
12}代わりに、キャッシュ項目あたりのサイズ制限を超えない、いくつかの妥当な大きさの項目でデータをラップします。
1// Do this instead.
2
3public class MyController {
4
5public void initCache() {
6 List<Account> accts = [SELECT Id, Name, Phone, Industry, Description FROM
7 Account limit 1000];
8 Cache.Org.put('accts', accts);
9 }
10}大きめの項目をキャッシュするもう 1 つのよい例は、データを Apex クラスにカプセル化することです。たとえば、個々のデータ項目ではなく、セッションデータをラップするクラスを作成し、そのクラスのインスタンスをキャッシュできます。クラスインスタンスをキャッシュすると、全体的なシリアライゼーションサイズとパフォーマンスが改善されます。
キャッシュ制限に注意する
項目をキャッシュに追加するときには、次の制限に注意します。
- キャッシュパーティションサイズ制限
- キャッシュパーティション制限に達すると、キャッシュが 100 % の容量に削減されるまでキーが強制削除されます。プラットフォームキャッシュでは、Least Recently Used (LRU) アルゴリズムを使用してキャッシュからキーを強制削除します。
- ローカルキャッシュサイズ制限
-
項目をキャッシュに追加するときには、1 要求内のローカルキャッシュ制限を超えないようにしてください。セッションキャッシュのローカルキャッシュ制限は 500 KB、組織キャッシュは 1,000 KB です。ローカルキャッシュ制限を超えた場合、要求がコミットされる前に項目がローカルキャッシュから強制削除されることがあります。この強制削除によって、予期しない欠落や長時間のシリアライゼーションが発生しかねず、リソースが浪費される場合があります。
- 単一キャッシュ項目のサイズ制限
- 個々のキャッシュ項目のサイズは、100 KB に制限されています。項目のシリアライズサイズがこの制限を超えると、Cache.ItemSizeLimitExceededException 例外が発生します。この例外をキャッチし、キャッシュ項目のサイズを削減することをお勧めします。
キャッシュ診断ページを (慎重に) 使用する
- ([ユーザの詳細] ページで) ユーザの [キャッシュ診断] が有効であることを確認します。
- [プラットフォームキャッシュ区分] ページで、パーティション名をクリックします。
- パーティションの [診断] ページへのリンクをクリックします。
高コストの操作を最小限に抑える
高コストの操作を最小限に抑えるには、次のガイドラインを考慮します。
- Cache.Org.getKeys() および Cache.Org.getCapacity() は慎重に使用します。どちらのメソッドも高コストです。これは、すべてのパーティション関連情報をトラバースして特定のパーティションを探したり、そのパーティションの計算を行ったりするためです。
- contains(key) メソッドの後に get(key) メソッドをコールするのは避けてください。キー値を使用する場合は、get(key) メソッドをコールし、値が null ではないことを確認するだけにします。
- キャッシュは必要な場合にのみクリアします。キャッシュのクリアでは、すべてのパーティション関連キャッシュ空間をトラバースします。つまり、高コストです。キャッシュをクリアした後、アプリケーションは、データベースクエリ��計算を呼び出してキャッシュを再生成する可能性があります。この再生成は複雑で広範囲に及ぶことがあるため、アプリケーションのパフォーマンスに影響を与えます。