Skip to content

Commit 34b4a33

Browse files
authored
Automatic load redistribution (#1212)
* ref: Extract "move endpoints" logic to a separate class. * feat: Automatic bridge load redistribution. * ref: Remove unnecessary wrapper.
1 parent b62948d commit 34b4a33

File tree

8 files changed

+221
-67
lines changed

8 files changed

+221
-67
lines changed

jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/Bridge.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ class Bridge @JvmOverloads internal constructor(
246246
}
247247
}
248248

249+
/** Updates the "endpoints moved" metric for this bridge. */
250+
fun endpointsMoved(count: Long) {
251+
BridgeMetrics.endpointsMoved.add(count, listOf(jid.resourceOrEmpty.toString()))
252+
}
249253
fun endpointRemoved() = endpointsRemoved(1)
250254
fun endpointsRemoved(count: Int) {
251255
endpoints.addAndGet(-count)
@@ -261,6 +265,8 @@ class Bridge @JvmOverloads internal constructor(
261265
if (removed.compareAndSet(false, true)) {
262266
BridgeMetrics.restartRequestsMetric.remove(listOf(jid.resourceOrEmpty.toString()))
263267
BridgeMetrics.endpoints.remove(listOf(jid.resourceOrEmpty.toString()))
268+
BridgeMetrics.failingIce.remove(listOf(jid.resourceOrEmpty.toString()))
269+
BridgeMetrics.endpointsMoved.remove(listOf(jid.resourceOrEmpty.toString()))
264270
}
265271
}
266272
internal fun updateMetrics() {

jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/BridgeConfig.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class BridgeConfig private constructor() {
157157
if (region == null) emptySet() else regionGroups[region] ?: setOf(region)
158158

159159
val iceFailureDetection = IceFailureDetectionConfig()
160+
val loadRedistribution = LoadRedistributionConfig()
160161

161162
companion object {
162163
const val BASE = "jicofo.bridge"
@@ -166,7 +167,7 @@ class BridgeConfig private constructor() {
166167
}
167168
}
168169

169-
class IceFailureDetectionConfig {
170+
class IceFailureDetectionConfig internal constructor() {
170171
val enabled: Boolean by config {
171172
"$BASE.enabled".from(JitsiConfig.newConfig)
172173
}
@@ -187,3 +188,29 @@ class IceFailureDetectionConfig {
187188
const val BASE = "jicofo.bridge.ice-failure-detection"
188189
}
189190
}
191+
192+
class LoadRedistributionConfig internal constructor() {
193+
val enabled: Boolean by config {
194+
"$BASE.enabled".from(JitsiConfig.newConfig)
195+
}
196+
val interval: Duration by config {
197+
"$BASE.interval".from(JitsiConfig.newConfig)
198+
}
199+
val timeout: Duration by config {
200+
"$BASE.timeout".from(JitsiConfig.newConfig)
201+
}
202+
val stressThreshold: Double by config {
203+
"$BASE.stress-threshold".from(JitsiConfig.newConfig)
204+
}
205+
val endpoints: Int by config {
206+
"$BASE.endpoints".from(JitsiConfig.newConfig)
207+
}
208+
209+
override fun toString(): String =
210+
"LoadRedistributionConfig(enabled=$enabled, interval=$interval, timeout=$timeout, " +
211+
"stressThreshold=$stressThreshold, endpoints=$endpoints)"
212+
213+
companion object {
214+
const val BASE = "jicofo.bridge.load-redistribution"
215+
}
216+
}

jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/BridgeMetrics.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,10 @@ class BridgeMetrics {
1919
"Whether a bridge is currently in the failing ICE state.",
2020
labelNames = listOf("jvb")
2121
)
22+
val endpointsMoved = metricsContainer.registerCounter(
23+
"bridge_endpoints_moved",
24+
"Total number of endpoints moved away from a bridge for automatic load redistribution.",
25+
labelNames = listOf("jvb")
26+
)
2227
}
2328
}

jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/BridgeSelector.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class BridgeSelector @JvmOverloads constructor(
6666
JicofoMetricsContainer.instance.metricsUpdater.addUpdateTask { updateMetrics() }
6767
}
6868

69+
fun hasNonOverloadedBridge(): Boolean = bridges.values.any { !it.isOverloaded }
70+
fun getAll(): List<Bridge> = bridges.values.toList()
71+
6972
val operationalBridgeCount: Int
7073
@Synchronized
7174
get() = bridges.values.count { it.isOperational && !it.isInGracefulShutdown }

jicofo-selector/src/main/resources/reference.conf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ jicofo {
9696
// the condition is met).
9797
timeout = 10 minutes
9898
}
99+
load-redistribution {
100+
// Whether automatic redistribution of endpoints away from overloaded bridges is enabled.
101+
enabled = false
102+
// The interval at which to run.
103+
interval = 1 minute
104+
// The threshold above which to redistribute endpoints away from a bridge. This needs to be higher than
105+
// jicofo.bridge.stress-threshold.
106+
stress-threshold = 0.9
107+
// The amount of time to wait before moving more endpoints away from a bridge.
108+
timeout = 3 minutes
109+
// The number of endpoints to move away from a bridge at a time.
110+
endpoints = 10
111+
}
99112
}
100113
// Configure the codecs and RTP extensions to be used in the offer sent to clients.
101114
codec {

jicofo/src/main/kotlin/org/jitsi/jicofo/JicofoServices.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import org.jitsi.jicofo.bridge.BridgeConfig
2626
import org.jitsi.jicofo.bridge.BridgeMucDetector
2727
import org.jitsi.jicofo.bridge.BridgeSelector
2828
import org.jitsi.jicofo.bridge.JvbDoctor
29+
import org.jitsi.jicofo.bridgeload.LoadRedistributor
2930
import org.jitsi.jicofo.health.HealthConfig
3031
import org.jitsi.jicofo.health.JicofoHealthChecker
3132
import org.jitsi.jicofo.jibri.JibriConfig
@@ -83,6 +84,8 @@ class JicofoServices {
8384
null
8485
}
8586

87+
private val loadRedistributor = LoadRedistributor(focusManager, bridgeSelector)
88+
8689
private val bridgeDetector: BridgeMucDetector? = BridgeConfig.config.breweryJid?.let { breweryJid ->
8790
BridgeMucDetector(
8891
xmppServices.getXmppConnectionByName(BridgeConfig.config.xmppConnectionName),
@@ -138,7 +141,7 @@ class JicofoServices {
138141
healthChecker,
139142
xmppServices.conferenceIqHandler,
140143
focusManager,
141-
bridgeSelector,
144+
loadRedistributor,
142145
{ getStats() }
143146
) { full, confId ->
144147
if (confId == null) {
@@ -169,6 +172,7 @@ class JicofoServices {
169172
bridgeSelector.removeHandler(it)
170173
it.shutdown()
171174
}
175+
loadRedistributor.shutdown()
172176
bridgeDetector?.shutdown()
173177
jibriDetector?.shutdown()
174178
sipJibriDetector?.shutdown()

0 commit comments

Comments
 (0)