python红包转账高并发处理

56 篇文章 1 订阅
47 篇文章 0 订阅

最近项目中有一个功能,就是转账红包(即时提现到支付宝,秒到账),每天限制用户提现一次,刚开始,每天和支付宝对账的时候都能对上,但是后来随着用户的增多,每天几万人提现,并发量上来了,发现有时候账单对不上,后来发现死锁了,然后使用事务并优化代码,这个问题解决了,随着时间的推移,突然发现有些用户提现了一次,支付宝给他连续转账了好几次,有的甚至几十次,然后看代码逻辑,怎么都没有发现问题,后来给支付宝提工单,支付宝那边回复是我这边连续调了转账接口好多次,然后就在思考这是为什么?

  1. 由于每个用户每天只能提现一次,所以请求一进来就我这边就会来查询这个用户是否提现过,如果体现过直接return,而且前端按钮也做了限制,只有我这边返回结果了才让用户点击下一次提现按钮,那到底是出现了什么问题那?
  2. 这件事就困扰了好久,突然有天早上发现,会不会这个用户采用非常规的方式,一直请求转账,一直疯狂请求,导致我这边数据库的数据还没修改过来(余额,是否提现成功等),下一次的请求就又过来了,然后支付宝接口就疯狂转账,想到了这里,我就在手机上下载了抓包工具,然后一瞬间向这个接口一次发送了99次请求,结果支付宝一下给我转了80笔钱,到这里,我瞬间明白了,那怎么处理那?
  3. 我们可以使用redis锁,就是请求一进来,我们就上锁,锁的名称就是user_id,体现成功或失败时释放锁即可,(一旦查询到这个user_id有锁就直接redis,这样就给我们数据库反应的时间了)
  4. 代码:
import uuid
import redis

#获取一个锁
# lock_name:锁定名称
# acquire_time: 客户端等待获取锁的时间
# time_out: 锁的超时时间
def acquire_lock(conn, lockname, identifier, expire=20):
    if conn.setnx(lockname, identifier):
        conn.expire(lockname, expire)
        return identifier
    elif not conn.ttl(lockname):
        conn.expire(lockname, expire)

    return False



#释放一个锁
def release_lock(conn, lockname, identifier):
    pipe = conn.pipeline(True)
    while True:
        try:
            pipe.watch(lockname)
            if str(pipe.get(lockname).decode()) == str(identifier):
                pipe.multi()
                pipe.delete(lockname)
                pipe.execute()
                return True
            pipe.unwatch()
            break
        # except redis.exceptions.WatchError:
        except Exception as e
            pass

    # we lost the lock
    return False


在视图中的应用:
# 先查询是否多次请求
redis_conn = django_redis.get_redis_connection('withdraw')
redis_add_lock = acquire_lock(redis_conn, user.id, user.id, expire=20)

if not redis_add_lock:
    return APIResponse.fail(message='每日限1次,提现时间:8:00-24:00')

# 提现成功或失败时释放锁:
release_lock(redis_conn, user.id, user.id)
  1. 这样我再用抓包工具一瞬间请求99次就会提现一次了,所以,以后一旦牵扯到钱的问题,就要有redis锁和事务,这样才不会被恶意攻击
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值