Cache penetration
Problem description
There must be no cache and data that cannot be queried. Because the cache is written passively when it misses, and for the sake of fault tolerance, if the data cannot 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 request, losing the significance of the cache.
Solution
- Using Bloom filter
- Hash all possible data into a large enough bitmap, and a certain non-existent data will be intercepted by the bitmap, so as to avoid the query pressure on the underlying storage system
- Cache empty results
- If the data returned by a query is empty (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 at most.
@Override public ArticleVO getArticle(Long articleId) { // Cache key String cacheKey = "article:" + articleId; // Determine whether there is a key in the cache if(redisTemplate.hasKey(cacheKey)){ // Get articles from cache return redisTemplate.opsForValue().get(cacheKey); } // Start database query ArticleVO article = articleDao.queryById(articleId); if (article != null) { // Data is not empty, put into cache redisTemplate.opsForValue().set(cacheKey, article, 60, TimeUnit.MINUTES); } else { // If the data is empty, set the default value, put it in for storage, and set a shorter time redisTemplate.opsForValue().set(cacheKey, null, 5, TimeUnit.MINUTES); } return article; }
Buffer breakdown
Problem description
Cache breakdown means that a key is very hot and is constantly carrying large concurrency. Large concurrency focuses on accessing this point. When the key fails, the continuous large concurrency will break through the cache and directly request the database.
Solution
- You can set hotspot data to never expire
- Implement the mutex lock, wait for the first request to build the cache, and then release the lock, so that other requests can access data through the key
Locking queuing is only to reduce the pressure on the database and does not improve the system throughput. Assuming that the key is locked during cache reconstruction under high concurrency, 999 of the last 1000 requests are blocked. It will also cause users to wait for timeout, which is a way to cure the symptoms rather than the root cause!
reference resources: redis based distributed shared locks
@Override public ArticleVO getArticle(Long articleId) { // Cache key String cacheKey = "article:" + articleId; // Determine whether there is a key in the cache if(redisTemplate.hasKey(cacheKey)){ // Get articles from cache return redisTemplate.opsForValue().get(cacheKey); } try { // Acquire lock boolean lock = redisLock.lock(cacheKey, articleId); if(!lock) { // Failed to acquire lock, return null return null; } // Start database query Object article = smsCouponDao.queryById(articleId); if (article != null) { // Data is not empty, put into cache redisTemplate.opsForValue().set(cacheKey, article, 60, TimeUnit.MINUTES); } else { // If the data is empty, set the default value, put it in for storage, and set a shorter time redisTemplate.opsForValue().set(cacheKey, null, 5, TimeUnit.MINUTES); } } finally { // Unlock redisLock.unlock(cacheKey, articleId); } return article; }
Cache avalanche
Problem description
Cache avalanche refers to that the cache is unavailable or a large number of caches fail in the same time period due to the same timeout, a large number of requests directly access the database, and the system avalanche is caused by excessive database pressure.
Solution
- In advance: redis is highly available, master-slave + sentinel, and redis cluster to avoid total collapse.
- In fact: local ehcache cache + hystrix current limiting & degradation to avoid MySQL being killed.
- Afterwards: redis is persistent. Once restarted, it will automatically load data from the disk and quickly recover cached data.
Optimization suggestions
-
It is recommended to disperse the cache expiration time as much as possible. The popular cache time is longer and the unpopular cache time is shorter, which can also save the resources of cache service.
-
The expiration time of the deposit can take a random value. This is done to avoid simultaneous cache invalidation.