秒杀系统 | 多级查询缓存 | 基于 Guava Cache 的本地热点缓存

本文介绍了本地热点缓存的特点,如对脏读不敏感,内存可控,并探讨了其设计考量,包括并发读写、失效机制和内存限制。GuavaCache作为实现本地热点缓存的工具,支持大小控制和超时设置,采用LRU策略。通过示例展示了GuavaCache在Spring环境中的使用,以及如何结合Redis提高缓存命中率,从而提升系统性能。本地缓存的引入使TPS从2000提升到4000+。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本地热点缓存的特点

  • 只有热点数据才能进入本地热点缓存;
  • 本地热点缓存对脏读要非常不敏感,比如商品名称在 MySQL 中的变更,这个变更没有更新到本地缓存中,这是 OK 的,用户下单时的商品名称和用户看到的商品名称不一样,这是 OK 的;
  • 本地热点缓存内存要可控:
    • 当商品信息在 MySQL 中变更时,Redis 中的过期数据只需清除即可;
    • 但对本地热点缓存来说,很少有方法能清除掉 JVM 中的数据的,因为要清除 JVM 中的数据,需要每台应用服务器都清除掉数据才行,可以使用 MQ 做广播消息的发送来实现,但这种操作是得不偿失的;
  • 本地热点缓存的生命周期不会特别长,比 Redis 中 key 的生命周期要短很多,这样才能做到被动失效造成的脏读非常少;

本地热点缓存的设计考量

  • 本地热点缓存的本质其实就是维护一个 HashMap 的数据结构,但维护这个结构是不容易的:
    • 首先要支持并发读写,ConcurrentHashMap 的性能不够理想;
    • 要考虑失效时间和内存容量限制的淘汰机制,比如10分钟自动失效、先进先出、最少访问频次 LRU;

Guava Cache 的特点

  • Guava Cache 可控制大小和超时时间,本质上也是可支持并发的 HashMap;
  • Guava Cache 可配置 LRU(最近最少访问的 key 优先被淘汰) 的策略;
  • Guava Cache 是线程安全的;

基于 Cuava Cache 的本地热点缓存的实现

  • 依赖
  1. <dependency>
  2. <groupId>com.google.guava</groupId>
  3. <artifactId>guava</artifactId>
  4. <version>18.0</version>
  5. </dependency>
  • 对本地缓存操作的封装
  1. public interface CacheService {
  2. void setCommonCache(String key, Object value);
  3. Object getFromCommonCache(String key);
  4. }
  1. package com.lixinlei.miaosha.service.impl;
  2. import com.google.common.cache.Cache;
  3. import com.google.common.cache.CacheBuilder;
  4. import com.lixinlei.miaosha.service.CacheService;
  5. import org.springframework.stereotype.Service;
  6. import javax.annotation.PostConstruct;
  7. import java.util.concurrent.TimeUnit;
  8. @Service
  9. public class CacheServiceImpl implements CacheService {
  10. private Cache<String, Object> commonCache = null;
  11. @PostConstruct
  12. public void init() {
  13. commonCache = CacheBuilder.newBuilder()
  14. .initialCapacity(10)
  15. .maximumSize(100)
  16. .expireAfterWrite(60, TimeUnit.SECONDS).build();
  17. }
  18. @Override
  19. public void setCommonCache(String key, Object value) {
  20. commonCache.put(key, value);
  21. }
  22. @Override
  23. public Object getFromCommonCache(String key) {
  24. return commonCache.getIfPresent(key);
  25. }
  26. }
  • Controller 层引入本地缓存逻辑
  1. @RequestMapping(value = "/get", method = {RequestMethod.GET})
  2. @ResponseBody
  3. public CommonReturnType get(@RequestParam(name = "id") Integer id) {
  4. ItemModel itemModel = null;
  5. // 先从本地缓存中找
  6. itemModel = (ItemModel)cacheService.getFromCommonCache("item_" + id);
  7. if (itemModel == null) {
  8. // 再从 Redis 中找
  9. itemModel = (ItemModel)redisTemplate.opsForValue().get("item_" + id);
  10. if (itemModel == null) {
  11. // 最后从 MySQL 中找
  12. itemModel = itemService.getItemById(id);
  13. redisTemplate.opsForValue().set("item_" + id, itemModel);
  14. redisTemplate.expire("item_" + id, 10, TimeUnit.MINUTES);
  15. }
  16. cacheService.setCommonCache("item_" + id, itemModel);
  17. }
  18. ItemVO itemVO = this.convertFromItemModel(itemModel);
  19. return CommonReturnType.create(itemVO);
  20. }

引入本地缓存性能提升

  • 相对于 Redis 缓存,在本地缓存全部命中的情况下,TPS 从 2000 提升到 4000 +(2核8G);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值