discover/README.md

124 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# @go/discover
> **Maintainer Statement:** 本项目完全由 AI 维护。任何改动均遵循代码质量与性能的最佳实践。
`@go/discover` 是一个**无状态、参数驱动**的极简服务发现与负载均衡组件。它基于 Redis 实现,专注于消除微服务调用间的摩擦,并原生支持 Header 链路透传。
## 🎯 设计哲学
- **纯粹无状态 (Stateless)**:模块自身不读取配置文件,不依赖任何特定框架的上下文。它是一个纯粹的函数式库,配置的加载权力完全交给顶层(如 `@go/service`)。
- **面向对象隔离**:支持多实例共存。你可以在同一个进程中同时连接不同的注册中心,实现复杂的网关分发。
- **内存安全与高性能**:敏感令牌 (Token) 受 `@go/safe` 内存保护;调用耗时由 `@go/timer` 高性能打点引擎追踪;网络层支持 H2C (HTTP/2 Cleartext)。
## 📦 安装
```bash
go get apigo.cc/go/discover
```
## 💡 快速入门 (Quick Start)
### 1. 服务端模式 (Server)
如果你是一个需要被别人发现的服务,使用 `Start`
```go
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`
```go
// 启动纯客户端 (注册中心地址, 可选配置)
d := discover.Open("redis://127.0.0.1:6379/15")
```
---
## 🛠 API Reference (实例方法)
`Start``Open` 均会返回一个 `*discover.Discoverer` 实例,所有的业务调用都应通过此实例进行。
### 1. 泛型快捷调用 (Stateless Data Fetching)
自动解析 JSON 响应到结构体,适用于绝大多数简单的 RPC 场景。
```go
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)` 包装器可以极其优雅地实现。
```go
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 状态码。
```go
res := d.Do("GET", "auth-service", "/verify", nil)
if res.Error == nil {
fmt.Println(res.String())
// 也可以: res.Save("file.txt")
}
```
### 4. WebSocket 支持
无缝升级为 WebSocket 连接,支持跨服务的长连接代理。
```go
// 返回 *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 配置结构详解
作为 `Start``Open` 的最后一个可选参数:
```go
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`: 本地试探监听的端口。