问题描述
目前我们有一个虚拟卡密提取接口,时常会有高并发请求的情况,每个请求进来后,必须马上返回分配的卡密数据,并标记为已提取。
当遇到高并发时候,就会出现同一卡密发给多人的情况。
问题出现的平台版本及自己尝试过哪些方法
查阅资料后,尝试过flock的文件锁,但是并发上来后,CPU马上跑满了,所有请求都堵死了,根本无法执行下去。
考虑如果使用消息队列的话,虽然能马上完成一次请求,避免重复领取,但是实际的出队和数据库的修改操作都是异步执行了,请求结束后,不能马上得到提取结果,一个提取动作只能分成两个步骤去完成了(效率比较低)
你期待的结果是什么?实际看到的错误信息又是什么?
有没有什么办法,能让每次请求都能得到结果,并且避免重复领取(偶尔出现个别重复是可接受的)简单办法?
###利用 Redis 的Queue
处理即可
- 将卡密数据的 ID同步一份到 Redis
- 处理请求时使用
LPOP
从Redis 获取卡密的 ID,获取失败则证明没卡密了 - 获取到卡密 ID 之后正常发号即可。
LPOP
是经常用来处理秒杀、抽奖之类场景的
做一个卡密池,无限循环保证卡密池有数据,用户从卡密池里拿数据行吗
###设计思路可以这样。请求并发高的话,已经决定了,只能用队列削峰。
你可以做一个设计,做一个预生成的功能,预先把生成的卡密存储到数据和队列A。假设队列A存储了卡密(card-no,card-secret),
用户请求的时候,消费队列A,同时向队列B(保存卡密-用户映射关系)push一条数据,数据有(card-no,user-id)
队列A 可以做个统计,当数量不够的时候,触发批量预生成。然后队列B可以酌情根据服务器的负载,数据的IO决定啥时候做持久化入库。
什么消息队列都是扯淡。因为这是需要同步返回数据的。
先想想,目前的瓶颈在哪?肯定是数据库啊。
你每次都去数据库查询,数据库才是瓶颈。所以从这里入手。
你为什么不把卡密数据放到redis里面?
10万个人的卡密数据,都存进redis,多大的成本?占多大的空间呢?
1秒钟多少并发?1000次?5000次?就算不用redis,用mongo之类的数据库,这点并发,一台普通的云服务器都能轻松胜任吧?所需要的成本也不过一个月几百块钱。
###可以试试在卡密表上增加用户uid。
领取的时候一条sql查询出一条不存在uid的记录把uid存进去。这样就不会把同一个卡密分配给不同用户。
卡密表:card,用户字段:uid(默认值0)
update card set uid=1 where id=(select minid from (SELECT min(id) as minid FROM card WHERE uid=0) as a)
如果一个用户只能领取一次的话,执行前先判断一下卡密表中是否已经存在用户uid。