The difference from cache penetration is that cache breakdown refers to hot data that is not in the cache but exists in the database.
For example: hot news on the homepage, hot data with a very large number of concurrent visits, if the cache expires and fails, the server will query the DB. At this time, if a large number of concurrent queries are made to the DB, the DB may be overwhelmed instantly.
Drawed a simple diagram, as shown below:
Solution: DB query plus distributed lock.
Before solving the problem, first take a look at the unprocessed code and operation conditions.
Query product details code based on product ID
Clear the Redis cache and open 5 threads for concurrent access testing. The test code is as follows :
We expected that the DB would only be queried once, and the next four queries would be fetched from the Redis cache, but the result was:
There is no distributed lock, and the result is expected. However, the container puts a lot of pressure on the DB.
If it is a single server, just use Java's synchronization lock directly
Unfortunately, usually after The client will deploy a cluster, and Java's synchronization lock cannot implement distributed locks.
Redis distributed lock solves cache breakdown
Java's built-in lock can only be applied on a single machine and cannot be distributed. It can be achieved using Redis. Distributed lock.
Code after adding distributed lock
//根据ID查询商品 @GetMapping("/{id}") public R id(@PathVariable String id){ //先查Redis缓存 Object o = redisTemplate.opsForValue().get(id); if (o != null) { //命中缓存 System.err.println("id:"+id+",命中redis缓存..."); return R.success(o); } //缓存未命中 查询数据库 String lockKey = "lock" + id; //加锁,10s后过期 for (;;) { if (redisTemplate.opsForValue().setIfAbsent(lockKey, System.currentTimeMillis(), 10L, TimeUnit.SECONDS)) { //加锁成功的线程,再次检查 o = redisTemplate.opsForValue().get(id); if (o != null) { //命中缓存 System.err.println("Thread:" + Thread.currentThread().getName() + ",id:"+id+",命中redis缓存..."); //释放锁 redisTemplate.delete(lockKey); return R.success(o); } //仍未命中 System.err.println("Thread:" + Thread.currentThread().getName() + ",id:" + id + ",查询DB..."); Goods goods = goodsMapper.selectById(id); //结果存入Redis redisTemplate.opsForValue().set(id, goods); //释放锁 redisTemplate.delete(lockKey); return R.success(goods); } //竞争不到锁,暂时让出CPU资源 Thread.yield(); } }
Start 5 threads for concurrent access. The result is as follows:
The above is the detailed content of How Redis distributed lock prevents cache breakdown. For more information, please follow other related articles on the PHP Chinese website!