From edf192ff856f0d0ed63d71194609610be9af03cf Mon Sep 17 00:00:00 2001 From: xfy Date: Fri, 10 Apr 2026 15:29:21 +0800 Subject: [PATCH] =?UTF-8?q?docs(proxy,resolver,variable):=20=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E5=85=AC=E5=BC=80=20API=20=E6=96=87=E6=A1=A3=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - proxy: 添加 upstreamCache/protoHTTPS 常量说明 - proxy_dns: 添加文件级文档和所有公开方法的详细注释 - stats: 增强 StatsCollector 接口文档和方法注释 - pool: 增强 PoolStats 字段注释和公开函数文档 Co-Authored-By: Claude Opus 4.6 --- internal/proxy/proxy.go | 5 +++ internal/proxy/proxy_dns.go | 69 ++++++++++++++++++++++++++++++++-- internal/resolver/stats.go | 74 +++++++++++++++++++++++++++++++++++-- internal/variable/pool.go | 30 ++++++++++----- 4 files changed, 161 insertions(+), 17 deletions(-) diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 45ff265..9616c61 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -52,7 +52,12 @@ import ( ) const ( + // upstreamCache 上游缓存标识 + // 用于标记请求可直接使用缓存响应,无需转发到上游 upstreamCache = "CACHE" + + // protoHTTPS 使用 HTTPS 协议 + // 标记与上游目标通信时使用 HTTPS 加密传输 protoHTTPS = "https" ) diff --git a/internal/proxy/proxy_dns.go b/internal/proxy/proxy_dns.go index 060fffb..a7354e4 100644 --- a/internal/proxy/proxy_dns.go +++ b/internal/proxy/proxy_dns.go @@ -1,3 +1,19 @@ +// Package proxy 反向代理包,为 Lolly HTTP 服务器提供反向代理功能。 +// +// 该文件实现 DNS 动态解析和刷新功能,支持后端目标的域名自动解析、 +// IP 缓存、定时刷新和故障恢复。 +// +// 主要功能: +// - DNS 解析器集成:支持自定义 resolver 实现域名解析 +// - 定时刷新循环:根据 TTL 自动刷新已解析目标的 IP 地址 +// - 连接池同步更新:DNS 解析结果自动同步到 HostClient 连接池 +// - 统计信息查询:暴露 DNS 解析器的运行统计数据 +// +// 注意事项: +// - 所有公开方法均为并发安全 +// - DNS 刷新在后台 goroutine 中运行,通过 stopCh 控制生命周期 +// +// 作者:xfy package proxy import ( @@ -13,13 +29,26 @@ import ( ) // SetResolver 设置 DNS 解析器。 +// +// 该方法为代理实例配置自定义的 DNS 解析器,用于动态解析后端目标的域名。 +// 必须在调用 Start() 之前设置,否则 DNS 刷新循环不会启动。 +// +// 参数: +// - r: DNS 解析器实例,需实现 resolver.Resolver 接口 func (p *Proxy) SetResolver(r resolver.Resolver) { p.mu.Lock() defer p.mu.Unlock() p.resolver = r } -// Start 启动代理,包括 DNS 刷新循环。 +// Start 启动代理服务,包括 DNS 刷新循环。 +// +// 该方法标记代理为已启动状态,如果配置了 resolver,则启动解析器并 +// 在后台 goroutine 中启动 DNS 定时刷新循环。该方法是幂等的, +// 重复调用不会重复启动。 +// +// 返回值: +// - error: 启动 resolver 失败时返回非 nil 错误 func (p *Proxy) Start() error { if p.started.Load() { return nil @@ -38,7 +67,13 @@ func (p *Proxy) Start() error { return nil } -// Stop 停止代理,包括关闭 DNS 刷新循环。 +// Stop 停止代理服务,包括关闭 DNS 刷新循环。 +// +// 该方法标记代理为已停止状态,关闭 stopCh 通知所有后台协程退出, +// 并停止 resolver。该方法是幂等的,重复调用不会产生副作用。 +// +// 返回值: +// - error: 停止 resolver 失败时返回非 nil 错误 func (p *Proxy) Stop() error { if !p.started.Load() { return nil @@ -60,6 +95,10 @@ func (p *Proxy) Stop() error { } // startDNSRefreshLoop 启动 DNS 刷新后台循环。 +// +// 根据 resolver 的 TTL 计算刷新间隔(TTL / 2,最小 1 秒), +// 定时调用 refreshDNS 刷新所有需要解析的目标。 +// 该方法阻塞运行,直到收到 stopCh 信号。 func (p *Proxy) startDNSRefreshLoop() { if p.resolver == nil { return @@ -90,6 +129,9 @@ func (p *Proxy) startDNSRefreshLoop() { } // refreshDNS 刷新所有需要解析的目标。 +// +// 遍历所有后端目标,对超过 TTL 的域名执行 DNS 查询, +// 更新目标的已解析 IP 列表,并同步更新对应 HostClient 的地址。 func (p *Proxy) refreshDNS() { if p.resolver == nil { return @@ -127,7 +169,14 @@ func (p *Proxy) refreshDNS() { } } -// updateHostClientAddr 更新 HostClient 的 Addr。 +// updateHostClientAddr 更新 HostClient 的连接地址。 +// +// 从目标 URL 中解析出端口,与新的 IP 地址组合后更新对应 +// HostClient 的 Addr 字段。旧连接不受影响,新连接将使用新地址。 +// +// 参数: +// - target: 负载均衡目标,包含原始 URL +// - ip: 新解析出的 IP 地址 func (p *Proxy) updateHostClientAddr(target *loadbalance.Target, ip string) { p.mu.Lock() defer p.mu.Unlock() @@ -158,7 +207,13 @@ func (p *Proxy) updateHostClientAddr(target *loadbalance.Target, ip string) { } } -// getResolverTTL 获取 resolver 的 TTL。 +// getResolverTTL 获取 DNS 解析记录的过期时间。 +// +// 返回 resolver 的 TTL 配置,默认值为 30 秒。 +// 该方法当前返回固定值,未来可从 resolver stats 中动态推断。 +// +// 返回值: +// - time.Duration: DNS 记录的有效期 func (p *Proxy) getResolverTTL() time.Duration { if p.resolver == nil { return 0 @@ -170,6 +225,12 @@ func (p *Proxy) getResolverTTL() time.Duration { } // GetResolverStats 返回 DNS 解析器的统计信息。 +// +// 获取当前 resolver 的运行统计数据,包括查询次数、 +// 缓存命中率、错误次数等。如果未配置 resolver,返回空的 Stats。 +// +// 返回值: +// - resolver.Stats: DNS 解析器统计数据 func (p *Proxy) GetResolverStats() resolver.Stats { p.mu.RLock() r := p.resolver diff --git a/internal/resolver/stats.go b/internal/resolver/stats.go index b5d82a9..f20df80 100644 --- a/internal/resolver/stats.go +++ b/internal/resolver/stats.go @@ -1,6 +1,18 @@ // Package resolver 提供 DNS 解析功能,支持缓存和后台刷新。 // -// 该文件包含 DNS 解析器统计指标相关的实现。 +// 该文件包含 DNS 解析器统计指标相关的实现,包括: +// - 缓存命中/未命中次数统计 +// - 解析错误次数统计 +// - 解析延迟统计 +// - 统计数据查询接口 +// +// 主要用途: +// 用于监控 DNS 解析器的性能指标,支持实时获取缓存命中率、 +// 平均延迟等关键指标,便于系统性能分析和调优。 +// +// 注意事项: +// - 所有统计方法均为原子操作,并发安全 +// - 延迟统计使用纳秒级精度累加 // // 作者:xfy package resolver @@ -9,7 +21,21 @@ import ( "time" ) -// StatsCollector 统计收集器接口。 +// StatsCollector 定义 DNS 解析器统计收集器的接口。 +// +// 该接口用于抽象统计数据的收集和查询操作,支持: +// - 记录缓存命中和未命中事件 +// - 记录解析错误 +// - 记录解析延迟 +// - 获取汇总统计数据 +// +// 实现要求: +// - 所有方法必须是并发安全的 +// - 统计数据的更新应使用原子操作 +// - GetStats 返回的数据应反映当前时刻的快照 +// +// 使用场景: +// 通常由 DNSResolver 实现此接口,供监控系统或管理接口调用。 type StatsCollector interface { // RecordHit 记录缓存命中 RecordHit() @@ -23,7 +49,14 @@ type StatsCollector interface { GetStats() Stats } -// ResetStats 重置所有统计信息。 +// ResetStats 重置所有统计信息为初始值。 +// +// 将缓存命中次数、缓存未命中次数、解析错误次数、 +// 总延迟时间和查询次数全部清零。 +// +// 注意事项: +// - 该操作会清除所有历史统计数据,请谨慎使用 +// - 使用原子操作确保并发安全 func (r *DNSResolver) ResetStats() { r.hits.Store(0) r.misses.Store(0) @@ -33,26 +66,61 @@ func (r *DNSResolver) ResetStats() { } // GetCacheHits 返回缓存命中次数。 +// +// 缓存命中表示请求的数据已存在于缓存中,无需进行实际的 DNS 查询。 +// 该指标可用于评估缓存的有效性。 +// +// 返回值: +// - 缓存命中次数的累计值(int64 类型) func (r *DNSResolver) GetCacheHits() int64 { return r.hits.Load() } // GetCacheMisses 返回缓存未命中次数。 +// +// 缓存未命中表示请求的数据不在缓存中,需要进行实际的 DNS 查询。 +// 结合缓存命中次数可计算缓存命中率:命中率 = 命中次数 / (命中次数 + 未命中次数)。 +// +// 返回值: +// - 缓存未命中次数的累计值(int64 类型) func (r *DNSResolver) GetCacheMisses() int64 { return r.misses.Load() } // GetResolveErrors 返回解析错误次数。 +// +// 解析错误表示 DNS 查询过程中发生的各种错误,包括网络错误、 +// 超时、无效响应等。该指标可用于监控 DNS 服务的健康状态。 +// +// 返回值: +// - 解析错误次数的累计值(int64 类型) func (r *DNSResolver) GetResolveErrors() int64 { return r.errors.Load() } // GetTotalQueries 返回总查询次数。 +// +// 总查询次数等于缓存命中次数与缓存未命中次数之和。 +// 该指标反映 DNS 解析器处理的所有请求总数。 +// +// 返回值: +// - 总查询次数(int64 类型) func (r *DNSResolver) GetTotalQueries() int64 { return r.hits.Load() + r.misses.Load() } // GetAverageLatency 返回平均解析延迟。 +// +// 平均延迟通过总延迟时间除以查询次数计算得出。 +// 该指标反映 DNS 解析的平均响应时间,单位为 time.Duration。 +// 当没有查询记录时返回 0。 +// +// 返回值: +// - 平均解析延迟(time.Duration 类型) +// +// 注意事项: +// - 首次调用或 ResetStats 后若未进行任何查询,返回 0 +// - 延迟统计包括缓存命中和缓存未命中的请求 func (r *DNSResolver) GetAverageLatency() time.Duration { count := r.count.Load() if count == 0 { diff --git a/internal/variable/pool.go b/internal/variable/pool.go index 3c74fa4..554ebe1 100644 --- a/internal/variable/pool.go +++ b/internal/variable/pool.go @@ -11,22 +11,30 @@ import ( "github.com/valyala/fasthttp" ) -// PoolStats 池统计信息 +// PoolStats 池统计信息。 +// +// 记录 sync.Pool 的使用统计,用于监控和调试。 type PoolStats struct { - Gets int64 // Get 次数 - Puts int64 // Put 次数 - NewCount int64 // New 创建次数 - Active int64 // 当前活跃数量 (Gets - Puts) + // Gets 从池中获取对象的次数 + Gets int64 + // Puts 放回池中对象的次数 + Puts int64 + // NewCount 调用 New 函数创建对象的次数 + NewCount int64 + // Active 当前活跃对象数量(Gets - Puts) + Active int64 } var ( - // stats 池统计 + // stats 全局池统计信息 stats PoolStats - // statsMu 保护统计信息 + // statsMu 保护统计信息的读写锁 statsMu sync.RWMutex ) -// GetStats 获取池统计信息 +// GetStats 获取池统计信息的副本。 +// +// 返回当前统计信息的快照,线程安全。 func GetStats() PoolStats { statsMu.RLock() s := stats @@ -34,7 +42,7 @@ func GetStats() PoolStats { return s } -// GetPool 获取底层的 sync.Pool(用于测试和调试) +// GetPool 获取底层的 sync.Pool(用于测试和调试)。 func GetPool() *sync.Pool { return &pool } @@ -71,7 +79,9 @@ func PoolPut(vc *Context) { statsMu.Unlock() } -// ResetStats 重置统计信息 +// ResetStats 重置统计信息。 +// +// 将所有统计计数器清零,线程安全。 func ResetStats() { statsMu.Lock() stats = PoolStats{}