soulomoon/python-throttle
在假如多线程和多进程测试前一切都是好好的, 感觉好开心(^・ω・^ )
但是加入多线程,多进程测试后发现出现了 race condition😢
但是写的时候我已经好好地去尝试规避这个问题了,找不到原因😫
race condition 的问题出现在 test_limiter 中(;´༎ຶД༎ຶ`)
def add_key(self, key, expired):
"""use lua script to avoid race condition"""
multiply = self.redis.register_script(self.lua_incr)
return multiply([key, expired])
出现问题的地方在这儿0 - 0
不好意思 这个才是fixed windows的测试, 实际上,两种implementation都fail了
1
holyghost 2018-03-13 21:29:09 +08:00 via iPhone 1
手机上看的,看测试大概了解了思路,不成熟的想法
如果你真要这么做,用 incr 保证线程安全 另外,你没有考虑到滑动窗口的问题 最后 token bucket 了解下? |
2
soulomoon OP @holyghost
不好意思 我图放错了 0 0。 这里我有两种 implementaion, 一个用 ordered set, 一个用 incr 写在 luascript,redis 官方是这么推荐的 0。 都用 expire。 token bucket 要单开 put token 的进程吧? |
3
soulomoon OP ```python
lua_incr = """ local current current = redis.call("incr",KEYS[1]) if tonumber(current) == 1 then redis.call("expire",KEYS[1],KEYS[2]) end return current-1 """ ``` 这个是我改过的 lua script,原版的在[这里]( https://redis.io/commands/incr) |
4
holyghost 2018-03-13 22:18:54 +08:00
@soulomoon
我的理解,incr 不需要放在 lua script 里面来保证单线程吧? incr 本身是有返回值的, 比较下返回值和 threshold 应该就可以了 另外,粗略算的话,token bucket 不需要另外开进程,可以在消耗时顺便添加 token (当然了,这种实现需要带时间戳) |
5
soulomoon OP incr 放进去是为了和 expire 一起,保证 key 不会因为没有 set expire 而 leak @holyghost,现在我怀疑 redis-py run script 的特点,因为是通过 register 到远端,然后再通过 sha1 作为 key 执行,可能是多个 instance 同时执行了同一 script,获取到了相同的返回值。。。
还有一个 sliding log 的 implementaion,pipeline 看 redis-py 的简介 0 0 理论上是一个 multi exce 的行为,0 0, 也是 fail。这样的: def add_key(self, key, expired): """use ordered set for counting keys get_set manner """ now = time.time() with self.redis.pipeline() as session: session.zremrangebyscore(key, 0, now - expired) session.zrange(key, 0, -1) session.zadd(key, now, uuid.uuid4().hex) session.expire(key, expired) result = session.execute() return len(result[1]) |
6
soulomoon OP *多个 instance 接受了同一个 script 的执行结果。。
|
7
soulomoon OP 发现即使是简单如
def add_key(self, key, expired): return self.redis.incr(key) 也会有同样的问题 who's to blame.... |
8
soulomoon OP 发现问题了, 是我写 unittest 的问题,interleaving 多个不同时限的 limiter 到相同的 key 中,当然会出现不同的结果 ozn
好开心解决了,原来不是我 implementaion 的问题是我的测试的问题,看来要好好学习测试, 最后谢谢 @holyghost 的回答。 |