Cache penetration, cache breakdown, cache avalanche

Time:2020-5-31

Cache penetration

Cache penetration, cache breakdown, cache avalanche

Cache penetration
It refers to querying a certain nonexistent data, because the cache is written passively when it is not hit, and for the sake of fault tolerance, if the data can not be found from the storage layer, it will not be written to the cache, which will cause the nonexistent data to be queried in the storage layer every time, losing the significance of the cache. When the traffic is large, the DB may hang up. If someone uses the nonexistent key to attack our application frequently, this is the vulnerability.

Solution
There are many ways to effectively solve the problem of cache penetration. The most common one is to use the bloom filter to hash all possible data into a big enough bitmap. A certain non-existent data will be intercepted by the bitmap, thus avoiding the query pressure on the underlying storage system. In addition, there is a simpler and crude method (this is what we use). If the data returned by a query is empty (no matter whether the data does not exist or the system fails), we still cache the empty result, but its expiration time will be very short, no more than five minutes.

Cache avalanche

Cache avalanche
It means that when we set the cache, we use the same expiration time, which causes the cache to fail at a certain time, and all requests are forwarded to the DB. The instant pressure of the DB is too heavy and avalanche.

Solution
The avalanche effect of cache failure has a terrible impact on the underlying system. Most system designers consider using lock or queue mode to ensure the single thread (process) write of cache, so as to avoid a large number of concurrent requests falling on the underlying storage system in case of failure. Here is a simple scheme to share. For example, we can add a random value based on the original failure time, such as 1-5 minutes random, so that the repetition rate of each cache expiration time will be reduced, and it is difficult to cause collective failure events.

For more avalanche effects, see https://www.iteye.com/blog/ca…

Cache breakdown

Cache breakdownFor some keys with expiration time set, if these keys may be accessed at some point in time, they are very “hot” data. At this time, we need to consider a problem: the cache is “broken down”. The difference between this and the cache avalanche is that it is aimed at a certain key cache. The former is a lot of keys.

When the cache expires at a certain time point, there are a large number of concurrent requests for the key at that time point. These requests find that the cache expires and will generally load data from the back-end dB and set it back to the cache. At this time, the large concurrent requests may crush the back-end dB in an instant.

Solution

1. Use mutex key

The common practice in the industry is to usemutex。 Simply put, when the cache fails (the value judged to be empty), instead of immediately loading dB, first use some operations with the return value of successful operations (such as setnx of redis or add of Memcache) of the cache tool to set a mutex key, and then load when the operation returns success DB and reset the cache; otherwise, retry the entire get cache method.

Setnx is the abbreviation of “set if not exists”. It can be used to achieve the effect of lock. Before redis 2.6.1, setnx expiration time was not implemented, so here are two version code References:

Cache penetration, cache breakdown, cache avalanche

2.6.1 previous single machine 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 {  
        //Other threads rest for 50 milliseconds and try again  
        Thread.sleep(50);  
        get(key);  
    }  
  }  
}

Latest version code

public String get(key) {
      String value = redis.get(key);
      If (value = = null) {// indicates cache value expires
          //Set the timeout of 3 minutes to prevent the next time the Del operation fails, the cache will not be able to load dB
          if ( redis.setnx (key_ Mutex, 1, 3 * 60 = = 1) {// indicates that the setting succeeds
               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 reset it to the cache. At this time, try again to get the cache value
                      sleep(50);
                      Get (key); // try again
              }
          } else {
              return value;      
          }
 }

Memcache code

if (memcache.get(key) == null) {  
    // 3 min timeout to avoid mutex holder crash  
    if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
        value = db.get(key);  
        memcache.set(key, value);  
        memcache.delete(key_mutex);  
    } else {  
        sleep(50);  
        retry();  
    }  
} 

2. Use mutex key in advance:
Set a timeout value (timeout1) within value, which is smaller than the actual Memcache timeout (timeout2). When timeout1 is read from cache and found to be expired, extend timeout1 and reset to cache. Then load the data from the database and set it to the cache. The pseudo code is as follows:

v = memcache.get(key);  
if (v == null) {  
    if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
        value = db.get(key);  
        memcache.set(key, value);  
        memcache.delete(key_mutex);  
    } else {  
        sleep(50);  
        retry();  
    }  
} else {  
    if (v.timeout <= now()) {  
        if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
            // extend the timeout for other threads  
            v.timeout += 3 * 60 * 1000;  
            memcache.set(key, v, KEY_TIMEOUT * 2);  
  
            // load the latest value from db  
            v = db.get(key);  
            v.timeout = KEY_TIMEOUT;  
            memcache.set(key, value, KEY_TIMEOUT * 2);  
            memcache.delete(key_mutex);  
        } else {  
            sleep(50);  
            retry();  
        }  
    }  
} 

3. “never expire”:

There are two meanings of “never expire”:
(1) From the perspective of redis, there is no expiration time set, which ensures that there will be no hot key expiration problem, that is, “physical” does not expire.
(2) In terms of function, if it doesn’t expire, it will become static? So we store the expiration time in the value corresponding to the key. If it is to expire, we build the cache through a background asynchronous thread, that is, “logic” expires
From the practical point of view, this method is very performance friendly. The only disadvantage is that when building the cache, other threads (threads not building the cache) may access the old data, but this is tolerable for general Internet functions.

Cache penetration, cache breakdown, cache avalanche

String get(final String key) {

V v = redis.get(key);  
    String value = v.getValue();  
    long timeout = v.getTimeout();  
    if (v.timeout <= System.currentTimeMillis()) {  
        //Asynchronous update background exception execution  
        threadPool.execute(new Runnable() {  
            public void run() {  
                String keyMutex = "mutex:" + key;  
                if (redis.setnx(keyMutex, "1")) {  
                    // 3 min timeout to avoid mutex holder crash  
                    redis.expire(keyMutex, 3 * 60);  
                    String dbValue = db.get(key);  
                    redis.set(key, dbValue);  
                    redis.delete(keyMutex);  
                }  
            }  
        });  
    }  
    return value;

}

4. Resource protection:

Cache penetration, cache breakdown, cache avalanche

Using the hystrix of Netflix, you can do the main thread pool of resource isolation and protection. If you apply this to the construction of cache, it’s not too bad.

Conclusion: there is no best but the most suitable

Cache penetration, cache breakdown, cache avalanche

Four kinds of scheme source network, please link for details: http://carlosfu.iteye.com/blo…
Original link: https://blog.csdn.net/zeb_ per…

Recommended Today

The way of nonlinear optimization

Mathematical knowledge 1、 Nonlinear functionLinear function is another name of a function of first degree, then nonlinear function means that the function image is not a function of a straight line.Nonlinear functions include exponential function, power function, logarithmic function, polynomial function and so on. 2、 Taylor expansion1. Taylor formula:Taylor’s formula is to add a_ The […]