- Add atomic EWMA Stats field to Target - Implement LeastTime balancer with header_time and last_byte metrics - Support Select and SelectExcluding with zero-lock design - Add ResponseTimeRecorder interface for proxy integration
102 lines
2.7 KiB
Go
102 lines
2.7 KiB
Go
package loadbalance
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// ResponseTimeRecorder 响应时间记录接口。
|
|
type ResponseTimeRecorder interface {
|
|
RecordResponseTime(target *Target, headerTime, lastByteTime time.Duration)
|
|
}
|
|
|
|
// LeastTime 基于响应时间 EWMA 的负载均衡器。
|
|
type LeastTime struct {
|
|
metric string
|
|
defaultTime time.Duration
|
|
}
|
|
|
|
// NewLeastTime 创建一个新的基于响应时间的负载均衡器。
|
|
//
|
|
// 参数:
|
|
// - metric: 选择指标,"header" 表示使用首字节时间,其他值使用完整响应时间
|
|
// - defaultTime: 无统计信息时的默认响应时间,必须 > 0
|
|
func NewLeastTime(metric string, defaultTime time.Duration) *LeastTime {
|
|
if metric != "header" {
|
|
metric = "last_byte"
|
|
}
|
|
if defaultTime <= 0 {
|
|
defaultTime = time.Millisecond
|
|
}
|
|
return &LeastTime{
|
|
metric: metric,
|
|
defaultTime: defaultTime,
|
|
}
|
|
}
|
|
|
|
// Select 根据响应时间 EWMA 选择一个目标。
|
|
// 只考虑可用目标。如果没有可用目标则返回 nil。
|
|
func (l *LeastTime) Select(targets []*Target) *Target {
|
|
fc := acquireFilterContext()
|
|
defer releaseFilterContext(fc)
|
|
available := filterInto(fc, targets)
|
|
return l.selectFrom(available)
|
|
}
|
|
|
|
// SelectExcluding 根据响应时间 EWMA 选择一个目标,排除指定的目标列表。
|
|
// 用于故障转移场景,避免选择已失败的目标。
|
|
func (l *LeastTime) SelectExcluding(targets []*Target, excluded []*Target) *Target {
|
|
fc := acquireFilterContext()
|
|
defer releaseFilterContext(fc)
|
|
available := filterIntoExcluding(fc, targets, excluded)
|
|
return l.selectFrom(available)
|
|
}
|
|
|
|
// selectFrom 从可用目标列表中选择响应时间最短的目标。
|
|
func (l *LeastTime) selectFrom(available []*Target) *Target {
|
|
if len(available) == 0 {
|
|
return nil
|
|
}
|
|
|
|
var selected *Target
|
|
var minTime int64 = -1
|
|
defaultNano := l.defaultTime.Nanoseconds()
|
|
|
|
for _, t := range available {
|
|
var currentTime int64
|
|
if t.Stats != nil {
|
|
if l.metric == "header" {
|
|
currentTime = int64(t.Stats.HeaderTime())
|
|
} else {
|
|
currentTime = int64(t.Stats.LastByteTime())
|
|
}
|
|
}
|
|
|
|
if currentTime == 0 {
|
|
currentTime = defaultNano
|
|
}
|
|
|
|
if selected == nil || currentTime < minTime {
|
|
selected = t
|
|
minTime = currentTime
|
|
}
|
|
}
|
|
|
|
return selected
|
|
}
|
|
|
|
// RecordResponseTime 记录目标服务器的响应时间。
|
|
// 更新目标的 EWMA 统计信息。
|
|
func (l *LeastTime) RecordResponseTime(target *Target, headerTime, lastByteTime time.Duration) {
|
|
if target != nil && target.Stats != nil {
|
|
target.Stats.Record(headerTime, lastByteTime)
|
|
}
|
|
}
|
|
|
|
// GetMetric 返回当前使用的响应时间指标。
|
|
func (l *LeastTime) GetMetric() string {
|
|
return l.metric
|
|
}
|
|
|
|
var _ Balancer = (*LeastTime)(nil)
|
|
var _ ResponseTimeRecorder = (*LeastTime)(nil)
|