Partager via


Didacticiel SOA HPC Pack III – Mode interactif

Dans tutoriel II nous avons discuté de la façon de traiter un service chronophage en employant une session durable. Toutefois, le mode batch n’est pas le seul mode de calcul dans le monde HPC. Certains calculs peuvent être terminés en quelques secondes à quelques minutes. L’utilisateur final peut s’attendre à une réponse quasi en temps réel.

Ce mode présente différents défis par rapport au mode batch. Le temps de réponse est plus critique. Par conséquent, la surcharge de démarrage de session ne peut pas être ignorée. Dans un cluster HPC classique, il faut quelques secondes pour démarrer une nouvelle session. Si d’autres travaux s’exécutent sur le cluster, la session nouvellement créée doit attendre que les ressources soient disponibles, ce qui rend le temps de démarrage beaucoup plus long. Heureusement, HPC Pack offre un moyen de gérer cette situation et de réduire les coûts inutiles.

Consultez l’exemple de code associé pour suivre les étapes décrites dans cet article.

Implémenter le service

Nous utilisons le même service que dans didacticiel II : le service de factorisation prime. Pour répondre aux exigences en temps réel, nous allons simplement passer de petits nombres au service.

Voici le contrat de service :

[ServiceContract]
public interface IPrimeFactorization
{
    [OperationContract]
    List<int> Factorize(int n);
}

Voici l’implémentation du service :

public List<int> Factorize(int n)
{
    List<int> factors = new List<int>();

    for (int i = 2; n > 1;)
    {
        if (n % i == 0)
        {
            factors.Add(i);
            n /= i;
        }
        else
        {
            i++;
        }
    }

    return factors;
}

Implémenter le client

Pour gagner du temps de démarrage du nouveau travail, le client doit réutiliser la session existante au lieu de en créer un, car la création d’une nouvelle session signifie démarrer un nouveau travail. Pour réutiliser la session existante, nous devons créer la session comme suit :

const string headnode = "head.contoso.com";
const string serviceName = "PrimeFactorizationService";

SessionStartInfo info = new SessionStartInfo(headnode, serviceName);

//Enable session pool
info.ShareSession = true;
info.UseSessionPool = true;

Vous remarquerez peut-être qu’il existe deux nouvelles propriétés de SessionStartInfo attribuées ici.

La définition de ShareSession sur true signifie que n’importe quel utilisateur peut envoyer des demandes au répartiteur, pas seulement celle qui crée la session.

La définition de UseSessionPool sur true garantit que chaque nouveau client utilise la session existante au lieu de créer une autre session. Le pool de sessions est géré côté serveur : il garantit que lorsqu’un client se connecte au même service avec l’indicateur défini sur true, il retourne toujours la même session tant qu’elle est toujours vivante.

Nous pouvons maintenant créer la session. Nous ne voulons pas utiliser une session durable, car elle peut affecter les performances.

//create an interactive session
using (Session session = Session.CreateSession(info))
{
    Console.WriteLine("Session {0} has been created", session.Id);
    …
}

Créez un client broker pour envoyer des demandes et obtenir des réponses.

Dans le cas du code précédent, nous avons maintenant une situation où il peut y avoir de nombreux clients broker dans une seule session. Dans ce cas, nous devons affecter un ID unique au client.

//in one session, each broker client should have a unique id
string ClientId = Guid.NewGuid().ToString();
using (BrokerClient<IPrimeFactorization> client = new BrokerClient<IPrimeFactorization>(ClientId, session))
{
    Console.WriteLine("BrokerClient {0} has been created", ClientId);
    Random random = new Random();
    int num = random.Next(1, Int32.MaxValue);

    //Send request
    FactorizeRequest request = new FactorizeRequest(num);
    client.SendRequest<FactorizeRequest>(request, num);
    client.EndRequests();

    //Get response
    foreach (BrokerResponse<FactorizeResponse> response in client.GetResponses<FactorizeResponse>())
    {
        int number = response.GetUserData<int>();
        int[] factors = response.Result.FactorizeResult;
        Console.WriteLine("{0} = {1}", number, string.Join<int>(" * ", factors));
    }
}

Exécutez maintenant le client deux fois. Vous verrez que les clients partagent le même ID de session, à la suite du pool de sessions activé. En outre, le premier client s’exécute beaucoup plus longtemps que le deuxième, ce qui indique que le nouveau client réutilise la session créée.

Étant donné que GetResponses est une fonction synchrone, le client est bloqué et conservé en attente des résultats. Ce n’est pas une situation d’accueil dans un système en temps réel. Nous allons donc essayer une autre façon d’obtenir des réponses.

Nous pouvons définir une rappel asynchrone pour le client à l’aide de SetResponseHandler comme suit :

//use this event sync main thread and callback
AutoResetEvent done = newAutoResetEvent(false);

//set callback function. this handler will be invoke before service replies.
client.SetResponseHandler<FactorizeResponse>((response) =>
{
    int number = response.GetUserData<int>();
    int[] factors = response.Result.FactorizeResult;
    Console.WriteLine("{0} = {1}", number, string.Join<int>(" * ", factors));

    //release the lock
    done.Set();
});

Ainsi, après l’envoi normal de demandes, le client peut continuer avec d’autres tâches. Lorsque les réponses sont prêtes, le gestionnaire de réponses est appelé pour afficher les résultats.

Déployer et tester le service

Vous pouvez suivre ce didacticiel pour déployer et tester le cas pas à pas.

Vous pouvez exécuter plusieurs clients. La sortie sera semblable à ceci :

0624.clip_image008_51125C34

Notez que tous les clients partagent le même ID de session.

Croissance automatique du cluster et réduction automatique

Une situation courante du mode interactif consiste à exécuter un service de longue durée servant plusieurs clients. Pour répondre à chaque demande le plus rapidement possible, nous devons maintenir la session en vie. Mais, d’autre part, avoir un travail SOA occupe un grand nombre de ressources pendant les heures creuses est gaspiller.

HPC Pack offre une fonctionnalité permettant de développer et de réduire les ressources en fonction du nombre de demandes. S’il n’y a aucune demande, il réduit le nombre de ressources au nombre minimal spécifié par le travail. Lors de la réception de demandes, il augmente automatiquement les ressources pour les gérer.

Remarque: une session expire si aucun client ne se connecte pendant une période donnée. Pour faire d’une session un service de longue durée, vous pouvez modifier l' sessionIdleTimeout lors du démarrage de la session.