一、熱點數據預加載
// 使用Redis HyperLogLog統計訪問頻率
public void recordAccess(Long productId) {
String key = "access:product:" + productId;
redis.pfadd(key, UUID.randomUUID().toString());
redis.expire(key, 60); // 統計最近60秒
}
// 定時任務檢測熱點
@Scheduled(fixedRate = 10000)
public void detectHotKeys() {
Set<String> keys = redis.keys("access:product:*");
keys.forEach(key -> {
long count = redis.pfcount(key);
if (count > 1000) { // 閾值
Long productId = extractId(key);
preloadProduct(productId);
}
});
}
二、空值緩存
public Product getProduct(Long id) {
String key = "product:" + id;
Product product = redis.get(key);
if (product != null) {
if (product.isEmpty()) { // 空對象標識
return null;
}
return product;
}
product = productDao.findById(id);
if (product == null) {
redis.setex(key, 300, "empty"); // 緩存空值5分鐘
return null;
}
redis.setex(key, 3600, product);
return product;
}
三、需要增加熔斷降級
@HystrixCommand(fallbackMethod = "getProductFallback",
commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
})
public Product getProduct(Long id) {
return productDao.findById(id);
}
public Product getProductFallback(Long id) {
return new Product().setDefault(); // 返回兜底數據
}
四、延遲雙刪策略
@Transactional
public void updateProduct(Product product) {
// 1. 先刪緩存
redis.delete("product:" + product.getId());
// 2. 更新數據庫
productDao.update(product);
// 3. 延時再刪
executor.schedule(() -> {
redis.delete("product:" + product.getId());
}, 500, TimeUnit.MILLISECONDS);
}