商城项目要点整理
2023-02-15 10:09:40 0 举报
AI智能生成
畅购商城B2C模式要点整理
作者其他创作
大纲/内容
电商技术特点
技术新
技术范围广
分布式
高并发、集群、负载均衡、高可用
海量数据
业务复杂
系统安全
主要电商模式
B2B
交易双方都是商家
比如:阿里巴巴、慧聪网
C2C
交易双方都是个人
比如:咸鱼、瓜子二手车
B2C
商家对客户
比如:唯品会、乐蜂网
C2B
客户对商家
比如:海尔商城、尚品宅配
O2O
线上对线下
比如:美团、饿了么
F2C
工厂对客户
厂商到消费者
B2B2C
<div>供应商对企业对客户</div>
比如:京东、天猫
项目介绍
项目描述
技术描述
微服务架构
SpringCloud 全家桶
Gateway
过滤
路由
限流
令牌桶限流
Hystrix
微服务保护
默认<b><font color="#ff0000">线程池</font></b>隔离
通过feign远程调用时为了避免令牌无法传递过去
需要将隔离策略换成<b><font color="#ff0000">信号量</font></b>隔离
Feign
远程调用
Nacos
注册中心与配置中心
SpringSecurity OAuth2.0<br>
JWT token增强
授权微服务
Seata
分布式事务
ElasticSearch
海量数据实时搜索
Mysql<br>
数据存储
Canal
Mysql数据同步
Redis
数据缓存
OpenResty
处理最外层的大量并发<br>
结合Redis做多级缓存
LVS+Keepalive+Nginx
解决单点故障问题
七层负载均衡
RabbitMQ
异步
削峰
解耦
MinIO
对象存储
Freemarker
模板引擎
商品静态页生成
XXL-Job
分布式任务调度
Jenkins
持续集成
服务拆分
业务微服务
商品微服务<br>
广告微服务<br>
订单微服务<br>
权限微服务<br>
用户微服务<br>
秒杀微服务<br>
管理员后台微服务<br>
公共组件微服务<br>
Seata分布式微服务<br>
OAuth2.0授权微服务
RabbitMQ微服务<br>
Canal微服务
支付微服务
技术架构
涉及技术
系统架构
系统架构图
核心业务
购物车<br>
未登录也可以使用购物车<br>
未登录前,存储在cookie(或者localStage里面)里面,登录后存储在redis里面
必须登录才能使用购物车
存储在redis里面,使用hash类型
订单<br>
流程描述
选择收货地址,选择支付方式后,才能提交订单。
提交订单后会创建订单,并从购物车中删除商品(如果是从购物车中进行结算的话)
创建订单后会生成两张表,一张订单表,一张订单明细表<br>
在这个阶段要注意可能会产生<b><font color="#ff0000">超卖</font></b>问题<br>
问题描述
每次下单前,都要有个<b><font color="#ff0000">价格校验</font></b>,不能使用购物车里面的价格,要使用当前商品的价格和购物车价格进行比较
如果一致就可以进行下单,如果不一致,需要修改价格才行
这个逻辑必须得有,因为我们购物车的数据不会一直去请求服务端,<br>在购物车没发生变化的情况下,会缓存在本地<br>
因此缓存的商品价格可能是很久以前的价格了
支付
流程图
流程描述
用户请求经过网关转发到订单微服务(<b><font color="#ff0000">下单操作</font></b>)
订单微服务创建订单,订单会存储在数据库中;<br>并将一条消息(订单id等即可)发送到延迟队列中(延迟30分钟)<br>
同时订单微服务会监听延迟队列,30分钟后会消费到这条消息,<br>我们和查询数据库进行比较,如果这单还未完成支付,<br>那么订单微服务就会执行这条消息,回滚这条订单响应的所有操作<br>
但是回滚前,一定要先把这个订单关闭掉(也可以理解成关闭掉支付)。<br>关闭掉后就无法进行支付了,避免再回滚操作的同时,有人进行了支付操作<br>
访问支付微服务(需要携带订单编号)
支付微服务访问微信服务(通过http请求的方式去请求微信系统)
微信服务会根据订单账号生成一个<b><font color="#ff0000">预付费记录</font></b>
<b><font color="#ff0000">预付费记录</font></b>会把一个预付款的地址给到我们的系统(即预付费记录中包含有预付款的地址)
拿到<b><font color="#ff0000">预付款的地址</font></b>后,以这个地址为内容,去创建<b><font color="#ff0000">生成二维码</font></b>
用户就可以扫码进行支付
扫码支付
扫码后与微信服务器进行一个授权认证
微信服务会检查这个链接是否有效
有效的话,会弹出一个授权的界面
授权成功后就会调微信的服务开始进行交易
如果用户名密码正确就能完成交易
交易成功后,会通知给用户
同时,会调用我们的一个notifyUrl<br>(一般是<b><font color="#ff0000">支付微服务</font></b>的一个地址,我们进行预付费请求的时候会携带该地址)<br>
支付系统收到通知后,会发送消息给mq
订单系统监听mq,消费消息,更新订单的状态<br>(支付成功,或者支付失败)<br>
秒杀
流程图
流程描述
秒杀的商品录入到数据库中(mysql)
mysql定时同步到redis中
用户的请求打到OpenResty,<br>通过OpenResty去请求秒杀的<b><font color="#ff0000">频道</font></b>和<b><font color="#ff0000">商品详情页</font></b><br>
去redis中请求<b><font color="#ff0000">秒杀列表页</font></b>的数据
如果用户点击了某个具体的商品,那么商品详情页的数据页也是从redis中读取
用户进行了下单<br>
需要检验是否有库存,通过OpenResty检验库存,<br>库存数据在redis中(通过OpenResty将大量无效的请求过滤掉,<br>即这部分不合法的请求压根就不会进入到我们的微服务系统中去)<br>
如果库存充足,则验证用户有没有登录
未登录,进行OAuth2.0授权登录
进入秒杀微服务<br>
<b><font color="#ff0000">不采用传统的抢单模式</font></b>,传统抢单模式,需要进行一系列的校验,<br>校验通过后<b><font color="#ff0000">才有资格进行抢单</font></b>,但是这一些校验<b><font color="#ff0000">非常耗时</font></b>,<br>因此在大量请求下很容易出问题(所有请求都会阻塞在这里,服务会被搞挂掉)。<br>一系列的校验包括:<br>
账号是否异常
24小时内是否购买过该商品
是否存在未支付的秒杀商品
<span style="font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px; orphans: 4; white-space: pre-wrap;"><font color="#ffffff">该秒杀商品是否还有库存</font></span><br>
该秒杀商品抢购人数是否达到上线<br>
使用队列模式,将抢单信息(包含订单信息、商品信息、用户信息)存储到redis的队列中<br>(需要有用户排队信息队列用来标识用户是否重复排队,需要有用户排队状态队列,用于检测用户的排队状态 ),<br>避免服务器一口气处理所有请求,达到削峰减流的一个效果,避免服务器被搞挂<br>
进入redis队列后,提示用户进入了排队当中
同时后台利用多线程进行一个下单操作(多线程抢单)
多线程下单也要检查传统抢单模式中信息,只有校验通过后才有资格抢单
同时利用redis中的原子操作去实现库存的递减
下单成功后会同步更新用户排队的状态
用户就抢单成功进入<b><font color="#ff0000">支付环节</font></b>了,<b><font color="#ff0000">用户支付成功后,将redis中的订单信息删除掉</font></b>
同时会插入一条延时消息到延迟队列中(包含订单信息、商品信息、用户信息)
当延迟时间到了后,取出来查看下redis中是否有这个订单,<br>如果有(如果支付完成了,redis中的订单数据就被移除了),<br>表示还未完成支付,那么进行取消订单的操作(<b><font color="#ff0000">关闭支付、清理订单、回滚库存</font></b>)<br>
常见问题
如果用户支付成功了,但是微信服务没有把支付状态同步过来(比如网络原因),<br>在你的系统没有收到支付状态的情况下,你们系统怎么办?是怎么处理的?<br>
腾讯的微信支付提供了一个<b><font color="#ff0000">支付状态查询接口</font></b>,如果支付系统没有收到支付状态的回调,<br>我们可以在订单系统中主动调用支付状态查询接口,主动去进行查询(只需要根据本地订单号去查询即可)。<br>
或者可以在用户查看订单的时候进行判断,如果订单的状态是支付中并且超时很久了的话,就可以调用下<b><font color="#ff0000">支付状态查询接口</font></b>
如何解决秒杀中重复排队问题?
利用redis的特性,给每个排队的用户整一个排队标识,默认值为1。<br>
如果值大于1,即表示重复排队了。(给一个key做+1的操作,key不存在,则生成key,并将值设为1)
如何解决并发削峰问题?
利用redis的队列来实现削峰填谷
如何防止秒杀超卖问题?
给每个商品的个数存一个队列,比如商品A有五个,那么GoodsList:A(key) 1,1,1,1,1 给它存五个元素进去<br>
卖的时候,每次从队列里面拿一个,如果能拿到表示当前还有库存
如何实现超时订单回滚问题?
定时扫表
性能差
Java内存延迟队列
优点
基于jvm内存<br>
效率高
任务触发延迟低<br>
缺点
存在jvm内存中,服务重启数据丢失
依赖代码硬编码,无法进行集群扩充
依赖jvm内存,如果订单过多,会出现oom问题
MQ实现
方案
利用RabbitMQ延迟队列来实现, 30分钟后执行任务,<br>同时判断redis有没有订单信息存在,有的话,表示没有进行支付<br>
我们就可以关闭支付,关闭订单,回滚库存
优点
缺点
Redis实现
List + Zset实现
被动取消
在每次用户查询订单时<br>
判断订单时间,超时则取消
优点
缺点
重复支付问题<br>
支付时序图
可能原因
解决方法
数据修复
问题处理
异常订单问题<br>
支付但未开单<br>
对账一般一天一次
因此会存在延迟
未支付但已开单
回调延迟问题<br>
支付路由问题
支付中心对接多个支付路由
价格分摊问题
如何避免财务无法平账问题
退单处理问题
保障用户权益
限时购买商品自动下架问题
和超时订单回滚一致<br>
库存管理问题
乐观锁
悲观锁
直接数据库操作的话,数据库会扛不住
因此一般用redis缓存,然后做decr处理<br>
正常下单后,在使用mq异步更新到数据库
双11可能存在的问题
内部瓶颈
外部服务
数据库调优
开启慢查询日志
执行计划分析
缓存优化
热点数据预热
细粒度设计
可用性<br>
收藏
收藏
0 条评论
下一页