2026-05-09 14:56:38 +08:00
2026-05-09 14:56:38 +08:00

@go/discover

Maintainer Statement: 本项目完全由 AI 维护。任何改动均遵循代码质量与性能的最佳实践。

@go/discover 是一个无状态、参数驱动的极简服务发现与负载均衡组件。它基于 Redis 实现,专注于消除微服务调用间的摩擦,并原生支持 Header 链路透传。

🎯 设计哲学

  • 纯粹无状态 (Stateless):模块自身不读取配置文件,不依赖任何特定框架的上下文。它是一个纯粹的函数式库,配置的加载权力完全交给顶层(如 @go/service)。
  • 面向对象隔离:支持多实例共存。你可以在同一个进程中同时连接不同的注册中心,实现复杂的网关分发。
  • 内存安全与高性能:敏感令牌 (Token) 受 @go/safe 内存保护;调用耗时由 @go/timer 高性能打点引擎追踪;网络层支持 H2C (HTTP/2 Cleartext)。

📦 安装

go get apigo.cc/go/discover

💡 快速入门 (Quick Start)

1. 服务端模式 (Server)

如果你是一个需要被别人发现的服务,使用 Start

import "apigo.cc/go/discover"

// 可选配置
conf := discover.Config{
    Weight: 100,
    Calls: map[string]string{
        "auth-service": "1s:my-token", // 依赖外部 auth 服务超时1s附加令牌
    },
}

// 启动并注册 (注册中心地址, 我的服务名, 我的可访问地址, 可选配置)
d := discover.Start("redis://127.0.0.1:6379/15", "user-service", "198.18.0.1:8080", conf)
defer d.Stop() // 优雅注销

2. 纯客户端模式 (Client)

如果你只是一个脚本或 API 网关,只需要调用别人,使用 Open

// 启动纯客户端 (注册中心地址, 可选配置)
d := discover.Open("redis://127.0.0.1:6379/15")

🛠 API Reference (实例方法)

StartOpen 均会返回一个 *discover.Discoverer 实例,所有的业务调用都应通过此实例进行。

1. 泛型快捷调用 (Stateless Data Fetching)

自动解析 JSON 响应到结构体,适用于绝大多数简单的 RPC 场景。

type User struct { ID int }

// Get[T] / Post[T] / Put[T] / Delete[T]
user, err := discover.Get[User](d, "user-service", "/api/info")

2. 链路透传调用 (Stateful Context Propagation)

在微服务网状网络中,我们需要将前置网关的 TraceID, UserID, X-Real-IP 等信息继续向后透传。使用 From(r) 包装器可以极其优雅地实现。

func MyHandler(w http.ResponseWriter, r *http.Request) {
    // d 假设是你的全局发现实例
    // From 会自动提取 r 中的上下文 Header 并发送给 user-service
    res := d.From(r).Post("user-service", "/create", reqData)
    
    // 或者结合泛型
    user, err := gohttp.To[User](d.From(r).Get("user-service", "/info"))
}

3. 直接获取结果 (Raw Result)

兼容 @go/http 模块的 *Result 对象,便于处理非 JSON 响应或检查原始 HTTP 状态码。

res := d.Do("GET", "auth-service", "/verify", nil)
if res.Error == nil {
    fmt.Println(res.String())
    // 也可以: res.Save("file.txt")
}

4. WebSocket 支持

无缝升级为 WebSocket 连接,支持跨服务的长连接代理。

// 返回 *websocket.Conn
ws := d.Open("chat-service", "/stream") 

5. 动态路由与负载管控

  • func (d *Discoverer) AddExternalApp(app, callConf string) bool: 在运行时动态添加一个新的下游依赖服务。
  • func (d *Discoverer) SetNode(app, addr string, weight int): 手动硬编码设置节点信息(常用于本地 Mock 测试或灰度引流)。
  • func (d *Discoverer) SetLoadBalancer(lb LoadBalancer): 自定义复杂负载均衡算法。
  • func (d *Discoverer) SetRoute(route func(ac *AppClient, r *http.Request)): 设置请求的拦截/重写路由规则。

⚙️ Config 配置结构详解

作为 StartOpen 的最后一个可选参数:

type Config struct {
	Weight         int               // 权重,默认为 100
	Calls          map[string]string // 提前声明调用的下游服务及其参数 (格式:超时时间:Token:H2C开关)
	CallRetryTimes int               // 请求单个下游节点的最大失败重试次数 (默认 10)
	IpPrefix       string            // 在 EasyStart 模式下过滤并绑定指定网段的 IP
	Logger         *log.Logger       // 自定义日志接口
}

环境变量 (EasyStart 模式)

仅在使用 discover.EasyStart()(自动探测本地 IP 和随机端口启动)时,支持以下环境变量:

  • DISCOVER_LISTEN: 本地试探监听的端口。
Description
No description provided
Readme 235 KiB
Languages
Go 100%