当前位置:网站首页>秒杀整体的技术难点
秒杀整体的技术难点
2022-06-11 12:09:00 【log.info(小吕同学)】
首先我就用华为官网 来说明秒杀的 整体流程,在华为官网某个秒杀场次点击商品信息

我们就会跳转到商品详情页中来,具体这里的技术难点 我上一篇文章也说了, 然后点击 立即抢购
点击抢购 到达商品确认页--->之后点击下单 付款

也就是秒杀这里的业务流程就是(在某个活动下选择 某个场次 ,在某个场次下选择具体的商品,比如 618活动选择12 点到2点的场次, 在12点到2点的场次下选择 华为Pro20)
(活动--->场次---->具体的商品) 点击商品---->商品详情页---->(立即抢购)商品确认页---------->{确认下单}
这就是秒杀这里的业务流程

秒杀的业务特点就是

呢么 在秒杀中我们应该注意一些什么技术问题呢?

商品详情页就是 之前说过了 采用nignx+lua+本地缓存 +redis 实现三级缓存策略
.对用户的频率实现限制 不能让用户频繁访问
秒杀 1.高并发解决超卖问题 首先我们要明白超卖问题是怎么产生的
--- table Info 我们的表结构
CREATE TABLE `tb_product_stock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`product_id` bigint(32) NOT NULL COMMENT '商品ID',
`number` INT(8) NOT NULL DEFAULT 0 COMMENT '库存数量',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`modify_time` DATETIME NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `index_pid` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品库存表';
// ProductStock pojo
class ProductStock {
private Long productId; //商品id
private Integer number; //库存量
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
}
-------------<<<< 不考虑并发的时候 我们(select )查库存--->(update) 更改库存--->(insert ) 新增订单
多线程并发情况下,会存在超卖的可能。
/**
* 更新库存(不考虑并发)
* @param productId
* @return
*/
public boolean updateStockRaw(Long productId){
// 查库存
ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId}", productId);
if (product.getNumber() > 0) {
// 更改
int updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId}", productId);
if(updateCnt > 0){ //更新库存成功
return true;
}
}
return false;
}

看以上的图 假设线程1 和线程2 同时查询到了 此时的库存有100个
线程1 查询 100库存 进行update 更改库存(扣减库存) 更新为99
如果线程1 此时由于网络原因阻塞了, 此时
线程2 查询 100库存 进行update 更改库存(扣减库存) 更新为99,
因为在线程1 没有更新结束的时候 线程2就开始了查询 这样就发生了超卖 ,
我卖了2件商品 但是库存中只是扣减了一次
我们可以使用mysql的悲观锁来解决 select ... for update
使用mysql 的select ...for update 悲观锁来解决超卖问题 悲观锁具有排他性
我当前的事务没有提交或者回滚, 你其他线程是不可以操作这一条数据的
/**
* 更新库存(使用悲观锁)
* @param productId
* @return
*/
public boolean updateStock(Long productId){
//先锁定商品库存记录
ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId} FOR UPDATE", productId);
if (product.getNumber() > 0) {
int updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId}", productId);
if(updateCnt > 0){ //更新库存成功
return true;
}
}
return false;
}
/**
* 下单减库存---------------->乐观锁 我们也可以使用Mysql 的乐观锁 ci
* @param productId
* @return
*/
public boolean updateStock(Long productId){
int updateCnt = 0;
while (updateCnt == 0) {
ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId}", productId);
if (product.getNumber() > 0) {
.................... 这里 我们更改的时候加上 之前查询的数量如果是100的化 就更改 , 或者加个版本号 或者加上uuid
updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId} AND number=#{number}", productId, product.getNumber());
if(updateCnt > 0){ //更新库存成功
return true;
}
} else { //update fill 更改失败
return false;
}
}
return false;
}
1. 无论是乐观锁还是悲观锁 我们都要操作db, 都要上锁 会影响性能的 而且我们db的性能是优先的
比如说1w个人来抢购,商品有100个, 就会有1w个人来操作db ,但是我此时只想让100 个人操作db,不让(1w-100)个人操作db
我们可以采用redis 做预热

我们同样可以使用本地缓存 标志位true 加上redis 做预热来解决当前性能问题 这样我们的查询db 只会查询一部分 减少了db的压力
边栏推荐
- 创建线程的四种方式
- 2、CompletableFuture
- centos安装mysql5.7
- 11. Synchronized and lock escalation
- 12、AbstractQueuedSynchronizer之AQS
- Flink data flow graph, parallelism, operator chain, jobgraph and executiongraph, task and task slot
- YARN 切换ResourceManager(Failed to connect to server:8032 retries get failed due to exceeded maximum)
- Record a CODIS memory cleanup
- Some common websites
- Splunk Bucket 背后的秘密
猜你喜欢

你管这破玩意儿叫 MQ?

反射真的很耗时吗,反射 10 万次,耗时多久。

Flink deployment mode and runtime architecture (session mode, single job mode, application mode, jobmanager, taskmanager, yarn mode deployment and runtime architecture)

Installation and use of saltstack

SQLServer连接数据库(中文表)部分数据乱码问题解决

This is our golden age

Flip window join, interval join, window cogroup

Splunk certificate expired, making kV store unable to start

数据如何在 Splunk 中老化?

9、聊聊ThreadLocal
随机推荐
yapi安装
InputStream读取文件OutputStream创建文件
.net core 抛异常对性能影响的求证之路
Record a CODIS memory cleanup
Android 11+ 配置SqlServer2014+
flink 时间语义、水位线(Watermark)、生成水位线、水位线的传递
8、原子操作类之18罗汉增强
UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xc5 in position 13: invalid continuation byte
mysql 导入宝塔中数据库data为0000-00-00,enum为null出错
gocron 定时任务管理平台
(solve) the kV store down problem of Splunk
General O & M structure diagram
Wechat applet startup page automatically jumps
saltstack安装与使用
Splunk 手工同步search head
9、聊聊ThreadLocal
Yapi installation
Acwing50+Acwing51周赛+Acwing3493.最大的和(未完结)
flink 窗口表值函数
Splunk manually synchronize search head