Redis キャッシュ削除戦略とトランザクションを使用して楽観的ロックを実装する方法

WBOY
リリース: 2023-06-03 16:05:29
転載
907 人が閲覧しました

    キャッシュ削除戦略

    タイトル LRU 原則

    LRU (最も最近使用されていない、最も最近使用されていない) アルゴリズムは、履歴アクセスに基づいています。データの記録 データを排除するための中心的な考え方は、「データに最近アクセスされた場合、将来アクセスされる可能性も高い」ということです。

    最も一般的な実装は、リンクされたリストを使用してキャッシュされたデータを保存することです。詳細なアルゴリズムは次のように実装されます:

    Redis キャッシュ削除戦略とトランザクションを使用して楽観的ロックを実装する方法

    • ## 新しいデータがリンク リストの先頭に挿入されます;

    • キャッシュがヒットする (つまり、キャッシュされたデータがアクセスされる) たびに、データはリンク リストの先頭;

    • リンク リストがいっぱいの場合、リンク リストの末尾のデータを破棄します。

    Java では、LinkHashMap を使用して、ハッシュ リンク リストの実装を使用して LRU を実装できます。

    Redis キャッシュ削除戦略とトランザクションを使用して楽観的ロックを実装する方法

    Title Redis キャッシュの削除戦略

    最大キャッシュの設定

    Redis では、ユーザーは最大メモリ サイズ maxmemory を設定できます。デフォルトは 0 です。最大キャッシュは指定されていません。新しいデータが追加されると、最大メモリを超えると Redis がクラッシュするため、設定する必要があります。

    redis メモリ データ セットのサイズが特定のサイズに増加すると、データ削除戦略が実装されます。

    排除戦略

    redis 排除戦略の構成: maxmemory-policy voltile-lru、ホット構成をサポート

    redis は 6 種類のデータを提供します削除戦略:

    • volatile-lru: 有効期限が設定されている、最も最近使用されていないデータ セット (server.db[i].expires) を選択します。データ削除

    • volatile-ttl:有効期限を設定したデータセット(server.db[i].expires)から期限切れとなるデータを選択します.

    • volatile-random: 有効期限が設定されているデータセット (server.db[i].expires) から削除するデータをランダムに選択します

    • allkeys-lru: データ セット (server.db[i].dict) から最も最近使用されていないデータを選択して、

    • を削除します
    • allkeys-random: データ セット (server.db[i].dict) からデータをランダムに選択して、

    • no-enviction を排除します。 (エビクション): データのエビクションを禁止します

    Redis トランザクション

    Redis トランザクションの概要

    • Redis トランザクションは終了しますMULTI、EXEC、DISCARD、WATCH、UNWATCH の 5 つのコマンドを完了します。

    • Redis の個々のコマンドはアトミックであるため、トランザクション オブジェクトがコマンド セットであることを確認する必要があります。

    • Redis はコマンド セットをシリアル化し、同じトランザクション内でコマンド セットが継続的かつ中断なく実行されるようにします

    • Redis は return Roll をサポートしていません手術。トランザクション コマンド

    MULTI

    は、トランザクション ブロックの開始をマークするために使用されます。 Redis は後続のコマンドを 1 つずつキューに入れ、アトミック EXEC コマンドを使用してこのコマンド シーケンスを実行します。

    構文:

    multi
    ログイン後にコピー

    EXEC

    トランザクション内で以前にキューに入れられたすべてのコマンドを実行し、通常の接続状態を復元します

    構文:

    exec
    ログイン後にコピー

    DISCARD

    トランザクション内で以前にキューに入れられたすべてのコマンドをクリアし、通常の接続状態を復元します。

    構文:

    discard
    ログイン後にコピー

    WATCH

    [トランザクションを条件付きで実行する必要がある]場合、このコマンドを使用して、指定された [ キーが設定されているを変更します[監視対象へ] ステータス。

    構文:

    watch key [key…]
    ログイン後にコピー

    注: このコマンドを使用して、Redis の楽観的ロックを実装します。

    UNWATCH

    トランザクションに対して以前に監視されていたすべてのキーをクリアします

    構文:

    unwatch
    ログイン後にコピー

    コマンドの図:

    Redis キャッシュ削除戦略とトランザクションを使用して楽観的ロックを実装する方法

    トランザクションのデモ:

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set s1 111
    QUEUED
    127.0.0.1:6379> hset set1 name zhangsan
    QUEUED
    127.0.0.1:6379> exec
    1) OK
    2) (integer) 1
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set s2 222
    QUEUED
    127.0.0.1:6379> hset set2 age 20
    QUEUED
    127.0.0.1:6379> discard
    OK
    127.0.0.1:6379> exec (error) ERR EXEC without MULTI 
    127.0.0.1:6379> watch s1
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set s1 555
    QUEUED 127.0.0.1:6379> exec # 此时在没有exec之前,通过另一个命令窗口对监控的s1字段进行修改 
    (nil)
    127.0.0.1:6379> get s1
    111
    ログイン後にコピー

    Redis はトランザクションのロールバックをサポートしていません (理由)

    大多数のトランザクション失敗の原因は構文エラーまたは型エラーです。これらのエラーはどちらも開発段階で予見可能です。Redis はパフォーマンス上の理由からトランザクションのロールバックを無視します。

    Redis Optimistic Lock

    Optimistic Lock は CAS (Compare And Swap) のアイデア (比較と置換) に基づいており、相互排他的ではなく、ロック待機を引き起こしたりリソースを消費したりすることはありませんが、再試行を繰り返す必要がありますが、再試行メカニズムにより、より高速に応答できます。したがって、redis を使用して

    オプティミスティック ロックを実装できます。具体的なアイデアは次のとおりです。

    • redis の watch 関数を使用して、この redisKey のステータス値を監視します。

    • Get the redisKey の値

    • redis トランザクションの作成

    • このキーの値を 1

      にします

    • 然后去执行这个事务,如果key的值被修改过则回滚,key不加1

    public void watch() {
    	try {
    		String watchKeys = "watchKeys";
    		//初始值 value=1
    		jedis.set(watchKeys, 1);
    		//监听key为watchKeys的值
    		jedis.watch(watchkeys);
    		//开启事务
    		Transaction tx = jedis.multi();
    		//watchKeys自增加一
    		tx.incr(watchKeys);
    		//执行事务,如果其他线程对watchKeys中的value进行修改,则该事务将不会执行
    		//通过redis事务以及watch命令实现乐观锁
    		List<Object> exec = tx.exec();
    		if (exec == null) {
    			System.out.println("事务未执行");
    		} else {
    			System.out.println("事务成功执行,watchKeys的value成功修改");
    		}
    	} catch (Exception e) {
    		e.printStackTrace();
    	} finally {
    		jedis.close();
    	}
    }
    ログイン後にコピー

    Redis乐观锁实现秒杀

    public class RedisLock {
        public static void main(String[] arg) {
            //库存key 
            String redisKey = "stock";
            ExecutorService executorService = Executors.newFixedThreadPool(20);
            try {
                Jedis jedis = new RedisProperties.Jedis("127.0.0.1", 6378);
                // 可以被秒杀的库存的初始值,库存总共20个
                jedis.set(redisKey, "0");
                jedis.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 1000; i++) {
                executorService.execute(() -> {
                    Jedis jedis1 = new Jedis("127.0.0.1", 6378);
                    try {
                        jedis1.watch(redisKey);
                        String redisValue = jedis1.get(redisKey);
                        int valInteger = Integer.valueOf(redisValue);
                        String userInfo = UUID.randomUUID().toString();
                        // 没有秒完
                        if (valInteger < 20) {
                            Transaction tx = jedis1.multi();
                            tx.incr(redisKey);
                            List list = tx.exec();
                            // 秒成功 失败返回空list而不是空
                            if (list != null && list.size() > 0) {
                                System.out.println("用户:" + userInfo + ",秒杀成 功!当前成功人数:" + (valInteger + 1));
                            }
                            // 版本变化,被别人抢了。
                            else {
                                System.out.println("用户:" + userInfo + ",秒杀失 败");
                            }
                        }
                        // 秒完了
                        else {
                            System.out.println("已经有20人秒杀成功,秒杀结束");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        jedis1.close();
                    }
                });
            }
            executorService.shutdown();
        }
    }
    ログイン後にコピー

    以上がRedis キャッシュ削除戦略とトランザクションを使用して楽観的ロックを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!