zoukankan      html  css  js  c++  java
  • 高并发下接口的并发问题

    事故

    前些天上线的扫码送会员活动。
    场景:用户登录账号之后,扫二维码,送七天黄金会员,限制每个帐号只能领取一个
    有恶意用户刷接口,在高并发下越过限制。

    原因

    领取会员流程:
        1.后端先生成卡卷,将卡号放到消息队列中
        2.用户扫码请求领取会员接口
            2-1).先检查用户是否已经领取过该活动会员
            2-2).领取过return “该帐号已领取”的标示  
            2-3).没领取从消息队列中拿取一张卡号
            2-4).激活卡
            2-5).更新用户本次活动为已经激活

    这个流程在一般环境下是没有问题的,在高并发下就不行了。
                    2-1)        2-2)        2-3)       2-4)      2-5)
    
        线程a                                                   -->
    
        线程b                                      -->
    
        线程c                                 -->

    高并发下模拟几个线程同时请求

    现在的rpc服务,除去极其敏感性数据的操作,其它数据的接口基本都没有做数据一致性控制。

    其实做了控制也不能解决这个问题。再来说这个问题,高并发下因为线程a已经执行完激活卡的操作,用户的会员已经建立权益。但这时候线程a还没有执行到2-5,还没更新用户的领取卡卷的状态,这时候,又有一个这个用户的领取卡卷请求过来。2-1的check 操作并不能阻止这个请求,同样的再次领取卡卷并且激活,导致线程a在的执行在2-1到2-5之间都会有其它的线程越过检查。

    解决

    解决这种并发问题无非是两种,悲观锁和乐观锁。
    悲观锁阻塞,乐观锁快速响应失败。

                    优点                      缺点
    
    悲观锁     可以响应重复请求,幂等         高并发下请求堆积
    
    
    乐观锁     高并发下没有大量线程阻塞        不可重复响应,不幂等
    

    考虑并发量比较大,采用的乐观锁实现。对流程进行加锁。

    2种实现方式:redis和MySQL,考虑下在不修改原表的情况下,使用redis的SETNX的api

    实现:

            2-0).活动-帐号形成key,SETNX(key)成功返回1,失败返回0
                  只有返回1,才能进行后续流程,将并发控制交给redis,redis是线程模型没有并发问题
            2-1).先检查用户是否已经领取过该活动会员
            2-2).领取过return “该帐号已领取”的标示  
            2-3).没领取从消息队列中拿取一张卡号
            2-4).激活卡
            2-5).更新用户本次活动为已经激活
            2-6).将删除活动-帐号形成的key
    
    
                2-0)    2-1)   2-2)     2-3)  2-4)  2-5)   2-6)
    
        线程a   ->1                                         
    
        线程b   ->0                                   
                 <- 
        线程c  ->0                            
                 <-
    
        只有线程a已经执行过2-6,才能线程b进入流程,但是这时候用户已经为领取过卡卷状态           
        线程a                                                 ->
    
        线程b  ->1 用户卡卷已经更新过
    
        线程c  ->0                                            
    
     
  • 相关阅读:
    hive中map与reduce的个数问题
    count(*) 与 count(1)的区别?
    星型模型与雪花模型有什么优缺点
    如何估计数据需要存储空间
    element-ui的table控件得到所有的表头label值
    vue-image-crop-upload通过params带参的时候key总是img
    vue通过window.addEventListener('scroll', XXXX)无法监听屏幕滚动事件
    在vue里面无法通过document.getElementById来修改ElementUI自带的标签
    Vue-Router升级导致的Uncaught (in promise)问题【转载别人的】
    node安装依赖以及使用api
  • 原文地址:https://www.cnblogs.com/zhaoding/p/6894986.html
Copyright © 2011-2022 走看看