彻夜怒肝!SpringBoot+Reids高并发秒杀系统源码!
在电商业务中,秒杀属于技术挑战最大的业务,只有经验够丰富、底子够稳的程序员,才能够hold住从搭建、上线到调优全链路。双十一就是一个经典的秒杀案例,动辄数十万笔的交易请求,对于我们来说,核心的两个问题:1-高并发读取与写入(涉及到集群,负载,读写分离,分库分表等操作)2-性能优化(玩转降级、限流、拒绝服务这三件法宝)程序员们应该都知道这样一句话:在工作中如果知道问题出现在哪里、是怎么发生的,问题就解决了一半。而从“不懂”到“知道”,中间不是鸿沟天堑,往往只差一次亲身经历。此外,应对工作中可能出现的突发情况,你也能知道从哪些环节来设计兜底方案。比如核心的抢单线程池设计与实现:public class AsyncConfiguration {
@Bean(“doSomethingExecutor”)
public Executor doSomethingExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:线程池创建时候初始化的线程数
executor.setCorePoolSize(10);
// 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(20);
// 缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(500);
// 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
// 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix(“create-seckill-order”);
// 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
executor.initialize();
return executor;
}
}
再比如复杂的多线程异步操作实现:
/*****
* 异步操作方法
* run
* 注解:@Async
*/
@Async
public void createOrder(){
try {
log.info(“—-准备@Async执行—-“);
//Thread.sleep(10000);
// redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<SeckillStatus>(SeckillStatus.class));
SeckillStatus seckillStauts = (SeckillStatus) redisTemplate.boundListOps(“SeckillOrderQueue”).rightPop();
//用户抢单数据
String username=seckillStauts.getUsername();
String time=seckillStauts.getTime();
Long id=seckillStauts.getGoodsId();
//获取队列中的商品id,使用Redis的队列来解决超卖的问题
// redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Long[]>(Long[].class));
Object sid = redisTemplate.boundListOps(“SeckillGoodsCountList_” + id).rightPop();
//售罄
if(sid==null){
//清理排队信息
clearQueue(seckillStauts);
return;
}
//查询商品详情
// redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<SeckillGoods>(SeckillGoods.class));
SeckillGoods goods = (SeckillGoods) redisTemplate.boundHashOps(“SeckillGoods_”+time).get(id);
//Thread.sleep(10000);
log.info(username+”:”+Thread.currentThread().getId()+”—-查询到 的商品库存:”+goods.getStockCount());
if(goods!=null && goods.getStockCount()>0){
//创建订单
SeckillOrder seckillOrder = new SeckillOrder();
seckillOrder.setId(idWorker.nextId());
seckillOrder.setSeckillId(id);
seckillOrder.setMoney(goods.getCostPrice());
seckillOrder.setUserId(username);
seckillOrder.setSellerId(goods.getSellerId());
seckillOrder.setCreateTime(new Date());
seckillOrder.setStatus(“0”);
//TODO 支付成功后再入库
seckillOrderMapper.insertSelective(seckillOrder);
redisTemplate.boundHashOps(“SeckillOrder”).put(username,seckillOrder);
//库存削减【关键的判断因素,需要从Redis中进行判断,否则两个库存同时进入这儿的逻辑,真是库存都是1,实际是0;使用自增来解决】
//Integer stockCount = goods.getStockCount()-1;
//Long surplusCount = stockCount.longValue();
Long surplusCount = redisTemplate.boundHashOps(“SeckillGoodsCount”).increment(goods.getId(), -1);
log.info(“库存消减后剩余:”+surplusCount);
goods.setStockCount(surplusCount.intValue());
//商品库存=0->将数据同步到MySQL,并清理Redis缓存
if(surplusCount<=0){
seckillGoodsMapper.updateByPrimaryKeySelective(goods);
//清理Redis缓存
redisTemplate.boundHashOps(“SeckillGoods_”+time).delete(id);
}else{
//将数据同步到Redis
redisTemplate.boundHashOps(“SeckillGoods_”+time).put(id,goods);
}
log.info(“—-准备更新seckillStauts—-“);
//变更抢单状态
seckillStauts.setOrderId(seckillOrder.getId());
seckillStauts.setMoney(seckillOrder.getMoney().floatValue());
seckillStauts.setStatus(2); //抢单成功,待支付
redisTemplate.boundHashOps(“UserQueueStatus”).put(username,seckillStauts);
log.info(“—-准备更新seckillStauts完毕—-“);
//发送延迟消息
//延时30m发送,级别是16
SendResult result=rocketMQTemplate.syncSend(“seckill_order:delay”, MessageBuilder.withPayload(seckillStauts).build(),2000,16);
System.out.println(result.toString());
}
log.info(“—-正在执行—-“);
} catch (Exception e) {
e.printStackTrace();
}
}
/***
* 清理用户排队信息
* @param seckillStauts
*/
private void clearQueue(SeckillStatus seckillStauts) {
//清理重复排队标识
redisTemplate.boundHashOps(“UserQueueCount”).delete(seckillStauts.getUsername());
//清理排队存储信息
redisTemplate.boundHashOps(“UserQueueStatus”).delete(seckillStauts.getUsername());
}
}
这都是我在实战中总结的经验。可以说,不论是跳槽到更好的工作岗位,还是想提升自己的代码质量,都离不开高并发环境下真实项目的锤炼,初级开发想要增加自己对复杂并发系统的掌控力,一套模拟大厂真实并发量的秒杀系统是最好的实训项目。当然,从0设计一个高性能秒杀系统并非易事,其实包含许多复杂的问题。下面这个秒杀系统架构【精准千人千面闯关实战】,由前转转平台架构部负责人东叔精心设计,截至目前已有8w+人报名,干货多到值得重复听2遍、3遍,已经帮助过无数后端开发突破成长瓶颈,强化自身基础。在闯关实战开始前,加赠理论单元👇
01
什么是“精准千人千面闯关实战”?
02
报名享双重勤学福利
▶勤学福利1:报名训练营即可免费领取高薪工程师(P6~P9)能力模型评估一次,帮助你针对薄弱技术维度精准查漏补缺。03
累计8w+人学过,好评如潮!
截至目前已有8w+人订阅学习,这么多期以来几乎从未收到过负面评价,清一水的好评:内容很干、很实用、给工作面试带来不少启发。干货
干货多到值得重复听2、3遍
实用
收获不止于课程内容
机遇
面试Offer拿到手软
04
金牌教研团打造一站式学习服务
课程期间,奈学的教研团队还提供全程答疑服务。奈学金牌教研团,平均从业年限10年以上,具备大厂实战经验,对技术深度钻研,对教学精益求精,让我们有理由相信,这套课程绝对物超所值。“1+1+1”闯关学习新模式,理论单元 + 案例剖析 + 场景实战
从 Redis 底层架构入手,深入浅出“Redis为什么这么快?”;
3 大实战项目,详解 Redis 秒杀系统、统计系统、广播系统;
重点解决面试必考之 Redis 主从复制、集群原理难题;
3 天重磅实战内容升级,免费附赠项目源码 + 课件。
训练营将基于一线秒杀、广播等企业级生产环境项目,帮助你深入理解 Redis 缓存机制及作为 MQ 的优势与亮点,彻底掌握秒杀系统的主从复制集群、持久化等核心技术点。
推荐给所有初、中级 Java 开发工程师,真的很值得一看。
发表回复