秒杀多级缓存-----商品详情页

商品模块的技术难点 以及订单秒杀业务的技术难点

我们商品的流程是
商家入住--->商品资料-->图片处理--->发布--->定时维护 {库存}-->用户购买下单 
一般有2个入口 
管理端负责对商品的
	上架 发布 下架 以及定时维护 比如说增加库存 降低库存
我用户对商品的操作
	浏览,下单购买 
商品有那些技术难点	第一个问题是表的设计,针对商品的这个场景我此时表是设计1个表还是多个表进行存储
比如说 我京东关于Iphone12这张商品详情页 ,有分类 有品牌 有规格属性 这些我该怎么去设计我的表呢

在这里插入图片描述

在这里插入图片描述

我们用一个表的进行存储的时候似乎不好存储 Iphone有内存大小,衣服没有内存大小  但是一张表的时候查询的时候是很方便的

我们可以用多张表
一个商品页面查询很多表 关联查询的时候效率肯定慢, 像阿里高并发场景 每一个详情页都要访问db,而且关联好几张表的查询  肯定就G

在这里插入图片描述

step1  我们筛选的时候 比如说 苹果12 属于苹手机  可以加个分类

在这里插入图片描述

step2  基于用户的角度,比如说 我想选择小米 的手机 , 我们可以加个品牌 ,让结果更加准确一点

在这里插入图片描述
在这里插入图片描述

这样用户就可以根据分类或者品牌进行搜索了,搜索的结果更加接近用户的目标

在这里插入图片描述

这样的话我们可以根据品牌分类 选择出 spu,在某一个spu 下面选择一个具体的sku
但是优秀的设计师,设计这样的产品

在这里插入图片描述

用户可以通过筛选条件进一步筛选得到自己想要的产品

在这里插入图片描述

所以我们表的设计就可以这样设计了

在这里插入图片描述

我们的表可以这样设计

在这里插入图片描述
在这里插入图片描述

通过这4个条件用户可以更加容易的选择出来用户想要的产品
然后我们的代码 就可以通过 商品Id 可以多表查询处该商品详情页了,但是目前,如果是高并发场景,多表查询走db 肯定是不可能的,而且 我此时商品详情页 不需要登录,谁都可以访问,商品详情页还要面对各种爬虫[我的知道其他平台的商品价格 而更改我的价格 所以我要实时监控竞争对手的价格]  此时就得做一些抓包 监控, 所以说商品详情页此时流量是很大得,我们该如何做优化? 达到我们的Qps

在这里插入图片描述
在这里插入图片描述

通过jmeter 测试 测试 通过id--->应用服务器--->mysql的吞吐量大约就是800左右
目前为止我们扛并发只有几百的吞吐量 而且我们的业务比较简单,如果是京东这样的电商网站 就不可以了

我们可以使用静态化页面 ,比如html.css.我们都认为他是一个静态化的数据
我们可以吧一些经常访问到的页面放在cdn上 这样前端可以直接从cdn上读取页面,这样就不用我们去查询接口了


第一我们可以使用模板技术 比如说thymealf.使用一个固定模板

在这里插入图片描述

	.... 我们添加静化 只需要吧吧这个商品id 根据模板做成商品详情页  ,之后再吧详情页面放到cdn上
    public String toStatic(Long id) {
        //查询商品信息
        PmsProduct pmsProduct = productMapper.selectByPrimaryKey(id);
        if (pmsProduct == null) {
            return null;
        }
        String outPath = "";
        try {
            String userHome = System.getProperty("user.home");
            // 第一步:创建一个Configuration对象,直接new一个对象。构造方法的参数就是freemarker对于的版本号。
            Configuration configuration = new Configuration(Configuration.getVersion());

            // 第二步:设置模板文件所在的路径。
            configuration.setDirectoryForTemplateLoading(new File(userHome + "/template/ftl"));

            // 第三步:设置模板文件使用的字符集。一般就是utf-8.
            configuration.setDefaultEncoding("utf-8");

            // 第四步:加载一个模板,创建一个模板对象。
            Template template = null;

            template = configuration.getTemplate("report.ftl");
            // 第五步:创建一个模板使用的数据集,可以是pojo也可以是map。一般是Map。
            Map dataModel = new HashMap();
            // 向数据集中添加数据
            dataModel.put("item", pmsProduct);

            String images = pmsProduct.getPic();
            if (StringUtils.isNotEmpty(images)) {
                String[] split = images.split(",");
                List<String> imageList = Arrays.asList(split);
                dataModel.put("imageList", imageList);
            }

            // 第六步:创建一个Writer对象,一般创建一FileWriter对象,指定生成的文件名。
            outPath = userHome + "/template/report/1000" + pmsProduct.getId() + ".html";
            Writer out = new FileWriter(new File(outPath));
            // 第七步:调用模板对象的process方法输出文件。
            template.process(dataModel, out);
            // 第八步:关闭流。
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException te) {
            te.printStackTrace();
        }
        return outPath;
    }
我定义一个模板,根据模板 生成静态化文件 
2. 吧生成好的文件放到cdn上 减轻你后台服务的压力、
同样吧对应的css,js 也放在cdn进行加速
或者放在对应nginx上   这样就能提高我们系统的吞吐量以及并发
但是静态化页面只是在小型电商网站使用 (商品数量不多的情况)
我们点击静化的时候 此时是新增 ,新增意味着就有修改
1个商品需要静态化  1000个商品就需要1000个静态化页面
假如我要改模板的化 ,就得更改已经生成好的静态页
//如果此时商品像京东这样数量比较多的化 此时做到更改已经生成好的静态页就比较麻烦了
比如说此时吧自营改成京东自营

在这里插入图片描述


我们可以通过模板引擎加大 网站吞吐量 问题就是在商品多的时候 模板需要修改 的时候 他有些致命的问题
所以  此时的静态化页面只能说是针对于商品比较少的电商网站, 但是商品比较多的 比如说京东就不太适合了,更改比较麻烦

我们此时可以用redis(换数据库)
我们此时的流程是 浏览器访问我们的服务器,服务器访问我们的db,这中间就会涉及到网络Io和磁盘Io,mysql是个磁盘IO,redis基于内存操作的, 内存的肯定大于硬盘  提高了性能


在这里插入图片描述

商品详情页属于一个读多写少的场景,小儿在后台吧商品维护后基本上就不会去修改了  但是商品访问的概率是很大  我们就可以把数据放在缓存
我们使用redis 可以这样做
但是使用redis 进行缓存就会涉及一个问题 数据可能不一致 redis中数据可能不能和mysql 进行数据的同步一致
此时问题又来了
数据不一致 怎么解决数据的一致性,是全量还是增量,怎么去解决
1. 最终一致性 // redis.set(id,productInfo,5分钟);// 最终一致性 我们可以在redis中间加一个缓存时间,

2. 实时  以后再说


  public Map getProductInfo1(Long id) {
        Map productInfo = redis.get(id);
        if (ObjectUtils.isEmpty(productInfo)) {
            productInfo =portalProductDao.getProductInfo(id);
            redis.set(id,productInfo);
        }
        return productInfo;
    }

我们可以使用redis 的超时机制来解决数据行的一致性,
此时我们还是有问题的,第一个就是并发的问题 第二个就是我们需要对数据进行压缩处理
虽然此时使用了redis,但是redis 的本质是内存型db,替换mysql 的 磁盘操作,此时依然有网络IO的存在

我们的浏览器-------->服务器------->redis [传输数据量大的化就会慢]
他此时的商品详情页的数据基于一个商品Id查询的结果有商品数据 营销数据,满减数据 肯定有大几十兆,如果浏览量大的化,网络IO 数据量就会变大 ,可能带宽就不够了,就会查询效率慢 所以我们可以使用压缩手段将数据进行压缩

通过数据的压缩 可以达到在一定带宽内加大应用的吞吐量

在这里插入图片描述

剩下的问题就是 并发  因为此时业务简单  没有什么大的逻辑,如果多线程同时执行这些代码 可能会查多次数据库,我们理论上只想让查询一次数据库,然后其余的线程就可以从缓存中获取了,所以我们需要加锁 来让查询数据库的这段操作同时只有一个线程访问,单节点的化 我们可以加 synchronized 或者
Lock lock=new ReentrantLock(); 来进行操作  如果多节点的化我们可以使用redis 或者zk分布式锁来解决

在这里插入图片描述

我们商品详情页使用了页面模板静态化,也是用了redis, 我们采用redis架构方案可以解决我们磁盘的问题,减少了磁盘上面的Io,但是网络IO依然存在)
我们可以使用本地缓存来解决网络io的问题,最简单的ConcurrentHashMap,但是 随着内存越来越大我们对缓存有个删除策略比如说lru	,

ConcurrentHashMap可以实现对我们本地缓存的需求 但是他无法对我们的数据进行清除
(初始值,最大值  以及多长时间进行清除策略 )

在这里插入图片描述
在这里插入图片描述

我们可以使用gava的cache框架 来做本地缓存的存储
我还可以使用布隆过滤器 提前将 商品的id进行存储在布隆过滤器中 这样,当访问的时候
如果布隆过滤器中没有 就代表是非法数据

通过后置处理器吧数据全部加载到布隆过滤器中  布隆过滤器中只存储key (数据量会小一点)
然后可以写一个拦截器 进行拦截,判断布隆过滤器中有没有 如果没有的话就就代表是非法数据

此时也可以减少我们对db的依赖

在这里插入图片描述


我们讲一个页面静态化 页面静态化 如果我们模板修改了 我们的所有商品都需要修改
这种方案并不是流量小,而是他的商品数量少
小米的数量少  京东就不行
京东的平台 不适合,因为商品非常多,一旦我们修改模板所有的商品都需要修改

我们可以使用 nginx OpenResty 基于nginx和Lua的web平台,针对请求进行拦截,我们最终的流程图可能就是这样
 

在这里插入图片描述

我们的三层缓存策略 每一层的分工不一样
1. nginx+lua {将数据 json 进行存储}// 存储数据量小,只会存储最热的数据 所有的商品都是非常热的 比如说618 最火爆的热单数据
2. 本地缓存gava //存储比如说首页
3. redis
/lua中可以采用lru算法。也就是说永远存储用户的最新数据{}
https://www.cnblogs.com/jiyukai/p/14809447.html  可以看看这个
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值