在使用redis实现流量控制时,如何防止竞争情况?

2024-09-29 23:24:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我们有一个服务器,如果有太多的用户同时登录(意味着间隔不到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解决这个问题?在

我试过redispy pipeline功能,但当然,直到r.get()调用时,才获得实际值。。。在


Tags: 用户服务器redisget间隔timemy时间
1条回答
网友
1楼 · 发布于 2024-09-29 23:24:40

我会记录下答案以防其他人发现。。。在

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.

比原来的三行要复杂一点。。。在

相关问题 更多 >

    热门问题