ホームページ > データベース > Redis > RedisのLRUアルゴリズムを詳しく解説した記事

RedisのLRUアルゴリズムを詳しく解説した記事

青灯夜游
リリース: 2021-10-13 10:33:30
転載
4809 人が閲覧しました

この記事では、Redis の LRU (Least Recent Used) について紹介します。

RedisのLRUアルゴリズムを詳しく解説した記事

#Redis は、メモリ ストレージに基づいたキーと値のデータベースです。メモリは高速ですが、空き容量が少ないことがわかっています。物理メモリが上限に達すると、スワップ メカニズムはメモリ データの一部をスワップ パーティションに転送し、スワップとの交換によってシステムは確実に動作し続けるため、非常に遅くなります。ただし、スワップはハードディスク ストレージであり、特に Redis の場合、速度はメモリの速度よりもはるかに遅く、QPS が非常に高いサービスの場合、この状況は容認できません。 (スワップ パーティション メモリもいっぱいの場合、システムでエラーが発生することに注意してください。) [関連する推奨事項:

Redis ビデオ チュートリアル ]

Linux オペレーティング システムはスワップを表示できます。 through free -m Size: \

RedisのLRUアルゴリズムを詳しく解説した記事

したがって、Redis でこれが起こらないようにする方法は非常に重要です (面接官は、質問されたときにこの知識ポイントについて尋ねることはほとんどありません)レディス)。

2. maxmemory 設定

Redis は、上記の問題に対して maxmemory 設定を提供します. この設定では、Redis ストレージの最大データセットを指定できます. 通常、これは redis.conf ファイルでも設定されます1 回限りの構成は、CONFIG SET コマンドを使用して実行時に実行できます。


redis.conf ファイルの構成項目の概略図: \

RedisのLRUアルゴリズムを詳しく解説した記事

maxmemory 構成項目は、デフォルトでは有効になっていません。Redis は公式に64 ビット オペレーションを導入 システムにはデフォルトでメモリ制限がありません。32 ビット オペレーティング システムのデフォルトは 3GB の暗黙的なメモリ構成です。maxmemory が 0 の場合、メモリが制限されていないことを意味します。


したがって、キャッシュ アーキテクチャを構築するときは、ハードウェア リソースとビジネス要件に基づいて適切な maxmemory 構成を作成する必要があります。


3. メモリが maxmemory に達した場合の対処方法

明らかに最大メモリが設定されており、maxmemory が最大制限に達すると、Redis の動作を停止することはできません。 Redis はそれに対処しますか? この問題についてはどうですか?これがこの記事の焦点です。Redis は、maxmemory-policy の削除戦略 (

この記事では LRU についてのみ説明し、LFU は含まれません、LFU については次の記事で説明します) を提供し、次の条件を満たすキーを削除します。古いものに別れを告げ、新しいものを歓迎する条件。
maxmemory-policy 排除ポリシー:

  • noeviction: メモリ制限に達し、クライアントがメモリ制限を超える可能性のあるコマンドを実行しようとしたとき使用するメモリ エラーが返されます。簡単に言うと、読み取り操作は引き続き許可されますが、新しいデータの書き込みは許可されません。del (削除) リクエストは 可能です。
  • allkeys-lru: すべてのキーから、lru (最も最近使用されていない - 最も最近使用されていない) アルゴリズムを通じてそれらを削除します。
  • allkeys-random: すべてのキーからランダムに削除します
  • volatile-lru: lru (最も最近使用されていない - 最も最近使用されていない) アルゴリズムを通じて設定された有効期限を持つすべてのキーから削除します。有効期限が設定されておらず、永続化する必要がある場合は、削除対象として選択されません
  • volatile-random: 有効期限が設定されているすべてのキーをランダムに削除します
  • volatile-ttl: 有効期限が設定されているすべてのキーのうち、キーの残り有効期限 TTL 値を比較し、TTL が小さいほど早く削除されます
  • #Also , volatile-lfu/allkeys-lfu については後述しますが、この 2 つのアルゴリズムは異なります。


ランダムなランダム削除では、メモリ領域を削除して解放するためにいくつかのキーをランダムに選択するだけで済みます。ttl の有効期限は短く、ttl のサイズとキーを比較することによって最初にキーが削除されます。小さな ttl 値は削除されます。メモリ領域を解放するだけです。

それでは、LRU はどのように実装されるのでしょうか? Redis はどのキーが最近使用され、どのキーが最近使用されていないかをどのようにして知るのでしょうか?



4. LRU アルゴリズムの実装

最初に Java コンテナを使用して単純な LRU アルゴリズムを実装し、ConcurrentHashMap を使用してキーと値の結果ストレージ要素のマッピング関係を行い、 ConcurrentLinkedDeque は、キーのアクセス順序を維持します。

#LRU 実装コード:


package com.lizba.redis.lru;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;

/**
 * <p>
 *      LRU简单实现
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/9/17 23:47
 */
public class SimpleLru {

    /** 数据缓存 */
    private ConcurrentHashMap<string> cacheData;
    /** 访问顺序记录 */
    private ConcurrentLinkedDeque<string> sequence;
    /** 缓存容量 */
    private int capacity;

    public SimpleLru(int capacity) {
        this.capacity = capacity;
        cacheData = new ConcurrentHashMap(capacity);
        sequence = new ConcurrentLinkedDeque();
    }


    /**
     * 设置值
     *
     * @param key
     * @param value
     * @return
     */
    public Object setValue(String key, Object value) {
        // 判断是否需要进行LRU淘汰
        this.maxMemoryHandle();
        // 包含则移除元素,新访问的元素一直保存在队列最前面
        if (sequence.contains(key)) {
            sequence.remove();
        }
        sequence.addFirst(key);
        cacheData.put(key, value);
        return value;
    }


    /**
     * 达到最大内存,淘汰最近最少使用的key
     */
    private void maxMemoryHandle() {
        while (sequence.size() >= capacity) {
            String lruKey = sequence.removeLast();
            cacheData.remove(lruKey);
            System.out.println("key: " + lruKey + "被淘汰!");
        }
    }


    /**
     * 获取访问LRU顺序
     *
     * @return
     */
    public List<string> getAll() {
        return Arrays.asList(sequence.toArray(new String[] {}));
    }
}复制代码</string></string></string>
ログイン後にコピー
テスト コード:

package com.lizba.redis.lru;

/**
 * <p>
 *      测试最近最少使用
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/9/18 0:00
 */
public class TestSimpleLru {

    public static void main(String[] args) {
        SimpleLru lru = new SimpleLru(8);
        for (int i = 0; i <strong></strong>テスト結果: \<p><strong></strong></p><p> 上記のテスト結果から、最初に追加された key0 と key1 が削除され、最後に追加されたキーもシーケンスの先頭に保存された最新のキーであることがわかります。 <img src="https://img.php.cn/upload/image/775/594/750/163409191823487Redis%E3%81%AELRU%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%82%92%E8%A9%B3%E3%81%97%E3%81%8F%E8%A7%A3%E8%AA%AC%E3%81%97%E3%81%9F%E8%A8%98%E4%BA%8B" title="163409191823487RedisのLRUアルゴリズムを詳しく解説した記事" alt="RedisのLRUアルゴリズムを詳しく解説した記事">このソリューションを通じて、LRU アルゴリズムは簡単に実装できますが、欠点も非常に明らかです。このソリューションでは、キー アクセス シーケンスを保存するために追加のデータ構造を使用する必要があるため、Redis のメモリ消費量が増加し、それ自体がメモリの最適化: この解決策は大量のメモリを消費しますが、これは明らかに実現不可能です。 </p><p></p><h2 data-id="heading-4">5. Redis のおおよその LRU </h2><p>この状況に対応して、Redis は近似 LRU アルゴリズムを使用しますが、最近最も使用頻度の低いキーを削除する点では完全に正確ではありませんが、全体的な精度も高くなります。保証されています。 <br>近似 LRU アルゴリズムは非常に単純です。Redis キー オブジェクトには、最新のアクセスのシステム タイムスタンプを格納するために 24 ビットが追加されます。クライアントがキー書き込み関連のリクエストを Redis サーバーに送信すると、次のことがわかります。メモリが maxmemory に達すると、遅延削除がトリガーされ、Redis サービスはランダム サンプリングを通じて条件を満たす 5 つのキーを選択します (このランダム サンプリング <strong>allkeys-lru</strong> はすべてのキーからランダムにサンプリングされることに注意してください。 ##volatile-lru<strong>有効期限が設定されたすべてのキーからランダムにサンプリングされます)、キー オブジェクトに記録されている最新のアクセス タイムスタンプと比較し、メモリがまだ十分でない場合は、これら 5 つのキーのうち最も古いキーを削除します続けてこのステップを繰り返します。 </strong><br></p><p>5 は Redis のデフォルトのランダム サンプリング値のサイズであり、redis.conf の maxmemory_samples を通じて構成できることに注意してください。 <strong></strong>## 上記のランダム LRU アルゴリズムに関して、Redis はテスト精度のデータ チャートを公式に提供しています。 </p><p><img src="https://img.php.cn/upload/image/866/655/134/163409192913128Redis%E3%81%AELRU%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%82%92%E8%A9%B3%E3%81%97%E3%81%8F%E8%A7%A3%E8%AA%AC%E3%81%97%E3%81%9F%E8%A8%98%E4%BA%8B" title="163409192913128RedisのLRUアルゴリズムを詳しく解説した記事" alt="RedisのLRUアルゴリズムを詳しく解説した記事"></p>#最上位層の明るい灰色は、削除されたキーを示します。図図 1 は、標準的な LRU アルゴリズムの削除の概略図です。<p><strong>中央の濃い灰色のレイヤーは、削除されていない古いキーを表します。</strong></p>一番下の薄緑色のレイヤーは、最近アクセスされたキーを表します。 key
ログイン後にコピー
  • Redis 3.0 では、maxmemory_samples が 10 に設定されている場合、Redis の近似 LRU アルゴリズムは実際の LRU アルゴリズムに非常に近くなりますが、明らかに maxmemory_samples を 10 に設定するとより多くなります。 maxmemory_samples を 5 に設定するよりも CPU 計算時間が高くなります。毎回サンプリングされるサンプル データが増加するため、計算時間も増加します。
Redis3.0 の LRU アルゴリズムは、Redis2.8

の LRU アルゴリズムよりも正確です。これは、Redis3.0 が maxmemory_samples と同じサイズの消去プールを追加するためです。キーが消去されるたびに、プール内で削除待ちのキーを比較し、最終的に最も古いキーを削除します 実際には、削除対象に選択されたキーをまとめて比較し、その中で最も古いキーを削除します。 RedisのLRUアルゴリズムを詳しく解説した記事

6. 問題点


LRU アルゴリズムは使いやすそうに見えますが、エリミネーション 1 時間前には 2 つのキー A と B が同じであったなど、不合理な箇所もあります。 Redis に時間が追加されます。A は最初の 49 分間に 1,000 回アクセスされましたが、最後の 11 分間はアクセスされませんでした。B は、この時間の 59 分間に 1 回のみアクセスされました。この時点で LRU アルゴリズムが使用されている場合、 Redis サンプリングによって A、B がすべて選択され、A が除外される場合、これは明らかに不合理です。 このような状況を受けて、Redis 4.0 では、最も使用頻度の低い LFU アルゴリズム (Leastfrequency used) が追加されました。このアルゴリズムは、LRU よりも合理的です。除去アルゴリズムについては、以下で一緒に学習します。必要に応じて、私のコラムに注目してください。

プログラミング関連の知識について詳しくは、

プログラミング教育

をご覧ください。 !

以上がRedisのLRUアルゴリズムを詳しく解説した記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート