Go Redis 扫描所有Key
遍历 Key
使用 KEYS prefix:*
命令可以遍历前缀为 prefix 的所有 key,但如果 redis 中有上百万或更多的 key,会变得非常慢。
go-redis 提供了 SCAN 来迭代遍历前缀为 prefix 的 key:
var cursor uint64
for {
var keys []string
var err error
keys, cursor, err = rdb.Scan(ctx, cursor, "prefix:*", 0).Result()
if err != nil {
panic(err)
}
for _, key := range keys {
fmt.Println("key", key)
}
// 没有更多key了
if cursor == 0 {
break
}
}
上面的代码也可以简化成:
iter := rdb.Scan(ctx, 0, "prefix:*", 0).Iterator()
for iter.Next(ctx) {
fmt.Println("keys", iter.Val())
}
if err := iter.Err(); err != nil {
panic(err)
}
集合和哈希类型
你可以使用 iterate
来迭代 redis 集合:
iter := rdb.SScan(ctx, "set-key", 0, "prefix:*", 0).Iterator()
哈希类型:
iter := rdb.HScan(ctx, "hash-key", 0, "prefix:*", 0).Iterator()
iter := rdb.ZScan(ctx, "sorted-hash-key", 0, "prefix:*", 0).Iterator()
Cluster 和 Ring
如果你使用的是 Redis Cluster 或 Redis Ring,需要分别扫描集群每个节点:
err := rdb.ForEachMaster(ctx, func(ctx context.Context, rdb *redis.Client) error {
iter := rdb.Scan(ctx, 0, "prefix:*", 0).Iterator()
...
return iter.Err()
})
if err != nil {
panic(err)
}
删除无过期时间的 Key
你可以使用 SCAN
删除没有 TTL 的 key:
iter := rdb.Scan(ctx, 0, "", 0).Iterator()
for iter.Next(ctx) {
key := iter.Val()
d, err := rdb.TTL(ctx, key).Result()
if err != nil {
panic(err)
}
if d == -1 { // -1 means no TTL
if err := rdb.Del(ctx, key).Err(); err != nil {
panic(err)
}
}
}
if err := iter.Err(); err != nil {
panic(err)
}
你也可以使用管道提高效率,请参见 示例