calling: update TurnCallRouter to shuffle instance IPs to prevent allocation skew

Co-authored-by: Jonathan Klabunde Tomer <125505367+jkt-signal@users.noreply.github.com>
This commit is contained in:
adel-signal 2024-05-02 12:34:34 -07:00 committed by GitHub
parent cc6ec1d351
commit 854ab353b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 19 additions and 11 deletions

View File

@ -747,7 +747,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
callRoutingTableManager, callRoutingTableManager,
manualCallRoutingTableManager, manualCallRoutingTableManager,
configTurnRouter, configTurnRouter,
geoIpCityDatabaseManager geoIpCityDatabaseManager,
false
); );
final ClientConnectionManager clientConnectionManager = new ClientConnectionManager(); final ClientConnectionManager clientConnectionManager = new ClientConnectionManager();

View File

@ -32,19 +32,23 @@ public class TurnCallRouter {
private final Supplier<CallRoutingTable> manualRouting; private final Supplier<CallRoutingTable> manualRouting;
private final DynamicConfigTurnRouter configTurnRouter; private final DynamicConfigTurnRouter configTurnRouter;
private final Supplier<DatabaseReader> geoIp; private final Supplier<DatabaseReader> geoIp;
// controls whether instance IPs are shuffled. using if & boolean is ~5x faster than a function pointer
private final boolean stableSelect;
public TurnCallRouter( public TurnCallRouter(
@Nonnull Supplier<CallDnsRecords> callDnsRecords, @Nonnull Supplier<CallDnsRecords> callDnsRecords,
@Nonnull Supplier<CallRoutingTable> performanceRouting, @Nonnull Supplier<CallRoutingTable> performanceRouting,
@Nonnull Supplier<CallRoutingTable> manualRouting, @Nonnull Supplier<CallRoutingTable> manualRouting,
@Nonnull DynamicConfigTurnRouter configTurnRouter, @Nonnull DynamicConfigTurnRouter configTurnRouter,
@Nonnull Supplier<DatabaseReader> geoIp @Nonnull Supplier<DatabaseReader> geoIp,
boolean stableSelect
) { ) {
this.performanceRouting = performanceRouting; this.performanceRouting = performanceRouting;
this.callDnsRecords = callDnsRecords; this.callDnsRecords = callDnsRecords;
this.manualRouting = manualRouting; this.manualRouting = manualRouting;
this.configTurnRouter = configTurnRouter; this.configTurnRouter = configTurnRouter;
this.geoIp = geoIp; this.geoIp = geoIp;
this.stableSelect = stableSelect;
} }
/** /**
@ -139,10 +143,10 @@ public class TurnCallRouter {
CallDnsRecords dnsRecords = this.callDnsRecords.get(); CallDnsRecords dnsRecords = this.callDnsRecords.get();
List<InetAddress> ipv4Selection = datacenters.stream() List<InetAddress> ipv4Selection = datacenters.stream()
.flatMap(dc -> Util.randomNOfStable(dnsRecords.aByRegion().get(dc), limit).stream()) .flatMap(dc -> randomNOf(dnsRecords.aByRegion().get(dc), limit, stableSelect).stream())
.toList(); .toList();
List<InetAddress> ipv6Selection = datacenters.stream() List<InetAddress> ipv6Selection = datacenters.stream()
.flatMap(dc -> Util.randomNOfStable(dnsRecords.aaaaByRegion().get(dc), limit).stream()) .flatMap(dc -> randomNOf(dnsRecords.aaaaByRegion().get(dc), limit, stableSelect).stream())
.toList(); .toList();
// increase numV4 if not enough v6 options. vice-versa is also true // increase numV4 if not enough v6 options. vice-versa is also true
@ -157,6 +161,10 @@ public class TurnCallRouter {
).toList(); ).toList();
} }
private static <E> List<E> randomNOf(List<E> values, int n, boolean stableSelect) {
return stableSelect ? Util.randomNOfStable(values, n) : Util.randomNOfShuffled(values, n);
}
private static List<String> getUrlsForInstances(List<String> instanceIps) { private static List<String> getUrlsForInstances(List<String> instanceIps) {
return instanceIps.stream().flatMap(ip -> Stream.of( return instanceIps.stream().flatMap(ip -> Stream.of(
String.format("turn:%s", ip), String.format("turn:%s", ip),

View File

@ -169,21 +169,18 @@ public class Util {
} }
/** /**
* Chooses min(values.size(), n) random values. * Chooses min(values.size(), n) random values in shuffled order.
* <br> * <br>
* Copies the input Array - use for small lists only or for when n/values.size() is near 1. * Copies the input Array - use for small lists only or for when n/values.size() is near 1.
*/ */
public static <E> List<E> randomNOf(List<E> values, int n) { public static <E> List<E> randomNOfShuffled(List<E> values, int n) {
if(values == null || values.isEmpty()) { if(values == null || values.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<E> result = new ArrayList<>(values); List<E> result = new ArrayList<>(values);
if(n >= values.size()) {
return result;
}
Collections.shuffle(result); Collections.shuffle(result);
return result.stream().limit(n).toList(); return result.stream().limit(n).toList();
} }

View File

@ -108,7 +108,9 @@ public class TurnCallRouterTest {
() -> performanceTable, () -> performanceTable,
() -> manualTable, () -> manualTable,
configTurnRouter, configTurnRouter,
() -> geoIp () -> geoIp,
// set to true so the return values are predictable
true
); );
} }