后端存储实战课总结(上)

news/2024/7/8 8:34:01

创建和更新订单

表设计

最少应该有以下几张表:

  1. 订单主表:保存订单基本信息
  2. 订单商品表:保存订单中的商品信息
  3. 订单支付表:保存订单支付和退款信息
  4. 订单优惠表:保存订单的优惠信息

订单主表和字表是一对多关系,关联的外键是订单主表的主键(订单号)。

幂等性

可能出现重复下单的场景:一种是就是用户多点了,另外就是网络错误导致(RPC、网关的重试机制)

解决方案:通过一个专门生成全局唯一订单号的服务,插入数据的时候将其保存

ABA 问题

更新订单相关信息的时候可能出现。

解决方案:在表中加个时间戳或者版本的字段,每次查询的时候将其返回,更新的时候要比较下当前订单数据的版本号,是否和预期的一致。不一致直接拒绝更新,一致的话在一个事务中更新数据的同时将版本号+1。

商品详情页

问题

一是高并发,商品的详情页每天都会有很高的 DAU(日均访问次数)。

二是商品数据规模的问题,比如下图中要存储的:后端存储实战课

方案

基本信息相对来说比较固定,可以在数据库中建表存储,也要提供缓存(比如 Redis、Memcached)帮助系统抗一些读请求。另外要注意的是,要保留商品的历史版本,因为订单中关联的商品数据必须是下单哪个时刻的商品数据,可以用一张历史表来保存。

商品参数指商品特征,比如内存大小、屏幕尺寸、口红色号等,和基本属性一样,是结构化的数据,但是不同类型的商品参数也是不一样的。对于属性不固定的数据来说,可以使用 MongoDB 来存储,因为 MongoDB 没有数据表要有固定结构的要求。

MongoDB 中的每一行数据,在存储层就是简单地被转化成 BSON 格式后存起来,这个 BSON 就是一种更紧凑的 JSON。所以,即使在同一张表里面,它每一行数据的结构都可以是不一样的。当然,这样的灵活性也是有代价的,MongoDB 不支持 SQL,多表联查和复杂事务比较孱弱,不太适合存储一般的数据。

图片和视频由于占用空间比较大,一般的存储方式是在数据库中只保留图片视频的 id 或者 url,实际的图片视频以文件方式存储,可以保存在对象存储(Object Storage)中。

对象存储可以简单理解为无限容量的大文件 KV 存储,key 是唯一的,对象是 value,可以通过 key 操作 value(写入、访问、删除)。对象存储提供了客户端 API,可以在 Web 页面或者 app 中直接访问,而不用通过后端服务。页面通过提供的 URL 直接访问,省事不占带宽,同时,对象存储云服务也提供了自带 CDN(Content Delivery Network)服务,响应时间比直接请求业务服务器更短。云服务厂商还会提供针对性优化,比如说缩放和转码服务。

商品介绍在商详页中占得比重是最大的,包含了大量的带格式文字、图片和视频。其中图片和视频自然要存放在对象存储里面,商品介绍的文本,一般都是随着商详页一起静态化,保存在 HTML 文件中。

静态化是相对于动态页面来说的。一般我们部署到 Tomcat 中的 Web 系统,返回的都是动态页面,也就是在 Web 请求时,动态生成的。比如说商详页,一个 Web 请求过来,带着 SKUID,Tomcat 中的商详页模块,再去访问各种数据库、调用后端服务,动态把这个商详页拼出来,返回给浏览器。
商详页的绝大部分内容都是商品介绍,它是不怎么变的。那不如就把这个页面事先生成好,保存成一个静态的 HTML,访问商详页的时候,直接返回这个 HTML。这就是静态化。
商详页静态化之后,不仅仅是可以节省服务器资源,还可以利用 CDN 加速,把商详页放到离用户最近的 CDN 服务器上,让商详页访问更快。
至于商品价格、促销信息等这些需要频繁变动的信息,不能静态化到页面中,可以在前端页面使用 AJAX 请求商品系统动态获取。这样就兼顾了静态化带来的优势,也能解决商品价格等信息需要实时更新的问题。

购物车

场景

  1. 未登录,浏览器加购,关闭浏览器再打开,加购商品应该存在
  2. 未登录,浏览器加购,然后登录,加购的物品存在
  3. 登录后再注销,关闭浏览器,步骤 2 中加购的商品不登录看不到(未登录特定账号看到的购物车是空的)
  4. 手机登录,步骤 2 中的加购的存在

原则

用户未登录,需要临时暂存购物车中的商品;

用户登录,将暂存购物车的商品加入到用户购物车,清空暂存购物车;

用户登录后,各端同步用户购物车。

设计

暂存购物车

如果存在服务端,需要唯一标识存储,浪费服务端资源,故需要存储在客户端。

存在客户端的途径:SESSION 不合适(时间短,SESSION 数据其实还是在服务端);Cookie 存储的话,实现简单,通过服务端读写 Cookie 实现具体的加减购物车合并购物车逻辑;LocalStorage 存储的话,实现复杂(客户端和服务端都需要实现逻辑),但是容量大,不用每次请求都携带,节省带宽。

用户购物车

还是推荐 MySQL,如果用 Redis 存在丢数据的情况,查询方式和事务都不如 MySQL。

引入 Redis 需考虑问题:

  1. 不同用户不同购物车,缓存命中率不高,为了维护缓存,还提高了系统复杂度,有没有必要
  2. Redis 的缓存更新策略

账户系统

目的

对账系统存在的目的:来核对、矫正账户系统和其他系统之间的数据差异。

每个账户系统都不是孤立存在的,至少要和财务、订单、交易这些系统有着密切的关联。理想情况下,账户系统内的数据应该是自洽的。所有用户的账户余额加起来,应该等于这个电商公司在银行专用账户的总余额。账户系统的数据也应该和其他系统的数据能对的上。比如说,每个用户的余额应该能和交易系统中充值记录,以及订单系统中的订单对的上。

记录流水,可以修改由于系统 bug 或者认为篡改导致的账户余额的问题。流水的数据模型至少要包含:流水 ID、交易金额、交易时间戳、交易双方的系统、账户、交易单号等信息。

原则

  1. 流水记录只能新增,一旦记录成功不允许修改和删除。即使是由于正当原因需要取消一笔已经完成的交易,也不应该去删除交易流水。正确的做法是再记录一笔“取消交易”的流水。
  2. 流水号必须是递增的,我们需要用流水号来确定交易的先后顺序。

在对账的时候,一旦出现了流水和余额不一致,并且无法通过业务手段来确定到底是哪儿记错了的情况,一般的处理原则是以交易流水为准来修正余额数据,这样才能保证后续的交易能“对上账”。

方案

首先要保证只有记录流水的时候更新余额,不可以将更新余额单独提供;其次使用数据库事务,记录流水和修改余额两个操作要么都成功,要么都失败。

MySQL 事务和 ACID 相关内容不在此赘述

分布式事务

背景

分布式环境下跨系统数据一致性问题。

方案

2PC、3PC、TCC、Saga、本地消息表都是分布式事务的解决方案


http://lihuaxi.xjx100.cn/news/204857.html

相关文章

Node.js 入门教程 51 Node.js Buffer

Node.js 入门教程 Node.js官方入门教程 Node.js中文网 本文仅用于学习记录,不存在任何商业用途,如侵删 文章目录Node.js 入门教程51 Node.js Buffer51.1 什么是 buffer?51.2 为什么需要 buffer?51.3 如何创建buffer51.4 使用 buff…

RabbitMQ系列【16】AmqpTemplate接口详解

有道无术,术尚可求,有术无道,止于术。 文章目录前言AmqpTemplateAPIsendconvertAndSendreceivereceiveAndConvertreceiveAndReplysendAndReceiveconvertSendAndReceive前言 RabbitTemplate 是spring-amqp提供的一个 RabbitMQ 消息操作模板类…

时间序列:时间序列模型---自回归过程(AutoRegressive Process)

本文是Quantitative Methods and Analysis: Pairs Trading此书的读书笔记。 这次我们构造一个由无限的白噪声实现(white noise realization) 组成的时间序列,即。这个由无限数目的项组成的值却是一个有限的值,比如时刻的值为, 而…

Codeforces Round #290 (Div. 2) C. Fox And Names

翻译: Fox Ciel将发表一篇关于FOCS (Fox操作的计算机系统,发音:“Fox”)的论文。她听到一个谣言:报纸上的作者名单总是按照词典顺序排列的。 在查看了一些例子后,她发现有时这不是真的。在一些论文中,作者的名字没有按照正常意义…

Spring(Spring的理解+DI+Spring的创建)

目录 1. Spring 是什么 2. DI 3. 面试题: IoC 和 DI 有什么区别? 4. Spring 的创建 5. 将 Bean (对象) 存储到 Spring (容器) 中 6. 将 Bean (对象) 从 Spring (容器) 中取出来 7. 面试题: ApplicationContext 和 BeanFactory的区别 8. getBean 更多用法 1. Spring 是…

Spring Boot+Mybatis:实现数据库登录注册与两种properties配置参数读取

〇、参考资料 1、hutool介绍 https://blog.csdn.net/abst122/article/details/124091375 2、Spring BootMybatis实现登录注册 https://www.cnblogs.com/wiki918/p/16221758.html 3、Spring Boot读取自定义配置文件 https://www.yisu.com/zixun/366877.html 4、Spring Boot读取p…

PyQt5可视化编程-控件

控件就像是应用这座房子的一块块砖。PyQt5有很多的控件,比如按钮,单选框,滑动条,复选框等等。我们将介绍一些很有用的控件: QCheckBox,ToggleButton,QSlider,QProgressBar, QCalendarWidget,QPixmap,QLineEdit,QSplitt…

javascript中数组和对象的解构

对象的解构 解构出来的属性,可以重命名 重命名这个主意了是用的冒号,有的时候typescript用多了以为是a as b这样,可就大错特错了等号左侧 source: target,target是新的重命名后的值 const { a: newA } { a: 111} console.log(ne…