我们的服务器如果有太多用户同时登录(即相隔不到 7 秒)就会变得暴躁。用户一旦登录就没有问题(一两个同时登录也不是问题,但是当尝试10-20次时整个服务器就会陷入死亡螺旋叹气) .
我正在尝试编写一个页面来吸引用户(显示动画倒计时等)并让他们间隔 7 秒。算法很简单
- 获取上次登录时的时间戳 (t)
- 如果
t+7
是过去的时间,则启动登录并将now()
存储为新时间戳 - 如果
t+7
是将来的时间,则将其存储为新时间戳,等到t+7
,然后开始登录。
一个直接的 python/redis 实现是:
import time, redis
SLOT_LENGTH = 7 # seconds
now = time.time()
r = redis.StrictRedis()
# lines below contain race condition..
last_start = float(r.get('FLOWCONTROL') or '0.0') # 0.0 == time-before-time
my_start = last_start + SLOT_LENGTH
r.set('FLOWCONTROL', max(my_start, now))
wait_period = max(0, my_start - now)
time.sleep(wait_period)
# .. login
这里的竞争条件很明显,许多进程可以同时位于 my_start =
行。如何使用redis解决这个问题?
我已经尝试了 redis-py pipeline
功能,但是当然直到在 r.get()
调用中才获得实际值。 .
最佳答案
我会记录答案,以防其他人发现这个......
r = redis.StrictRedis()
with r.pipeline() as p:
while 1:
try:
p.watch('FLOWCONTROL') # --> immediate mode
last_slot = float(p.get('FLOWCONTROL') or '0.0')
p.multi() # --> back to buffered mode
my_slot = last_slot + SLOT_LENGTH
p.set('FLOWCONTROL', max(my_slot, now))
p.execute() # raises WatchError if anyone changed TCTR-FLOWCONTROL
break # break out of while loop
except WatchError:
pass # someone else got there before us, retry.
比原来的三行稍微复杂一点...
关于python - 使用redis实现流控时如何防止race condition?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19732546/