Rumah > Soal Jawab > teks badan
业务
大转盘抽奖活动 奖品分实物和红包 限制用户只能中一个实物
使用redis
防同一用户并发
超领实物 即中了多个实物
获得奖池
AwardPool chooseAwardFromPool(){ //得到奖池
// 查询所有有效奖品
// 若用户之前已中了实物 排除实物奖品
if(hasWinedRealObject && award.type==实物)
continue;
//...
}
award = chooseAwardFromPool(pool); //从奖池中随机选择一个奖品
若用户还未抽中实物, 且同一用户并发进入, 存在随机选择的奖品都为实物的可能, 如同一用户10个并发请求进来, 其中3个请求碰巧随机选择的奖品均为实物, 于是该用户就能中3个实物, 于是需要引入redis
来防并发
超中实物. 如下所示
//选中奖品后处理
if(award.type == 实物){ // 若奖品为实物
key = "user_"+userId+"_实物_count";
count = redis.incr(key);
if(count == 1){
redis.expire(key, 10*60); //设置过期时间10分钟
}
if(count > 1){ //同一用户中了多个实物
award = 未中奖; //此时默认替换为未中奖奖品
}
}
对过期时间
我始终不知该如何评估, 设置多长时间合适, 因为基本上是针对恶意用户并发请求才引入redis
的, 正常用户的正常页面操作无需做任何处理, 因为若前一次中了实物,后面再来抽奖的话, 一开始取得奖池时就会排除掉实物奖品, 故后面抽奖奖池中压根就没有实物奖品了, 也就不会中实物了.
为什么设置10分钟呢? 因为我觉得两个并发请求--且是均中了实物的两个请求--不可能执行redis.incr(key)
时相隔了10分钟, 如下所示
#请求1 用户尚未中实物 从奖池中随机返回了一个实物奖品
award = chooseAwardFromPool(pool); //从奖池中随机选择一个奖品
#请求n 用户尚未中实物 也从奖池中随机返回了一个实物奖品
award = chooseAwardFromPool(pool); //从奖池中随机选择一个奖品
#请求1 执行redis操作
count = redis.incr(key);
#请求n 执行redis操作
count = redis.incr(key);
我觉得10分钟能够保证请求n执行redis
操作时, key
不会过期, 故能够防超中实物.
但又不是很笃定, 怎觉得存在请求2执行时key
会过期的情况, 但又想不出什么情况下会有这样的情况.
请求数并发量特别大的情况下会存在这种可能吗? 如
ab -n 1000000 -c 1000 -T "application/x-www-form-urlencoded" -p post_draw http://localhost:8080/draw
如请求1过来的时候随机选中了一个实物, 等到请求n过来的时候, 请求1还没有提交到数据库中, 于是请求n有可能随机返回一个实物奖品, 等到请求n执行redis.incr(key)
时, 已经过了10分钟了, 于是请求n仍能中实物.于是同一用户中了两个实物.
PHP中文网2017-04-25 09:04:25
1 Mengikut reka bentuk anda, gunakan redis untuk mengendalikannya. Mengapa anda tidak menetapkan masa kepada kekal? Tunggu permintaan A dihantar sebelum mengosongkannya, dan kemudian ikut pertimbangan logik biasa anda
2. Tanpa redis, gunakan pangkalan data untuk mencapai kawalan berbilang konkurensi Pertama sekali, anda mesti mempunyai jadual pengumpulan hadiah mempunyai medan yang menunjukkan pemenang Setiap Apabila pengguna memenangi hadiah, jadual kumpulan hadiah akan dikemas kini untuk menetapkan pemenang, dan kemudian anda akan menambah syarat kawalan kuantiti hadiah fizikal apabila mengemas kini SQL