登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis CLIENT INFO 怎样读取当前连接的数据库与网络地址

来源:17golang原创

时间:2026-11-13 13:25:05 100浏览 收藏

排查 Redis 连接时,经常会遇到两个看似简单的问题:这条连接当前选中了哪个逻辑库?它究竟从哪个客户端地址连进来?直接执行 CLIENT INFO 就能回答这两个问题。它返回的是发出这条命令的当前客户端,其中 db 是当前数据库编号,addr 是客户端地址,laddr 是 Redis 接收这条连接时使用的本地地址。

官方文档:https://redis.io/docs/latest/commands/client-info/

本文只讨论当前连接的字段读取,不把它扩展成全实例连接治理。要查看所有客户端,才考虑 CLIENT LIST。

前置条件:先把“当前连接”限定清楚

CLIENT INFO 从 Redis 6.2.0 开始提供,复杂度为 O(1),返回格式与 CLIENT LIST 的单条客户端信息一致,但内容只属于当前客户端。因此,同一个 Redis 实例上,不同连接执行这条命令,看到的 db、addr 和 name 可能不同。

这里有三个字段最值得先记住:

字段含义排查时看什么
db当前连接选中的逻辑数据库编号确认命令是否落在预期的 DB
addr客户端的地址和端口识别是哪台应用或代理建立了连接
laddrRedis 侧接收连接的本地地址和端口判断连接命中了哪个监听地址

Redis 的逻辑库状态属于连接本身。新连接默认使用数据库 0;如果连接执行过 SELECT 3,随后读取到的 db 就应当是 3。重连后客户端需要重新选择数据库,不能把旧连接的状态当成新连接的状态。

用 redis-cli 读取 db 与网络地址

先让 redis-cli 在目标逻辑库上建立连接,再执行 CLIENT INFO。下面的 -n 3 只影响这一次 CLI 连接,不会修改其他客户端。

# 让这条 CLI 连接先进入逻辑库 3,再读取它自己的连接信息
redis-cli -h 127.0.0.1 -p 6379 -n 3 CLIENT INFO

返回结果通常是一行以空格分隔的 key=value 字段。示例中只保留与本文有关的字段,实际 Redis 还可能返回客户端 ID、空闲时间、协议版本和客户端库信息:

id=17 addr=192.0.2.24:48152 laddr=192.0.2.10:6379 db=3 name=worker-a

读这行结果时按下面的顺序判断:

  1. db=3 表示当前这条连接正在使用逻辑库 3,不代表实例只有 3 个库。
  2. addr=192.0.2.24:48152 是 Redis 看到的客户端端点;经过 NAT 或代理时,它可能不是应用进程的真实内网地址。
  3. laddr=192.0.2.10:6379 是 Redis 这一侧被连接的本地端点,可用于判断多网卡或多监听地址场景。
Redis CLIENT INFO 当前连接字段与地址边界的结构说明图
图1:结构说明图,展示当前连接、db、addr 与 laddr 的字段归属;这是静态说明图,不是 Redis 控制台截图。

在 Go 程序中解析关键字段

程序化读取时不要按字段位置切片,因为 Redis 后续可能增加新的 key=value 字段。更稳妥的方式是按空白拆分,再按键名提取目标值;未知字段直接跳过。

package main

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"github.com/redis/go-redis/v9"
)

// ClientFields 只保留排查当前连接所需的字段。
type ClientFields struct {
	ID    int64
	Addr  string
	LAddr string
	DB    int
}

// parseClientInfo 按 key=value 解析,忽略 Redis 新增的未知字段。
func parseClientInfo(raw string) (ClientFields, error) {
	var info ClientFields
	for _, token := range strings.Fields(raw) {
		key, value, ok := strings.Cut(token, "=")
		if !ok {
			continue
		}
		switch key {
		case "id":
			id, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return info, fmt.Errorf("解析 id 失败: %w", err)
			}
			info.ID = id
		case "addr":
			info.Addr = value
		case "laddr":
			info.LAddr = value
		case "db":
			db, err := strconv.Atoi(value)
			if err != nil {
				return info, fmt.Errorf("解析 db 失败: %w", err)
			}
			info.DB = db
		}
	}
	return info, nil
}

func main() {
	ctx := context.Background()
	// DB=3 让这条连接从逻辑库 3 开始,连接池重建时也会重新应用它。
	client := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379", DB: 3})
	defer client.Close() // 示例结束时释放连接池资源。

	raw, err := client.Do(ctx, "CLIENT", "INFO").Text()
	if err != nil {
		panic(fmt.Errorf("读取 CLIENT INFO 失败: %w", err))
	}
	info, err := parseClientInfo(raw)
	if err != nil {
		panic(err)
	}
	fmt.Printf("db=%d addr=%s laddr=%s id=%d\n", info.DB, info.Addr, info.LAddr, info.ID)
}

这个示例的关键点有两个:一是命令通过同一个客户端连接发出,所以 db 对应的正是该连接;二是解析器只依赖字段名,不依赖返回字段顺序。生产代码可以把 panic 换成日志或上层错误返回,并对空地址、负数据库编号做业务级处理。

Go 客户端解析 Redis CLIENT INFO 字段并保留未知字段的结构说明图
图2:结构说明图,展示 Go 客户端、CLIENT INFO 字符串和字段解析结果之间的关系;这是代码结构示意,不是运行截图。

看到结果后怎样判断

如果你只想确认当前连接是否进了正确的逻辑库,优先看 db;如果要定位来源客户端,看 addr,同时结合应用连接池或代理日志;如果 Redis 有多个监听地址,则把 laddr 作为服务端接入点来对照。

不要用 CLIENT INFO 推断全实例连接数量。它只返回当前客户端;全量连接、按类型筛选或按客户端 ID 查询属于 CLIENT LIST 的范围。也不要把 addr 当成稳定的应用身份:端口通常是临时端口,代理、NAT 和容器网络都会改变可见地址。

另一个常见边界是 Redis Cluster。官方文档说明 Cluster 只支持数据库 0,不能依赖 SELECT 切换多库;这时 db=0 是正常结果,业务隔离应通过 key 命名或集群设计完成。

常见误区与总结

  • 把 db 当实例配置:它描述的是当前连接状态,换连接或重连后要重新确认。
  • 按固定位置解析:返回字段可能扩展,应按键名提取并忽略未知字段。
  • 把 addr 当真实主机:它是 Redis 侧看到的端点,经过代理时只能作为连接线索。
  • 拿 CLIENT INFO 做全量巡检:当前连接诊断与全实例连接列表是两个不同问题。

最小结论可以记成一句话:CLIENT INFO 看当前连接,db 看它选中的逻辑库,addr 看客户端端点,laddr 看 Redis 本地接入端点;需要全部客户端时再切换到 CLIENT LIST。

相关问题

CLIENT INFO 和 CLIENT LIST 有什么区别?

CLIENT INFO 只返回发出命令的当前客户端;CLIENT LIST 返回连接列表,并支持按类型或客户端 ID 过滤。

为什么重连后 db 又变成 0?

数据库选择属于连接状态,新连接默认使用数据库 0。连接池重建连接时,要在客户端配置中设置目标 DB,或在连接建立后重新执行选择逻辑。

addr 能直接对应到业务机器吗?

不一定。没有代理和地址转换时通常有帮助;存在 NAT、Sidecar 或代理时,它更适合作为 Redis 侧看到的网络线索。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>