Positionnement des grains
Orleans garantit que lorsqu’un appel de grain est effectué, il existe une instance de ce grain disponible en mémoire sur un serveur du cluster pour gérer la demande. Si le grain n'est pas actuellement actif dans le cluster, Orleans choisit l'un des serveurs sur lequel activer le grain. Cela s'appelle le placement de grains. Le placement est aussi un moyen d'équilibrer la charge : même le placement de grains occupés contribue à répartir la charge de travail à l'échelle du cluster.
Le processus de placement dans Orleans est entièrement configurable : les développeurs peuvent choisir parmi un ensemble de stratégies de placement prêtes à l’emploi, telles que des stratégies de placement aléatoires, locales de préférence et basées sur la charge ou une logique personnalisée peuvent être configurées. Cela permet une flexibilité totale pour décider où les grains sont créés. Par exemple, les grains peuvent être placés sur un serveur proche des ressources sur lesquelles ils doivent fonctionner ou près d’autres grains avec lesquels ils communiquent. Par défaut, Orleans choisissez un serveur compatible aléatoire.
La stratégie de placement que Orleans utilise peut être configurée globalement ou par classe de grain.
Placement aléatoire
Un serveur est sélectionné de manière aléatoire à partir des serveurs compatibles dans le cluster. Cette stratégie de placement est configurée en ajoutant l'attribut RandomPlacementAttribute à un grain.
Placement local
Si le serveur local est compatible, sélectionnez le serveur local, sinon sélectionnez un serveur aléatoire. Cette stratégie de placement est configurée en ajoutant l'attribut PreferLocalPlacementAttribute à un grain.
Positionnement basé sur le hachage
Hachez l'ID de grain en entier non négatif et faites une opération modulo avec le nombre de serveurs compatibles. Sélectionnez le serveur correspondant dans la liste des serveurs compatibles classés par adresse du serveur. Notez que cela n’est pas garanti pour rester stable à mesure que l’appartenance au cluster change. Plus précisément, l’ajout, la suppression ou le redémarrage de serveurs peuvent modifier le serveur sélectionné pour un ID de grain donné. Étant donné que les grains placés à l’aide de cette stratégie sont inscrits dans le répertoire des grains, ce changement de décision de placement à mesure que les changements d’appartenance n’ont généralement pas d’effet notable.
Cette stratégie de placement est configurée en ajoutant l'attribut HashBasedPlacementAttribute à un grain.
Placement basé sur le nombre d’activations
Cette stratégie de placement vise à placer de nouvelles activations de grain sur le serveur le moins chargé en fonction du nombre de grains récemment occupés. Il inclut un mécanisme dans lequel tous les serveurs publient régulièrement leur nombre total d’activations sur tous les autres serveurs. Le directeur de placement sélectionne ensuite un serveur qui est prédit pour avoir les activations les plus rares en examinant le nombre d’activations les plus récemment signalés et prédit le nombre d’activations actuel en fonction du nombre d’activations récent effectué par le directeur de placement sur le serveur actuel. Le directeur sélectionne plusieurs serveurs au hasard lors de cette prédiction, afin d’éviter plusieurs serveurs distincts surchargeant le même serveur. Par défaut, deux serveurs sont sélectionnés de manière aléatoire, mais cette valeur est configurable via ActivationCountBasedPlacementOptions.
Cet algorithme est basé sur la thèse La puissance de deux choix dans l’équilibrage de charge aléatoire par Michael David Mitzenmacher, et est également utilisé dans Nginx pour l’équilibrage de charge distribué, comme décrit dans l’article NGINX et la « puissance de deux choix » Load-Balancing Algorithme.
Cette stratégie de placement est configurée en ajoutant l'attribut ActivationCountBasedPlacementAttribute à un grain.
Placement des workers sans état
Il s'agit d'une stratégie de placement spéciale utilisée par les grains de worker sans état. Ce placement fonctionne presque de la même façon que PreferLocalPlacement, sauf que chaque serveur peut avoir plusieurs activations du même grain et que le grain n’est pas inscrit dans le répertoire des grains, car il n’y a pas besoin.
Cette stratégie de placement est configurée en ajoutant l'attribut StatelessWorkerAttribute à un grain.
Placement en fonction du rôle de silo
Stratégie de placement déterministe qui place les grains sur des silos avec un rôle spécifique. Cette stratégie de placement est configurée en ajoutant l'attribut SiloRoleBasedPlacementAttribute à un grain.
Placement optimisé des ressources
La stratégie de placement optimisé des ressources tente d'optimiser les ressources du cluster en équilibrant les activations de grains entre les silos en fonction de la mémoire disponible et de l'utilisation du processeur. Il affecte des pondérations aux statistiques d’exécution pour hiérarchiser différentes ressources et calcule un score normalisé pour chaque silo. Le silo avec le score le plus bas est choisi pour placer l’activation à venir. La normalisation garantit que chaque propriété contribue proportionnellement au score global. Les pondérations peuvent être ajustées via le ResourceOptimizedPlacementOptions en fonction des exigences et des priorités spécifiques de l’utilisateur pour différentes ressources.
En outre, cette stratégie de placement expose une option permettant de créer une préférence plus forte pour le silo local (, celui qui a reçu la demande de création d’une nouvelle disposition), afin d'être choisi comme cible pour l’activation. Ceci est contrôlé via la propriété LocalSiloPreferenceMargin
qui fait partie des options.
En outre, un algorithme adaptatif en ligne fournit un effet de lissage qui évite les chutes rapides du signal en le transformant en un processus de décroissance de type polynomial. Cela est particulièrement important pour l’utilisation du processeur, et contribue globalement à éviter la saturation des ressources sur les silos, en particulier une fois nouvellement joint.
Cet algorithme est basé sur : placement basé sur les ressources avec filtrage Kalman en double mode coopératif
Cette stratégie de placement est configurée en ajoutant l'attribut ResourceOptimizedPlacementAttribute à un grain.
Choisir une stratégie de placement
Le choix de la stratégie de placement de grain appropriée, au-delà des valeurs par défaut que Orleans fournit, nécessite la surveillance et l’évaluation des développeurs. Le choix de la stratégie de placement doit être basé sur la taille et la complexité de l’application, des caractéristiques de charge de travail et de l’environnement de déploiement.
Le placement aléatoire s'appuie sur la Loi des grands nombres, il est donc généralement un bon choix par défaut lorsqu'il existe une charge imprévisible répartie sur un grand nombre de grains (10 000 ou plus).
L’emplacement basé sur le nombre d’activations a également un élément aléatoire, en s’appuyant sur le principe Power of Two Choices, qui est un algorithme couramment utilisé pour l’équilibrage de charge distribué et est utilisé dans les équilibreurs de charge populaires. Les silos publient fréquemment des statistiques d'exécution sur d'autres silos du cluster, notamment celles-ci :
- Mémoire disponible, mémoire physique totale et utilisation de la mémoire.
- Utilisation du processeur.
- Nombre total d’activations et nombre d’activations actives récentes.
- Fenêtre glissante des activations qui étaient actives quelques secondes auparavant, parfois appelée jeu de travail des activations.
À partir de ces statistiques, seuls les nombres d’activations sont actuellement utilisés pour déterminer la charge sur un silo donné.
En fin de compte, vous devez expérimenter différentes stratégies et surveiller les métriques de performances pour déterminer le meilleur ajustement. En sélectionnant la stratégie de placement des grains appropriée, vous pouvez optimiser les performances, l’extensibilité et l’efficacité de vos applications Orleans.
Configurer la stratégie de placement par défaut
Orleans utilisera un placement aléatoire, sauf si la valeur par défaut est remplacée. La stratégie de placement par défaut peut être remplacée en inscrivant une implémentation de PlacementStrategy pendant la configuration :
siloBuilder.ConfigureServices(services =>
services.AddSingleton<PlacementStrategy, MyPlacementStrategy>());
Configurer la stratégie de placement d’un grain
La stratégie de placement d’un type de grain est configurée en ajoutant l’attribut approprié sur la classe de grain. Les attributs pertinents sont spécifiés dans les sections des stratégies de placement .
Exemple de stratégie de placement personnalisée
Commencez par définir une classe qui implémente IPlacementDirector interface, nécessitant une seule méthode. Dans cet exemple, nous partons du principe que vous disposez d’une fonction GetSiloNumber
définie pour renvoyer un numéro de silo en fonction de la Guid du grain sur le point d’être créé.
public class SamplePlacementStrategyFixedSiloDirector : IPlacementDirector
{
public Task<SiloAddress> OnAddActivation(
PlacementStrategy strategy,
PlacementTarget target,
IPlacementContext context)
{
var silos = context.GetCompatibleSilos(target).OrderBy(s => s).ToArray();
int silo = GetSiloNumber(target.GrainIdentity.PrimaryKey, silos.Length);
return Task.FromResult(silos[silo]);
}
}
Vous devez ensuite définir deux classes pour permettre aux classes de grain d’être affectées à la stratégie :
[Serializable]
public sealed class SamplePlacementStrategy : PlacementStrategy
{
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class SamplePlacementStrategyAttribute : PlacementAttribute
{
public SamplePlacementStrategyAttribute() :
base(new SamplePlacementStrategy())
{
}
}
Après quoi, étiquetez les classes de grain que cette stratégie doit utiliser avec l'attribut suivant :
[SamplePlacementStrategy]
public class MyGrain : Grain, IMyGrain
{
// ...
}
Enfin, enregistrez la stratégie lorsque vous construisez le SiloHost:
private static async Task<ISiloHost> StartSilo()
{
var builder = new HostBuilder(c =>
{
// normal configuration methods omitted for brevity
c.ConfigureServices(ConfigureServices);
});
var host = builder.Build();
await host.StartAsync();
return host;
}
private static void ConfigureServices(IServiceCollection services)
{
services.AddPlacementDirector<SamplePlacementStrategy, SamplePlacementStrategyFixedSiloDirector>();
}
Pour un deuxième exemple simple montrant une utilisation plus poussée du contexte de placement, reportez-vous à l'article PreferLocalPlacementDirector
dans le référentiel source Orleans.