Redis作为一款高性能的缓存数据库,为许多应用提供了快速的数据访问和存储能力。然而,在使用Redis时,我们不可避免地会面对一些常见的问题,如缓存雪崩、缓存穿透和缓存击穿。
本文将深入探讨这些问题的本质,以及针对这些问题的解决方案。
因以上两点导致大量请求直接打到数据库,从而引发数据库压力激增,甚至崩溃的现象。
import redis.clients.jedis.Jedis;
public class RedisExpirationDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
// Key for caching
String key = "my_data_key";
String value = "cached_value";
int randomExpiration = (int) (Math.random() * 60) + 1; // Random value between 1 and 60 seconds
jedis.setex(key, randomExpiration, value);//设置过期时间
jedis.set(hotKey, hotValue);//永不过期
// Retrieving data
String cachedValue = jedis.get(key);
System.out.println("Cached Value: " + cachedValue);
// Closing the connection
jedis.close();
}
}
使用 redis 缓存集群,实现主从集群高可用
ehcache本地缓存 + redis 缓存
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import redis.clients.jedis.Jedis;
public class EhcacheRedisDemo {
public static void main(String[] args) {
// Configure ehcache
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
cacheManager.init();
Cache<String, String> localCache = cacheManager.createCache("localCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class));
// Configure Redis
Jedis jedis = new Jedis("localhost", 6379);
String key = "data_key";
String value = "cached_value";
// Check if data is in local cache
String cachedValue = localCache.get(key);
if (cachedValue != null) {
System.out.println("Value from local cache: " + cachedValue);
} else {
// Retrieve data from Redis and cache it locally
cachedValue = jedis.get(key);
if (cachedValue != null) {
System.out.println("Value from Redis: " + cachedValue);
localCache.put(key, cachedValue);
} else {
System.out.println("Data not found.");
}
}
// Closing connections
jedis.close();
cacheManager.close();
}
}
限流降级需要结合其他工具和框架来实现,比如 Sentinel、Hystrix等。
缓存穿透指的是恶意或者非法的请求,其请求的数据在缓存和数据库中均不存在,由于大量的请求导致直接打到数据库,造成数据库负载过大。
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import redis.clients.jedis.Jedis;
public class BloomFilterDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
// Create and populate a Bloom Filter
int expectedInsertions = 1000;
double falsePositiveRate = 0.01;
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(), expectedInsertions, falsePositiveRate);
String key1 = "data_key_1";
String key2 = "data_key_2";
String key3 = "data_key_3";
bloomFilter.put(key1);
bloomFilter.put(key2);
// Check if a key exists in the Bloom Filter before querying the database
String queryKey = key3;
if (bloomFilter.mightContain(queryKey)) {
String cachedValue = jedis.get(queryKey);
if (cachedValue != null) {
System.out.println("Cached Value: " + cachedValue);
} else {
System.out.println("Data not found in cache.");
}
} else {
System.out.println("Data not found in Bloom Filter.");
}
// Closing the connection
jedis.close();
}
}
import redis.clients.jedis.Jedis;
public class CacheEmptyValueDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
String emptyKey = "empty_key";
String emptyValue = "EMPTY";
// Cache an empty value with a short expiration time
jedis.setex(emptyKey, 10, emptyValue);
// Check if the key exists in the cache before querying the database
String queryKey = "nonexistent_key";
String cachedValue = jedis.get(queryKey);
if (cachedValue != null) {
if (cachedValue.equals(emptyValue)) {
System.out.println("Data does not exist in the database.");
} else {
System.out.println("Cached Value: " + cachedValue);
}
} else {
System.out.println("Data not found in cache.");
}
// Closing the connection
jedis.close();
}
}
对非法的IP或账号进行请求限制。
异常参数校验,如id=-1、参数空值。
缓存击穿指的是一个查询请求针对一个在数据库中存在的数据,但由于该数据在某一时刻过期失效,导致请求直接打到数据库,引发数据库负载激增。
import redis.clients.jedis.Jedis;
public class HotDataNeverExpireDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
String hotKey = "hot_data_key";
String hotValue = "hot_cached_value";
// Set the hot key with no expiration
jedis.set(hotKey, hotValue);
// Retrieving hot data
String hotCachedValue = jedis.get(hotKey);
System.out.println("Hot Cached Value: " + hotCachedValue);
// Closing the connection
jedis.close();
}
}
import redis.clients.jedis.Jedis;
public class MutexLockDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
String mutexKey = "mutex_key";
String mutexValue = "locked";
// Try to acquire the lock
Long lockResult = jedis.setnx(mutexKey, mutexValue);
if (lockResult == 1) {
// Lock acquired, perform data regeneration here
System.out.println("Lock acquired. Generating cache data...");
// Simulating regeneration process
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Release the lock
jedis.del(mutexKey);
System.out.println("Lock released.");
} else {
System.out.println("Lock not acquired. Another thread is regenerating cache data.");
}
// Closing the connection
jedis.close();
}
}
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。