繁体   English   中英

使用 Sanic 和 Redis 出现问题

[英]Trouble using Sanic and Redis

我正在与 2 名工人一起使用 Sanic。 我正在尝试使计费系统正常工作,即计算用户点击 API 端点的次数。 以下是我的代码:

class User(object):
    def __init__(self, id, name, age, address, mobile, credits=0):
        self.id = id
        self.name = name
        self.credits = count
        self.details = {"age": age, "address": address, "mobile_number": mobile}

上面的用户 Class 用于制作我使用另一个 python 脚本上传到 Redis 的对象,如下所示:

user = User(..., credits = 10)
string_obj = json.dumps(user)
root.set(f"{user.user_id}", string_obj)

当我想维护端点接收的命中数并使用用户 object 跟踪它并将其上传回 Redis 时,就会出现主要问题。 我的代码如下:

from sanic_redis_ext import RedisExtension

app = Sanic("Testing")
app.config.update(
{
    "REDIS_HOST": "127.0.0.1",
    "REDIS_PORT": 6379,
    "REDIS_DATABASE": 0,
    "REDIS_SSL": None,
    "REDIS_ENCODING": "utf-8",
    "REDIS_MIN_SIZE_POOL": 1,
    "REDIS_MAX_SIZE_POOL": 10,
})

@app.route("/test", methods=["POST"])
@inject_user()
@protected()
async def foo(request, user):
    user.credits -= 1
    if user.credits < 0:
        user.credits = 0
        return sanic.response.text("Credits Exhausted")

    result = process(request)

    if not result:
        user.credits += 1

    await app.redis.set(f"{user.user_id}", json.dumps(user))
    return sanic.response.text(result)

这就是我检索用户的方式:

async def retrieve_user(request, *args, **kwargs):
    if "user_id" in kwargs:
        user_id = kwargs.get("user_id")
    else:
        if "payload" in kwargs:
            payload = kwargs.get("payload")
        else:
            payload = await request.app.auth.extract_payload(request)
        if not payload:
            raise exceptions.MissingAuthorizationHeader()
        user_id = payload.get("user_id")

    user = json.loads(await app.redis.get(user_id))
    return user

当我使用 JMeter 以 10 个线程作为同一用户测试 API 端点时,信用系统似乎不起作用。 在这种情况下,当用户从 10 个积分开始时,他们最终可能会剩下 7 或 8 个(不可预测)积分,而他们应该还剩下 0 个积分。 据我说,这是由于工作人员没有共享用户 object 并且没有变量的更新副本,这导致他们覆盖彼此的更新。 谁能帮我找到解决方法,这样即使同一个用户同时点击端点,他/她也应该被完美计费,用户 object 应该被保存回 Redis。

问题是您从 Redis 中读取了 credits 信息,将其扣除,然后将其保存回 Redis,这不是原子过程。 这是一个并发问题。

我不知道 Python,所以我将使用伪代码。

首先为用户 {user_id} 设置 10 个积分。

app.redis.set("{user_id}:credits", 10)

然后这个用户进来了

# deduct 1 from the user credits and get the result
int remaining_credits=app.redis.incryBy ("{user_id}:credits",-1) 
if(remaining_credits<=0){
   return sanic.response.text("Credits Exhausted")} else{
   return "sucess" # or some other result}

将您的用户信息与有效负载一起保存在其他地方并检索“{user_id}:credits”并在您检索用户时将它们组合起来。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM