目次
皆さんこんにちは、ネザです。
私が初めてキャッシングに触れたときはマップを使ってキャッシングをしていましたが、その時はリアルタイムのデータ同期機能をやっていました。
要件は単純に見えますが、1 回のパスで済みます
- 当時、サーバー データは WebSocket を通じて取得されていました。
- 次に、データ カテゴリに従ってローカル マップにデータをキャッシュします。
- スケジュールされたタスクを作成し、ftp 経由でサードパーティのサーバーにアップロードします。
同時実行が発生するとマップが機能せず、データが乱れてしまいますが、ConcurrentHashMap を使用することで同時データの乱れの問題を解決できます。
- オンサイトのネットワークは非常に不安定で、FTP が起動したり停止したりします。
- 私たちが行っているのは、セキュリティ問題をリアルタイムで監視するシステムですが、サードパーティ データの要件は依然として非常に厳しく、100% 正確である必要があります。
この矛盾をどのように解決するかは不明である。
最初は再起動で解決しました(笑)、再起動ですべての問題が解決しました。
- ハートビート機能を追加して、FTP サービスのステータスをリアルタイムで監視します。
- 7秒以上壊れると警報機能が採用され、現場担当者にFTPネットワークの確認を促すために火災警報音楽を設定したことを覚えています。
- 1分以上切断された場合、ソフトウェアは自動的に再起動します。
しかし、データが失われるという新たな問題が発生します。
データのキャッシュ、つまりローカルキャッシュにConcurrentHashMapを使っているので再起動するとデータが消えてしまうのでしょうか?兄弟。
後から知ったのですが、当時私がやったことは本当にお粗末で、ローカルキャッシュにはたくさんの機能があるはずですが、当時はそれらの機能がありませんでした。
- 最大制限を超える場合は、LRU、LFU などの対応する排除戦略があります。
- タイミング、遅延、定期などの有効期限の排除
- 持久化
- 統計的モニタリング
キャッシュ、ローカル キャッシュ、Redis キャッシュ、Redis キャッシュ戦略の次の側面から、総合的かつ体系的にキャッシュについて学びます。
1. キャッシュ
キャッシュとは、従来のリレーショナルデータベースからアクセス量の多いホットデータをメモリ上にロードすることで、ユーザーが再度アクセスする際にはメモリ上からロードすることで、データベースへのアクセス回数を削減し、問題を解決します。同時実行性が高いシナリオでは、データベースのダウンタイムが発生しやすくなります。
キャッシュのカテゴリは何ですか:
- オペレーティング システムのディスク キャッシュにより、ディスクの機械的動作が軽減されます。
- ファイルシステムの I/O を削減するデータベース キャッシュ
- データベースへのクエリを減らすためのアプリケーション キャッシュ
- Web サーバーのキャッシュ、アプリケーション サーバーのリクエストの削減
- Web サイトへのアクセスを減らすためのクライアント ブラウザーのキャッシュ
ローカル キャッシュ: クライアントがサーバーに書き戻すデータをキャッシュするために、クライアントのローカル物理メモリの一部を確保します。ローカル ライトバック キャッシュがキャッシュしきい値に達すると、データがサーバーに書き込まれます。
次に、ローカル キャッシュの利点を分析します。
データ キャッシュには多くの利点がありますが、そのうちの 2 つは重要です。
- データベースの負荷を軽減する: よく使用されるデータを高速アクセス メモリに保存することで、キャッシュによってバックエンド データベースの負荷が効果的に軽減されます。これは、データベースが頻繁に繰り返される読み取りリクエストに対処する代わりに、複雑なクエリと更新操作の処理に集中できることを意味します。
- 応答速度の向上: データをキャッシュに保存すると、システムはユーザーのリクエストにより迅速に応答できるようになります。毎回データベースからデータを取得する場合と比較して、キャッシュを使用すると必要な情報をミリ秒以内に提供できるため、ユーザー エクスペリエンスが大幅に向上します。
3. ローカルキャッシュソリューション?
ConcurrentHashMap については上で紹介しているので、ここでは詳しく説明しません。
1. Guava Cacheをベースとしたローカルキャッシュを実現
Guava は、Google チームによってオープンソース化された Java コア拡張ライブラリであり、コレクション、同時実行、キャッシュ、IO、リフレクション、その他のツールボックスのパフォーマンスと安定性が含まれており、広く使用されています。
Guava キャッシュは多くの機能をサポートしています。
- 最大容量制限をサポート
- 挿入時間とアクセス時間の 2 つの有効期限削除戦略をサポートします。
- 簡単な統計関数をサポート
- LRUアルゴリズムに基づく実装
2.Caffeineベースのローカルキャッシュを実現
Caffeine は Java8 をベースに実装された新世代のキャッシュ ツールで、キャッシュ性能は理論上の最適値に近く、Guava Cache の強化版とも言え、機能も同様です。
違いは、Caffeine が LRU と LFU の利点を組み合わせたアルゴリズム W-TinyLFU を使用していることです。これには、パフォーマンスにおいて明らかな利点があります。
3. Encacheをベースとしたローカルキャッシュの実現
Encache は、高速で無駄のない機能を備えた純粋な Java インプロセス キャッシュ フレームワークです。
Caffeine や Guava Cache と比較して、Encache は機能が豊富で拡張性が優れています。
アドバンテージ:
- LRU、LFU、FIFOを含む複数のキャッシュ削除アルゴリズムをサポート
- キャッシュはヒープ内ストレージ、オフヒープ ストレージをサポートし、ディスク ストレージは永続性をサポートします
- データ共有の問題を解決するために複数のクラスター ソリューションをサポートする
4.Redisの導入
その後、事故により当事者 A は規制プラットフォームから 100 万元の罰金を課せられましたが、その本質的な理由はデータの損失でした。
これでいいのか、私も冷や汗をかきながら一晩考えた修正案、最終解決策は「Redisの導入」です。
Redis は、高性能のメモリストレージ キャッシュ データベースとして、データをキャッシュするシナリオで広く使用されています。
- ユーザーが初めてデータにアクセスするときは、キャッシュにデータが存在しないため、ディスクからデータを読み取るプロセスが比較的遅いため、データベースからデータを取得する必要があります。
- データを取得したら、そのデータをキャッシュに保存します。
- ユーザーが 2 回目にデータにアクセスするときは、キャッシュがメモリを直接操作するため、データ アクセス速度が比較的高速であるため、キャッシュから直接データを取得できます。
以下では、LRU (最も最近使用されていない) や LFU (最も頻繁に使用されていない) などのアルゴリズムに焦点を当てて、Redis のデータ キャッシュ戦略について詳しく説明し、パフォーマンスの最適化を通じてキャッシュ システムの効率を向上させる方法を共有します。
5. Redis データキャッシュ戦略
1. データ キャッシュ戦略が必要なのはなぜですか?
最新のアプリケーションでは、データ キャッシュが重要な役割を果たします。
頻繁にアクセスされるデータをメモリに保存することで、不必要なデータベース クエリを回避でき、システムの応答性とスループットが大幅に向上します。
ただし、アプリケーションの規模とユーザーの訪問数が継続的に増加するにつれて、効果的なデータ キャッシュ戦略が特に重要になります。
さまざまなニーズや課題に対応するには、パフォーマンスとリソース使用率の最適なバランスを見つける必要があります。
これはさらに、さまざまなアプリケーション シナリオに適合する適切なデータ キャッシュ戦略をどのように選択するかという重要な疑問につながります。
次の図は、データ キャッシュの利点と、適切なデータ キャッシュ戦略を選択するプロセスを詳細に示しています。
上の図を通じて、データ キャッシュの利点を詳しく調査し、適切なキャッシュ戦略を選択する際に、パフォーマンスの向上とリソース使用率の最適なバランスを見つける方法を示しました。
適切な戦略を選択すると、データベースへの負荷が効果的に軽減され、応答速度が向上してより良いユーザー エクスペリエンスが提供されます。
2. キャッシュとしての Redis の利点
Redis (リモート ディクショナリ サーバー) は、強力で高性能なオープン ソース メモリ データベースであり、キャッシュ シナリオで広く使用されるだけでなく、キュー、パブリッシュ/サブスクライブ システムなどとしても使用されます。キャッシュ データベースとして、Redis には一連の優れた利点があります。
(1) 高い機能性
Redis データはメモリに保存されるため、優れた読み取りおよび書き込みパフォーマンスを発揮します。その効率的なデータ構造と最適化されたアルゴリズムにより、読み取りおよび書き込み操作のほとんどがマイクロ秒以内に完了し、同時実行性の高いアプリケーションのニーズを満たします。
(2) 多様なキャッシュ戦略
Redis はさまざまなデータ キャッシュ戦略を提供し、開発者がビジネスの特性に基づいて適切な戦略を選択できるようにします。この柔軟性により、アクセス パターン、使用頻度、その他の要因に基づいて、データをいつクリーニングするか保持するかを決定できます。
次の図は、キャッシュ戦略の選択プロセスを示しています。
データ アクセス パターンを分析することにより、データのアクセス頻度に応じて適切なキャッシュ戦略を選択します。実際の状況に応じてデータアクセスを継続的に監視し、キャッシュ戦略を最適化し、これらの戦略をさまざまなシナリオに柔軟に適用します。
6. LRU アルゴリズム: 最も最近使用されていないアルゴリズム
LRU (最も最近使用されていない) アルゴリズムは、古典的なキャッシュ置換戦略であり、その中心的な考え方は、まず最も最近使用されていないデータを削除して、新しいデータ用のスペースを確保することです。データ キャッシュ シナリオでは、LRU アルゴリズムは人気のあるデータを保持できるため、キャッシュ ヒット率が向上します。
1. LRUアルゴリズムの原理の解析
LRU アルゴリズムの原理は非常に直感的です。キャッシュ スペースがいっぱいになると、システムはまず、長期間アクセスされていないデータを削除します。この戦略の背後にある考え方は、データが最近アクセスされなかった場合、将来もアクセスされなくなる可能性があるということです。この置換戦略は、キャッシュ内のデータ热数据
、つまり最近アクセスされたデータを最新の状態に保つのに役立ちます。
上図は、LRU アルゴリズムがアクセス順序に従ってデータをキャッシュに保持する様子を示しています。最後にアクセスされたデータはキャッシュに保持されますが、最も古いアクセスされたデータが最初に置き換えられます。
サンプル コードは次のとおりで、LinkedHashMap
継承を通じて LRU キャッシュを実装する方法を示しています。
import java.util.LinkedHashMap;
import java.util.Map;
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int MAX_CAPACITY;
public LRUCache(int capacity) {
super(capacity, 0.75f, true);
MAX_CAPACITY = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > MAX_CAPACITY;
}
}
この例では、LRUCache
を継承するクラスを作成しますLinkedHashMap
。メソッドを書き換えることでremoveEldestEntry
、キャッシュサイズが一定の閾値を超えた場合に、長期間アクセスのなかったデータを自動的に削除するように指定しました。
2. Redis に LRU アルゴリズムを適用する
Redis では、maxmemory-policy
構成オプションを通じて LRU アルゴリズムのキャッシュ戦略を有効にすることができます。Redis のメモリ使用量が制限に達すると、LRU アルゴリズムを使用して一部のデータが削除され、新しいデータ用のスペースが確保されます。
Redis で LRU キャッシュ戦略を有効にする方法の例を次に示します。
# 启用LRU缓存策略
CONFIG SET maxmemory-policy allkeys-lru
3. LRU アルゴリズムの利点と制限
LRU (最も最近使用されていない) アルゴリズムは、一般的に使用されるデータ キャッシュ戦略ですが、キャッシュされたデータを管理する場合、いくつかの明らかな利点といくつかの制限があります。
アドバンテージ
アドバンテージ | 説明する |
---|---|
ホットデータ用 | LRU アルゴリズムは、最後にアクセスされたデータを保持するため、明らかなアクセス ホットスポットがあるシナリオに非常に適しています。 |
シンプルで効果的な | LRU アルゴリズムの実装は比較的単純で、複雑な計算やメンテナンスは必要ありません。 |
限界
限界 | 説明する |
---|---|
定期訪問 | LRU アルゴリズムは、特に一部の特殊なビジネス シナリオにおいて、定期的なデータ アクセスにより不必要なデータ置換を引き起こす可能性があります。 |
キャッシュ汚染 | LRU アルゴリズムは、突然の大量のアクセスの影響を受けやすく、キャッシュ内の「ホット」データが削除され、キャッシュの効果に影響を与える可能性があります。 |
7、LFU アルゴリズム: 最も使用頻度が低い
LFU (Least Frequently Used) アルゴリズムは、LRU に似たキャッシュ置換戦略であり、その中心的な考え方は、まず使用頻度の低いデータを削除して、新しいデータ用のスペースを確保することです。一部の特定のシナリオでは、LFU アルゴリズムはデータ アクセス パターンの変化によりよく適応できます。
1. LFUアルゴリズムの原理の解析
LFU アルゴリズムの原理は LRU アルゴリズムと似ていますが、異なる点は、LFU アルゴリズムでは、アクセスの時系列順だけでなく、アクセスされるデータの頻度に基づいて置換の決定を行うことです。LFU アルゴリズムはデータのアクセス頻度を記録しており、データを削除する必要がある場合は、アクセス頻度が最も低いデータが最初に選択されます。
上の図は、LFU アルゴリズムがデータ アクセスの頻度に応じてデータをキャッシュにどのように保持するかを示しています。頻繁にアクセスされるデータは保持されますが、アクセス頻度の低いデータは最初に置き換えられます。
2. Redis に LFU アルゴリズムを適用する
Redis では、maxmemory-policy オプションを構成することで、LFU アルゴリズムのキャッシュ ポリシーを有効にできます。Redis のメモリ使用量が制限に達すると、LFU アルゴリズムを使用して一部のデータが削除され、新しいデータ用のスペースが確保されます。
Redis で LFU キャッシュ戦略を有効にする方法の例を次に示します。
# 启用LFU缓存策略
CONFIG SET maxmemory-policy allkeys-lfu
3. LFUアルゴリズムの利点と限界
LFU (Least Frequently Used) アルゴリズムは代替データ キャッシュ戦略ですが、さまざまなシナリオで明らかな利点といくつかの制限があります。
アドバンテージ
アドバンテージ | 説明する |
---|---|
頻繁なリフレッシュに最適 | LFU アルゴリズムは、頻繁に更新されるデータの保持を優先することができるため、一部の定期的なアクセス シナリオに適しています。 |
データ熱の変化に敏感 | LRU アルゴリズムと比較して、LFU アルゴリズムはデータ アクセス パターンの変化により適応し、データの熱をよりよく反映できます。 |
限界
限界 | 説明する |
---|---|
計算の複雑さ | LFU アルゴリズムはデータ アクセス頻度の記録を維持する必要があるため、特に大規模なデータ シナリオでは、特定の計算が複雑になる可能性があります。 |
コールドスタートの問題 | アクセスされたばかりのデータの場合、アクセス頻度の情報が不十分なため、LFU アルゴリズムが適切な置換の決定を行うことが困難になる可能性があります。 |
8. その他のデータ キャッシュ戦略
1、最も最近使用されていないサンプリング(LRUS)
従来の LRU アルゴリズムに加えて、改良版である LRUS (Least Recent Used with Sampling) アルゴリズムがあります。LRUS アルゴリズムは定期的なサンプリングを通じてデータ アクセスを記録するため、最近使用されたデータをより適切に推定し、LRU アルゴリズムの「コールド スタート」問題を軽減します。
LRUS アルゴリズムの原理
LRUS アルゴリズムでは、一部のデータのアクセス ステータスを定期的に記録することで、どのデータがホットでどのデータがコールドであるかをより正確に判断するサンプリング メカニズムが導入されています。従来の LRU アルゴリズムとは異なり、LRUS アルゴリズムはデータ アクセス パターンの変化によりよく適応し、データ キャッシュのヒット率を向上させることができます。
上図の LRUS アルゴリズムは、どのデータを保持し、どのデータを置き換えるべきかをより正確に決定するために、定期的なサンプリングを通じてデータ アクセスを記録します。
2. ランダム置換
ランダム置換は、シンプルですが効果的なキャッシュ戦略です。LRU や LFU とは異なり、ランダム置換戦略ではデータのアクセス時間や頻度は考慮されませんが、置換されるデータがランダムに選択されます。これは賢くないように思えますが、シナリオによっては、ランダムな置換戦略が予期せぬ利点を示します。
ランダム置換の原理
ランダム置換の中心的な考え方は、データを置換する必要があるたびに、キャッシュから置換対象のデータをランダムに選択することです。この戦略ではデータの人気や頻度は考慮されていませんが、特殊なケースでは、ランダムな置換により特定のデータが頻繁に削除されるのを防ぎ、ある程度のデータの多様性を維持できます。
上図では、ランダム置換アルゴリズムにより置換対象のデータがランダムに選択されるため、場合によってはデータの多様性が維持されます。
9. 性能の最適化と実用化
1. データ キャッシュ戦略のパフォーマンスに関する考慮事項
パフォーマンスは、データ キャッシュ戦略を選択および構成する際の重要な要素です。さまざまなキャッシュ戦略がさまざまなビジネス シナリオに適用できるため、意思決定を行う際には複数の要素を包括的に考慮する必要があります。
(1) キャッシュサイズとヒット率のバランス
キャッシュ サイズを構成するときは、キャッシュの合計サイズと実際に保存されるデータの量を比較検討する必要があります。キャッシュが小さすぎるとヒット率が低下し、データベースの負荷を効果的に軽減できない可能性があり、キャッシュが大きすぎるとメモリ リソースが無駄になる可能性があります。キャッシュ サイズは通常、ヒット率とキャッシュ使用率を監視することで最適化できます。
(2) データアクセスモードの解析
適切なキャッシュ戦略を選択するには、ビジネスのデータ アクセス パターンを分析することが重要です。たとえば、一部のデータが頻繁にアクセスされ、他のデータがほとんどアクセスされない場合、適切な戦略を選択することでキャッシュの効率を向上させることができます。頻繁にアクセスされるホット データの場合は、LRU または LFU 戦略を選択でき、アクセス頻度の低いコールド データの場合は、ランダム置換戦略を検討できます。
2. 活用事例:ECサイト
実際の適用例を使用して、ビジネス ニーズに応じて適切なキャッシュ戦略を選択する方法を示しましょう。ユーザーが製品リスト、製品詳細、ショッピング カート ページに頻繁にアクセスする電子商取引サイトを考えてみましょう。このシナリオでは、パフォーマンスを最適化するためにさまざまなキャッシュ戦略を選択できます。
(1) ECサイトのキャッシュ戦略の選択
製品一覧ページ: 製品一覧ページの製品情報は頻繁に変更されるため、LRU またはランダム交換戦略を選択できます。これにより、最近の商品データが保存され、ページの読み込み速度が向上します。
// 使用LRU算法实现商品列表页缓存
LRUCache<String, List<Product>> productListCache = new LRUCache<>(1000); // 缓存容量1000
List<Product> cachedProductList = productListCache.get("productList");
if (cachedProductList == null) {
// 从数据库获取商品列表数据
List<Product> productList = database.getProductList();
productListCache.put("productList", productList);
cachedProductList = productList;
}
商品詳細ページ: 商品詳細ページのデータは比較的安定しているため、LFU 戦略の選択に適しています。これにより、頻繁にアクセスされる商品詳細データを保存し、ページの応答速度を向上させることができます。
// 使用LFU算法实现商品详情页缓存
LFUCache<String, ProductDetails> productDetailsCache = new LFUCache<>(500); // 缓存容量500
ProductDetails cachedProductDetails = productDetailsCache.get("product123");
if (cachedProductDetails == null) {
// 从数据库获取商品详情数据
ProductDetails productDetails = database.getProductDetails("product123");
productDetailsCache.put("product123", productDetails);
cachedProductDetails = productDetails;
}
ショッピング カート ページ: ショッピング カート ページのデータはユーザーと密接に関連しており、LRU または LRUS 戦略を選択できます。これにより、最後にアクセスしたカート データが保存され、ユーザー エクスペリエンスが向上します。
// 使用LRUS算法实现购物车页缓存
LRUSCache<String, ShoppingCart> shoppingCartCache = new LRUSCache<>(200); // 缓存容量200
ShoppingCart cachedShoppingCart = shoppingCartCache.get("user123");
if (cachedShoppingCart == null) {
// 从数据库获取购物车数据
ShoppingCart shoppingCart = database.getShoppingCart("user123");
shoppingCartCache.put("user123", shoppingCart);
cachedShoppingCart = shoppingCart;
}
(2) 性能の最適化と実用化の改善
実際のアプリケーションでは、電子商取引 Web サイトは、キャッシュ戦略を適切に構成し、キャッシュ サイズを最適化することで、ページの読み込み速度とユーザー エクスペリエンスを大幅に向上させることができます。同時に、データ アクセス パターンの変化を監視することで、キャッシュ戦略を動的に調整してパフォーマンスをさらに最適化できます。
10. 概要と実践的なガイダンス
1. Redis データキャッシュ戦略の重要性
データ キャッシュにより、システムのパフォーマンスが向上するだけでなく、バックエンド データベースへの負荷も軽減され、応答時間が短縮され、ユーザー エクスペリエンスが向上します。最新の同時実行性の高いアプリケーションでは、データ キャッシュ戦略の最適化がシステム設計の不可欠な部分になっています。
2. 適切なキャッシュ戦略を選択する方法
実際のアプリケーションでは、適切なキャッシュ戦略を選択することが重要です。さまざまなビジネス シナリオやデータ アクセス パターンに応じて、LRU、LFU、LRUS、ランダム置換などのキャッシュ戦略を柔軟に選択できます。同時に、実際のニーズに応じてキャッシュのサイズを動的に調整し、パフォーマンスとリソース使用率の最適なバランスを実現できます。
実践的なガイダンス:
- データ アクセス パターンを分析する: キャッシュ戦略を選択する前に、まずデータ アクセス パターンを詳細に分析する必要があります。頻繁にアクセスされるデータはどれですか? どのデータの変化が少ないでしょうか? この情報に基づいて、適切なキャッシュ戦略を選択します。
- 適切なアルゴリズムを選択する: ビジネス要件に基づいて、適切なキャッシュ アルゴリズムを選択します。LRU は最近アクセスされたデータを保持するのに適しており、LFU は最も頻繁にアクセスされたデータを保持するのに適しており、LRUS はアクセス パターンの変化に対処するのに適しています。
- 監視と最適化: キャッシュ戦略は静的ではないため、データ アクセス状況を継続的に監視し、キャッシュ サイズと戦略を最適化する必要があります。ヒット率とキャッシュの使用率を監視することで、動的に調整を行うことができます。
- 柔軟なアプリケーション: ビジネス モジュールが異なれば、異なるキャッシュ戦略が必要になる場合があります。実際の状況に応じて、パフォーマンスを最大化するためにシステムでさまざまなキャッシュ戦略を採用できます。