Home  >  Article  >  Database  >  How to use Redis cache elimination strategy and transactions to implement optimistic locking

How to use Redis cache elimination strategy and transactions to implement optimistic locking

WBOY
WBOYforward
2023-06-03 16:05:29913browse

    Cache elimination strategy

    Title LRU principle

    LRU (Least recently used, least recently used) algorithm is based on the historical access records of the data To eliminate data, the core idea is "if the data has been accessed recently, the probability of being accessed in the future is also higher."

    The most common implementation is to use a linked list to save cached data. The detailed algorithm is implemented as follows:

    How to use Redis cache elimination strategy and transactions to implement optimistic locking

    • ## New data is inserted into the head of the linked list;

    • Whenever the cache hits (that is, the cached data is accessed), the data is moved to the head of the linked list;

    • When the linked list is full, discard the data at the end of the linked list.

    In Java, you can use LinkHashMap to implement LRU using hash linked list implementation:

    How to use Redis cache elimination strategy and transactions to implement optimistic locking

    Title Redis Cache elimination strategy

    Set the maximum cache

    In redis, users are allowed to set the maximum memory size maxmemory. The default is 0. The maximum cache is not specified. If new data is added, Exceeding the maximum memory will cause redis to crash, so it must be set.

    redis When the size of the memory data set increases to a certain size, the data elimination strategy will be implemented.

    Elimination strategy

    redis elimination strategy configuration: maxmemory-policy voltile-lru, supports hot configuration

    redis provides 6 types of data elimination Strategy:

    • volatile-lru: Select the least recently used data set (server.db[i].expires) with an expiration time set Data elimination

    • volatile-ttl:Select the data that will expire from the data set (server.db[i].expires) that has set the expiration time.

    • volatile-random: Randomly select data to eliminate from the data set (server.db[i].expires) that has set expiration time

    • allkeys-lru: Select the least recently used data from the data set (server.db[i].dict) to eliminate

    • allkeys-random: Randomly select data from the data set (server.db[i].dict) to eliminate

    • no-enviction (eviction): Prohibit eviction of data

    Redis transaction

    Redis transaction introduction

    • Redis transaction is through MULTI, EXEC, DISCARD and WATCH, UNWATCH these five commands to complete.

    • Redis’ individual commands are atomic, so you need to ensure that the transactional object is a command set.

    • Redis serializes the command set and ensures the continuous and uninterrupted execution of the command set in the same transaction

    • Redis does not support return Roll operation. The transaction command

    MULTI

    is used to mark the beginning of a transaction block. Redis will put subsequent commands into the queue one by one, and then use the atomic EXEC command to execute this command sequence.

    Syntax:

    multi

    EXEC

    Execute all previously queued commands in a transaction and then restore the normal connection state

    Syntax:

    exec

    DISCARD

    Clears all commands previously queued in a transaction and then restores the normal connection state.

    Syntax:

    discard

    WATCH

    When a [transaction needs to be executed conditionally], use this command to change the given [ key is set to monitored] status.

    Syntax:

    watch key [key…]

    Notes: Use this command to implement Redis’s optimistic locking.

    UNWATCH

    Clear all keys previously monitored for a transaction

    Syntax:

    unwatch

    Command illustration:

    How to use Redis cache elimination strategy and transactions to implement optimistic locking

    Transaction demonstration:

    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 does not support transaction rollback (why)

    大Most transaction failures are due to syntax errors or type errors. Both of these errors are foreseeable during the development stage. Redis ignores transaction rollback for performance reasons.

    Redis Optimistic Lock

    Optimistic lock is based on the CAS (Compare And Swap) idea (compare and replace). It is not mutually exclusive and will not cause lock waiting and consume resources, but it needs to be repeated retry, but also because of the retry mechanism, it can respond faster. Therefore, we can use redis to

    implement optimistic locking. The specific ideas are as follows:

    • Use the watch function of redis to monitor the status value of this redisKey

    • Get the value of redisKey

    • Create redis transaction

    • Give the value of this key 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();
        }
    }

    The above is the detailed content of How to use Redis cache elimination strategy and transactions to implement optimistic locking. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete