Java电商系统商品详情页存储方案设计

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
对象存储 OSS,20GB 3个月
云数据库 Tair(兼容Redis),内存型 2GB
简介: Java电商系统商品详情页存储方案设计

先考虑好两个

1 核心问题

1.1 并发

不管什么电商系统,商品详情页一定是整个系统中日均访问次数最高的页面之一.不难理解,用户购物,看商品详情不一定买,一定会看好多商品详情页货比三家.如果在设计存储时,没有考虑到并发,on sale 时,支撑商详页的商品系统必然是第一个被流量冲垮的系统

1.2 数据规模

比如淘宝网,SKU(库存单元,可以直接理解为“商品”)的数量大约在几亿到几十亿。当然实际上并没有这么多种商品,原因很多,比如同一个商品它有不同版本型号,再比如,商家为了促销需要,可能会反复上下架同一个商品或者给同一个商品配不同的马甲,这都导致了SKU数量爆炸。

- 重量大

打开一个商详页看一下,从上拉到底,how long!海量图文甚至视频/AR/VR!

支持商品系统的存储,要保存这么多的“大胖子”,还要支撑高并发,任务艰巨。

商品服务需要

2 保存什么?

27.png

左边彩色部分都是商品服务需要存储的.

那么能否直接设计一张商品表,把这些数据都放进去?

要是一张表存不下,就再加几张子表?

小型电商还就这么干的,简单可靠易实现,但是,支持不了太大数据量和并发.

规模再大就不能这么干了。

不能用数据库,那应该选择哪种存储系统来保存这么复杂的商品数据呢?

任何一种存储都是没办法满足的,解决的思路是分而治之,可以把商品系统需要存储的数据按照特点,分成

  • 商品基本信息
  • 商品参数
  • 图片视频
  • 商品介绍

几个部分来分别存储。

2.1 商品基本信息怎么存?

它包括商品的主副标题、价格、颜色等一些商品最基本、主要的属性.

这些属性都是固定的,不太可能会因为需求或者不同的商品而变化,而且,这部分数据也不会太大。所以,建议在数据库中建一张表来保存商品的基本信息。


然后,还需要在数据库前面,加一个缓存,抵挡大部分的读请求.可以使用Redis/Memcached

使用前置缓存来缓存商品数据。

处理商品信息的读请求时,先去缓存查找,如果

  • 找到,直接返回缓存中的数据
  • 没找到,再查数据库,把从数据库中查到的商品信息返回给页面,重置缓存

2.1.1 Cache Aside

最简单实用的一种缓存更新策略,适用范围也最广泛。如果你要缓存数据,没有什么特殊的情况,首先就应该考虑使用这个策略.

更新商品信息时,在更新数据库的同时,也要把缓存中的数据给删除掉.

不然就可能出现数据库中的数据变了,而缓存中的数据没变,商详页上看到的还是旧数据.

2.1.2 保留商品数据的每一个历史版本

因为商品数据是随时变化的,但是订单中关联的商品数据,必须是下单那个时刻的商品数据,这一点很重要。你可以为每一个历史版本的商品数据保存一个快照,可以创建一个历史表保存到MySQL中,也可以保存到一些KV存储中。

2.2 MongoDB保存商品参数

商品参数,参数就是商品的特征。比如说,电脑的内存大小、手机的屏幕尺寸、酒的度数、口红的色号等等。和商品的基本属性一样,都是结构化的数据.

但麻烦的是,不同类型的商品,它的参数是完全不一样的。


如果我们设计一个商品参数表,那这个表的字段就会太多了,并且每增加一个品类的商品,这个表就要加字段,这个方案行不通。


既然一个表不能解决问题,那就每个类别分别建一张表

比如说


建一个电脑参数表,里面的字段有CPU型号、内存大小、显卡型号、硬盘大小等

建一个酒类参数表,里面的字段有酒精度数、香型、产地等

如果品类较少,100个内,用几十张表分别保存不同品类的商品参数,这样做也是可以的。

但是,有没有更好的方法呢?


大多数据库要求数据表要有一个固定的结构。

但有一种数据库,没有这个要求。特别适合保存像“商品参数”这种,属性不固定的数据-MongoDB。


MongoDB是一个面向文档存储的NoSQL数据库

MongoDB中表、行、列对应的概念分别是:collection、document、field

MongoDB最大的特点

“表结构”不需要事先定义,在MongoDB中根本没有表结构。

由于没有表结构,支持任意数据放在同一张表,甚至可以在一张表里保存商品数据、订单数据、物流信息等结构完全不同的数据。并且,还能支持按照数据的某个字段进行查询。

它是怎么做到的呢?

MongoDB中的每一行数据,在存储层就是简单地被转化成BSON格式,一种更紧凑的JSON。

所以,即使在同一张表,每一行数据的结构都可以是不一样。

这样的灵活性也是有代价的,MongoDB不支持SQL,多表联查和复杂事务比较孱弱,不太适合存储一般的数据。


但对于商品参数信息,数据量大、数据结构不统一,这些MongoDB都可以很好的满足。我们也不需要事务和多表联查,MongoDB简直就是为了保存商品参数的!

使用对象存储保存图片和视频

图片和视频由于占用存储空间比较大,一般的存储方式都是,在数据库中只保存图片视频的ID或者URL,实际的图片视频以文件的方式单独存储。

现在首选的方式就是保存在对象存储(Object Storage)中。可以简单理解为一个无限容量的大文件KV存储,它的存储单位是对象,其实就是文件,可以是一张图片,一个视频,也可以是其他任何文件。每个对象都有一个唯一的key,利用这个key就可以随时访问对应的对象。基本的功能就是写入、访问和删除对象。


云服务厂商的对象存储大多都提供了客户端API,可以在Web页面或者App中直接访问而不用通过后端服务来中转。这样,App和页面在上传图片视频的时候,直接保存到对象存储中,然后把对应key保存在商品系统中就可以了。


访问图片视频的时候,真正的图片和视频文件也不需要经过商品系统的后端服务,页面直接通过对象存储提供的URL来访问,又省事儿又节约带宽。而且,几乎所有的对象存储云服务都自带CDN(Content Delivery Network)加速服务,响应时间比直接请求业务的服务器更短。


国内的很多云厂商的对象存储对图片和视频,都做了非常多的针对性优化。最有用的是,缩放图片和视频转码,你只要把图片和视频丢到对象存储中,就可以随时获得任意尺寸大小的图片,视频也会自动转码成各种格式和码率的版本,适配各种App和场景。我只能说,谁用谁知道,真香!

商品介绍静态化

商品介绍在商详页中占得比重最大,包含大量的带格式文字、图片和视频.

其中图片和视频自然要存放在对象存储里面,商品介绍的文本,一般都是随着商详页一起静态化,保存在HTML文件中。


静态化是相对于动态页面来说的。一般我们部署到Tomcat中的Web系统,返回的都是动态页面,也就是在Web请求时,动态生成的。比如说商详页,一个Web请求过来,带着SKUID,Tomcat中的商详页模块,再去访问各种数据库、调用后端服务,动态把这个商详页拼出来,返回给浏览器。


不过,现在基本上没有系统会这么干了,你想,对于每个SKU的商详页,你每次动态生成的页面内容不是完全一样的么?生成这么多次,不仅浪费服务器资源,速度还慢,关键问题是,Tomcat能能抗的并发量和Nginx完全不是一个数量级的。


商详页的绝大部分内容都是商品介绍,它是不怎么变的。那不如就把这个页面事先生成好,保存成一个静态的HTML,访问商详页的时候,直接返回这个HTML。这就是静态化。


商详页静态化之后,不仅仅是可以节省服务器资源,还可以利用CDN加速,把商详页放到离用户最近的CDN服务器上,让商详页访问更快。


至于商品价格、促销信息等这些需要频繁变动的信息,不能静态化到页面中,可以在前端页面使用AJAX请求商品系统动态获取。这样就兼顾了静态化带来的优势,也能解决商品价格等信息需要实时更新的问题。

总结

商品系统的存储需要提供商品的基本信息、商品参数、图片和视频以及商品介绍等等这些数据。商品的基本信息和商品参数分别保存在MySQL和MongoDB中,用Redis作为前置缓存,图片和视频存放在对象存储中,商品介绍随着商详页一起静态化到商详静态页中。


这样一个商品系统的存储最终的效果是什么样的?


实线表示每访问一次商详页,需要真正传输的数据

虚线表示当商详页数据发生变化的时候才需要进行一次数据传输

用户打开一个SKU的商详页时,首先去CDN获取商详页的HTML,然后访问商品系统获取价格等频繁变化的信息,这些信息从Redis缓存中获取。图片和视频信息,也是从对象存储的CDN中获取。


分析一下效果,数据量最大的图片、视频和商品介绍都是从离用户最近的CDN服务商获取的,速度快,节约带宽。真正打到商品系统的请求,就是价格这些需要动态获取的商品信息,一般做一次Redis查询就可以了,基本不会有流量打到MySQL中。


这样一个商品系统的存储的架构,把大部分请求都转移到了又便宜速度又快的CDN服务器上,可以用很少量的服务器和带宽资源,抗住大量的并发请求。


目录
相关文章
|
3月前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
119 3
|
3月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
50 3
|
3月前
|
存储 Java
【编程基础知识】 分析学生成绩:用Java二维数组存储与输出
本文介绍如何使用Java二维数组存储和处理多个学生的各科成绩,包括成绩的输入、存储及格式化输出,适合初学者实践Java基础知识。
99 1
|
14天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
97 2
|
28天前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
60 10
|
27天前
|
存储 Java
Java 11 的String是如何优化存储的?
本文介绍了Java中字符串存储优化的原理和实现。通过判断字符串是否全为拉丁字符,使用`byte`代替`char`存储,以节省空间。具体实现涉及`compress`和`toBytes`方法,前者用于尝试压缩字符串,后者则按常规方式存储。代码示例展示了如何根据配置决定使用哪种存储方式。
|
2月前
|
数据采集 存储 Web App开发
Java爬虫:深入解析商品详情的利器
在数字化时代,信息处理能力成为企业竞争的关键。本文探讨如何利用Java编写高效、准确的商品详情爬虫,涵盖爬虫技术概述、Java爬虫优势、开发步骤、法律法规遵守及数据处理分析等内容,助力电商领域市场趋势把握与决策支持。
|
2月前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
142 2
|
4月前
|
存储 Java
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
4月前
|
SQL JSON JavaScript
JavaWeb基础9——VUE,Element&整合Javaweb的商品管理系统
Vue 指令、生命周期、this和$、vue脚手架进行模块化开发/ElementUI框架、综合案例,element商品列表展示增删改查
JavaWeb基础9——VUE,Element&整合Javaweb的商品管理系统