jetcache
jetcache copied to clipboard
两级缓存不支持缓存预热
问题:
- 两级缓存,本地缓存 linkedhashmap 和远程缓存 redis, 我在服务启动的时候希望能够自动将 redis 中已经缓存的数据预热刷新到 local cache 里面,
- 我看了 cache 里面的方法, getall 需要通过 key 集合去获取,我这边 key 大概有 50w 个,如果我去查询数据库来构建这个 key 的话,查询的时间比较长。
- 希望能够提供一种方法,或者 api 去通过将 redis 已经暂存的缓存,刷到 local cache 里面去
代码:
import com.alibaba.fastjson2.JSON;
import com.alicp.jetcache.*;
import com.alicp.jetcache.embedded.LinkedHashMapCache;
import com.alicp.jetcache.embedded.LinkedHashMapCacheBuilder;
import com.alicp.jetcache.redis.lettuce.RedisLettuceCacheBuilder;
import com.alicp.jetcache.support.*;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.RedisClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@SpringBootApplication
public class Main {
private Cache<String, Order> orderCache;
@PostConstruct
public void init() throws InterruptedException {
// todo 初始化 redis 缓存到 local cache 里面
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//内存缓存,读取 hashmap
Cache<String, Order> memoryCache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder()
//缓存 null
.cacheNullValue(true)
.limit(100)
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();
//空缓redis缓存
RedisClient redisClient =
//这里可以直接配置 slave
RedisClient.create("redis://127.0.0.1");
redisClient.setOptions(ClientOptions.builder().
disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.build());
Cache<String, String> redisCache = RedisLettuceCacheBuilder.createRedisLettuceCacheBuilder()
.keyConvertor(Fastjson2KeyConvertor.INSTANCE)
//缓存 null
.cacheNullValue(true)
//key 前缀
.keyPrefix("c:p:")
//广播
.broadcastChannel("c:h:")
//value 编码
.valueEncoder(Fastjson2ValueEncoder.INSTANCE)
//value 解码
.valueDecoder(Fastjson2ValueDecoder.INSTANCE)
//过期时间
.expireAfterWrite(3600, TimeUnit.SECONDS)
.addMonitor(event -> System.out.println("date=" + getDate(dateFormat) + "cache event=" + JSON.toJSONString(event)))
//redis client
.redisClient(redisClient)
.buildCache();
orderCache = MultiLevelCacheBuilder.createMultiLevelCacheBuilder()
.addCache(memoryCache, redisCache)
.expireAfterWrite(100, TimeUnit.SECONDS)
.buildCache();
MultiGetResult<String, Order> allResult = orderCache.GET_ALL(new HashSet<>());
Order value = createOrder();
orderCache.PUT("bp001", value);
soutLocalCacheAll(dateFormat, memoryCache);
int i = 1;
while (i++ < 100) {
Order bp001 = orderCache.get("bp001");
System.out.println("date=" + getDate(dateFormat) + ", p=" + getOrderToString(bp001));
if (i == 2) {
orderCache.put("bp" + i, createOrder());
}
if (i == 3) {
orderCache.put("bp" + i, createOrder());
}
soutLocalCacheAll(dateFormat, memoryCache);
Thread.sleep(1000L);
}
}
private static void soutLocalCacheAll(SimpleDateFormat dateFormat, Cache<String, Order> memoryCache) {
if (memoryCache instanceof LinkedHashMapCache) {
LinkedHashMapCache<String, CacheValueHolder<Order>> linkHashMapCache = (LinkedHashMapCache) memoryCache;
LinkedHashMap<String, CacheValueHolder<Order>> map = linkHashMapCache.unwrap(LinkedHashMap.class);
String strPosi = map.values().stream().map((CacheValueHolder<Order> h) -> {
Order p = h.getValue();
return getOrderToString(p);
}).collect(Collectors.joining(",", "[", "]"));
System.out.println("date=" + getDate(dateFormat) + ", allP=" + strPosi);
}
}
private static String getDate(SimpleDateFormat dateFormat) {
return dateFormat.format(new Date());
}
private static String getOrderToString(Order p) {
return "p=" + p.getPrice() + ",q=" + p.getQuantity();
}
private static Order createOrder() {
Random random = new Random(System.currentTimeMillis());
int randomCount = random.nextInt(100);
Order value = new Order();
value.setQuantity(randomCount * 1000);
value.setPrice(new BigDecimal(randomCount));
return value;
}
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
public static class Order {
private BigDecimal price;
private Integer quantity;
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
}
}
这缺少普遍适用的方法来实现它,或者能实现它的方法在大多数情况下不是好的实践,所以没有这个能力。
理解,确实这个是一个特殊的场景,因为大多数情况下,确实不需要预热全部的缓存数据
mark
mark