python - 使用redis实现流控时如何防止race condition?

标签 python redis redis-py

我们的服务器如果有太多用户同时登录(即相隔不到 7 秒)就会变得暴躁。用户一旦登录就没有问题(一两个同时登录也不是问题,但是当尝试10-20次时整个服务器就会陷入死亡螺旋叹气) .

我正在尝试编写一个页面来吸引用户(显示动画倒计时等)并让他们间隔 7 秒。算法很简单

  1. 获取上次登录时的时间戳 (t)
  2. 如果 t+7 是过去的时间,则启动登录并将 now() 存储为新时间戳
  3. 如果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/

相关文章:

Redis HSCAN 多重匹配

python - 如何将 torch.tensor 或 np.array 保存到 redis 并搜索向量相似度?

python - get 上的 Redis 通配符键

python - pycharm recnoizes 导入但仍然 ValueError : Attempted relative import beyond toplevel package django project on make migrations

java - Java Collections Framework 的 Python 等价物是什么?

python - 查找二维 numpy 数组的相对最大值

redis - 如何使用 ReJSON 设置嵌套值(对象)

ruby-on-rails - Resque: worker 状态不对

python - python opencv错误找到轮廓

python - 使用 Python 在 Redis 中增加哈希字段的值