秒杀系统设计

导读:本篇文章讲解 秒杀系统设计,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、秒杀商品上架

一般是后台指定一个定时任务,上架秒杀商品
在这里插入图片描述
假如是集群部署的情况,就会出现分布式问题,可能会存在商品重复上架问题
解决方案也很简单,加一个分布式锁
在这里插入图片描述
商品上架流程图:
在这里插入图片描述

二、秒杀系统需要考虑的问题

在这里插入图片描述
在这里插入图片描述
1:抽取一个秒杀服务,独立部署,集群部署
2:采用动态随机码,加密处理
3:信号量控制-原子性
4:nginx动静分离
5:识别恶意攻击
6:使用各种手段,使得用户流程错峰
7:限流降级等
8:队列削峰,添加一个队列接受秒杀成功的请求

三、秒杀流程

1、加入购物车秒杀流程:
在这里插入图片描述
2、立即抢购秒杀流程:
在这里插入图片描述
秒杀接口实现:

public String kill(String killId, String key, Integer num) {

        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();

        // 1、获取当前秒杀商品的详细信息
        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
        String s = ops.get(killId);
        if(!StringUtils.isEmpty(s)) {
            SeckillSkuRedisTo redisTo = JSON.parseObject(s, SeckillSkuRedisTo.class);
            // 校验合法性
            Long startTime = redisTo.getStartTime();
            Long endTime = redisTo.getEndTime();

            long ttl = endTime - startTime;
            // 校验时间的合法性
            if(startTime <= new Date().getTime() && new Date().getTime() <= endTime ) {
                // 校验随机码和商品id
                String randomCode = redisTo.getRandomCode();
                String skuId = redisTo.getPromotionSessionId() + "_" + redisTo.getSkuId();
                if(randomCode.equals(key) && killId.equals(skuId)) {
                    // 3、验证购物数量是否合法
                    if(num <= redisTo.getSeckillLimit()) {
                        // 4、验证这个人是否已经购买过。幂等性;如果只有秒杀成功,就去占位
                        String redisKey = memberRespVo.getId() + "_" + skuId;
                        // 自动过期
                        Boolean absent = redisTemplate.opsForValue().setIfAbsent(redisKey, num.toString(), ttl, TimeUnit.MILLISECONDS);
                        if(absent) {
                            // 占位成功,没买过
                            RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + randomCode);
                            boolean tryAcquire = semaphore.tryAcquire(num);
                            if(tryAcquire) {
                                // 秒杀成功
                                // 快速下单 发送MQ消息
                                String timeId = IdWorker.getTimeId();
                                SeckillOrderTo seckillOrderTo = new SeckillOrderTo();
                                seckillOrderTo.setOrderSn(timeId);
                                seckillOrderTo.setMemberId(memberRespVo.getId());
                                seckillOrderTo.setNum(num);
                                seckillOrderTo.setPromotionSessionId(redisTo.getPromotionSessionId());
                                seckillOrderTo.setSeckillPrice(redisTo.getSeckillPrice());
                                seckillOrderTo.setSkuId(redisTo.getSkuId());
                                rabbitTemplate.convertAndSend("order-event-exchange","order.seckill.order",seckillOrderTo);
                                return timeId;
                            }
                        }
                    }
                }
            }
        }


        return null;
    }

四、秒杀成功创建订单流程

在这里插入图片描述
监听削峰队列,创建订单

@RabbitListener(queues = "order.seckill.order.queue")
@Component
public class OrderSeckillListener {

    @RabbitHandler
    public void listener(SeckillOrderTo seckillOrder, Channel channel, Message message) throws IOException {
        try {
            log.info("准备创建秒杀单的详细信息...");
            // 创建订单
			// 业务逻辑
			
			// ack确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
        }
    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/90989.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!