рабочий вариант, но скороть 10 МБит
This commit is contained in:
@@ -21,6 +21,7 @@ type PeerRecoveryPlanConfig struct {
|
||||
Connections PeerConnectionSnapshot
|
||||
TargetReadyPeers int
|
||||
MaxProbeCandidates int
|
||||
PreferredRegion string
|
||||
Now time.Time
|
||||
}
|
||||
|
||||
@@ -42,6 +43,7 @@ type PeerRecoveryPlan struct {
|
||||
type PeerRecoveryCandidate struct {
|
||||
NodeID string `json:"node_id"`
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
Warm bool `json:"warm"`
|
||||
WarmReason string `json:"warm_reason,omitempty"`
|
||||
RecoverySeed bool `json:"recovery_seed"`
|
||||
@@ -57,6 +59,7 @@ type PeerRecoveryCandidate struct {
|
||||
|
||||
type peerRecoveryCandidateBuild struct {
|
||||
PeerRecoveryCandidate
|
||||
PublicIngressCount int
|
||||
}
|
||||
|
||||
func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
@@ -96,6 +99,7 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
ready := 0
|
||||
degraded := 0
|
||||
backoff := 0
|
||||
readyExternalRegions := map[string]struct{}{}
|
||||
for nodeID, connection := range connectionByNode {
|
||||
entry, ok := entryByNode[nodeID]
|
||||
if !ok || strings.TrimSpace(entry.Endpoint) == "" {
|
||||
@@ -104,6 +108,10 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
switch connection.State {
|
||||
case PeerConnectionReady:
|
||||
ready++
|
||||
region := strings.TrimSpace(entry.BestRegion)
|
||||
if region != "" && (strings.TrimSpace(cfg.PreferredRegion) == "" || !strings.EqualFold(region, cfg.PreferredRegion)) {
|
||||
readyExternalRegions[strings.ToLower(region)] = struct{}{}
|
||||
}
|
||||
case PeerConnectionRelayReady:
|
||||
// Relay-ready peers remain valuable for control-plane reachability,
|
||||
// but they do not satisfy the target for direct-ready transport paths.
|
||||
@@ -125,6 +133,7 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
if mode == PeerRecoveryModeSteady {
|
||||
limit = target
|
||||
}
|
||||
missingExternalRegions := missingPeerRecoveryExternalRegions(cfg.PeerCache, cfg.PreferredRegion, readyExternalRegions, target)
|
||||
|
||||
candidates := make([]peerRecoveryCandidateBuild, 0, len(cfg.PeerCache.Entries))
|
||||
for _, entry := range cfg.PeerCache.Entries {
|
||||
@@ -138,13 +147,14 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
if connection.State == PeerConnectionBackoff && connection.BackoffUntil.After(now) {
|
||||
continue
|
||||
}
|
||||
reason, ok := peerRecoveryCandidateReason(mode, entry, connection)
|
||||
reason, ok := peerRecoveryCandidateReason(mode, entry, connection, missingExternalRegions, cfg.PreferredRegion)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
candidate := PeerRecoveryCandidate{
|
||||
NodeID: entry.NodeID,
|
||||
Endpoint: strings.TrimSpace(entry.Endpoint),
|
||||
Region: strings.TrimSpace(entry.BestRegion),
|
||||
Warm: entry.Warm,
|
||||
WarmReason: entry.WarmReason,
|
||||
RecoverySeed: entry.RecoverySeed,
|
||||
@@ -155,9 +165,12 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
LastLatencyMs: connection.LastLatencyMs,
|
||||
BackoffUntil: connection.BackoffUntil,
|
||||
Reason: reason,
|
||||
Priority: peerRecoveryCandidatePriority(entry, connection, reason),
|
||||
Priority: peerRecoveryCandidatePriority(entry, connection, reason, cfg.PreferredRegion),
|
||||
}
|
||||
candidates = append(candidates, peerRecoveryCandidateBuild{PeerRecoveryCandidate: candidate})
|
||||
candidates = append(candidates, peerRecoveryCandidateBuild{
|
||||
PeerRecoveryCandidate: candidate,
|
||||
PublicIngressCount: entry.PublicIngressCount,
|
||||
})
|
||||
}
|
||||
sort.SliceStable(candidates, func(i, j int) bool {
|
||||
if candidates[i].Priority != candidates[j].Priority {
|
||||
@@ -166,7 +179,7 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
return candidates[i].NodeID < candidates[j].NodeID
|
||||
})
|
||||
if len(candidates) > limit {
|
||||
candidates = candidates[:limit]
|
||||
candidates = trimPeerRecoveryCandidates(candidates, limit, cfg.PreferredRegion)
|
||||
}
|
||||
|
||||
outCandidates := make([]PeerRecoveryCandidate, 0, len(candidates))
|
||||
@@ -194,11 +207,143 @@ func PlanPeerRecovery(cfg PeerRecoveryPlanConfig) PeerRecoveryPlan {
|
||||
}
|
||||
}
|
||||
|
||||
func peerRecoveryCandidateReason(mode string, entry PeerCacheEntry, connection PeerConnectionState) (string, bool) {
|
||||
func missingPeerRecoveryExternalRegions(snapshot PeerCacheSnapshot, preferredRegion string, readyExternalRegions map[string]struct{}, target int) map[string]struct{} {
|
||||
preferredRegion = strings.TrimSpace(preferredRegion)
|
||||
availableExternalRegions := map[string]struct{}{}
|
||||
for _, entry := range snapshot.Entries {
|
||||
region := strings.TrimSpace(entry.BestRegion)
|
||||
if region == "" {
|
||||
continue
|
||||
}
|
||||
if preferredRegion != "" && strings.EqualFold(region, preferredRegion) {
|
||||
continue
|
||||
}
|
||||
availableExternalRegions[strings.ToLower(region)] = struct{}{}
|
||||
}
|
||||
if len(availableExternalRegions) == 0 {
|
||||
return nil
|
||||
}
|
||||
desiredExternal := len(availableExternalRegions)
|
||||
if desiredExternal > 2 {
|
||||
desiredExternal = 2
|
||||
}
|
||||
if target > 0 && desiredExternal > target {
|
||||
desiredExternal = target
|
||||
}
|
||||
if len(readyExternalRegions) >= desiredExternal {
|
||||
return nil
|
||||
}
|
||||
missing := map[string]struct{}{}
|
||||
for region := range availableExternalRegions {
|
||||
if _, ok := readyExternalRegions[region]; ok {
|
||||
continue
|
||||
}
|
||||
missing[region] = struct{}{}
|
||||
}
|
||||
if len(missing) == 0 {
|
||||
return nil
|
||||
}
|
||||
return missing
|
||||
}
|
||||
|
||||
func trimPeerRecoveryCandidates(candidates []peerRecoveryCandidateBuild, limit int, preferredRegion string) []peerRecoveryCandidateBuild {
|
||||
if len(candidates) <= limit || limit <= 0 {
|
||||
return candidates
|
||||
}
|
||||
preferredRegion = strings.TrimSpace(preferredRegion)
|
||||
externalRegions := map[string]struct{}{}
|
||||
for _, candidate := range candidates {
|
||||
region := strings.TrimSpace(candidate.Region)
|
||||
if region == "" || (preferredRegion != "" && strings.EqualFold(region, preferredRegion)) {
|
||||
continue
|
||||
}
|
||||
externalRegions[strings.ToLower(region)] = struct{}{}
|
||||
}
|
||||
if len(externalRegions) < 2 {
|
||||
return candidates[:limit]
|
||||
}
|
||||
selected := make([]peerRecoveryCandidateBuild, 0, limit)
|
||||
selectedNodeIDs := map[string]struct{}{}
|
||||
selectedRegions := map[string]struct{}{}
|
||||
for _, candidate := range candidates {
|
||||
if len(selected) >= limit {
|
||||
break
|
||||
}
|
||||
region := strings.TrimSpace(candidate.Region)
|
||||
if region == "" || (preferredRegion != "" && strings.EqualFold(region, preferredRegion)) {
|
||||
continue
|
||||
}
|
||||
regionKey := strings.ToLower(region)
|
||||
if _, exists := selectedRegions[regionKey]; exists {
|
||||
continue
|
||||
}
|
||||
selected = append(selected, candidate)
|
||||
selectedNodeIDs[candidate.NodeID] = struct{}{}
|
||||
selectedRegions[regionKey] = struct{}{}
|
||||
}
|
||||
if len(selected) < limit && !selectedHasPublicIngress(selected) {
|
||||
for _, candidate := range candidates {
|
||||
if len(selected) >= limit {
|
||||
break
|
||||
}
|
||||
if _, exists := selectedNodeIDs[candidate.NodeID]; exists {
|
||||
continue
|
||||
}
|
||||
if candidatePublicIngressCount(candidate) <= 0 {
|
||||
continue
|
||||
}
|
||||
selected = append(selected, candidate)
|
||||
selectedNodeIDs[candidate.NodeID] = struct{}{}
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
if len(selected) >= limit {
|
||||
break
|
||||
}
|
||||
if _, exists := selectedNodeIDs[candidate.NodeID]; exists {
|
||||
continue
|
||||
}
|
||||
selected = append(selected, candidate)
|
||||
selectedNodeIDs[candidate.NodeID] = struct{}{}
|
||||
}
|
||||
if len(selected) > limit {
|
||||
selected = selected[:limit]
|
||||
}
|
||||
return selected
|
||||
}
|
||||
|
||||
func selectedHasPublicIngress(candidates []peerRecoveryCandidateBuild) bool {
|
||||
for _, candidate := range candidates {
|
||||
if candidatePublicIngressCount(candidate) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func candidatePublicIngressCount(candidate peerRecoveryCandidateBuild) int {
|
||||
return candidate.PublicIngressCount
|
||||
}
|
||||
|
||||
func peerRecoveryCandidateReason(mode string, entry PeerCacheEntry, connection PeerConnectionState, missingExternalRegions map[string]struct{}, preferredRegion string) (string, bool) {
|
||||
if mode == PeerRecoveryModeSteady {
|
||||
if connection.State == PeerConnectionReady || connection.State == PeerConnectionRelayReady {
|
||||
return "maintain_ready", true
|
||||
}
|
||||
region := strings.ToLower(strings.TrimSpace(entry.BestRegion))
|
||||
if region != "" && len(missingExternalRegions) > 0 {
|
||||
if _, ok := missingExternalRegions[region]; ok {
|
||||
if preferredRegion == "" || !strings.EqualFold(strings.TrimSpace(entry.BestRegion), preferredRegion) {
|
||||
if connection.State == PeerConnectionDegraded {
|
||||
return "recover_external_area", true
|
||||
}
|
||||
if entry.Warm || entry.RecoverySeed || connection.State == PeerConnectionDisconnected || connection.State == PeerConnectionConnecting {
|
||||
return "recover_external_area", true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
if connection.State == PeerConnectionReady || connection.State == PeerConnectionRelayReady {
|
||||
@@ -216,7 +361,7 @@ func peerRecoveryCandidateReason(mode string, entry PeerCacheEntry, connection P
|
||||
return "recover_peer", true
|
||||
}
|
||||
|
||||
func peerRecoveryCandidatePriority(entry PeerCacheEntry, connection PeerConnectionState, reason string) int {
|
||||
func peerRecoveryCandidatePriority(entry PeerCacheEntry, connection PeerConnectionState, reason string, preferredRegion string) int {
|
||||
score := 0
|
||||
if entry.Warm {
|
||||
score += 1000
|
||||
@@ -237,6 +382,17 @@ func peerRecoveryCandidatePriority(entry PeerCacheEntry, connection PeerConnecti
|
||||
if entry.BestCandidateID != "" {
|
||||
score += 150
|
||||
}
|
||||
if entry.PublicIngressCount > 0 {
|
||||
score += entry.PublicIngressCount * 90
|
||||
}
|
||||
preferredRegion = strings.TrimSpace(preferredRegion)
|
||||
entryRegion := strings.TrimSpace(entry.BestRegion)
|
||||
switch {
|
||||
case preferredRegion != "" && entryRegion != "" && !strings.EqualFold(entryRegion, preferredRegion):
|
||||
score += 275
|
||||
case preferredRegion != "" && entryRegion != "" && strings.EqualFold(entryRegion, preferredRegion):
|
||||
score += 25
|
||||
}
|
||||
score += entry.BestCandidateScore / 10
|
||||
switch connection.State {
|
||||
case PeerConnectionReady, PeerConnectionRelayReady:
|
||||
@@ -251,6 +407,8 @@ func peerRecoveryCandidatePriority(entry PeerCacheEntry, connection PeerConnecti
|
||||
switch reason {
|
||||
case "maintain_ready":
|
||||
score += 500
|
||||
case "recover_external_area":
|
||||
score += 450
|
||||
case "recover_degraded":
|
||||
score += 300
|
||||
case "recover_seed":
|
||||
|
||||
Reference in New Issue
Block a user