整体性能优化

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
isViperEnabled bool
viperInstance *viper.Viper
// ✅ 配置缓存变量
cachedConfig *AppConfig
configCacheTime time.Time
configCacheTTL = 5 * time.Second
configCacheMutex sync.RWMutex
)
// DefaultConfig 返回默认配置
@@ -141,21 +147,45 @@ func DefaultConfig() *AppConfig {
// GetConfig 安全地获取配置副本
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.Security.WhiteList = append([]string(nil), appConfig.Security.WhiteList...)
configCopy.Security.BlackList = append([]string(nil), appConfig.Security.BlackList...)
configCopy.Proxy.WhiteList = append([]string(nil), appConfig.Proxy.WhiteList...)
configCopy.Proxy.BlackList = append([]string(nil), appConfig.Proxy.BlackList...)
appConfigLock.RUnlock()
return &configCopy
cachedConfig = &configCopy
configCacheTime = time.Now()
return cachedConfig
}
// setConfig 安全地设置配置
@@ -163,6 +193,11 @@ func setConfig(cfg *AppConfig) {
appConfigLock.Lock()
defer appConfigLock.Unlock()
appConfig = cfg
// ✅ 配置更新时清除缓存
configCacheMutex.Lock()
cachedConfig = nil
configCacheMutex.Unlock()
}
// LoadConfig 加载配置文件
@@ -190,9 +225,7 @@ func LoadConfig() error {
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
}
@@ -218,7 +251,7 @@ func enableViperHotReload() {
}
isViperEnabled = true
fmt.Println("热重载已启用")
// 热重载已启用,不显示额外信息
// 🚀 启用文件监听
viperInstance.WatchConfig()

View File

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

View File

@@ -10,6 +10,7 @@ import (
"log"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/google/go-containerregistry/pkg/authn"
@@ -525,8 +526,7 @@ var globalImageStreamer *ImageStreamer
// initImageStreamer 初始化镜像下载器
func initImageStreamer() {
globalImageStreamer = NewImageStreamer(nil)
log.Printf("镜像下载器初始化完成,并发数: %d缓存: %v",
globalImageStreamer.concurrency, isCacheEnabled())
// 镜像下载器初始化完成
}
// formatPlatformText 格式化平台文本
@@ -724,7 +724,11 @@ func (is *ImageStreamer) StreamMultipleImages(ctx context.Context, imageRefs []s
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 {
log.Printf("下载镜像 %s 失败: %v", imageRef, err)
return fmt.Errorf("下载镜像 %s 失败: %w", imageRef, err)

View File

@@ -3,12 +3,14 @@ package main
import (
"embed"
"fmt"
"github.com/gin-gonic/gin"
"io"
"log"
"net/http"
"regexp"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
//go:embed public/*
@@ -66,6 +68,15 @@ func main() {
gin.SetMode(gin.ReleaseMode)
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下载路由
initImageTarRoutes(router)
@@ -103,7 +114,10 @@ func main() {
router.NoRoute(RateLimitMiddleware(globalLimiter), handler)
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))
if err != nil {

View File

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

View File

@@ -114,22 +114,29 @@ func (c *Cache) Set(key string, data interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
// 如果缓存已满,删除最旧的条目
if len(c.data) >= c.maxSize {
oldest := time.Now()
var oldestKey string
for k, v := range c.data {
if v.timestamp.Before(oldest) {
oldest = v.timestamp
oldestKey = k
}
// ✅ 先清理过期项,防止内存泄漏
now := time.Now()
for k, v := range c.data {
if now.Sub(v.timestamp) > cacheTTL {
delete(c.data, 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{
data: data,
timestamp: time.Now(),
timestamp: now,
}
}