Sensibilisation autour du Work Manager

Nos plateformes OSB peuvent parfois être fortement sollicitées, pouvant, en cas de surcharge, provoquer des indisponibilités de services voire de toute la plateforme.
Afin de se prémunir de genre de désagréments, Oracle propose un mécanisme de « Work Manager » qui permet de protéger les environnements.

Définition

Un « Work Manager » ou « gestionnaire de travaux » est un mécanisme permettant de contrôler le nombre de threads d’exécution alloués en parallèle à un service donné au sein de l’OSB.
Cela permet donc d’établir une notion de priorisation des services en fonction de leur criticité et du temps de réactivité attendu, mais également d’éviter de bloquer l’ensemble des services de façon simultanée en cas de pic de charge.

Par défaut, si aucun Work Manager n’est défini, le service utilise un pool de threads commun géré par le nœud d’administration au sein de Weblogic. En cas de saturation de ce Work Manager, l’ensemble des services s’en retrouve pénalisé.

 

 

 

 

 

 

 

 

Il est donc fortement recommandé de cloisonner les services en utilisant des Work Managers distincts. La stratégie à adopter étant bien sûr propre à chaque plateforme : par priorité, par criticité, par domaine fonctionnel…

 

Il est ainsi possible de fixer un nombre minimum ou maximum de threads pour chaque Work Manager mais également de définir un comportement à appliquer en cas d’atteinte de la limite maximum.

Création de Work Managers

Par la console d’administration

Les Work Managers sont définis dans la console Weblogic par le menu Environnement => Gestionnaires de travaux.

Les 2 propriétés principales sont le « minimum thread constraint » et le « maximum thread constraint ». Elles permettent de fixer respectivement le nombre de threads d’exécution simultanés minimum et maximum alloués au Work Manager.

Le « capacity constraint » permet, quant à lui, de préciser le nombre de requêtes mises en file d’attente une fois la « contrainte maximum » atteinte. Si la « capacity contrainte » est atteinte, les messages sont rejetés, ce qui permet de protéger la plateforme d’une éventuelle surcharge. Par défaut, la valeur est positionnée à « -1 » ce qui met tous les messages entrant en fil d’attente.

Par script

Il est également possible de créer les Work Manager par script pour plus de facilité dans le cadre de l’industrialisation de projet.

Voici donc un exemple de script WLST qui crée un Work Manager avec les 3 contraintes associées (minimum, maximum et capacity).

from wlstModule import *#@UnusedWildImport

##################################################################
#
# CREATION D'UN WORK MANAGER WEBLOGIC
#
# clusterNames        : "MonCluster" 
# workmanagerName     : "MonWM"
# minThreadConstraint : 1
# maxThreadConstraint : 5
# capacityConstraint  : 10
# ignoreStuckThread   : true
# 
##################################################################
def add_target(clusterNames,object,isCluster) :
    if isCluster :
      for clusterName in clusterNames:
        targetMB=getMBean("/Clusters/"+ clusterName)
        object.addTarget(targetMB)
    else:
      for clusterName in clusterNames:
        targetMB=getMBean("/Servers/"+ clusterName)
        object.addTarget(targetMB)

def create_workManager(clusterNames, workmanagerName, minThreadConstraint, maxThreadConstraint, capacityConstraint, ignoreStuckThread, isCluster=True, overwrite=False) :
    # CREATION DU WORKMANAGER
    currentDomainName=getMBean(pwd()).getName()
    capacityConstraintName=workmanagerName + "_capacityConstraint"
    maxThreadConstraintName=workmanagerName + "_maxThreads"
    minThreadConstraintName=workmanagerName + "_minThreads"
    workManagersPath='/SelfTuning/' + currentDomainName
    print ""
    print " Debut de creation du workmanager " + workmanagerName
    print ""
    print " Nom du domaine : " + currentDomainName
    # Vérification existence du domaine
    stMBean=getMBean(workManagersPath)
    if stMBean is None:
        print "@@@ Invalid DOMAIN Name : " + currentDomainName
        exit()
    wmMBean=getMBean(workManagersPath + "/WorkManagers/" + workmanagerName)
    wmMaxMBean=getMBean(workManagersPath + "/MaxThreadsConstraints/" + maxThreadConstraintName)
    wmMinMBean=getMBean(workManagersPath + "/MinThreadsConstraints/" + minThreadConstraintName)
    wmCapaMBean=getMBean(workManagersPath + "/Capacities/" + capacityConstraintName)
    if overwrite :
        print ""
        print " # 0.1 Suppression de l'ancien workmanager " + workmanagerName + "..."
        if wmMBean is None:
            print " ## Le work manager n'existe pas !!!"
        else :
            stMBean.destroyWorkManager(wmMBean)
            print " ## Suppression effectuee !!!"
        print ""
        print " # 0.2 Suppression de la contrainte Max Thread " + maxThreadConstraintName + "..."
        if wmMaxMBean is None:
            print " ## Le contrainte n'existe pas !!!"
        else :
            stMBean.destroyMaxThreadsConstraint(wmMaxMBean)
            print " ## Suppression effectuee !!!"
        print ""
        print " # 0.3 Suppression de la contrainte Min Thread " + minThreadConstraintName + "..."
        if wmMinMBean is None:
            print " ## Le contrainte n'existe pas !!!"
        else :
            stMBean.destroyMinThreadsConstraint(wmMinMBean)
            print " ## Suppression effectuee !!!"
        print ""
        print " # 0.4 Suppression de la contrainte Capacity " + capacityConstraintName + "..."
        if wmCapaMBean is None:
            print " ## Le contrainte n'existe pas !!!"
        else :
            stMBean.destroyCapacity(wmCapaMBean)
            print " ## Suppression effectuee !!!"
    print ""
    print " # 1.1 Creation de la contrainte Max Thread " + maxThreadConstraintName + "..." + " => Valeur : " + maxThreadConstraint
    if overwrite or wmMaxMBean is None:       
        maxThreadConstInstance=stMBean.createMaxThreadsConstraint(maxThreadConstraintName)
        #maxThreadConstInstance.addTarget(targetsTab)
        add_target(clusterNames,maxThreadConstInstance,isCluster)
        maxThreadConstInstance.setCount(int(maxThreadConstraint))
        wmMaxMBean=getMBean(workManagersPath + "/MaxThreadsConstraints/" + maxThreadConstraintName)
        print " ## Contrainte creee !!!"
    else :
        print " ## La contrainte existe déjà !!!"
    print ""
    print " # 1.2 Creation de la contrainte Min Thread " + minThreadConstraintName + "..." + " => Valeur : " + minThreadConstraint
    if overwrite or wmMinMBean is None:       
        minThreadConstInstance=stMBean.createMinThreadsConstraint(minThreadConstraintName)
        add_target(clusterNames,minThreadConstInstance,isCluster)
        minThreadConstInstance.setCount(int(minThreadConstraint))
        wmMinMBean=getMBean(workManagersPath + "/MinThreadsConstraints/" + minThreadConstraintName)
        print " ## Contrainte creee !!!"
    else :
        print " ## La contrainte existe déjà !!!"
    print ""
    print " # 1.3 Creation de la contrainte Capacity " + capacityConstraintName + "..." + " => Valeur : " + capacityConstraint
    if overwrite or wmCapaMBean is None:       
        capacityConstInstance=stMBean.createCapacity(capacityConstraintName)
        add_target(clusterNames,capacityConstInstance,isCluster)
        capacityConstInstance.setCount(int(capacityConstraint))
        wmCapaMBean=getMBean(workManagersPath + "/Capacities/" + capacityConstraintName)
        print " ## Contrainte creee !!!"
    else :
        print " ## La contrainte existe déjà !!!"
    print ""
    print " # 1.4 Creation du work manager " + workmanagerName + "..."
    if overwrite or wmMBean is None:       
        workManagerInstance=stMBean.createWorkManager(workmanagerName)
        add_target(clusterNames,workManagerInstance,isCluster)
        workManagerInstance.setMinThreadsConstraint(wmMinMBean)
        workManagerInstance.setMaxThreadsConstraint(wmMaxMBean)
        workManagerInstance.setCapacity(wmCapaMBean)
        workManagerInstance.setIgnoreStuckThreads(ignoreStuckThread)
        print " ## Work manager cree !!!"
    else :
        print " ## Le work manager existe déjà !!!"
    print ""
    print " Fin de creation du workmanager " + workmanagerName
    print ""
    return 1

Affectation des Work Managers

Une fois le Work Manager créé, il ne reste plus qu’à l’associer au service concerné (proxy service ou business service) dans l’onglet transport, dans la propriété « dispatch policy ».