redis分布式缓存(二十七)一一淘宝聚划算商品列表解决方

一、需求分析

image.png

image.png

淘宝聚划算

这张页面的特点:

  1. 数据量少,聚划算就一页,滚动分页,共展示了65*2=130个商品。
  2. 高并发,请求量大,聚划算在淘宝首页有入口,由于商品价格有优惠,请求量巨大。

二、高并发的技术方案

  • 对于高并发请求,我们不能直接请求数据库,而是采用缓存,所以用到了redis。
  • 一般的做法是先把数据库中的数据抽取到redis里面。采用定时器,来定时缓存
  • 这张页面的特点,数据量不多。最大的特点就要支持分页
  • redis的 list数据结构天然支持这种高并发分页查询功能。
  • 具体的技术方案采用list的lpush 和 lrange来实现。
## 先用定时器把数据刷新到list中
127.0.0.1:6379> lpush jhs p1 p2 p3 p4 p5 p6 p7 p8 p9 p10
(integer) 10
## 用lrange来实现分页
127.0.0.1:6379> lrange jhs 0 4
1) "p10"
2) "p9"
3) "p8"
4) "p7"
5) "p6"
127.0.0.1:6379> lrange jhs 5 10
1) "p5"
2) "p4"
3) "p3"
4) "p2"
5) "p1"
复制代码

三、案例实战

定时器刷特价商品信息到redis

@Service
@Slf4j
public class TaskService {

    @Autowired
    private RedisTemplate redisTemplate;

    @PostConstruct
    public void initJHS(){
        log.info("启动定时器..........");
        new Thread(()->runJhs()).start();
    }

    /**
     * 模拟定时器,定时把数据库的特价商品,刷新到redis中
     */
    public void runJhs() {
        while (true){
            //模拟从数据库读取100件特价商品,用于加载到聚划算的页面中
            List<Product> list=this.products();
            //采用redis list数据结构的lpush来实现存储
            this.redisTemplate.delete(Constants.JHS_KEY);
            //lpush命令
            this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY,list);
            try {
                //间隔一分钟 执行一遍
                Thread.sleep(1000*60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("runJhs定时刷新..............");
        }
    }


    /**
     * 模拟从数据库读取100件特价商品,用于加载到聚划算的页面中
     */
    public List<Product> products() {
        List<Product> list=new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Random rand = new Random();
            int id= rand.nextInt(10000);
            Product obj=new Product((long) id,"product"+i,i,"detail");
            list.add(obj);
        }
        return list;
    }
}
复制代码

商品分页查询

    /**
     * 分页查询:在高并发的情况下,只能走redis查询,走db肯定扛不住
     */
    @GetMapping(value = "/find")
    public List<Product> find(int page, int size) {
        List<Product> list=null;
        long start = (page - 1) * size;
        long end = start + size - 1;
        try {
            //采用redis list数据结构的lrange命令实现分页查询
            list = this.redisTemplate.opsForList().range(Constants.JHS_KEY, start, end);
            if (CollectionUtils.isEmpty(list)) {
                //TODO 走DB查询
            }
            log.info("查询结果:{}", list);
        } catch (Exception ex) {
            //这里的异常,一般是redis瘫痪 ,或 redis网络timeout
            log.error("exception:", ex);
            //TODO 走DB查询
        }
        return list;
    }

复制代码

思考

聚划算页面高并发的请求,在更新商品信息时,如何解决缓存击穿问题??

下一章节再探究这一问题。

redis分布式缓存系列文章

上一章节:redis分布式缓存(二十六)一一 常用命令(list)