Redis process lock to avoid cache breakdown

 

Redis process lock to avoid cache breakdown

 

First of all, due to the characteristics of the system, it knows which keys are hotkeys. For these hotkeys, which thread finds that it is empty now, it will be locked immediately to obtain the qualification for downward operation, and other blocks will be blocked (so that it will not put a lot of pressure on the db ( Otherwise, go to access db)) , and then immediately this UI thread requests db to get data to fill the cache

 

cache breakdown

For some keys with an expiration time set, if these keys may be accessed with high concurrency at certain points in time, it is a very "hot" data. At this time, there is a problem that needs to be considered: the problem of the cache being "broken down". The difference between this and the cache avalanche is that the cache is for a certain key, and the former is for many keys.

 

When the cache expires at a certain point in time, there are a large number of concurrent requests for this key at this point in time. These requests generally load data from the back-end DB and set it back to the cache when the cache expires. At this time, large concurrent requests It may instantly overwhelm the backend DB.

 

solution

1. Use a mutex key

The more common practice in the industry is to use mutex. To put it simply, when the cache is invalid (it is judged that the value taken out is empty), instead of going to load db immediately, use some operations of the cache tool with the return value of a successful operation (such as Redis's SETNX or Memcache). ADD) to set a mutex key, when the operation returns successfully, perform the load db operation and reset the cache; otherwise, retry the entire get cache method.

SETNX is the abbreviation of "SET if Not eXists", that is, it is only set when it does not exist, and it can be used to achieve the effect of locking. Before redis 2.6.1, the expiration time of setnx was not implemented, so here are two versions of the code for reference:

[java] view plain copy on CODE view code slice derived to my code slice

//Pre-2.6.1 stand-alone version lock  

String get(String key) {    

   String value = redis.get(key);    

   if (value  == null) {    

    if (redis.setnx(key_mutex, "1")) {    

        // 3 min timeout to avoid mutex holder crash    

        redis.expire(key_mutex, 3 * 60)    

        value = db.get(key);    

        redis.set(key, value);    

        redis.delete(key_mutex);    

    } else {    

        // Retry after other threads rest for 50ms    

        Thread.sleep(50);    

        get(key);    

    }    

  }    

}  

Latest version code:

[java] view plain copy on CODE view code slice derived to my code slice

public String get(key) {  

      String value = redis.get(key);  

      if (value == null) { //Represents that the cached value expires  

          //Set a timeout of 3min to prevent the failure of the del operation, the next cache expiration will not be able to load db  

          if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { // means the setting is successful  

               value = db.get(key);  

                      redis.set(key, value, expire_secs);  

                      redis.del(key_mutex);  

              } else { //At this time, it means that other threads at the same time have loaded db and set it back to the cache. At this time, you can retry to get the cache value  

                      sleep(50);  

                      get(key); //retry  

              }  

          } else {  

              return value;        

          }  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326265541&siteId=291194637