redis slave 上的 info 命令列出的过期密钥数量与我所看到的不一致



当我在 redis 3.2.4 服务器上redis-cli运行info命令时,它向我显示了过期:

expires=223518

但是,当我运行keys *命令并询问每个键的ttl,并且只打印出 ttl> 0 的键时,我只看到几百个。

我以为expires是过期密钥数量的计数,但我什至不在这个数字的一个数量级内。

有人可以澄清expires到底要传达什么吗?这是否包括即将过期和以前过期但尚未逐出的密钥?


更新:

以下是我计算即将过期的密钥数量的方法:

task count_tmp_keys: :environment do
redis = Redis.new(timeout: 100)
keys = redis.keys '*'
ct_expiring = 0
keys.each do |k|
ttl = redis.ttl(k)
if ttl > 0
ct_expiring += 1
puts "Expiring: #{k}; ttl is #{ttl}; total: #{ct_expiring}"
STDOUT.flush
end
end
puts "Total expiring: #{ct_expiring}"
puts "Done at #{Time.now}"
end

当我运行此脚本时,它显示我的总到期时间为 78

当我运行信息时,它说db0:keys=10237963,expires=224098,avg_ttl=0

因为224098比78大得多,所以我很困惑。是否有更好的方法来获取所有 225k 即将过期的密钥的列表?

另外,我的平均 ttl 怎么是 0?你不希望它是非零的吗?


更新

我有新的信息和一个简单的,100%在本地重现这种情况!

重现:在笔记本电脑上本地设置两个 redis 进程。让一个人成为另一个人的奴隶。在从进程上,设置以下内容:

config set slave-serve-stale-data yes
config set slave-read-only no

现在,连接到从站(不是主站(并运行:

set foo 1
expire foo 10

10 秒后,您将无法再访问 foo,但info命令仍会显示您有 1 个密钥即将过期,平均 ttl 为 0。

有人可以解释这种行为吗?

expires包含TTL即将过期的现有密钥,不包括已经过期的密钥。 示例(为简洁起见,省略了info命令中的额外信息(:

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> SETEX mykey1 1000 "1"
OK
127.0.0.1:6379> SETEX mykey2 1000 "2"
OK
127.0.0.1:6379> SETEX mykey3 1000 "3"
OK
127.0.0.1:6379> info
# Keyspace
db0:keys=3,expires=3,avg_ttl=992766
127.0.0.1:6379> SETEX mykey4 1 "4"
OK
127.0.0.1:6379> SETEX mykey5 1 "5"
OK
127.0.0.1:6379> info
# Keyspace
db0:keys=3,expires=3,avg_ttl=969898
127.0.0.1:6379> keys *
1) "mykey2"
2) "mykey3"
3) "mykey1"
127.0.0.1:6379> 

鉴于在您的情况下,您正在询问奴隶的密钥到期时间,根据 https://github.com/antirez/redis/issues/2861:

从服务器上的密钥未主动过期,因此avg_ttl 从未计算过

根据 https://groups.google.com/forum/#!topic/redis-db/NFTpdmpOPnc:

avg_ttl永远不会在从属服务器上初始化,因此它可以是 任意值驻留在该位置的内存中。

因此,可以预期info命令在从服务器上的行为不同。

过期仅返回将过期的密钥的大小,而不是时间。

3.2.4 的源代码

long long keys, vkeys;
keys = dictSize(server.db[j].dict);
vkeys = dictSize(server.db[j].expires);
if (keys || vkeys) {
info = sdscatprintf(info,
"db%d:keys=%lld,expires=%lld,avg_ttl=%lldrn",
j, keys, vkeys, server.db[j].avg_ttl);
}

它只是计算server.db[j].expires的大小。(注意 j 是数据库索引(。

最新更新