redis - Redis 在行动 - 不公平的信号量
问题描述
我正在阅读Redis 中关于semaphores的行动电子书章节。这是使用redis实现信号量的python代码
def acquire_semaphore(conn, semname, limit, timeout=10):
identifier = str(uuid.uuid4())
now = time.time()
pipeline = conn.pipeline(True)
pipeline.zremrangebyscore(semname, '-inf', now - timeout)
pipeline.zadd(semname, identifier, now)
pipeline.zrank(semname, identifier)
if pipeline.execute()[-1] < limit:
return identifier
conn.zrem(semname, identifier)
return None
这个基本的信号量很好用——它很简单,而且速度很快。但是如果我们有多个主机,依靠每个进程都可以访问相同的系统时间来获取信号量可能会导致问题。对于我们的特定用例来说,这不是一个大问题,但是如果我们有两个系统 A 和 B,其中 A 的运行速度甚至比 B 快 10 毫秒,那么如果 A 获得最后一个信号量,而 B 试图在 10 内获得一个信号量毫秒,B 实际上会在 A 不知情的情况下“窃取”A 的信号量。
我没明白这是什么意思:如果A ran even 10 milliseconds faster than B
那么B would actually “steal” A’s semaphore without A knowing it.
我的想法:A 的时间是10:10:10:200
和 B 的时间10:10:10:190
和 A 有信号量。然后 B 尝试在 10 毫秒内获取信号量(现在 B 的本地时间是10:10:10:200
)。B 将删除过期的项目并添加其自身。B怎么能steal
得到A的信号量?同时,如果 A 的时间是10:59
B 的时间是11:02
B 可能因为时差而移除 A 的信号量。但这不是书中描述的情况。
解决方案
如果 B 比 A 慢 10 毫秒,那么 B 的分数小于 A,因为我们使用本地时间作为排序集的分数。
所以 B 的秩,即pipeline.zrank(semname, identifier)
小于 A 的秩,它小于limit
,即if pipeline.execute()[-1] < limit:
。B认为它得到了信号量,即return identifier
。事实上,它从 A那里窃取了信号量。
推荐阅读
- python - 如何在我的 python 包中正确组织我的模块导入?
- java - 多个Java对象中的Json反序列化
- ios - 为什么在我的代码中隐式解包 Optional 值时意外发现 nil?
- c++ - 如何在“.json”配置文件中包含 .dylib 文件?- Mac iOS 上的 VS Code - Clang++ 编译器 - 语言:c++
- python - 生成一个列表的列表,其元素来自另一个列表(Python)
- google-sheets - 三列范围及其总和的条件格式
- amazon-web-services - 如何在 Quicksight 中按百分比值分组
- batch-file - Bat文件帮助-尝试创建新文件夹-> copyAll->添加时间戳-测试数据管理
- docker - 使用 fluentd 日志记录驱动程序时停止 docker 容器生成日志
- javascript - 在测试中从 axios mock 获取请求参数