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 solve the problem of redis distributed Lock

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

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

This article mainly shows you "how to solve the problem of redis distributed locks". The content is simple and clear. I hope it can help you solve your doubts. Let me lead you to study and learn this article "how to solve the problem of redis distributed locks".

Distributed lock

In a distributed environment, in order to ensure normal access to business data and prevent repeated requests, distributed locks are used to block subsequent requests. Let's first write a problematic business code:

Public void doSomething (String userId) {User user=getUser (userId); if (user==null) {user.setUserName ("xxxxx"); user.setUserId (userId); insert (user); return;} update (user);}

The above code is simple to query whether there is any corresponding user data in db, if so, perform an update operation, and insert if not.

We know that the above code is not thread-safe, and problems can occur in a multithreaded environment. In order to ensure the correctness of the data, in a stand-alone environment, we can use the synchronized method to ensure thread safety and modify:

Public synchronized void doSomething (String userId) {User user=getUser (userId); if (user==null) {user.setUserName ("xxxxx"); user.setUserId (userId); insert (user); return;} update (user);}

The problem of thread safety can be solved in a single machine environment, but what about in a distributed environment? Distributed locks are needed at this time.

Distributed locks need to be implemented with the help of other components, including redis and zookeeper. Next, we will use the implementation of redis to illustrate the following problems. The specific implementation methods of distributed locks are as follows

Public void doSomething (String userId) {String lock=RedisUtils.get ("xxxx" + userId); if (StringUtils.isNotEmpty (lock)) {/ / indicates that the current userId has been locked return;} RedisUtils.set ("xxxx" + userId,userId,1000); / / locked 10s User user=getUser (userId); if (user==null) {insert (user); RedisUtils.delete ("xxxx" + userId); return;} update (user); RedisUtils.delete ("xxxx" + userId);}

The above code solves the problem of concurrency in a distributed environment. However, it is also important to consider that if the insert and update operations are abnormal, the distributed lock will not be released and subsequent requests will be intercepted.

So we re-optimize to increase the catch of exceptions.

Public void doSomething (String userId) {try {String lock=RedisUtils.get ("xxxx" + userId); if (StringUtils.isNotEmpty (lock)) {/ / indicates that the current userId has been locked return;} RedisUtils.set ("xxxx" + userId,userId,1000); / / Lock 1s User user=getUser (userId); if (user==null) {insert (user); return;} update (user) } catch (Exception ex) {} finally {RedisUtils.delete ("xxxx" + userId);}}

Now even if the program is abnormal, the lock will be released automatically. However, get and set of redis will also have concurrency problems. Let's continue to optimize and use the setnx method in redis.

Public void doSomething (String userId) {try {boolean lock=RedisUtils.setnx ("xxxx" + userId,userId,1000); / / Lock 1s if (! lock) {/ / indicates that the current userId has been locked return;} User user=getUser (userId); if (user==null) {insert (user); return;} update (user);} catch (Exception ex) {} finally {RedisUtils.delete ("xxxx" + userId);}}

There seems to be no problem with the above code, but there are also great hidden dangers. Let's analyze, assuming that the first request comes and the lock is successfully executed, and the program starts to run, but the insert and update operations block for 1 second, and the cache of the lock expires with the second request, and the second lock is successfully executed. At this time, the first request completes and the lock is released, the second request is released by the first request, and the third request will cause thread unsafe problems.

How to optimize it again? The main problem is that the lock was mistakenly deleted on the first request, so we have to determine whether it can be removed when we remove the lock.

Idea: when locking, value uses the current timestamp to determine whether it expires when deleting. If it does not expire, do not delete it. The specific code is as follows:

Public void doSomething (String userId) {try {boolean lock=RedisUtils.setnx ("xxxx" + userId,LocalDateTime.now (), 1000); / Lock 10s if (! lock) {/ / indicates that the current userId has been locked return;} User user=getUser (userId); if (user==null) {insert (user); return;} update (user);} catch (Exception ex) {} finally {LocalDateTime lockTIme= RedisUtils.get ("xxxx" + userId) If (lockTIme.compare (LocalDateTime.now ()

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