- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
Redis作为一款高性能的缓存数据库,为许多应用提供了快速的数据访问和存储能力。然而,在使用Redis时,我们不可避免地会面对一些常见的问题,如缓存雪崩、缓存穿透和缓存击穿。本文将深入探讨这些问题的本质,以及针对这些问题的解决方案.
在某个时间点,缓存中的大量数据同时过期失效.
Redis宕机.
因以上两点导致大量请求直接打到数据库,从而引发数据库压力激增,甚至崩溃的现象.
将 redis 中的 key 设置为永不过期,或者TTL过期时间间隔开 。
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 缓存集群,实现主从集群高可用 。
见 《Redis从入门到放弃(9):集群模式》 。
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 等.
缓存穿透指的是恶意或者非法的请求,其请求的数据在缓存和数据库中均不存在,由于大量的请求导致直接打到数据库,造成数据库负载过大.
使用布隆过滤器 :布隆过滤器是一种数据结构,用于快速判断一个元素是否存在于集合中。部署在Redis的前面,去拦截数据,减少对Redis的冲击,将所有可能的查询值都加入布隆过滤器,当一个查询请求到来时,先经过布隆过滤器判断是否存在于缓存中,避免不必要的数据库查询.
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();
}
}
import redis.clients.jedis.Jedis;
import java.util.concurrent.CompletableFuture;
public class AsyncCacheUpdateDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
String key = "data_key";
String value = "cached_value";
// Set initial cache
jedis.setex(key, 60, value);
// Simulate data update
CompletableFuture<Void> updateFuture = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(3000); // Simulate time-consuming update
String updatedValue = "updated_value";
jedis.setex(key, 60, updatedValue);
System.out.println("Cache updated asynchronously.");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// Do other work while waiting for the update
System.out.println("Performing other work while waiting for cache update...");
// Wait for the update to complete
updateFuture.join();
// Retrieve updated value
String updatedCachedValue = jedis.get(key);
System.out.println("Updated Cached Value: " + updatedCachedValue);
// Closing the connection
jedis.close();
}
}
在使用Redis时,缓存雪崩、缓存穿透和缓存击穿是常见的问题,但通过合理的设置缓存策略、使用数据结构和锁机制,以及采用异步更新等方法,可以有效地减少甚至避免这些问题的发生。因此,在入门Redis后,不应因为这些问题而轻易放弃,而是应当深入了解并采取相应的解决方案,以充分发挥Redis在提升应用性能方面的优势.
最后此篇关于Redis从入门到放弃(11):雪崩、击穿、穿透的文章就讲到这里了,如果你想了解更多关于Redis从入门到放弃(11):雪崩、击穿、穿透的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个关于 Redis Pubsub 的练习,如下所示: 如果发布者发布消息但订阅者没有收到服务器崩溃。订阅者如何在重启服务器时收到该消息? 请帮帮我,谢谢! 最佳答案 在这种情况下,消息将永远消失
我们正在使用 Service Stack 的 RedisClient 的 BlockingDequeue 来保存一些数据,直到它可以被处理。调用代码看起来像 using (var client =
我有一个 Redis 服务器和多个 Redis 客户端。每个 Redis 客户端都是一个 WebSocket+HTTP 服务器,其中包括管理 WebSocket 连接。这些 WebSocket+HTT
我有多个 Redis 实例。我使用不同的端口创建了一个集群。现在我想将数据从预先存在的 redis 实例传输到集群。我知道如何将数据从一个实例传输到集群,但是当实例多于一个时,我无法做到这一点。 最佳
配置:三个redis集群分区,跨三组一主一从。当 Master 宕机时,Lettuce 会立即检测到中断并开始重试。但是,Lettuce 没有检测到关联的 slave 已经将自己提升为 master
我想根据从指定集合中检索这些键来删除 Redis 键(及其数据集),例如: HMSET id:1 password 123 category milk HMSET id:2 password 456
我正在编写一个机器人(其中包含要禁用的命令列表),用于监视 Redis。它通过执行禁用命令,例如 (rename-command ZADD "")当我重新启动我的机器人时,如果要禁用的命令列表发生变化
我的任务是为大量听众使用发布/订阅。这是来自 docs 的订阅的简化示例: r = redis.StrictRedis(...) p = r.pubsub() p.subscribe('my-firs
我一直在阅读有关使用 Redis 哨兵进行故障转移的内容。我打算有1个master+1个slave,如果master宕机超过1分钟,就把slave变成master。我知道这在 Sentinel 中是
与仅使用常规 Redis 和创建分片相比,使用 Redis 集群有哪些优势? 在我看来,Redis Cluster 更注重数据安全(让主从架构解决故障)。 最佳答案 我认为当您需要在不丢失任何数据的情
由于 Redis 以被动和主动方式使 key 过期, 有没有办法得到一个 key ,即使它的过期时间已过 (但 在 Redis 中仍然存在 )? 最佳答案 DEBUG OBJECT myKey 将返回
我想用redis lua来实现monitor命令,而不是redis-cli monitor。但我不知道怎么办。 redis.call('monitor') 不起作用。 最佳答案 您不能从 Redis
我读过 https://github.com/redisson/redisson 我发现有几个 Redis 复制设置(包括对 AWS ElastiCache 和 Azure Redis 缓存的支持)
Microsoft.AspNet.SignalR.Redis 和 StackExchange.Redis.Extensions.Core 在同一个项目中使用。前者需要StackExchange.Red
1. 认识 Redis Redis(Remote Dictionary Server)远程词典服务器,是一个基于内存的键值对型 NoSQL 数据库。 特征: 键值(key-value)型,value
1. Redis 数据结构介绍 Redis 是一个 key-value 的数据库,key 一般是 String 类型,但 value 类型多种多样,下面就举了几个例子: value 类型 示例 Str
1. 什么是缓存 缓存(Cache) 就是数据交换的缓冲区,是存贮数据的临时地方,一般读写性能较高。 缓存的作用: 降低后端负载 提高读写效率,降低响应时间 缓存的成本: 数据一致性成本 代码维护成本
我有一份记录 list 。对于我的每条记录,我都需要进行一些繁重的计算,因为我要在Redis中创建反向索引。为了达到到达记录,需要在管道中执行多个redis命令(sadd为100 s + set为1
我有一个三节点Redis和3节点哨兵,一切正常,所有主服务器和从属服务器都经过验证,并且哨兵配置文件已与所有Redis和哨兵节点一起更新,但是问题是当Redis主服务器关闭并且哨兵希望选举失败者时再次
我正在尝试计算Redis中存储的消息之间的响应时间。但是我不知道该怎么做。 首先,我必须像这样存储chat_messages的时间流 ZADD conversation:CONVERSATION_ID
我是一名优秀的程序员,十分优秀!