1
langmoe 2016-11-23 21:40:59 +08:00
数据库读锁
|
2
lynnworld 2016-11-23 21:45:15 +08:00
redis incr
|
3
batnss 2016-11-23 21:46:12 +08:00
redis 生成一个 10 个元素的队列
|
4
virusdefender 2016-11-23 21:53:16 +08:00
二楼说的对, redis incr 可以
|
5
cxbig 2016-11-23 22:01:09 +08:00
同 2 楼,十万用户还是交给缓存来处理。
|
6
php71 2016-11-23 22:04:05 +08:00
让请求只能进来 10 个,不直接操作数据库,我看别人做秒杀也是这个思路
|
7
Yunhao 2016-11-23 22:08:36 +08:00 via iPhone
无脑写入,把前一百的用户请求存起来,排个序,前十的给个红包 (逃...
|
9
tulongtou 2016-11-23 23:27:18 +08:00 via iPhone
JS 上做个处理,提交的时候截掉一部分,请求到后台了再截掉一部分,剩下的到业务逻辑的就不多了,再去进行秒杀
|
10
php71 2016-11-23 23:52:21 +08:00
|
12
abelyao 2016-11-24 00:32:11 +08:00
先抽奖,中奖的话再去 count 数据库,再确认是否真的中奖,可以很大很大的降低数据库请求量。
|
13
helloccav 2016-11-24 00:43:35 +08:00
@php71 正如楼主所说, "cache 读写间隔时间比数据库少很多,但还是有间隔时间,仍然没有办法限制 10 个红包", redis 也一样吧?
|
15
lianyue 2016-11-24 01:21:11 +08:00
。。。。。。 很简单吧
INSERT 发布的红包 (id, count) values(1, 10) result = UPDATE 发布的红包 SET count = count - 1 WHERE id = 1 AND count > 0; if (result === true) { INSERT 已经抢了的红包 ..... } |
16
lianyue 2016-11-24 01:24:50 +08:00
这样绝对不会多 可能会少一个进程异常中断等。。造成
如果要绝对的强一致性 可以用 sql 事务 |
18
ryd994 2016-11-24 04:25:17 +08:00 via Android
很明显你那个锁就是错的
对的锁只有慢的没有不一致的 这种需求不要用 SQL ,反正数据量不大,加内存用 Redis |
19
Time2 2016-11-24 08:56:13 +08:00
redis 队列正解
|
20
qq496844026 2016-11-24 09:15:10 +08:00 1
Nginx 控制请求数量,然后 redis 的 incr 保证处理的正确性.这样可以最大程度的处理高并发了
|
21
amey9270 2016-11-24 09:48:02 +08:00 3
对于这种大并发抽奖, 注意 3 点
1. redis incr 使用原子计数可以解决, 并发情况下不会超发的问题 2. 用户锁, 解决同一用户同时多次秒杀, 除非你不 care 一个用户中了多次奖品 3. 防人机, 简单的方案是图形码 或者是 CSRF 都可以 |
22
amey9270 2016-11-24 09:53:15 +08:00
补充一下
注意一下流控, 不要让大流量冲垮你的系统, 宁愿让用户看到系统忙, 也不要让用户看到 500 |
23
lijinma 2016-11-24 10:03:01 +08:00 1
使用 Redis 两个思路,楼上都提到了。
因为 Redis 支持原子操作,所以你可以使用 Redis 做。 1. 比如 redis incr ,因为是原子操作,你不需要担心并发的问题,你只需要判断每次 incr 后的值是否小于等于 10. 2. 使用有限资源的模式,比如使用 redis list ,先创建好 10 个资源,然后每次操作都是 pop ,因为只有 10 个资源,不会 pop 出来 11 个资源的,谁拿到资源谁就中奖。 另外,一般的配置, Redis 并发几万的请求一点问题也没有。 |
24
amey9270 2016-11-24 10:38:52 +08:00
@lijinma @lynnworld @ryd994 @qq496844026 哈哈,插个题外话, 阿里云的开发职位不知道你们是否有兴趣, 我是阿里云的开发, 不是猎头, 如果有兴趣可以发我 email: [email protected], 我们可以电话聊一聊.
|
25
shuiguyu 2016-11-24 10:50:51 +08:00
@lianyue 这个是乐观锁的思路吧,加个版本号。
控制超卖。 但是高并发的情况下,可能限流更明显一些。可以用计数器也可以用令牌桶。 限速的情况可能令牌桶更好一些,可以控制发令牌的间隔,不至于都是前面的人抢到。 |
26
suren1986 2016-11-24 11:09:37 +08:00 1
1. 用 Redis 的 queue ,开奖前 enqueue 10 个元素进去,开奖后 dequeue ;
2. 用 Redis 的 setNx ,预定义 10 个 key ,能 setNx 成功表示得奖了 http://redis.io/commands |
27
shibingsw 2016-11-24 11:18:08 +08:00
cache 读写间隔时间比数据库少很多,但还是有间隔时间,仍然没有办法限制 10 个红包。
----- 你把更新和读做成原子的不就行了, redis 的 incr ,数据库的 update 都行啊。可是如果你要是先 get 再减一,再判断,然后再 set 这样自然不行了。。 |
28
quericy 2016-11-24 11:28:57 +08:00
2 楼正解, 原子性的操作就可以了
|
29
zts1993 2016-11-24 11:36:07 +08:00
感觉在 nginx 上用 lua+redis 控制更好.冲到 server 上,如果服务器少得话还是有可能跪..
|
30
huigeer 2016-11-24 11:37:04 +08:00
redis incr
|
31
vus520 2016-11-24 11:50:04 +08:00 1
0 ,请求直接进 mysql 肯定是不对的,文件锁在单机上是可靠的,但有风险。
1 ,说了很多 redis 的方案,都是对的,用 redis 通过计数器和队列模式都可以, incr, decr, lpop 都行,不会有超发的情况 2 ,应该要有流控设计, 10 次红包、秒杀,可以按一定比例,控制流量,只放 1000 个进来,减少后端的计算压力 |
32
ipconfiger 2016-11-24 11:54:22 +08:00
9 楼正解, 其实现在大多数秒杀都在用这类方法, 其实不光是 js 上, 页面刷出来的时候就预先决定了你能不能真正进入"抽"的环节, 就没有那么大的流量冲击了, 再加上用 redis 的方案, 上亿级别的秒杀都轻松搞定啊
|
33
silenceeeee 2016-11-24 11:57:36 +08:00
@shuiguyu 他这个其实把所有压力放到 MySQL 上了 通过锁阻塞来实现. 个人感觉不是很合理. MySQL 的锁不应该这样应用
|
34
lostvincent 2016-11-24 12:26:45 +08:00 via iPhone
数据库层面的话,可以预先将红包分成 10 个,然后中奖者 id 留空,抢的时候 update set 中奖者 id=用户 id , where 红包=这个抢的红包,且中奖者 id=空(暂时我还没测试过可行性)
缓存上面都说的差不多了,自行参考吧 |
35
qq496844026 2016-11-24 12:35:49 +08:00
@amey9270 谢谢了,有朋友在阿里,觉得还是不太喜欢里面的氛围.现在我的团队不错,还想继续和我的小伙伴一起奋斗,可以做个朋友一起探讨技术
|
36
iyaozhen 2016-11-24 13:07:30 +08:00 via Android
我来说说我司的思路吧。把「抢」红包这个操作分成 2 个。先拿着红包 id 抢,这层业务只做拦截。然后再拿着红包 id 去拆红包。这时就是具体的资金业务了。当然也会拆失败。
还有就是使用 redis 。 |
37
shuiguyu 2016-11-24 13:08:15 +08:00
@silenceeeee 一般我们设计的原则是,凡是涉及到库存的,基本上都用乐观锁比较保险一点,但是那个已经是数据库层面的了。这种高并发的抢购,前面就要在请求数,缓存等拦截住请求了,然后再分批次的提交扣库存就保险了。
Guava 的 RateLimiter 类,能很方便的实现令牌桶,对抢购甩红包这种场景很实用。 |
38
jsq2627 2016-11-24 18:47:33 +08:00
var random = 生成 0-999 之间的一个随机整数
if (random == 0) { (此处按照中奖率 10%编写抽奖代码,无需考虑高并发) } return 没抽中 |
39
jsq2627 2016-11-24 19:02:12 +08:00
参照 redis benchmark :
http://redis.io/topics/benchmarks 10 万 qps 很有可能超出 redis 能力 在不同的业务情形下,总有一种妥协方式 比如不严格保证先到先得 或者让用户看五秒动画再反馈结果 在某个方面妥协一下,就能很容易实现啦 |
40
lynnworld 2016-11-24 21:36:13 +08:00
额, 10w 人在同一秒操作,保守估计 100w 人打开这个页面,就为这 10 个红包,想想也是心累:(
|
41
2owe 2016-11-24 21:52:19 +08:00
Redis 双队列,每次抢红包, rpoplpush 原子操作 A POP 、 B PUSH ,执行发红包处理:若有失败, B lRem 、 A lPush ;若成功, B lRem 。
我们是小产品哈,并发其实没很高。 |
42
2owe 2016-11-24 21:58:12 +08:00
|
43
fhefh 2017-07-23 21:24:45 +08:00
先 mark 谢谢
|
44
nash 2017-12-01 10:46:35 +08:00
nginx 控制请求次数,超过的直接返静态页面,请求通过的统统给我到 REDIS 上面排队,进行二次过滤,这样万无一失了
|