高并发下接口的并发问题

事故

前些天上线的扫码送会员活动。

场景:用户登录账号之后,扫二维码,送七天黄金会员,限制每个帐号只能领取一个

有恶意用户刷接口,在高并发下越过限制。

原因

领取会员流程:
    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
 
时间: 2024-10-13 00:59:04

高并发下接口的并发问题的相关文章

高并发下接口幂等性解决方案

一.幂等性概念 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同.幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数.这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变.例如,“getUsername()和setTrue()”函数就是一个幂等函数. 更复杂的操作幂等保证是利用唯一交易号(流水号)实现. 我的理解:幂等就是一个操作,不论执行多少次,产生的效果和返回的结果都是一样的. 二.幂等性场景1.查询操作:查询一次和查询多次,在数

EF+MySQL乐观锁控制电商并发下单扣减库存,在高并发下的问题

下订单减库存的方式 现在,连农村的大姐都会用手机上淘宝购物了,相信电商对大家已经非常熟悉了,如果熟悉电商开发的同学,就知道在买家下单购买商品的时候,是需要扣减库存的,当然有2种扣减库存的方式, 一种是预扣库存,相当于锁定库存, 一种是直接扣减库存. 我们采用的是预扣库存的方式,预扣库存的时候,在SalesInfo表中,将最大可售数量MaxSalesNum减去购买数量,用一条SQL语句来表示这个业务,就是下面这个样子的: update salesinfo set MaxSalesNum=MaxSa

php结合redis实现高并发下的抢购、秒杀功能

原文: http://blog.csdn.net/nuli888/article/details/51865401 抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis.重点在于第二个问题 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问

php 结合redis实现高并发下的抢购、秒杀功能

抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis.重点在于第二个问题 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数 [php] view plain copy <?php $conn=mysql_con

(高级篇)php结合redis实现高并发下的抢购、秒杀功能

抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis.重点在于第二个问题 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数 优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数

PHP开发中多种方案实现高并发下的抢购、秒杀功能

抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis. 重点在于第二个问题. 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数 <?php $conn=mysql_connect("localh

【转】php结合redis实现高并发下的抢购、秒杀功能

抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis.重点在于第二个问题 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数 优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数

Redis实现高并发下的抢购、秒杀功能

博主最近在项目中遇到了抢购问题!现在分享下.抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis.重点在于第二个问题常规写法:查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数 优化方案1:将库存字段number字段设为unsig

秒杀系统:并发队列 接口设计 并发请求数据安全处理

看秒杀系统的时候看到的关于并发队列的介绍,摘抄如下 并发队列的选择 Java的并发包提供了三个常用的并发队列实现,分别是:ArrayBlockingQueue.ConcurrentLinkedQueue 和 LinkedBlockingQueue  . ArrayBlockingQueue是初始容量固定的阻塞队列,我们可以用来作为数据库模块成功竞拍的队列,比如有10个商品,那么我们就设定一个10大小的数组队列. ConcurrentLinkedQueue使用的是CAS原语无锁队列实现,是一个异步