当前位置:网站首页>Redis cache penetration, cache breakdown, cache avalanche solution
Redis cache penetration, cache breakdown, cache avalanche solution
2022-07-03 15:11:00 【Miss, do you fix the light bulb】
Please understand redisson, The distributed lock mentioned before and the bloom filter and read-write lock mentioned below all need to be used redisson.
Cache penetration
When visiting a nonexistent key, It will cause you to hit the database directly through the cache , At this time, if a hacker maliciously uses the pressure measurement tool to visit all the time , Cause the database to collapse under excessive pressure .
Solution : Cache nonexistent null values , Given an expiration time , Prevent malicious attacks in a short time . But there will still be malicious input of a large number of nonexistent key, You will still query the database once , Then you can use the bloom filter to intercept before accessing the cache .
The bloon filter : Through a variety of algorithms hash After taking the mold, set a certain position as 1, The combination of multiple bits is 1 It means being , Bron said that existence may not necessarily exist , But if it doesn't exist, it must not exist . We can add all the data to be cached to the bloom filter before the project starts , In business, new data can also be sent to bloom filter , When querying, judge whether there is... Through bloom , There is no direct return . In fact, there is also a disadvantage of bron filter , Can't delete data , Only reinitialize , The time can be chosen to start when no one uses it in the morning .

Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
// structure Redisson
RedissonClient redisson = Redisson.create(config);
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("nameList");
// Initialize the bloon filter : The expected element is 100000000L, The error rate is 3%, Based on these two parameters, the bottom level will be calculated bit Array size
bloomFilter.tryInit(100000L,0.03);
// Insert data into the bloom filter
bloomFilter.add("key1");
bloomFilter.add("key2");
bloomFilter.add("key3");
// Determine whether the following numbers are in the bloom filter
System.out.println(bloomFilter.contains("key1"));//false
System.out.println(bloomFilter.contains("key2"));//false
System.out.println(bloomFilter.contains("key4"));//true
}
Cache breakdown
a large number of key Fail at the same time , There are a lot of key The request also causes too much pressure by directly hitting the database
The solution is to make the cache time of data scattered and not invalidate at the same time , Hot data makes it useful
So far above 2 The pseudo code of the scenario is as follows :
public class RedissonBloomFilter {
private static RedisTemplate redisTemplate;
static RBloomFilter<String> bloomFilter;
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
// structure Redisson
RedissonClient redisson = Redisson.create(config);
bloomFilter = redisson.getBloomFilter("nameList");
// Initialize the bloon filter : The expected element is 100000000L, The error rate is 3%, Based on these two parameters, the bottom level will be calculated bit Array size
bloomFilter.tryInit(100000L, 0.03);
// Query all data to be cached from the database
List<Map> keys = null;
keys = DAOkeys();
Iterator<Map> iterator = keys.iterator();
// Initialize all data
if (iterator.hasNext()){
Map key = iterator.next();
// Put in the bloom filter
bloomFilter.add(key.id);
// Put into cache
redisTemplate.opsForValue().set(key.id,key);
}
}
Object get(String id) {
// First, judge whether it is in the bloom filter
boolean contains = bloomFilter.contains(id);
if (!contains) {
return " Nonexistent data ";
} else {
// The query cache
Object o = redisTemplate.opsForValue().get(id);
if (StringUtils.isEmpty(o)){
// Query the database
Object obj= DAOById(id);
// Add to cache
redisTemplate.opsForValue().set(id,obj);
// If the queried data is empty, a shorter expiration time , Solve the existing problems key however value It's not worth it
if (obj==null){
// Plus a random expiration time
int time= new Random().nextInt(1000)+1000;
redisTemplate.expire(id,time, TimeUnit.SECONDS);
}
return o;
}else{
return o;
}
}
}
}
Cache avalanche
The cache layer cannot support or is down, resulting in all data hitting the database
Solution :1. Cache needs to support high availability , Use redis sentinel Sentinel mode or redis culster Cluster pattern
2. The back end is fused with current limiting and degraded , Current limiting degraded components sentinel or hystrix
Hot cache key Reconstruction optimization
The hot data reconstruction cache generally requires that it never expire , If the expiration time is up , There are too many concurrent threads to create a cache , have access to redis To ensure that a thread can always create a cache successfully , Other threads that do not get the lock sleep for a few milliseconds and then get the cache again .
Hot cache key Reconstruction optimization
atypism , Inconsistent reading and writing )
Double write refers to synchronously updating the cache when writing to the database
Read / write refers to deleting the cache when writing to the database , Write cache when reading database
Generally, the second one is recommended . But it can be seen from the figure that there are problems under concurrency .
Solution : By adding a read-write lock, it ensures that concurrent reads and writes are queued in sequence and executed serially , It's like reading without a lock .( Be careful lock() The lock of the parameterless method is not obtained , Will spin and wait )
package com.redisson;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@Autowired
private Redisson redisson;
@Autowired
private StringRedisTemplate stringRedisTemplate;
private volatile int count;
@RequestMapping("/deduct_stock")
/* problem : For high concurrency scenarios , In order to ensure that it will not oversold , Data consistency 1.synchronized Shackles on code , But it can only be solved in the same process Stand alone application , Insufficient granularity , If distributed deployment is not feasible // synchronized (this){} 2. have access to setnx Distributed locks control every thread , Fine granularity is feasible . Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "zhuge"); //jedis.setnx(k,v) When there is no successful locking, the front-end error code is returned directly , If you succeed, you can directly carry out inventory operations if (!result) { return "error_code"; } And then in finally Release the lock inside , Avoid program errors , The lock does not release stringRedisTemplate.delete(lockKey); 2.1 Considering that if the program does not report an error , It's a direct collapse , For example, operation and maintenance directly kill process , instead of shutdown, Then it will still deadlock , So the solution is to add an expiration time ****** If this lock is added, there will be a serious oversold problem , The meaning of shackles is only to solve the problem of downtime. Downtime is not a problem , But the application runs slowly, but the lock time is short , There will be lock release inventory that has not been operated , Other threads get the lock to operate again and the lock is released by other threads ,****** Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "zhuge"); //jedis.setnx(k,v) stringRedisTemplate.expire(lockKey, 10, TimeUnit.SECONDS); 2.2 To ensure atomicity ( In fact, it's just cutting corners , I'm afraid it will collapse before the expiration time is added ), Set up key Add the expiration time when Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "value", 30, TimeUnit.SECONDS); 3. Controls whether each thread releases the current lock , Although the strength is fine enough , There is a premise to know , Locking is on the third-party client redis On Deadlock will occur without adding expiration time , However, it can ensure that the lock will be released accurately after the main thread operation inventory is completed But in order to solve the problem of program downtime, the expiration time is added , But adding expiration time presents another problem , If the application is not finished , That is, the inventory operation is not finished , It's time to expire , The next thread can get the lock and start the operation , At this time, my last thread completed the inventory operation , Then release the lock , At this time, the lock of this thread has already been released because the expiration time has expired , Then the lock you release now is to release the lock of the next thread . In this way, oversold occurs repeatedly . Need to solve problem one : Ensure that the current thread can release the lock it has added accurately on the premise of adding the expiration time setnx Only right key Lock , Define a random string as the value of the lock to the lock ky String clientId = UUID.randomUUID().toString(); Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS); And then again finally Go inside this value , Judge that the value obtained by the current thread is the local variable generated by the current thread, and delete it if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) { stringRedisTemplate.delete(lockKey); } Problem 2 needs to be solved : Ensure that on the premise of adding the expiration time , It is also necessary to ensure that the lock is released after the warehouse inventory operation . Lock for life , Give a child thread a scheduled task iterm, After a period of time, check whether the main thread has finished executing , No, just add another expiration time Solution scheme : There is an implemented client toolkit Import <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.6.5</version> </dependency> register @Bean public Redisson redisson() { // This is stand-alone mode Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.0.60:6379").setDatabase(0); return (Redisson) Redisson.create(config); } Use , similar setnx RLock redissonLock = redisson.getLock(lockKey); // Lock redissonLock.lock(); //setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS); // Unlock redissonLock.unlock(); */
public String deductStock() {
String lockKey = "product_101";
RLock redissonLock = redisson.getLock(lockKey);
try {
// Lock
redissonLock.lock(); //setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS);
// synchronized (this){ Plan one plus synchronized, But it can only solve the situation of stand-alone application in the same process , If distributed deployment is not feasible
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)
count++;
System.out.println(" Deduction succeeded , Surplus stock :" + realStock);
} else {
System.out.println(" Deduction failed , Insufficient inventory , Total sales "+count);
}
// }
} finally {
redissonLock.unlock();
/*if (lock && clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) { stringRedisTemplate.delete(lockKey); }*/
}
return "end";
}
// @RequestMapping("/redlock")
// public String redlock() {
// String lockKey = "product_001";
// // You need to be different here redis Example of redisson Client connection , Here's just pseudo code with a redisson The client simplifies
// RLock lock1 = redisson.getLock(lockKey);
// RLock lock2 = redisson.getLock(lockKey);
// RLock lock3 = redisson.getLock(lockKey);
//
// /**
// * According to the multiple RLock Object building RedissonRedLock ( The core difference is here )
// */
// RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
// try {
// /**
// * waitTimeout The maximum waiting time to try to acquire the lock , Beyond that , It is considered that the acquisition of lock failed
// * leaseTime Lock holding time , After this time, the lock will automatically fail ( Value should be set to be greater than the time of business processing , Ensure that the business can be processed within the lock validity period )
// */
// boolean res = redLock.tryLock(10, 30, TimeUnit.SECONDS);
// if (res) {
// // Successful lock acquisition , Deal with business here
// }
// } catch (Exception e) {
// throw new RuntimeException("lock fail");
// } finally {
// // in any case , Finally, we need to unlock
// redLock.unlock();
// }
//
// return "end";
// }
//
@RequestMapping("/get_stock")
public String getStock(@RequestParam("clientId") Long clientId) throws InterruptedException {
String lockKey = "product_stock_101";
RReadWriteLock readWriteLock = redisson.getReadWriteLock(lockKey);
RLock rLock = readWriteLock.readLock();
String stock="";
rLock.lock();
System.out.println(" Acquire read lock successfully :client=" + clientId);
stock= stringRedisTemplate.opsForValue().get("stock");
if (StringUtils.isEmpty(stock)) {
System.out.println(" Query the database inventory as 10...");
Thread.sleep(5000);
stringRedisTemplate.opsForValue().set("stock", "10");
}
rLock.unlock();
System.out.println(" The read lock is released successfully :client=" + clientId);
return stock;
}
@RequestMapping("/update_stock")
public String updateStock(@RequestParam("clientId") Long clientId) throws InterruptedException {
String lockKey = "product_stock_101";
RReadWriteLock readWriteLock = redisson.getReadWriteLock(lockKey);
RLock writeLock = readWriteLock.writeLock();
writeLock.lock();
System.out.println(" Get write lock successfully :client=" + clientId);
System.out.println(" Modify the goods 101 The database inventory of is 6...");
stringRedisTemplate.delete("stock");
int i=1/0;
writeLock.unlock();
System.out.println(" The write lock is released successfully :client=" + clientId);
return "end";
}
}
边栏推荐
- .NET六大设计原则个人白话理解,有误请大神指正
- Vs+qt application development, set software icon icon
- PyTorch crop images differentiablly
- 视觉上位系统设计开发(halcon-winform)-3.图像控件
- 基于SVN分支开发模式流程浅析
- The method of parameter estimation of user-defined function in MATLAB
- Global and Chinese market of solder bars 2022-2028: Research Report on technology, participants, trends, market size and share
- Kubernetes帶你從頭到尾捋一遍
- 什么是one-hot encoding?Pytorch中,将label变成one hot编码的两种方式
- [ue4] cascading shadow CSM
猜你喜欢
redis缓存穿透,缓存击穿,缓存雪崩解决方案
Remote server background hangs nohup
Kubernetes带你从头到尾捋一遍
链表有环,快慢指针走3步可以吗
There are links in the linked list. Can you walk three steps faster or slower
Mysql报错:[ERROR] mysqld: File ‘./mysql-bin.010228‘ not found (Errcode: 2 “No such file or directory“)
[ue4] Niagara's indirect draw
视觉上位系统设计开发(halcon-winform)-4.通信管理
Chapter 04_ Logical architecture
[set theory] inclusion exclusion principle (complex example)
随机推荐
Didi off the shelf! Data security is national security
【云原生训练营】模块八 Kubernetes 生命周期管理和服务发现
【Transform】【NLP】首次提出Transformer,Google Brain团队2017年论文《Attention is all you need》
使用JMeter对WebService进行压力测试
【pytorch学习笔记】Datasets and Dataloaders
什么是Label encoding?one-hot encoding ,label encoding两种编码该如何区分和使用?
Byte practice surface longitude
redis单线程问题强制梳理门外汉扫盲
Redis主从、哨兵、集群模式介绍
【pytorch学习笔记】Transforms
socket.io搭建分布式Web推送服务器
高并发下之redis锁优化实战
Mmdetection learning rate and batch_ Size relationship
Global and Chinese markets for transparent OLED displays 2022-2028: Research Report on technology, participants, trends, market size and share
视觉上位系统设计开发(halcon-winform)-1.流程节点设计
App全局异常捕获
[pytorch learning notes] transforms
. Net six design principles personal vernacular understanding, please correct if there is any error
北京共有产权房出租新规实施的租赁案例
Yolov5进阶之七目标追踪最新环境搭建(二)