Skip to content

Commit 8ac1d41

Browse files
committed
nclm: adjust provider export
1 parent 36c7b9a commit 8ac1d41

3 files changed

Lines changed: 121 additions & 65 deletions

File tree

model/network_client_location_model.go

Lines changed: 107 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import (
55
// "encoding/hex"
66
"strings"
77
"sync"
8+
"sync/atomic"
89
"time"
910

10-
// "errors"
1111
"bytes"
1212
"encoding/gob"
13+
"errors"
1314
"fmt"
1415
// "math"
1516
mathrand "math/rand"
@@ -2119,7 +2120,8 @@ const MaxClientScore = 50
21192120
const ClientScoreSampleCount = 200
21202121

21212122
// choose a filter that has at least this number of providers
2122-
const MinExportNetReliabilityWeight = float64(200)
2123+
// FIXME this scale based on traffic for region
2124+
const MinExportNetReliabilityWeight = float64(400)
21232125

21242126
// the number of filtered providers to consider a location stable
21252127
const MinStableNetReliabilityWeight = float64(10)
@@ -2260,15 +2262,17 @@ func UpdateClientScores(ctx context.Context, ttl time.Duration) (returnErr error
22602262
scoreAdjust += missingSpeedScore
22612263
}
22622264

2263-
score := 0
22642265
if !exclude {
2265-
score = min(
2266+
score := min(
22662267
scorePerTier*netTypeScores[rankMode]+scoreAdjust,
22672268
MaxClientScore,
22682269
)
2270+
clientScore.Scores[rankMode] = score
2271+
clientScore.Tiers[rankMode] = score / scorePerTier
2272+
} else {
2273+
clientScore.Scores[rankMode] = 0
2274+
clientScore.Tiers[rankMode] = (MaxClientScore + scorePerTier - 1) / scorePerTier
22692275
}
2270-
clientScore.Scores[rankMode] = score
2271-
clientScore.Tiers[rankMode] = score / scorePerTier
22722276
}
22732277
}
22742278

@@ -2501,36 +2505,27 @@ func UpdateClientScores(ctx context.Context, ttl time.Duration) (returnErr error
25012505
// to minimize the chance of bad providers in the `FindProviders2` randomized shuffle
25022506
// the last filter represents the worst case the network will expose to users
25032507
filters := []filter{
2504-
// filter{
2505-
// maxScore: scorePerTier,
2506-
// minIndependentReliabilityWeights: map[int]float64{
2507-
// 1: float64(0.999),
2508-
// 2: float64(0.99),
2509-
// 3: float64(0.9),
2510-
// },
2511-
// // minBytesPerSecond: Mib * 1,
2512-
// // maxRelativeLatencyMillis: 200,
2513-
// },
25142508
filter{
25152509
maxScore: 2 * scorePerTier,
25162510
minIndependentReliabilityWeights: map[int]float64{
2517-
1: float64(0.99),
2511+
1: float64(0.9),
25182512
2: float64(0.9),
2513+
3: float64(0.9),
2514+
},
2515+
// minBytesPerSecond: Kib * 512,
2516+
},
2517+
// this case allows for some recent outage to otherwise high-SLA providers
2518+
// this case catches system-wide issues
2519+
filter{
2520+
maxScore: 2 * scorePerTier,
2521+
minIndependentReliabilityWeights: map[int]float64{
2522+
1: float64(0.8),
2523+
2: float64(0.8),
25192524
3: float64(0.8),
25202525
},
2521-
// minBytesPerSecond: Mib * 1,
2522-
// maxRelativeLatencyMillis: 400,
2526+
// minBytesPerSecond: Kib * 512,
2527+
// maxRelativeLatencyMillis: 600,
25232528
},
2524-
// filter{
2525-
// maxScore: 2 * scorePerTier,
2526-
// minIndependentReliabilityWeights: map[int]float64{
2527-
// 1: float64(0.9),
2528-
// 2: float64(0.8),
2529-
// 3: float64(0.7),
2530-
// },
2531-
// // minBytesPerSecond: Kib * 512,
2532-
// // maxRelativeLatencyMillis: 600,
2533-
// },
25342529
}
25352530

25362531
exportClientScores := func(forceMinimum bool, rankMode RankMode, s map[server.Id]*ClientScore) (
@@ -2674,42 +2669,85 @@ func UpdateClientScores(ctx context.Context, ttl time.Duration) (returnErr error
26742669
}
26752670
clientLocationIds = append(clientLocationIds, maps.Values(countryCodeLocationIds())...)
26762671

2677-
server.Redis(ctx, func(r server.RedisClient) {
2678-
for _, forceMinimum := range []bool{false, true} {
2679-
for rankMode, _ := range performanceTargets {
2680-
for j, clientLocationId := range clientLocationIds {
2681-
pipe := r.TxPipeline()
2682-
2683-
glog.Infof("[nclm]export client location[%d/%d] %s\n", j+1, len(clientLocationIds), clientLocationId)
2684-
for locationId, clientScores := range locationClientScores {
2685-
activeClientScores := filterActive(clientScores, clientLocationId)
2686-
countsBytes, samplesBytes, filterBytes, counts, _, _ := exportClientScores(forceMinimum, rankMode, activeClientScores)
2687-
pipe.Set(ctx, clientScoreLocationCountsKey(forceMinimum, rankMode, locationId, clientLocationId), countsBytes, ttl)
2688-
pipe.Set(ctx, clientScoreLocationFilterKey(forceMinimum, rankMode, locationId, clientLocationId), filterBytes, ttl)
2689-
for i, sampleBytes := range samplesBytes {
2690-
pipe.Set(ctx, clientScoreLocationSampleKey(forceMinimum, rankMode, locationId, clientLocationId, i), sampleBytes, ttl)
2691-
}
2692-
glog.V(2).Infof("[nclm]update client scores location samples(%s)[%d] = %v\n", locationId, len(counts), counts)
2693-
}
2694-
for locationGroupId, clientScores := range locationGroupClientScores {
2695-
activeClientScores := filterActive(clientScores, clientLocationId)
2696-
countsBytes, samplesBytes, filterBytes, counts, _, _ := exportClientScores(forceMinimum, rankMode, activeClientScores)
2697-
pipe.Set(ctx, clientScoreLocationGroupCountsKey(forceMinimum, rankMode, locationGroupId, clientLocationId), countsBytes, ttl)
2698-
pipe.Set(ctx, clientScoreLocationGroupFilterKey(forceMinimum, rankMode, locationGroupId, clientLocationId), filterBytes, ttl)
2699-
for i, sampleBytes := range samplesBytes {
2700-
pipe.Set(ctx, clientScoreLocationGroupSampleKey(forceMinimum, rankMode, locationGroupId, clientLocationId, i), sampleBytes, ttl)
2672+
n := 48
2673+
m := (len(clientLocationIds) + n - 1) / n
2674+
allBlockClientLocationIds := [][]server.Id{}
2675+
for i := 0; i < len(clientLocationIds); i += m {
2676+
allBlockClientLocationIds = append(allBlockClientLocationIds, clientLocationIds[i:min(len(clientLocationIds), i+m)])
2677+
}
2678+
2679+
var wg sync.WaitGroup
2680+
var exportCount atomic.Uint32
2681+
returnErrs := make(chan error, n)
2682+
2683+
for i := 0; i < len(clientLocationIds); i += m {
2684+
blockClientLocationIds := clientLocationIds[i:min(len(clientLocationIds), i+m)]
2685+
2686+
wg.Add(1)
2687+
go connect.HandleError(func() {
2688+
defer wg.Done()
2689+
2690+
server.Redis(ctx, func(r server.RedisClient) {
2691+
for _, forceMinimum := range []bool{false, true} {
2692+
for rankMode, _ := range performanceTargets {
2693+
for _, clientLocationId := range blockClientLocationIds {
2694+
pipe := r.TxPipeline()
2695+
2696+
exportIndex := exportCount.Add(1)
2697+
glog.Infof("[nclm]export client location[%d/%d] %s\n", exportIndex+1, 2*len(performanceTargets)*len(clientLocationIds), clientLocationId)
2698+
for locationId, clientScores := range locationClientScores {
2699+
activeClientScores := filterActive(clientScores, clientLocationId)
2700+
countsBytes, samplesBytes, filterBytes, counts, _, _ := exportClientScores(forceMinimum, rankMode, activeClientScores)
2701+
pipe.Set(ctx, clientScoreLocationCountsKey(forceMinimum, rankMode, locationId, clientLocationId), countsBytes, ttl)
2702+
pipe.Set(ctx, clientScoreLocationFilterKey(forceMinimum, rankMode, locationId, clientLocationId), filterBytes, ttl)
2703+
for i, sampleBytes := range samplesBytes {
2704+
pipe.Set(ctx, clientScoreLocationSampleKey(forceMinimum, rankMode, locationId, clientLocationId, i), sampleBytes, ttl)
2705+
}
2706+
glog.V(2).Infof("[nclm]update client scores location samples(%s)[%d] = %v\n", locationId, len(counts), counts)
2707+
}
2708+
for locationGroupId, clientScores := range locationGroupClientScores {
2709+
activeClientScores := filterActive(clientScores, clientLocationId)
2710+
countsBytes, samplesBytes, filterBytes, counts, _, _ := exportClientScores(forceMinimum, rankMode, activeClientScores)
2711+
pipe.Set(ctx, clientScoreLocationGroupCountsKey(forceMinimum, rankMode, locationGroupId, clientLocationId), countsBytes, ttl)
2712+
pipe.Set(ctx, clientScoreLocationGroupFilterKey(forceMinimum, rankMode, locationGroupId, clientLocationId), filterBytes, ttl)
2713+
for i, sampleBytes := range samplesBytes {
2714+
pipe.Set(ctx, clientScoreLocationGroupSampleKey(forceMinimum, rankMode, locationGroupId, clientLocationId, i), sampleBytes, ttl)
2715+
}
2716+
glog.V(2).Infof("[nclm]update client scores location group samples(%s)[%d] = %v\n", locationGroupId, len(counts), counts)
2717+
}
2718+
2719+
_, err := pipe.Exec(ctx)
2720+
if err != nil {
2721+
select {
2722+
case <-ctx.Done():
2723+
return
2724+
case returnErrs <- err:
2725+
return
2726+
}
2727+
}
27012728
}
2702-
glog.V(2).Infof("[nclm]update client scores location group samples(%s)[%d] = %v\n", locationGroupId, len(counts), counts)
27032729
}
2730+
}
2731+
})
2732+
}, wg.Done)
2733+
}
27042734

2705-
_, returnErr = pipe.Exec(ctx)
2706-
if returnErr != nil {
2707-
return
2708-
}
2735+
wg.Wait()
2736+
close(returnErrs)
2737+
2738+
func() {
2739+
for {
2740+
select {
2741+
case <-ctx.Done():
2742+
return
2743+
case err, ok := <-returnErrs:
2744+
if !ok {
2745+
return
27092746
}
2747+
returnErr = errors.Join(returnErr, err)
27102748
}
27112749
}
2712-
})
2750+
}()
27132751

27142752
if returnErr == nil {
27152753
glog.Infof(
@@ -2841,6 +2879,9 @@ func FindProviders2(
28412879

28422880
excludeFinalDestinations := sync.OnceValue(func() map[server.Id]bool {
28432881
excludeFinalDestinations := map[server.Id]bool{}
2882+
for _, clientId := range findProviders2.ExcludeClientIds {
2883+
excludeFinalDestinations[clientId] = true
2884+
}
28442885
for _, destination := range findProviders2.ExcludeDestinations {
28452886
excludeFinalDestinations[destination[len(destination)-1]] = true
28462887
}
@@ -2924,7 +2965,7 @@ func FindProviders2(
29242965
glog.Infof("[nclm]findproviders2 load %.2fms (%d)\n", loadMillis, len(clientScores))
29252966
}
29262967

2927-
for _, clientId := range findProviders2.ExcludeClientIds {
2968+
for clientId, _ := range excludeFinalDestinations() {
29282969
delete(clientScores, clientId)
29292970
}
29302971
// the final hop is excluded
@@ -2936,7 +2977,11 @@ func FindProviders2(
29362977
clientScore.Scores[rankMode] += intermediaryScore
29372978
}
29382979
}
2939-
delete(clientScores, destination[len(destination)-1])
2980+
}
2981+
2982+
adjustedMaxClientScore := MaxClientScore
2983+
for _, clientScore := range clientScores {
2984+
adjustedMaxClientScore = max(adjustedMaxClientScore, clientScore.Scores[rankMode])
29402985
}
29412986

29422987
clientIds := maps.Keys(clientScores)
@@ -2946,7 +2991,7 @@ func FindProviders2(
29462991

29472992
connect.WeightedSelectFunc(clientIds, count, func(clientId server.Id) float32 {
29482993
clientScore := clientScores[clientId]
2949-
qualityWeight := max(0, MaxClientScore-clientScore.Scores[rankMode])
2994+
qualityWeight := max(0, adjustedMaxClientScore-clientScore.Scores[rankMode])
29502995
return float32(clientScore.ReliabilityWeight * float64(qualityWeight))
29512996
})
29522997
clientIds = clientIds[:min(count, len(clientIds))]

model/network_client_location_model_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,11 @@ func TestFindProviders2WithExclude(t *testing.T) {
431431
otherClientIds[clientIds[5]] = true
432432
otherClientIds[clientIds[7]] = true
433433
otherClientIds[clientIds[8]] = true
434+
excludeClientIds := map[server.Id]bool{}
435+
excludeClientIds[clientIds[0]] = true
436+
excludeClientIds[clientIds[3]] = true
437+
excludeClientIds[clientIds[6]] = true
438+
excludeClientIds[clientIds[9]] = true
434439

435440
// the match is a weighted shuffle so we should expect over
436441
// sufficient iterations the priority client ids will come first
@@ -452,11 +457,17 @@ func TestFindProviders2WithExclude(t *testing.T) {
452457
return netProviderIncludedCounts[b] - netProviderIncludedCounts[a]
453458
})
454459
for _, clientId := range orderedClientIds[:len(priorityClientIds)] {
455-
ok := priorityClientIds[clientId]
460+
ok := excludeClientIds[clientId]
461+
assert.Equal(t, ok, false)
462+
ok = otherClientIds[clientId]
463+
assert.Equal(t, ok, false)
464+
ok = priorityClientIds[clientId]
456465
assert.Equal(t, ok, true)
457466
}
458467
for _, clientId := range orderedClientIds[len(priorityClientIds):] {
459-
ok := otherClientIds[clientId]
468+
ok := excludeClientIds[clientId]
469+
assert.Equal(t, ok, false)
470+
ok = otherClientIds[clientId]
460471
assert.Equal(t, ok, true)
461472
}
462473

taskworker/work/network_client_location_work.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func ScheduleUpdateClientScores(clientSession *session.ClientSession, tx server.
2424
&UpdateClientScoresArgs{},
2525
clientSession,
2626
task.RunOnce("update_client_scores"),
27-
task.RunAt(server.NowUtc().Add(5*time.Second)),
27+
task.RunAt(server.NowUtc().Add(30*time.Second)),
2828
task.Priority(task.TaskPriorityFastest),
2929
task.MaxTime(120*time.Minute),
3030
)

0 commit comments

Comments
 (0)