电商缓存之如何更新20万个商品缓存

文章目录

  • 1 问题背景
  • 2 前言
  • 3 详细背景
  • 4 解决方案
    • 4.1 方案1
    • 4.2 方案2
    • 4.3 方案3

1 问题背景

需要在商品缓存中新增2个字段,redis中已存在20万个商品缓存,如何更新这20万个商品缓存

2 前言

本博客是笔者在真实的生产环境遇到的问题,非自学的demo或者单纯地研究理论。本博客仅供笔者自己总结参考,如有不正确的地方请指出。

3 详细背景

假如在redis中有如下结构的商品缓存:

{
	id: 1,
	title: "Iphone",
	skus: [
        {
            id: 1001,
            price: 6999.00,
            sale_price: 5999.00
        }
	]
}

解释:此缓存结构表示一个spu,它有1个sku。

现在要在sku层级新增两个字段:weight重量、weight_unit重量单位,结构如下所示:

{
	id: 1,
	title: "Iphone",
	skus: [
        {
            id: 1001,
            price: 6999.00,
            sale_price: 5999.00
            weight: 1.20,
            weight_unit: "kg"
        }
	]
}

往商品的缓存中加了字段,如果仍使用旧的缓存结构,那么查缓存时查出来新增的两个字段将会是null,会存在一定的问题(业务方面的问题,在此不做详细阐述),因此我们要在查询的时候,要获取最新的缓存结构,即要去db查并将值更新到缓存,就是要做缓存的更新。

生产环境上,不能直接粗暴地全部直接删掉。如果直接通过redis桌面管理软件进行删除操作,会删不干净,同时也会造成Redis阻塞。如果写代码去扫描数据库组装商品缓存的key,这样效率太低,而且也不可能组装全量商品缓存的key(因为这是要扫描整个商品库)。20万的商品缓存怎么更新呢?

4 解决方案

4.1 方案1

核心思想:设计一个字段标识查出来的商品缓存是否是最新的结构,此处假设用字段version标识商品缓存的版本,假设最新的版本为1,即version的值为1。

  1. 查商品缓存
  2. 判断商品缓存中的version字段是否为1,若是为空或者不为1,则表示此缓存不是最新的,需要去db查最新值并写回到缓存中。如下面代码所示:
{
    version: 1,
	id: 1,
	title: "Iphone",
	skus: [
        {
            id: 1001,
            price: 6999.00,
            sale_price: 5999.00
            weight: 1.20,
            weight_unit: "kg"
        }
	]
}
  1. 考虑到如果要动态控制version的值,可以将version的值放到配置中心中(比如nacos配置中心、apollo),那么无需改代码发版即可热更新version的值。

缺点: 需要加入逻辑代码判断缓存中是否有version字段或者判断其值是否为1。如何解决这样的问题?请看下面的方案2

4.2 方案2

核心思想: 在缓存的key中加上版本号version的值,形成新的redis key。获取缓存的时候直接使用带版本号version的key。

  • 查询商品缓存的key加上version值,例子:redis的key为product_info:{shopId}:{version},其中{shopId}表示店铺ID的值,{version}表示商品缓存版本的值

  • 可以考虑将version值放到配置中心,让系统可以热更新version的值

缺点: 需要占用大量的服务器内存,思想是用空间换性能。如何解决这种问题,请看上面的方案1

4.3 方案3

方案3是对方案1或方案2的补全。

  • 基于方案1或者方案2,可以考虑做一个缓存预热。针对近半个月或者近一个星期(这个量取决于有多少商品缓存,笔者接触的生产环境有20w,查了下单的商品,查近半个月有1万个下单的商品,查近一个星期只有1千个下单的商品,所以采用近半个月)的下单商品进行商品缓存预热。
  • 商品缓存的过期时间可以采用随机散列,比如1-7天,防止雪崩

你可能感兴趣的:(解决方案,Java面试题笔记,缓存,redis,数据库)