整体性能优化

This commit is contained in:
user123456
2025-06-13 11:55:53 +08:00
parent 018a8235e2
commit 8f4fa093c9
6 changed files with 111 additions and 43 deletions

View File

@@ -63,6 +63,12 @@ var (
appConfigLock sync.RWMutex appConfigLock sync.RWMutex
isViperEnabled bool isViperEnabled bool
viperInstance *viper.Viper viperInstance *viper.Viper
// ✅ 配置缓存变量
cachedConfig *AppConfig
configCacheTime time.Time
configCacheTTL = 5 * time.Second
configCacheMutex sync.RWMutex
) )
// DefaultConfig 返回默认配置 // DefaultConfig 返回默认配置
@@ -141,21 +147,45 @@ func DefaultConfig() *AppConfig {
// GetConfig 安全地获取配置副本 // GetConfig 安全地获取配置副本
func GetConfig() *AppConfig { func GetConfig() *AppConfig {
appConfigLock.RLock() // ✅ 快速缓存检查,减少深拷贝开销
defer appConfigLock.RUnlock() configCacheMutex.RLock()
if cachedConfig != nil && time.Since(configCacheTime) < configCacheTTL {
config := cachedConfig
configCacheMutex.RUnlock()
return config
}
configCacheMutex.RUnlock()
if appConfig == nil { // 缓存过期,重新生成配置
return DefaultConfig() configCacheMutex.Lock()
defer configCacheMutex.Unlock()
// 双重检查,防止重复生成
if cachedConfig != nil && time.Since(configCacheTime) < configCacheTTL {
return cachedConfig
} }
// 返回配置的深拷贝 appConfigLock.RLock()
if appConfig == nil {
appConfigLock.RUnlock()
defaultCfg := DefaultConfig()
cachedConfig = defaultCfg
configCacheTime = time.Now()
return defaultCfg
}
// 生成新的配置深拷贝
configCopy := *appConfig configCopy := *appConfig
configCopy.Security.WhiteList = append([]string(nil), appConfig.Security.WhiteList...) configCopy.Security.WhiteList = append([]string(nil), appConfig.Security.WhiteList...)
configCopy.Security.BlackList = append([]string(nil), appConfig.Security.BlackList...) configCopy.Security.BlackList = append([]string(nil), appConfig.Security.BlackList...)
configCopy.Proxy.WhiteList = append([]string(nil), appConfig.Proxy.WhiteList...) configCopy.Proxy.WhiteList = append([]string(nil), appConfig.Proxy.WhiteList...)
configCopy.Proxy.BlackList = append([]string(nil), appConfig.Proxy.BlackList...) configCopy.Proxy.BlackList = append([]string(nil), appConfig.Proxy.BlackList...)
appConfigLock.RUnlock()
return &configCopy cachedConfig = &configCopy
configCacheTime = time.Now()
return cachedConfig
} }
// setConfig 安全地设置配置 // setConfig 安全地设置配置
@@ -163,6 +193,11 @@ func setConfig(cfg *AppConfig) {
appConfigLock.Lock() appConfigLock.Lock()
defer appConfigLock.Unlock() defer appConfigLock.Unlock()
appConfig = cfg appConfig = cfg
// ✅ 配置更新时清除缓存
configCacheMutex.Lock()
cachedConfig = nil
configCacheMutex.Unlock()
} }
// LoadConfig 加载配置文件 // LoadConfig 加载配置文件
@@ -190,9 +225,7 @@ func LoadConfig() error {
go enableViperHotReload() go enableViperHotReload()
} }
fmt.Printf("配置加载成功: 监听 %s:%d, 文件大小限制 %d MB, 限流 %d请求/%g小时, 离线镜像并发数 %d\n", // 配置加载成功,详细信息在启动时统一显示
cfg.Server.Host, cfg.Server.Port, cfg.Server.FileSize/(1024*1024),
cfg.RateLimit.RequestLimit, cfg.RateLimit.PeriodHours, cfg.Download.MaxImages)
return nil return nil
} }
@@ -218,7 +251,7 @@ func enableViperHotReload() {
} }
isViperEnabled = true isViperEnabled = true
fmt.Println("热重载已启用") // 热重载已启用,不显示额外信息
// 🚀 启用文件监听 // 🚀 启用文件监听
viperInstance.WatchConfig() viperInstance.WatchConfig()

View File

@@ -79,7 +79,7 @@ func initDockerProxy() {
options: options, options: options,
} }
fmt.Printf("Docker代理初始化\n") // Docker代理初始化完成
} }
// ProxyDockerRegistryGin 标准Docker Registry API v2代理 // ProxyDockerRegistryGin 标准Docker Registry API v2代理

View File

@@ -10,6 +10,7 @@ import (
"log" "log"
"net/http" "net/http"
"strings" "strings"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn"
@@ -525,8 +526,7 @@ var globalImageStreamer *ImageStreamer
// initImageStreamer 初始化镜像下载器 // initImageStreamer 初始化镜像下载器
func initImageStreamer() { func initImageStreamer() {
globalImageStreamer = NewImageStreamer(nil) globalImageStreamer = NewImageStreamer(nil)
log.Printf("镜像下载器初始化完成,并发数: %d缓存: %v", // 镜像下载器初始化完成
globalImageStreamer.concurrency, isCacheEnabled())
} }
// formatPlatformText 格式化平台文本 // formatPlatformText 格式化平台文本
@@ -724,7 +724,11 @@ func (is *ImageStreamer) StreamMultipleImages(ctx context.Context, imageRefs []s
log.Printf("处理镜像 %d/%d: %s", i+1, len(imageRefs), imageRef) log.Printf("处理镜像 %d/%d: %s", i+1, len(imageRefs), imageRef)
manifest, repositories, err := is.streamSingleImageForBatch(ctx, tarWriter, imageRef, options) // ✅ 添加超时保护,防止单个镜像处理时间过长
timeoutCtx, cancel := context.WithTimeout(ctx, 15*time.Minute)
manifest, repositories, err := is.streamSingleImageForBatch(timeoutCtx, tarWriter, imageRef, options)
cancel()
if err != nil { if err != nil {
log.Printf("下载镜像 %s 失败: %v", imageRef, err) log.Printf("下载镜像 %s 失败: %v", imageRef, err)
return fmt.Errorf("下载镜像 %s 失败: %w", imageRef, err) return fmt.Errorf("下载镜像 %s 失败: %w", imageRef, err)

View File

@@ -3,12 +3,14 @@ package main
import ( import (
"embed" "embed"
"fmt" "fmt"
"github.com/gin-gonic/gin"
"io" "io"
"log"
"net/http" "net/http"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/gin-gonic/gin"
) )
//go:embed public/* //go:embed public/*
@@ -66,6 +68,15 @@ func main() {
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
router := gin.Default() router := gin.Default()
// ✅ 添加全局Panic恢复保护
router.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
log.Printf("🚨 Panic recovered: %v", recovered)
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Internal server error",
"code": "INTERNAL_ERROR",
})
}))
// 初始化镜像tar下载路由 // 初始化镜像tar下载路由
initImageTarRoutes(router) initImageTarRoutes(router)
@@ -103,7 +114,10 @@ func main() {
router.NoRoute(RateLimitMiddleware(globalLimiter), handler) router.NoRoute(RateLimitMiddleware(globalLimiter), handler)
cfg := GetConfig() cfg := GetConfig()
fmt.Printf("启动成功项目地址https://github.com/sky22333/hubproxy \n") fmt.Printf("🚀 HubProxy 启动成功\n")
fmt.Printf("📡 监听地址: %s:%d\n", cfg.Server.Host, cfg.Server.Port)
fmt.Printf("⚡ 限流配置: %d请求/%g小时\n", cfg.RateLimit.RequestLimit, cfg.RateLimit.PeriodHours)
fmt.Printf("🔗 项目地址: https://github.com/sky22333/hubproxy\n")
err := router.Run(fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)) err := router.Run(fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port))
if err != nil { if err != nil {

View File

@@ -92,8 +92,7 @@ func initGlobalLimiter() *IPRateLimiter {
// 启动定期清理goroutine // 启动定期清理goroutine
go limiter.cleanupRoutine() go limiter.cleanupRoutine()
fmt.Printf("限流器初始化: %d请求/%g小时, 白名单 %d个, 黑名单 %d个\n", // 限流器初始化完成,详细信息在启动时统一显示
cfg.RateLimit.RequestLimit, cfg.RateLimit.PeriodHours, len(whitelist), len(blacklist))
return limiter return limiter
} }
@@ -189,29 +188,40 @@ func (i *IPRateLimiter) GetLimiter(ip string) (*rate.Limiter, bool) {
return rate.NewLimiter(rate.Inf, i.b), true // 白名单中的IP不受限制 return rate.NewLimiter(rate.Inf, i.b), true // 白名单中的IP不受限制
} }
// 使用纯IP作为缓存键 now := time.Now()
// ✅ 双重检查锁定,解决竞态条件
i.mu.RLock() i.mu.RLock()
entry, exists := i.ips[cleanIP] entry, exists := i.ips[cleanIP]
i.mu.RUnlock() i.mu.RUnlock()
now := time.Now() if exists {
// 安全更新访问时间
if !exists {
// 创建新的限流器
i.mu.Lock() i.mu.Lock()
entry = &rateLimiterEntry{ if entry, stillExists := i.ips[cleanIP]; stillExists {
limiter: rate.NewLimiter(i.r, i.b), entry.lastAccess = now
lastAccess: now, i.mu.Unlock()
return entry.limiter, true
} }
i.ips[cleanIP] = entry
i.mu.Unlock()
} else {
// 更新最后访问时间
i.mu.Lock()
entry.lastAccess = now
i.mu.Unlock() i.mu.Unlock()
} }
// 创建新条目时的双重检查
i.mu.Lock()
if entry, exists := i.ips[cleanIP]; exists {
entry.lastAccess = now
i.mu.Unlock()
return entry.limiter, true
}
// 创建新条目
entry = &rateLimiterEntry{
limiter: rate.NewLimiter(i.r, i.b),
lastAccess: now,
}
i.ips[cleanIP] = entry
i.mu.Unlock()
return entry.limiter, true return entry.limiter, true
} }

View File

@@ -114,22 +114,29 @@ func (c *Cache) Set(key string, data interface{}) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
// 如果缓存已满,删除最旧的条目 // ✅ 先清理过期项,防止内存泄漏
if len(c.data) >= c.maxSize { now := time.Now()
oldest := time.Now() for k, v := range c.data {
var oldestKey string if now.Sub(v.timestamp) > cacheTTL {
for k, v := range c.data { delete(c.data, k)
if v.timestamp.Before(oldest) { }
oldest = v.timestamp }
oldestKey = k
} // 如果清理后仍然超限,批量删除最旧的条目
if len(c.data) >= c.maxSize {
toDelete := len(c.data) / 4 // 删除25%最旧的
for k := range c.data {
if toDelete <= 0 {
break
}
delete(c.data, k)
toDelete--
} }
delete(c.data, oldestKey)
} }
c.data[key] = cacheEntry{ c.data[key] = cacheEntry{
data: data, data: data,
timestamp: time.Now(), timestamp: now,
} }
} }