Day 5:配置中心+热更新——模型换了不用重启
今天做什么
目前模型配置是硬编码的。想加一个新模型?改代码、重新编译、重新部署。今天引入配置中心 + 热更新——改配置文件,网关自动生效。
代码
go
package main
import (
"encoding/json"
"os"
"sync"
"sync/atomic"
"time"
"github.com/fsnotify/fsnotify"
)
// ===== 配置定义 =====
type GatewayConfig struct {
Models []ModelConfig `json:"models"`
RateLimit RateLimitConfig `json:"rate_limit"`
CircuitBreaker CircuitBreakerConfig `json:"circuit_breaker"`
}
type ModelConfig struct {
Name string `json:"name"`
URL string `json:"url"`
APIKey string `json:"api_key,omitempty"`
Cost float64 `json:"cost"`
Priority int `json:"priority"` // 优先级,越小越优先
}
// ===== 热更新配置管理器 =====
type ConfigManager struct {
config atomic.Value // *GatewayConfig
mu sync.RWMutex
path string
}
func NewConfigManager(path string) (*ConfigManager, error) {
cm := &ConfigManager{path: path}
// 首次加载
if err := cm.load(); err != nil {
return nil, err
}
// 监听文件变化
go cm.watch()
return cm, nil
}
func (cm *ConfigManager) load() error {
data, err := os.ReadFile(cm.path)
if err != nil {
return err
}
var cfg GatewayConfig
if err := json.Unmarshal(data, &cfg); err != nil {
return err
}
cm.config.Store(&cfg)
log.Printf("✅ 配置已加载:%d 个模型", len(cfg.Models))
return nil
}
func (cm *ConfigManager) Get() *GatewayConfig {
return cm.config.Load().(*GatewayConfig)
}
// 监听配置文件变化
func (cm *ConfigManager) watch() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
watcher.Add(cm.path)
// 防抖:1秒内的多次变化合并
var debounceTimer *time.Timer
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
if debounceTimer != nil {
debounceTimer.Stop()
}
debounceTimer = time.AfterFunc(1*time.Second, func() {
if err := cm.load(); err != nil {
log.Printf("❌ 配置加载失败: %v", err)
} else {
log.Println("🔄 配置已热更新")
}
})
}
}
}
}
// ===== 基于配置的路由 =====
func (g *Gateway) buildRouter() *ModelRouter {
cfg := g.configManager.Get()
router := NewRouter()
for _, m := range cfg.Models {
router.AddModel(m.Name, &ModelEndpoint{
URL: m.URL,
APIKey: os.ExpandEnv(m.APIKey), // 支持 ${ENV_VAR}
Cost: m.Cost,
})
}
// 按优先级排序路由
router.SortByPriority()
return router
}
// 配置文件示例 gateway.json
const defaultConfig = `{
"models": [
{"name": "gpt-3.5", "url": "https://api.openai.com/v1",
"api_key": "$OPENAI_API_KEY", "cost": 0.0015, "priority": 2},
{"name": "gpt-4o", "url": "https://api.openai.com/v1",
"api_key": "$OPENAI_API_KEY", "cost": 0.03, "priority": 1},
{"name": "doubao", "url": "https://ark.cn-beijing.volces.com/api/v3",
"api_key": "$DOUBAO_API_KEY", "cost": 0.0008, "priority": 0}
],
"rate_limit": {"requests_per_second": 100, "burst": 200},
"circuit_breaker": {"failure_threshold": 10, "cooldown_seconds": 30}
}`运行
bash
echo "$defaultConfig" > gateway.json
go run main.go -config gateway.json
# 修改 gateway.json,增加一个新模型——网关自动生效
# 不需要重启 ❌ ./agent ✅Day 5 完成。改配置不用重启了。

