ホームページ バックエンド開発 PHPチュートリアル プログラミング技術のキャッシュ書き込み方式(3)

プログラミング技術のキャッシュ書き込み方式(3)

Nov 30, 2016 am 09:27 AM

前回はマルチレベルキャッシュについて説明しましたが、この章ではメモリキャッシュの設計方法を詳しく紹介します。

1: 分析と設計

次のように、マルチレベル キャッシュの使用を必要とする一定量の同時実行性を持つプロジェクトがあるとします。

プログラミング技術のキャッシュ書き込み方式(3)

実際にメモリ キャッシュを設計する前に、次のことを考慮する必要があります。問題:

1: Redis によるメモリ データの置換により、メモリ内のデータ ヒット率が可能な限り向上し、次のレベルでのプレッシャーが軽減されます。

2: メモリ容量の制限、キャッシュの数を制御する必要があります。

3: ホットスポット データの更新は異なり、単一キーの有効期限を構成できる必要があります。

4: 優れたキャッシュ有効期限削除戦略。

5: キャッシュ データ構造の複雑さを可能な限り低く保ちます。

置換とヒット率について:実装が簡単で、キャッシュキーのヒット率も非常に優れているため、LRUアルゴリズムを使用します。

LRU とは、最も最近アクセスされていないデータを削除し、頻繁にアクセスされるデータをホット データとします。

LRU データ構造について: キーの優先順位の昇格とキーの削除のため、シーケンシャルな構造が必要です。ほとんどの実装では、リンク リストの先頭に新しいデータが挿入され、ヒットしたデータが先頭に移動するというリンク リスト構造が採用されていることがわかりました。 複雑さを追加するのは O(1)、移動して複雑さを取得するのは O(N) です。

もっと複雑でないものはありますか? Dictionary があり、その複雑さは O(1) で最高のパフォーマンスを持っています。 では、キャッシュの優先順位を確実に向上させるにはどうすればよいでしょうか?

2: O(1) LRU 実装

LRUCache クラスを定義し、キャッシュの最大数を制御するパラメータ maxKeySize を構築します。

キャッシュ コンテナとして ConcurrentDictionary を使用し、スレッドの安全性を確保します。

public class LRUCache<TValue> : IEnumerable<KeyValuePair<string, TValue>>
   {
       private long ageToDiscard = 0;  //淘汰的年龄起点
       private long currentAge = 0;        //当前缓存最新年龄
       private int maxSize = 0;          //缓存最大容量
       private readonly ConcurrentDictionary<string, TrackValue> cache;
       public LRUCache(int maxKeySize)
       {
           cache = new ConcurrentDictionary<string, TrackValue>();
           maxSize = maxKeySize;
       }
   }
ログイン後にコピー

2 つの自己増加パラメーター ageToDiscard と currentAge は、キャッシュ リスト内の各キーの新しさをマークするために定義されています。

コアの実装手順は次のとおりです:

1: キーが追加されるたびに、currentAge が増分され、currentAge 値がこのキャッシュ値の Age に割り当てられます。

public void Add(string key, TValue value)
       {
           Adjust(key);
           var result = new TrackValue(this, value);
           cache.AddOrUpdate(key, result, (k, o) => result);
       }
       public class TrackValue
       {
           public readonly TValue Value;
           public long Age;
           public TrackValue(LRUCache<TValue> lv, TValue tv)
           {
               Age = Interlocked.Increment(ref lv.currentAge);
               Value = tv;
           }
       }
ログイン後にコピー

2:追加する際、最大数量を超えた場合。辞書に ageToDiscard 年齢キーがあるかどうかを確認します。巡回自動インクリメント チェックがない場合、削除と追加は成功します。

ageToDiscard+maxSize= currentAge なので、リンク リストの移動を使用する代わりに、O(1) で古いデータを確実に削除できるように設計されています。

public void Adjust(string key)
        {
            while (cache.Count >= maxSize)
            {
                long ageToDelete = Interlocked.Increment(ref ageToDiscard);
                var toDiscard =
                      cache.FirstOrDefault(p => p.Value.Age == ageToDelete);
                if (toDiscard.Key == null)
                    continue;
                TrackValue old;
                cache.TryRemove(toDiscard.Key, out old);
            }
        }
ログイン後にコピー

期限切れの削除戦略

ほとんどの場合、LRU アルゴリズムはホットスポット データに対して高いヒット率を示します。 しかし、突発的に大量のデータアクセスが突然発生すると、大量のコールドデータがメモリに格納され、キャッシュ汚染が発生します。

により、LRU がホットスポット データにヒットできなくなり、キャッシュ システムのヒット率が急激に低下します。 LRU-K、2Q、MQ などのバリアント アルゴリズムを使用してヒット率を向上させることもできます。

有効期限設定

1: 最大有効期限を設定することで、メモリ内にコールド データが常駐することを回避しようとします。

2: ほとんどの場合、各キャッシュの時間要件が一貫していないため、単一キーの有効期限が長くなります。

private TimeSpan maxTime;
public LRUCache(int maxKeySize,TimeSpan maxExpireTime){}
 
 //TrackValue增加创建时间和过期时间
public readonly DateTime CreateTime;
public readonly TimeSpan ExpireTime;
ログイン後にコピー

削除戦略

1: キーの有効期限の削除に関しては、スケジュールされた削除を使用するのが最善です。 これにより、占有されているメモリをできるだけ早く解放できますが、明らかに多数のタイマーは CPU にとって多すぎます。

2:所以我们采用惰性删除、在获取key的时检查是否过期,过期直接删除。

public Tuple<TrackValue, bool> CheckExpire(string key)
        {
            TrackValue result;
            if (cache.TryGetValue(key, out result))
            {
                var age = DateTime.Now.Subtract(result.CreateTime);
                if (age >= maxTime || age >= result.ExpireTime)
                {
                    TrackValue old;
                    cache.TryRemove(key, out old);
                    return Tuple.Create(default(TrackValue), false);
                }
            }
            return Tuple.Create(result, true);
        }
ログイン後にコピー

3:惰性删除虽然性能最好,对于冷数据来说,还是没解决缓存污染问题。 所以我们还需定期清理。

比如:开个线程,5分钟去遍历检查key一次。这个策略根据实际场景可配置。

public void Inspection()
        {
            foreach (var item in this)
            {
                CheckExpire(item.Key);
            }
        }
ログイン後にコピー

惰性删除+定期删除基本能满足我们需求了。

总结

如果继续完善下去,就是内存数据库的雏形,类似redis。

比如:增加删除key的通知,增加更多数据类型。 本篇也是参考了redis、Orleans的实现。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

正規表現を使用してPHP配列から重複した値を削除します 正規表現を使用してPHP配列から重複した値を削除します Apr 26, 2024 pm 04:33 PM

正規表現を使用して PHP 配列から重複値を削除する方法: 正規表現 /(.*)(.+)/i を使用して、重複値を照合して置換します。配列要素を反復処理し、preg_match を使用して一致をチェックします。一致する場合は値をスキップし、一致しない場合は重複値のない新しい配列に追加します。

プログラミングは何のためにあるのか、それを学ぶと何の役に立つのか? プログラミングは何のためにあるのか、それを学ぶと何の役に立つのか? Apr 28, 2024 pm 01:34 PM

1. プログラミングは、Web サイト、モバイル アプリケーション、ゲーム、データ分析ツールなど、さまざまなソフトウェアやアプリケーションの開発に使用できます。その応用分野は非常に幅広く、科学研究、医療、金融、教育、エンターテイメントなど、ほぼすべての業界をカバーしています。 2. プログラミングを学ぶことは、問題解決スキルと論理的思考スキルを向上させるのに役立ちます。プログラミング中、問題を分析して理解し、解決策を見つけてコードに変換する必要があります。この考え方は、分析能力と抽象能力を養い、実際的な問題を解決する能力を向上させることができます。

C++ プログラミング パズルのコレクション: 思考を刺激し、プログラミング スキルを向上させます C++ プログラミング パズルのコレクション: 思考を刺激し、プログラミング スキルを向上させます Jun 01, 2024 pm 10:26 PM

C++ プログラミング パズルは、フィボナッチ数列、階乗、ハミング距離、配列の最大値と最小値などのアルゴリズムとデータ構造の概念をカバーします。これらのパズルを解くことで、C++ の知識を強化し、アルゴリズムの理解とプログラミング スキルを向上させることができます。

Golang を使用してブラウザベースのアプリケーションを構築する Golang を使用してブラウザベースのアプリケーションを構築する Apr 08, 2024 am 09:24 AM

Golang を使用してブラウザベースのアプリケーションを構築する Golang は JavaScript と組み合わせて、動的なフロントエンド エクスペリエンスを構築します。 Golang をインストールする: https://golang.org/doc/install にアクセスします。 Golang プロジェクトをセットアップします。 main.go というファイルを作成します。 GorillaWebToolkit の使用: HTTP リクエストを処理するための GorillaWebToolkit コードを追加します。 HTML テンプレートの作成: template サブディレクトリに、メイン テンプレートであるindex.html を作成します。

Python による問題解決: 初心者プログラマーとして強力なソリューションをアンロックする Python による問題解決: 初心者プログラマーとして強力なソリューションをアンロックする Oct 11, 2024 pm 08:58 PM

Python は、問題解決の初心者に力を与えます。ユーザーフレンドリーな構文、広範なライブラリ、変数、条件文、ループによる効率的なコード開発などの機能を備えています。データの管理からプログラム フローの制御、反復的なタスクの実行まで、Python が提供します

Go Get を使用して Go モジュールをすばやく簡単に入手します Go Get を使用して Go モジュールをすばやく簡単に入手します Apr 07, 2024 pm 09:48 PM

GoGet を使用すると、Go モジュールをすばやく簡単に取得できます。手順は次のとおりです: ターミナルで goget[module-path] を実行します。ここで、 module-path はモジュール パスです。 GoGet は、モジュールとその依存関係を自動的にダウンロードします。インストールの場所は、GOPATH 環境変数によって指定されます。

コーディングの鍵: 初心者のための Python の力を解き放つ コーディングの鍵: 初心者のための Python の力を解き放つ Oct 11, 2024 pm 12:17 PM

Python は、学習の容易さと強力な機能により、初心者にとって理想的なプログラミング入門言語です。その基本は次のとおりです。 変数: データ (数値、文字列、リストなど) を保存するために使用されます。データ型: 変数内のデータの型 (整数、浮動小数点など) を定義します。演算子: 数学的な演算と比較に使用されます。制御フロー: コード実行のフロー (条件文、ループ) を制御します。

エラー処理には golang のエラー ラップおよびアンワインド メカニズムを使用する エラー処理には golang のエラー ラップおよびアンワインド メカニズムを使用する Apr 25, 2024 am 08:15 AM

Go のエラー処理には、ラップ エラーとアンラップ エラーが含まれます。エラーをラップすると、あるエラー タイプを別のエラー タイプでラップできるようになり、エラーのより豊富なコンテキストが提供されます。エラーを展開し、ネストされたエラー チェーンをたどって、デバッグを容易にするために最下位レベルのエラーを見つけます。これら 2 つのテクノロジを組み合わせることで、エラー状態を効果的に処理でき、より豊富なエラー コンテキストと優れたデバッグ機能が提供されます。

See all articles