首页 > 抽奖活动计数 redis vs mysql

抽奖活动计数 redis vs mysql

业务:

抽奖活动 限制每天抽奖次数 每个用户每天只能抽奖3次
同时若有中奖的话更新奖品中奖数和奖品库存数

方案一:
使用mysql(ssd硬盘) 如下所示

#更新用户抽奖次数
select * from draw_count;
+----+---------+------------+-------+
| id | user_id | draw_date  | count |
+----+---------+------------+-------+
|  1 |       1 | 2016-03-12 |     3 |
+----+---------+------------+-------+
#显式指定count<3 如果更新count失败 表示已抽完3次 使用这种方式也可以应对同一用户并发超抽的情况。
update draw_count set count=count+1 where user_id = 1 and draw_date=current_date and count<3;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0


#中奖后更新奖品中奖数和库存
select * from award_count;
+----+----------+-----------+-------+
| id | award_id | win_count | stock |
+----+----------+-----------+-------+
|  1 |        1 |         0 |   100 |
+----+----------+-----------+-------+
#显式指定stock>0 避免并发超抽的情况 只有更新成功了 才表示成功中奖
update award_count set win_count = win_count+1 , stock = stock-1 where award_id = 1 and stock>0;
Query OK, 1 row affected (0.06 sec)
Rows matched: 1  Changed: 1  Warnings: 0

方案二:
使用redis 如下所示

#更新用户抽奖次数
127.0.0.1:6379> incr 1_20160312
(integer) 1
127.0.0.1:6379> incr 1_20160312
(integer) 2
127.0.0.1:6379> incr 1_20160312
(integer) 3
127.0.0.1:6379> get 1_20160312
"3"

#更新奖品中奖数和库存
127.0.0.1:6379> incr 1_win_count
(integer) 1

127.0.0.1:6379> decr 1_stock
(integer) 99

使用redis来限制并发超抽的情况

好像面对上述场景大家想到的都是使用redis, 但使用mysql的劣势在哪呢?尤其当使用的是ssd硬盘的mysql


看具体情况,对并发比较大的情况下redis会比较有优势,而且incr系列api又是保证原子性操作。mysql速度会稍微差些,ssd也不会有内存快。对于这种有key/value操作显然nosql产品更有优势。


使用redis会有一个问题,那就是到最后你的商品数量剩余量可能是小于0的,即因为redis只能保证每个操作的原子性,如果你需要判断商品数量是否大于0,然后再决定是否减少余量,这样redis是没法保证原子性的,并发就会导致余量小于0,但是并不影响业务的正确性,因为你可以通过decr的返回值是否>=0来判断发奖成功与否。


MySQL毕竟是文件存储,肯定没法跟内存比,这种情况下一般方案是redis+mysql,这种数据不落DB谁放心呢。

【热门文章】
【热门文章】