Here we mainly record the problems and solutions of using distributed lock based on RedIS in the project.
The business scenario
My business scenario is as follows: Our service has inventory module, while my service is multi-node deployment, so there will be inventory difference in peak periods. After analyzing the problem later, I plan to use Redis to realize distributed lock (the main reason is that the service has integrated REDis, so there is no need to do additional configuration).
1. Database transaction timeout
Don’t be surprised how a distributed lock can cause a database transaction to time out. My code looks something like this:
@transaction (readOnly=false) void update(){do{redis= jedisutil.getJedis (); flag = getLock(key,redis); if(flag){ update(); } }while(true) }Copy the code
Database transaction timeout occurs when your key is not locked for a long time and database transactions have timeout limits. The solution
Database transactions changed to manual commit transactions;
2. The Redis key expires and services are not executed
My key expiration time is set to 30s. If the service execution is not completed within 30 seconds, the lock will be automatically released. After the lock is released, other threads will occupy the lock again, which will also cause problems. The solution
The simplest solution is to use Redisson; If you must use Redis to solve the problem, you can only use timer to detect the key. If the key is about to expire in 2 seconds, then reset the expiration time for 30 seconds for the key.
3. The Redis connection pool is full
Distributed lock just add after, produce a problem, is that redis. Clients. Jedis. Exceptions. JedisConnectionException: The developer Could not get a resource from the pool.
Fix the bug, and run for a long time online, and again redis. Clients. Jedis. Exceptions. JedisConnectionException: Could not get a resource from the pool
void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); }else{// Release the current redis connection // Because our business scenario is a time-consuming business, so sleep here for 1000 milliseconds redis.close(); sleep(1000); } }while(true) }Copy the code
1. Currently requests to obtain the lock. If the lock cannot be obtained, release the current connection and sleep for a while. 2. Properly configure the redis connection pool size based on the number of concurrent connections in specific service scenarios.
Step on the hole 4. You must tie the bell to untie the bell
To review the locking parameters:
set(key, vlue,"NX","PX", 30000);
Copy the code
Where: value, which I use to represent the locker, must be a unique identifier
For example, thread A key= Test value= 01THREAD B Key =test value=02 If the service execution time of thread A exceeds the lock holding time, the lock is automatically released. After the lock is automatically released, thread B successfully locks it again. However, thread A tries to release the lock after executing the service logic, but the lock of thread A has been automatically released. If there is no value, thread B may release the lock of thread B.
5. Redis cluster to achieve distributed locking
I have not encountered this situation because the company’s Redis cluster has been improved;
Here’s why this happens: If the master node is switched over for some reason, the lock is lost.
- [Fixed] Get lock on master node
- But the locked key has not been synchronized to the slave node;
- The master node fails and failover occurs. The slave node is upgraded to the master node.
- Therefore, the lock is lost;
The solution
By using the Redlock algorithm; Or use Redisson, which encapsulates the Redlock algorithm;