秒杀业务设计

       秒杀因其流量大,并发高,成为最经典的业务之一,并发的根源在于数据库,通常采用缓存+队列的方式减少数据库访问,降低访问速度。有幸接触到一个秒杀业务代码,采用redis+mq的方式实现,现整理流程如下:

      1. 数据库设计

       秒杀业务的商品和订单单独设表,不要和正常商品和商品订单混合一起。表格数据足够少,才能保证查询和写入速度。订单表将用户id和商品id设置为唯一索引,这样能保证同一个用户不会购买两件相同的秒杀商品。

       秒杀商品表商品库存更新语句添加>0条件,保证商品卖超的情况。

update miaosha_goods set stock_count = stock_count - 1 where goods_id = #{goodsId} and stock_count > 0

      2. 使用redis建立分布式session机制

        用户登录生成token,保存到redis中,key值使用前缀+token,value保存秒杀用户信息,将token封装进cookie中进行返回。

      3. 以拦截器方式验证所有接口用户信息是否合法,并将用户信息保存至上下文中

        首先通过容器方式对WebMvcConfigurerAdapter添加拦截器,并为方法添加参数;

@Configuration
public class WebConfig  extends WebMvcConfigurerAdapter{
	
	@Autowired
	UserArgumentResolver userArgumentResolver;
	
	@Autowired
	AccessInterceptor accessInterceptor;
	
    //为方法添加秒杀用户参数
	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
		argumentResolvers.add(userArgumentResolver);
	}
	
    //使用拦截器将用户信息保存至上下文中
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(accessInterceptor);
	}
	
}

 

@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

	@Autowired
	MiaoshaUserService userService;
	
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> clazz = parameter.getParameterType();
		return clazz==MiaoshaUser.class;
	}

	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		return UserContext.getUser();
	}

}

       AccessInterceptor继承HandlerInterceptorAdapter,实现 preHandle方法,根据token将用户信息从redis取出放入上下文中,上下文类使用ThreadLocal保存:

private static ThreadLocal<MiaoshaUser> userHolder = new ThreadLocal<MiaoshaUser>();

    4. 秒杀安全防护:防刷限流 

      1)秒杀开始前使用公式验证码进行验证,可用技术:scriptEngine

      2)隐藏秒杀接口,动态获取秒杀路径:路径可以使用localhost:8081/miaosha/{path}/doMiaosha的方式,{path}则通过动态方式生成,生成逻辑:UUID+盐值 然后使用MD5加密,同时保存至redis中一份:key使用用户id+商品id。

      3)添加访问限制注解,为获取动态秒杀接口添加访问限制,例如:3分钟内限制访问5次。

@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
	int seconds();
	int maxCount();
	boolean needLogin() default true;
}

    5. 实现秒杀业务逻辑:

     (1)判断用户是否存在,不存在则报session异常

     (2)判断路径是否存在,从redis中根据用户id和商品id查询路径,不存在则报请求非法

     (3)使用系统内存,减少redis访问,从系统内存中根据商品id获得是否还存在商品,true或者false,不存在则返回商品无剩余

private HashMap<Long, Boolean> localOverMap =  new HashMap<Long, Boolean>();

    (4)redis预减库存,如果库存减少为0,则更新本地内存,将id对应的商品设置为over

    (5)查询redis是否已存在订单,存在则返回重复秒杀

    (6)秒杀入队(mq) 

    (7)出队:

         a) 判断秒杀货物是否有剩余,无剩余则 return;

         b) 判断是否已经存在订单,存在则return;

         c) 减库存,下订单,保存秒杀订单

   总结

       秒杀业务的根本在于应用缓存提高并发量,减少数据库访问,使用mq缓冲将大流量数据进行削峰填谷,另外注意接口的防刷限流。

代码详见:https://download.csdn.net/download/u012466304/10751632

             

       

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值