The original link
Can insist on others can not insist, to have others have not. Pay attention to programming avenue public number, let us stick to what we think in mind, grow up together!
Set the expiration time and release resources
When using Redis for K-V storage, it is important to control the expiration time. Any K-V storage should be set to expire no matter how long it is. Generally, when encapsulating the Redis operation tool class, the API is provided to use the system public timeout time by default, so as to avoid the waste of memory caused by not setting the expiration time for novice users. Jedis Jedis = jedispool.getResource (); The best way to get a Redis connection is to use a try/finally block and call jedis.close() in the finally block; Return the connection to the connection pool, otherwise the connection will always be held and will most likely be reported missing at some point in the future. This is also a mistake made by a colleague before, leading to production bug!
The cache to penetrate
Do you think Redis is safe with caching? You’re just gonna do the classic thing? If there is a request, check the cache first, return the request directly, check the database if there is no request, save the cache first, then return the request, return the database if there is no request. If you do that, you’re probably missing something, which is cache penetration. As before in the project to do a requirements page ads can be configured to automatically line up and down (I wrote an article before introduce the demand evolution process step by step, is very helpful Redis novice, interested can look at the), the simple mention, such as for the complete page everyone should be seen, such as pay after the completion of the results page, There may be a red envelope pop up or something, advertising space at the bottom of the page, is a similar need. Because the page view is very large, into this page to check the advertising space data, when the operation recently do not want to configure advertising, this check is not empty ah? The database is empty, and the cache has no data, so many requests come, which causes stress on the database for no reason. What a waste! If it is other other business, the hacker took advantage of the loophole, special request your system does not exist data, request many, all hit the database, is very likely to kill your database. If you don’t think about this when you’re doing requirements, you’ll be on the hook later when things go wrong.
How to avoid it?
You can store data that does not exist in the database as a null value or an empty JSON (whatever your own agreement), also put it in Redis, set a short expiration time, the next time you see empty return. Alternatively, bloom filters can be used as a system-level protection to block non-existent keys.
Cache avalanche
After cache penetration, let’s talk about cache avalanche. For example, if you put user data in the cache, and at some point all of the data expires, a lot of requests come in, and you find that the cache can’t be hit, don’t they all go to the database, and the database fails with so many requests all at once? The solution is to try to spread out the expiration time of the key rather than concentrate it. Add a random value to a fixed expiration time. For example, if you set the expiration time to 5 hours, you can add a random value of 0-600 seconds.
Cache concurrency
When the cache fails, multiple requests request the same key at the same time, and all of them find that the cache is empty, so they all go to the database. This is not a waste of time. This is the problem of cache concurrency. When the request is very much, it will cause a great impact on the database, and it is possible to hang the database, right? Synchronized updates to the cache can be synchronized. No, because production is distributed and requires redis distributed locks.
For example, when the cache data is invalid, a thread uses the resource ID as the key to try to add a distributed lock. The thread that successfully adds the lock updates the cache and puts the found data into the cache. Then other threads can directly use the cache data.
A distributed lock
As mentioned above, synchronized is disabled in clustered deployments, so distributed locks come in handy. There are three common distributed lock implementation methods: based on database, based on Redis, based on Zookeeper.
For example, the setnx command of Redis is used. If the command is set successfully, the lock is obtained, and then the expiration time is set. If the command fails, the lock fails to be obtained. Be sure to pay attention to the setting of the expiration time of the lock, add the lock operation, also have to unlock the operation. For example, in our previous project, there was a temporary group walking activity and a group walking PK activity with 10 people. In the group forming stage, users could invite friends to join their group. Our group data is stored in Redis, including the number of people in each group. When a user initiates a group membership operation, the background logic obtains the number of existing members of the group from Redis. If the number is less than 10, the following logic can be used. In the concurrent scenario, if the leader shares the invitation to join the group with many people, the concurrent execution of these people’s request for joining the group may result in more than 10 people in the group. Because in concurrent scenarios, execution for current group membership that would have been more lines of code request access to, such as critical when group members have nine, at the same time to joined the league two requests, if uncontrolled, and perform all read while reading existing number of group members is 9, and then perform operation, the league for the bug can cause group members more than 10 people.
Therefore, a distributed lock must be added to the logic of the group request, and the subsequent logic can only be executed after the lock is obtained. Because the operation of acquiring the lock is to use the setnx command, and there is no mechanism for waiting for the lock, we need to add a spin to the logic of acquiring the lock, try to obtain the lock every certain time, and return locking failure after a certain time.
public boolean tryLock(String lockKey,long expireTime){
long waitTime = 0;
//setIfAbsent uses the redis setnx method
boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey,"jingzouLock".
expireTime,TimeUnit.MILLISECONDS);
if(success==true) {
return success;
}else{
while(success==false && waitTime <50000L) {
success = redisTemplate.opsForValue().setIfAbsent(lockKey,"jingzouLock".
expireTime, TimeUnit.MILLISECONDS);
try{
Thread.sleep(100);
}catch(Exception e){}
waitTime+=100L;
}
}
return success;
}
Copy the code
In addition, still need to follow the principle of “solution bell also must tie bell person”, who adds the lock who solves, otherwise the lock that oneself adds, was solved by others also can cause a problem. A, for example, A user request smoked, get distributed lock, if for some reason no execution of the code inside the lock timeout, the lock is released automatically overdue, if the request to join the same team, B got A distributed lock, if the request execution, A lock is released, but the release of the lock is B, It is also possible to cause a bug where the number of party members exceeds 10. Therefore, the value of A distributed lock can be set to different values. For example, when A requests A user whose ID is 12, this unique element can be used in the value of A distributed lock. When unlocking A distributed lock, verify that the value is 12 before unlocking the lock.
In addition to the above locking code, we add a String value to pass in the dynamic value. In the above scenario, we can use the user ID instead of the “jingzouLock” we wrote. Then in the lock release method, we first determine the value, and then perform delete.
public void releaseLock(String lockKey,String value){
String valueInRedis = redisTemplate.get(lockKey);
if(value.equals(valueInRedis)){
redisTemplate.delete(lockKey);
}
}
Copy the code
There is one more scenario to consider. When the Redis master fails, data is lost during the active/standby switchover, including the key-value of the distributed lock. This will cause the lock to be released indirectly. If the lock is held by another request before the operation is completed, the distributed lock will not work.
With this in mind, Redis officially provides the Redlock algorithm, as well as the corresponding open source implementation, Redisson. For distributed lock scenarios, you can use Redisson directly, which is very convenient, and you may write about Redisson’s technical dry stuff later.
In addition, if the system has high reliability requirements and distributed locks are required, you are advised to use other distributed locks, such as Zookeeper and ETCD.
Well, that’s it for today. If you find this article helpful, please feel free to read it and share your knowledge with more people
Please give it a thumbs up
Pay attention to the public number programming avenue, the first time to get the article push.
Feel good, please like, follow, forward oh ~
Hot
Hot
Hot