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 implement distributed Lock in SpringBoot+Redis

2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces SpringBoot+Redis how to achieve distributed locks, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, let the editor take you to understand it.

Nx generation lock for jedis

How to delete a lock

Simulate the action of grabbing an order (individual shooting for 10w)

Nx generation lock for jedis

For java to manipulate redis, a good way is to use jedis. First, introduce dependencies into pom:

Redis.clients jedis

For distributed lock generation, you usually need to pay attention to the following aspects:

Policy for creating locks: redis's ordinary key is generally allowed to be overridden. After user A set a certain key, B can also succeed when set the same key. If it is a lock scenario, it is impossible to know which user set succeeded. Here, the setnx method of jedis solves this problem for us. The simple principle is: when user A succeeds in set, then user B returns a failure when set, which satisfies that only one user is allowed to get the lock at a certain point in time.

Lock expiration time: if there is no concept of expiration in a rush purchase scenario, when user A generates a lock, but the subsequent process is blocked and cannot release the lock, then other users will always fail to acquire the lock and cannot complete the rush purchase activity. Of course, normally, there is no blocking, and the A user process will release the lock normally; the expiration time is only for more security.

Here is the code for the previous setnx operation:

Public boolean setnx (String key, String val) {Jedis jedis = null; try {jedis = jedisPool.getResource (); if (jedis = = null) {return false;} return jedis.set (key, val, "NX", "PX", 1000 * 60). EqualsIgnoreCase ("ok");} catch (Exception ex) {} finally {if (jedis! = null) {jedis.close ();}} return false;}

The note here lies in the set method of jedis, whose parameters are described as follows:

NX: whether there is key or not, set cannot succeed if it exists.

PX:key expiration time unit is set to milliseconds (EX: unit seconds)

If setnx fails, it can be directly encapsulated and returned to false. Let's call the setnx method through an api in get mode:

@ GetMapping ("/ setnx/ {key} / {val}") public boolean setnx (@ PathVariable String key, @ PathVariable String val) {return jedisCom.setnx (key, val);}

Visit the following test url. Normally, true is returned for the first time, and false is returned for the second time. Because the key of redis already exists at the time of the second request, the set cannot be successful.

As you can see from the figure above, there is only one set success, and key has a valid time, and the condition of distributed lock has been reached.

How to delete a lock

The lock is created above, and it also has a valid time, but we cannot completely rely on this effective time. For example, after the effective time is set for 1 minute and user An acquires the lock, there are no special circumstances after the rush purchase order is generated normally. At this time, other users should be able to place the order normally, but the lock can only be released automatically after 1 minute. Then other users cannot place an order normally in this 1 minute (because the lock belongs to user A), so we need user A to take the initiative to unlock it after the operation is finished:

Public int delnx (String key, String val) {Jedis jedis = null; try {jedis = jedisPool.getResource (); if (jedis = = null) {return 0 } / / if redis.call ('get','orderkey') = =' 1111' then return redis.call ('del','orderkey') else return 0 end StringBuilder sbScript = new StringBuilder (); sbScript.append ("if redis.call (' get','") .append (key) .append ("')). Append (" = = ") .append (val) .append ("'"). Append ("then"). Append ("return redis.call ('del','") .append (key) .append ("')"). Append ("else"). Append ("return 0"). Append ("end"); return Integer.valueOf (jedis.eval (sbScript.toString ()). ToString ());} catch (Exception ex) {} finally {if (jedis! = null) {jedis.close ();}} return 0;}

Jedis is also used here to execute the lua script directly: judge whether it exists according to val, and del if it exists

In fact, I think that after obtaining the val through jedis's get method, and then comparing whether value is the current user holding the lock, if it is deleted at last, the effect is actually quite good; it's just that the script is executed directly through eval, which avoids one more operation of redis and shortens the interval between atomic operations. (if you have any different opinions, please leave a message for discussion.) similarly, create a get api to test:

@ GetMapping ("/ delnx/ {key} / {val}") public int delnx (@ PathVariable String key, @ PathVariable String val) {return jedisCom.delnx (key, val);}

Note that when you delnx, you need to pass the value when the lock was created, because the value of et and the value of delnx are used to determine whether it is an operation request that holds the lock. Only value allows del.

Simulate the action of grabbing an order (individual shooting for 10w)

With the rough basis of the distributed lock above, we simulate the scenario in which a person grabs an order for 10w, which is actually a concurrent operation request. Because of the limited environment, we can only test this. Initialize 10w users and initialize inventory, goods and other information, as shown in the following code:

/ / Total inventory private long nKuCuen = 0; / / Product key name private String shangpingKey = "computer_key"; / / timeout seconds for acquiring locks private int timeout = 30 * 1000; @ GetMapping ("/ qiangdan") public List qiangdan () {/ / the user who grabs the product List shopUsers = new ArrayList () / / construct many users List users = new ArrayList (); IntStream.range (0, 100000). Parallel (). ForEach (b-> {users.add ("Shenniu -" + b);}); / / initialize inventory nKuCuen = 10 / / simulated firing users.parallelStream () .forEach (b-> {String shopUser = qiang (b); if (! StringUtils.isEmpty (shopUser)) {shopUsers.add (shopUser);}}); return shopUsers;}

With the above 10w different users, we set only 10 items in stock, and then simulate panic buying through parallel flow, as follows:

/ * simulate the action of grabbing an order * * @ param b * @ return * / private String qiang (String b) {/ / user firing time long startTime = System.currentTimeMillis () / / if you don't get it, continue to acquire the lock while ((startTime + timeout) > = System.currentTimeMillis ()) {/ / whether the product is left with if (nKuCuen) within 30 seconds

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

Development

Wechat

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

12
Report