Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the distributed lock in Redis

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

This article introduces the knowledge of "how to understand distributed locks in Redis". Many people will encounter this dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Redis distributed lock

Distributed locks are used in all projects, which are usually used for orderly operation of data, such as a refund of an order (if it can be returned multiple times). Or users place orders at multiple ends. [related recommendation: Redis video tutorial]

Maven dependence

My implementation is mainly based on Spring-Boot 2.1.2 + Jedis.

4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE cn.edu.cqvie redis-lock 1.0-SNAPSHOT UTF-8 1.8 2.9.0 5.0.7 org.springframework.boot spring-boot-autoconfigure Org.springframework.data spring-data-redis redis.clients jedis ${redis.version} org.springframework.boot spring-boot-starter-logging org.slf4j log4j-over-slf4j Org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin

Configuration file

The application.properties configuration file is as follows:

Spring.redis.host=127.0.0.1spring.redis.port=6379spring.redis.password=spring.redis.timeout=30000spring.redis.jedis.pool.max-active=8spring.redis.jedis.pool.min-idle=2spring.redis.jedis.pool.max-idle=4logging.level.root=INFO

Interface definition

Interface definition, for the lock our core is actually even the methods lock and unlock.

Public interface RedisLock {long TIMEOUT_MILLIS = 30000; int RETRY_MILLIS = 30000; long SLEEP_MILLIS = 10; boolean tryLock (String key); boolean lock (String key); boolean lock (String key, long expire); boolean lock (String key, long expire, long retryTimes); boolean unlock (String key);}

Distributed lock implementation

My implementation is done through setnx. If there is tryLock logic, I will retry it by spinning.

/ / AbstractRedisLock.java abstract class public abstract class AbstractRedisLock implements RedisLock {@ Override public boolean lock (String key) {return lock (key, TIMEOUT_MILLIS);} @ Override public boolean lock (String key, long expire) {return lock (key, TIMEOUT_MILLIS, RETRY_MILLIS);}} / / concrete implementation @ Componentpublic class RedisLockImpl extends AbstractRedisLock {private Logger logger = LoggerFactory.getLogger (getClass ()); @ Autowired private RedisTemplate redisTemplate Private ThreadLocal threadLocal = new ThreadLocal (); private static final String UNLOCK_LUA; static {StringBuilder sb = new StringBuilder (); sb.append ("if redis.call (\" get\ ", KEYS [1]) = = ARGV [1]"); sb.append ("then"); sb.append ("return redis.call (\" del\ ", KEYS [1])"); sb.append ("else") Sb.append ("return 0"); sb.append ("end"); UNLOCK_LUA = sb.toString ();} @ Override public boolean tryLock (String key) {return tryLock (key, TIMEOUT_MILLIS) } public boolean tryLock (String key, long expire) {try {return! StringUtils.isEmpty (redisTemplate.execute ((RedisCallback) connection-> {JedisCommands commands = (JedisCommands) connection.getNativeConnection (); String uuid = UUID.randomUUID (). ToString (); threadLocal.set (uuid); return commands.set (key, uuid, "NX", "PX", expire) });} catch (Throwable e) {logger.error ("set redis occurred an exception", e);} return false;} @ Override public boolean lock (String key, long expire, long retryTimes) {boolean result = tryLock (key, expire) While (! result & & retryTimes-- > 0) {try {logger.debug ("lock failed, retrying... {}", retryTimes); Thread.sleep (SLEEP_MILLIS);} catch (InterruptedException e) {return false;} result = tryLock (key, expire);} return result @ Override public boolean unlock (String key) {try {List keys = Collections.singletonList (key); List args = Collections.singletonList (threadLocal.get ()); Long result = redisTemplate.execute ((RedisCallback) connection-> {Object nativeConnection = connection.getNativeConnection () If (nativeConnection instanceof JedisCluster) {return (Long) ((JedisCluster) nativeConnection) .eval (UNLOCK_LUA, keys, args);} if (nativeConnection instanceof Jedis) {return (Long) ((Jedis) nativeConnection) .eval (UNLOCK_LUA, keys, args);} return 0L }); return result! = null & & result > 0;} catch (Throwable e) {logger.error ("unlock occurred an exception", e);} return false;}}

Test code

Finally, let's look at how to use it. (here is a scene that simulates a second kill)

@ RunWith (SpringRunner.class) @ SpringBootTestpublic class RedisLockImplTest {private Logger logger = LoggerFactory.getLogger (getClass ()); @ Autowired private RedisLock redisLock; @ Autowired private StringRedisTemplate redisTemplate; private ExecutorService executors = Executors.newScheduledThreadPool (8); @ Testpublic void lock () {/ / initialize inventory redisTemplate.opsForValue (). Set ("goods-seckill", "10"); List futureList = new ArrayList (); for (int I = 0; I)

< 100; i++) { futureList.add(executors.submit(this::seckill)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } // 等待结果,防止主线程退出 futureList.forEach(action ->

{try {action.get ();} catch (InterruptedException | ExecutionException e) {e.printStackTrace ();}} public int seckill () {String key = "goods"; try {redisLock.lock (key) Int num = Integer.valueOf (Objects.requireNonNull (redisTemplate.opsForValue (). Get ("goods-seckill")); if (num > 0) {redisTemplate.opsForValue () .set ("goods-seckill", String.valueOf (--num)); logger.info ("second kill, remaining inventory: {}", num) } else {logger.error ("second kill failed, remaining inventory: {}", num);} return num;} catch (Throwable e) {logger.error ("seckill exception", e);} finally {redisLock.unlock (key);} return 0;}} Summary

This paper is a simple implementation of Redis lock, and the retry operation of lock is realized based on jedis. However, there are some disadvantages, such as automatic renewal of locks, reentry of locks, and fairness (currently achieved through spin, which is equivalent to an unfair way).

That's all for "how to understand distributed locks in Redis". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report