mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
Refactor ServerStats weight calculation for improved clarity and accuracy
This commit is contained in:
parent
e1747bee13
commit
4861a10134
@ -148,14 +148,16 @@ class ServerManager(metaclass=singleton.Singleton):
|
|||||||
stats_and_servers = self.get_server_stats(fltrs)
|
stats_and_servers = self.get_server_stats(fltrs)
|
||||||
|
|
||||||
def _real_weight(stats: 'types.servers.ServerStats') -> float:
|
def _real_weight(stats: 'types.servers.ServerStats') -> float:
|
||||||
|
stats_weight = stats.weight()
|
||||||
|
|
||||||
if weight_threshold == 0:
|
if weight_threshold == 0:
|
||||||
return stats.weight()
|
return stats_weight
|
||||||
# Values under threshold are better, weight is in between 0 and 1, lower is better
|
# Values under threshold are better, weight is in between 0 and 1, lower is better
|
||||||
# To values over threshold, we will add 1, so they are always worse than any value under threshold
|
# To values over threshold, we will add 1, so they are always worse than any value under threshold
|
||||||
# No matter if over threshold is overcalculed, it will be always worse than any value under threshold
|
# No matter if over threshold is overcalculed, it will be always worse than any value under threshold
|
||||||
# and all values over threshold will be affected in the same way
|
# and all values over threshold will be affected in the same way
|
||||||
return (
|
return (
|
||||||
weight_threshold - stats.weight() if stats.weight() < weight_threshold else 1 + stats.weight()
|
weight_threshold - stats_weight if stats_weight < weight_threshold else 1 + stats_weight
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now, cachedStats has a list of tuples (stats, server), use it to find the best server
|
# Now, cachedStats has a list of tuples (stats, server), use it to find the best server
|
||||||
|
@ -33,6 +33,7 @@ import dataclasses
|
|||||||
import enum
|
import enum
|
||||||
import typing
|
import typing
|
||||||
import collections.abc
|
import collections.abc
|
||||||
|
import logging
|
||||||
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
@ -41,6 +42,8 @@ from uds.core.util import ensure, singleton
|
|||||||
|
|
||||||
IP_SUBTYPE: typing.Final[str] = 'ip'
|
IP_SUBTYPE: typing.Final[str] = 'ip'
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ServerType(enum.IntEnum):
|
class ServerType(enum.IntEnum):
|
||||||
TUNNEL = 1
|
TUNNEL = 1
|
||||||
@ -147,16 +150,6 @@ class ServerStats:
|
|||||||
current_users: int = 0 # Number of current users
|
current_users: int = 0 # Number of current users
|
||||||
stamp: float = 0 # Timestamp of this stats
|
stamp: float = 0 # Timestamp of this stats
|
||||||
|
|
||||||
@property
|
|
||||||
def cpufree_ratio(self) -> float:
|
|
||||||
# Returns a valuen between 0 and 1, being 1 the best value (no cpu used per user) and 0 the worst
|
|
||||||
return (1 - self.cpuused) / (self.current_users + 1)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def memfree_ratio(self) -> float:
|
|
||||||
# Returns a valuen between 0 and 1, being 1 the best value (no memory used per user) and 0 the worst
|
|
||||||
return (self.memtotal - self.memused) / (self.memtotal or 1) / (self.current_users + 1)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_valid(self) -> bool:
|
def is_valid(self) -> bool:
|
||||||
"""If the stamp is lesss than consts.cache.DEFAULT_CACHE_TIMEOUT, it is considered valid
|
"""If the stamp is lesss than consts.cache.DEFAULT_CACHE_TIMEOUT, it is considered valid
|
||||||
@ -174,20 +167,21 @@ class ServerStats:
|
|||||||
|
|
||||||
def weight(self, min_memory: int = 0) -> float:
|
def weight(self, min_memory: int = 0) -> float:
|
||||||
# Weights are calculated as:
|
# Weights are calculated as:
|
||||||
# 0.5 * cpu_usage + 0.5 * (1 - mem_free / mem_total) / (current_users + 1)
|
# 30% cpu usage
|
||||||
# +1 is because this weights the connection of current users + new user
|
# 60% memory usage
|
||||||
# Dividing by number of users + 1 gives us a "ratio" of available resources per user when a new user is added
|
# 10% current users, with a max of 1000 users
|
||||||
# Also note that +512 forces that if mem_free is less than 512 MB, this server will be put at the end of the list
|
# Weights are normalized to 0-1
|
||||||
|
# Lower weight is better
|
||||||
|
|
||||||
if self.memtotal - self.memused < min_memory:
|
if self.memtotal - self.memused < min_memory:
|
||||||
return 1000000000 # At the end of the list
|
return 1000000000 # At the end of the list
|
||||||
|
|
||||||
# Lower is better
|
w = (
|
||||||
# value can be between:
|
0.3 * self.cpuused
|
||||||
# (1 / (1 * 1.3 + 1) - 0.434) * 1.76 ~= 0.0 (worst case, no memory, all cpu)
|
+ 0.6 * (self.memused / (self.memtotal or 1))
|
||||||
# and
|
+ 0.1 * (min(1.0, self.current_users / 100.0))
|
||||||
# (1 / ((0 * 1.3 + 0) or 1) - 0.434) * 1.76 = 0.566 * 1.76 ~= 1.0 (best case, all memory, no cpu)
|
)
|
||||||
|
|
||||||
w = (1 / ((self.cpufree_ratio * 1.3 + self.memfree_ratio) or 1) - 0.434) * 1.76
|
|
||||||
return min(max(0.0, w), 1.0)
|
return min(max(0.0, w), 1.0)
|
||||||
|
|
||||||
def adjust(self, users_increment: int) -> 'ServerStats':
|
def adjust(self, users_increment: int) -> 'ServerStats':
|
||||||
|
Loading…
Reference in New Issue
Block a user