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:
parent
cc6ec1d351
commit
854ab353b3
|
@ -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();
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue