我是 Redis 的新手,正在阅读 <Redis in Action > 一书,在第 2.1 节(“登录和 cookie 缓存”)中有一个clean_sessions函数:
QUIT = False
LIMIT = 10000000
def clean_session:
while not QUIT:
size = conn.zcard('recent:')
if size <= LIMIT:
time.sleep(1)
continue
# find out the range in `recent:` ZSET
end_index = min(size-LIMIT, 100)
tokens = conn.zrange('recent:', 0, end_index-1)
# delete corresponding data
session_keys = []
for token in tokens:
session_keys.append('viewed:' + token)
conn.delete(*session_keys)
conn.hdel('login:', *tokens)
conn.zrem('recent:', *tokens)
Run Code Online (Sandbox Code Playgroud)
如果超过1000万条记录,它会删除登录令牌和相应的数据,问题是:
为什么每次最多删除 100 条记录?
为什么不立即删除size - LIMIT记录?
是否有一些性能考虑?
谢谢,感谢所有回复:)
我想这个选择有多种原因。
Redis 是一个单线程事件循环。这意味着大命令(例如大 zrange,或大 del、hdel 或 zrem)的处理速度将比几个小命令快,但会影响其他会话的延迟。如果一个大命令需要一秒钟来执行,那么所有访问 Redis 的客户端也将被阻止一秒钟。
因此,第一个原因是尽量减少这些清理操作对其他客户端进程的影响。通过将活动分割成几个小命令,它也为其他客户端提供了执行他们的命令的机会。
第二个原因是 Redis 服务器中通信缓冲区的大小。大命令(或大回复)可能会占用大量内存。如果要清除数百万个项目,lrange 命令的回复或del、hdel、zrem 命令的输入可以表示兆字节的数据。超过一定限制,Redis 将关闭连接以保护自己。所以最好避免处理非常大的命令或非常大的回复。
第三个原因是 Python 客户端的内存。如果必须清除数百万个项目,Python 将不得不维护非常大的列表对象(令牌和 session_keys)。它们可能适合也可能不适合内存。
建议的解决方案是增量式的:无论要删除多少项,都将避免在客户端和 Redis 端消耗大量内存。它也将避免达到通信缓冲区限制(导致连接被关闭),并将限制对访问 Redis 的其他进程的性能的影响。
请注意,100 值是任意的。较小的值将以较低的会话清理吞吐量为代价获得更好的延迟。更大的值将以更高的延迟为代价增加清理算法的吞吐量。
它实际上是清理算法的吞吐量和其他操作的延迟之间的经典权衡。
| 归档时间: |
|
| 查看次数: |
2027 次 |
| 最近记录: |