1. Cache penetration

concept

Cache penetration is access to data that does not exist in the database. High concurrency or malicious access to the data can cause requests to the database until the database crashes. For example, when we write projects, the primary key ID of an item is rarely negative. So maybe someone’s going to keep accessing the item with id -1. And the product doesn’t exist, causing our database to crash.

The solution

My usual solution here is to store an empty value in Redis for the item key when a request is called to the database and returns a null value. Make subsequent requests directly access Redis instead of accessing the database.

  jedis.setex(key,60."empty");
Copy the code

However, this approach is not completely safe, if you want to learn more, check out another article bloom filters

2. Cache avalanche

concept

Cache avalanche is when we set the cache data, set the period of validity of the same, at the same time, most of the cache expires at the same time, this time, don’t get the data in the redis, all request to access the database, the database has been under pressure all requests, in the case of high concurrency, tens of thousands of requests to the database, at the same time lead to database collapse Collapse.

The solution

For cache avalanches, we can conceptually find that multiple caches expire at the same time, so we can let them expire at different times. The implementation method is to set a Random valid time for the cache by using setex command and Random class to generate Random numbers. In this way, multiple caches will almost never expire at the same time, i.e. cache avalanches will almost never occur.

  int random=new Random().nextInt(60*10);
Copy the code
   jedis.setex(key,random,"empty");
Copy the code

3. Cache breakdown

concept

A cache breakdown is like a combination of cache penetration and cache avalanche, meaning that a data is too hot. In a high concurrency situation, the cache of the data expires, and thousands of requests bypass Redis and directly hit the database, causing the database to crash.

The solution

Distributed lock. Distributed lock is a restricted flow lock, like a security guard, guarding the entry to the database. Only the request that grabs the lock is allowed, and subsequent requests are queued. Wait for the lock holder to enter the database and retrieve the data from the database and store it in the cache, then allow the person behind to access. At this time, the person in front has stored the data in the cache, then the person behind can fetch the data from Redis instead of directly accessing the database. Please refer to my article for detailed implementation and explanation of distributed locks

Cache breakdown, cache avalanche and cache penetration

Cache breakdowns and cache avalanches are both cache penetrations and are just special manifestations of them

#. Complete code to handle three problems

    public Student selectStudentById(Integer id) {
    String key="student-20-10-2:"+id+"-key";
        String lockKey=key+":lock-"+id;
        String value= UUID.randomUUID().toString();
        Jedis jedis = redisUtils.getJedis();

        String s = jedis.get(key);
        Student student=null;
        if (s==null){
            System.out.println("key:["+key+"] Access database for data");
            RLock lock = redissonClient.getLock(lockKey);
            lock.lock(50, TimeUnit.SECONDS);
            /* String set = jedis.set(lockKey, value, "NX", "EX", 50); * /
            if (lock.isLocked()){
                student = studentMapper.selectByPrimaryKey(id);
                int random=new Random().nextInt(60*10);
                if (student==null){
                    jedis.setex(key,random,"empty");
                }else{
                    jedis.setex(key,random,JSON.toJSONString(student));
                }
/* if (jedis.get(lockKey).equals(value)){ jedis.del(lockKey); } * /
                lock.unlock();
            }else{
                /* No lock, callback */
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                returnselectStudentById(id); }}else{
            System.out.println("key:["+key+"] get data from Redis");
            if (s.equals("empty")) {
                student=null;
            }else{ student = JSON.parseObject(s, Student.class); }}return student;
       }
Copy the code