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:
In Java, you can use LinkHashMap to implement LRU using hash linked list implementation:
Title Redis Cache elimination strategySet the maximum cacheIn 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
Syntax:
multiEXECExecute all previously queued commands in a transaction and then restore the normal connection state
Syntax:
execDISCARDClears all commands previously queued in a transaction and then restores the normal connection state.
Syntax:
discardWATCHWhen 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.
UNWATCHClear all keys previously monitored for a transactionSyntax:
unwatch
Command illustration:
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 111Redis 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 LockOptimistic 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:
然后去执行这个事务,如果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(); } }
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!