jeudi 15 novembre 2012


Enfin un mariage consommé entre BEA Weblogic et Oracle Database. Le nouveau driver GridLink est un substitue du MultiDataSource pour se connecter à une DataBase Oracle en RAC (Real Application Clusters).

L’objectif étant d’utiliser les internes de la DataBase pour mieux coller à son architecture. Ce driver va plus loin est rend caduque tous les palliatifs de détection d’absence de ressource distante qui dégrade les performances du serveur d’application. Les avantages par rapport au MultiPool sont :

ü  Éliminer les tests de vérification de présence de base qui charge inutilement l’infrastructure (remonté de notification lors d’incident directement plutôt que test systématique de la connexion).
ü  Éliminer le polling pour être notifié d’une remontée d’un nœud DataBase.
ü  Cache l’infrastructure sous-jacente de la DataBase (Ajout ou suppression dynamique de nœud RAC sans modification de configuration Weblogic).
ü  Répartition de charge intelligente fonction de la charge des nœuds RAC (plutôt qu’un RoundRobine).
ü  Notification immédiate d’incident lors de perte sans devoir attendre de TIMEOUT (plus de perte de temps côté application).
ü  Conservation de la connexion sur une même transaction initiée par Weblogic (implémenté côté driver et non plus dans Weblogic) (non supporté en MultiDataSource dans le cas d’une transaction globale).
ü  Répartition sur les instances RAC lors de la création des connexions (un seul pool, plusieurs connexions différentes).

PRINCIPES


La différence du GridLink par rapport au MultiDataSource est qu’il n’utilise qu’un seul DataSource. Le MultiDataSource  est obligé de déclarer autant de pool que d’instance RAC.





   Ce driver utilise UCP (Universal Connection Pool) pour l’implémentation du pool et ses fonctionnalités de FCF (Fast Connection Failover) via les notifications d’événement FAN (Fast Application Notification). Cela permet de :

ü  Annuler et supprimer des connexions non valides.
ü  Arrêt transparent planifier ou non d’instance DataBase.
ü  S'adapter aux changements de topologie, tels que l'ajout ou la suppression d'un nœud.
ü  Distribution dynamique des requetâge selon la charge DataBase.

Pour la phase de connexion, le driver supporte le SCAN DataBase (Single Client Access Name) (RCLB : Runtime Connection Load-Balancing) qui permet de répartir les connexions sur l’ensemble des nœuds RAC. Le pool GridLink mélange donc des connexions différentes d’instances RAC.
                                                                           





C’est la partie ONS (Oracle Notification Service) qui notifie le client de tout changement dans l’architecture RAC (tombé volontaire ou non de nœud, ajout ou suppression de nœud, indication de stress des nœuds). Cela permet au GridLink d’adapter la charger et les connexions dynamiquement à l’état du cluster RAC et rendre transparent tout changement d’architecture.







Ci-dessous un extrait de documentation qui explique comment sont gérées les connexions lors de mouvement de nœuds RAC.

Planned down Event

Planned outages are defined as database maintenance or other activities that are needed to perform at a known point in time. Support for these events is available where an Oracle RAC service can be gracefully shutdown. In such scenarios, any borrowed or inuse connections are not interrupted and closed until work is completed and control of the connection is returned to the pool. This provides an extremely efficient way in large heterogeneous customer environments to manage planned outages.
           
Unplanned down Event

Support for unplanned outages is provided by detecting and removing stale connections to an Oracle RAC cluster. Stale connections include connections that do not have a service available on any instance in an Oracle RAC cluster due to service-down and nodedown events. Borrowed connections and available connections that are stale are detected, and their network connection is severed before removing them from the pool. These removed connections are not replaced by the pool. Instead, the application must retry connections before performing any work with a connection. The primary difference between unplanned and planned shutdown scenarios is how borrowed connections are handled. Stale connections that are idle in the pool (not borrowed) are removed in the same manner as the unplanned shutdown scenario.

Up Event

Oracle RAC Instance Rejoin and New Instance Scenarios -Scenarios where an Oracle RAC cluster adds instances that provide a service of interest are supported. The instance may be new to the cluster or may have been restarted after a down event. In both cases, WebLogic Connection Pool for JDBC recognizes the new instance and creates connections to the node as required

LOAD BALANCING


Ci dessous un extrait de documentation qui explique comment et géré l’attribution de connexion

Load Balancing


The load balancing advisory service issues FAN events that advise clients on the current state of the cluster including advice on where to direct connections to. WebLogic Server connection pool receives load balancing advisory events issued by the database, and distributes connections to the RAC nodes accordingly as shown in the diagram below.


• Manages pooled connections for high performance and scalability
• Receives continuous recommendations on the percentage of work to route to database instances
• Adjusts distribution of work based on different back-end node capacities such as CPU capacity or response time
• Reacts quickly to changes in cluster reconfiguration, application workload, overworked nodes, or hangs
• Receives metrics from the Oracle RAC Load Balance Advisory. Connections to well performing instances are used most often. New and unused connections to under-performing instances will gravitate away over time. When distribution metrics are not received, connection is selected using a random choice

Connection Affinity

Connection affinity allows a connection pool to select connections that are directed at a specific Oracle RAC instance to provide the best performance for the customer applications. The pool uses run-time connection load balancing to select an Oracle RAC instance to create the first connection and then subsequent connections are created with an affinity to the same instance.

Transaction-Based Affinity

Transaction-based affinity is an affinity to an Oracle RAC instance that can be released by either the client application or a failure event. Applications typically use this type of affinity when long-lived affinity to an Oracle RAC instance is desired or when the cost (in terms of performance) of being redirected to a new Oracle RAC instance is high. WebLogic XA connections that are enlisted in a distributed transaction keep an affinity to the Oracle RAC instance for the duration of the transaction. In this case, an application would incur a significant performance cost if a connection is redirect to a different Oracle RAC instance during the distributed transaction.

The affinity will be established based on the global transaction id, instead of by individual data source, to ensure that connections obtained from different data sources that are configured for the same RAC cluster are all associated with the same RAC instance.  The LLR two-phase commit optimization will be supported by the RAC data source and will also participate in XA affinity.





The Universal Connection Pool Java library

has been integrated with WebLogic Server and been utilized by WebLogic GridLink data source implementation to provide the Fast Connection Failover, Runtime Connection Load Balancing and Affinity features

Oracle Database services (services)

are logical abstractions for managing workloads in Oracle Database. Services divide workloads into logically disjoint groupings.  Each service represents a workload with common attributes, service-level thresholds, and priorities.  Services are built into the Oracle Database, providing a single system image for workloads, prioritization for workloads, performance measures for real transactions, and alerts and actions when performance goals are violated. Services enable database administrators to configure a workload, administer it, enable/disable it, and measure workload as a single entity.


PARAMETRAGE



Le fait de créer un DataSource de type GridLink avec le FAN active, désactive complètement les tests de validité de connexion (Test Connections On Reserve, Test Frequency) et de pooling (Connection Creation Retry Frequency). Ces paramètres peuvent être réactivés en désactivant le FAN.

Création d’un DataSource de type GridLink.





On  spécifie l’URL SCAN d’accès aux instances RAC.



Test de connexion en succès.


Spécification des instances ONS de notification avec les notifications FAN. On pourra spécifier ces certificats pour sécuriser les connexions avec les ONS Wallet.




Test de connexion en succès.



VALIDATION



Pour vérifier le bon fonctionnement de l’infrastructure mis en place, vous pouvez utiliser une petite application (gridlank_ha.war) qui démontre la répartition de charge des connexions.











mercredi 20 juin 2012

L’objectif de CommonJ est de proposer une interface de développement pour effectuer des traitements en parallèle dans un contexte JEE. Traditionnellement, pour réaliser des traitements en parallèle, il faut créer des Threads distincts pour exécuter chaque traitement hors cette chose est strictement interdite sur un serveur d’application, car trop dangereuse et dévolue au moteur de l’instance.

Un pattern de contournement était d’utiliser un pool MDB et une file JMS pour déclarer des traitements en parallèle (la taille du pool étant le nombre de traitements en parallèle possibles), mais cela impose de déclarer et administrer une file JMS.

Le principe de CommonJ et de s’appuyer sur les WorkManager pour déclarer les Thread et de proposer une interface de développement pour lancer les traitements à déployer sur ces WorkManager.

Il faut donc développer spécifiquement avec l’interface de CommonJ afin de déclarer les traitements à effectuer en parallèle et de récupérer une référence d’un Workmanager que l’on déclarer dans la configuration Weblogic via la console ou via les descripteurs JEE.

Cette API est utilisée en interne de beaucoup de framework éditeur comme Oracle Service Bus mais peut rependu dans les développements classique JEE car peut connu.

DEVELOPPEMENT



Nous allons reprendre un excellent article sur le sujet comme exemple de développement. Cet article montre la façon d’implémenter une méthode de simulation de traduction de mot via une Servlet qui fonctionne soit en série soit en parallèle.


J’ai donc repris ce code exemple dans une Web Application que j’ai appelé CommonjWAR, j’ai créé deux Servlet ServletSequential et ServletParallel issue de AbstractServlet. J’ai modifié ce code pour déclarer non pas 5 actions, mais 100 traitements.

AbstractServlet
private List getClientInput() {
             
   ArrayList arrList = new ArrayList();
   for( int i = 0; i < 100; i++ ) { arrList.add( Integer.toString(i)); }
             
   return arrList;
   // return Arrays.asList(new String[] { "one", "two", "three", "four", "five" } );
}

Le traitement séquentiel est réalise par la Servlet ServletSequential avec une bête boucle.

for (Iterator iter = input.iterator(); iter.hasNext();) {
             
   String source = (String) iter.next();
   Translator translator = new DummyTranslator(source, DELAY);
   translator.translate();
   result.add(translator.getTranslation());
}

Le traitement en parallèle est déclare dans la Servlet ServletParallel qui récupérer via un lookup JNDI une référence à un WorkManager de nom wm/MyWorkManager.


try {
                    
   InitialContext ctx = new InitialContext();
   this.workManager = (WorkManager) ctx.lookup("java:comp/env/wm/MyWorkManager");
                    
} catch (Exception e) { throw new ServletException(e); }

On injecte ensuite les traitements à réaliser sur le WorkManager, on attend la fin de l’ensemble des traitements que l’on re agrège

for (Iterator iter = input.iterator(); iter.hasNext();) {
                    
   String source = (String) iter.next();
   Translator translator = new DummyTranslator(source, 10 * 1000);

   // schedule
   Work work = new WorkTranslatorWrapper(translator);
   WorkItem workItem = this.workManager.schedule(work);
   jobs.add(workItem);
}

System.out.println( System.currentTimeMillis()  + " : All jobs scheduled at : " );
// wait for all jobs to complete
this.workManager.waitForAll(jobs, WorkManager.INDEFINITE);

// extract results
for (Iterator iter = jobs.iterator(); iter.hasNext();) {
                    
   WorkItem workItem = (WorkItem) iter.next();
   Translator translator = (Translator) workItem.getResult();
   result.add(translator.getTranslation());
}

J’ai déclaré dans le web.xml le nom du WorkManager que j’utilise dans mon code.


 <resource-ref>  
   <res-ref-name>wm/MyWorkManager</res-ref-name>  
   <res-type>commonj.work.WorkManager</res-type>  
   <res-auth>Container</res-auth>  
   <res-sharing-scope>Shareable</res-sharing-scope>  
 </resource-ref>  

ENVIRONNEMENT



Pour déployer cette  application, j’ai créé un domaine mono instance en mode production. J’ai déclaré un WorkManager du nom que j’ai déclaré dans le web.xml (wm/MyWorkManager). J’ai ajouté à ce WorkManager une contrainte minimum en concordance avec le nombre de traitements déclaré en parallèle dans mon code, c’est à dire 100.




Je déploie mon application sur cette instance et j’exécute les deux Servet en observant la sortie standard.

Avant activation, nous avons 6 Threads déclaré dans le pool de l’instance.


Activons le traitement en séquentiel.

http://localhost:7001/CommonjWAR/ServletSequential

L’affichage nous montre que les traitements s’effectuent en séquentiel et le temps pour réaliser tous les traitements est de 100*10s. On peut observer que seul le Thread 1 est utilisé pour le traitement.

begin
1339495038734 JOB[0] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
1339495048735 JOB[1] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
1339495058735 JOB[2] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
1339495068735 JOB[3] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
1339495078735 JOB[4] in 10001 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
1339495088736 JOB[5] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
1339495098736 JOB[6] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue:

….

1339495038734 JOB[99] in 10000 ms on [[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]
done in 1000045

Nombre de threads après traitement.


(Au bout de 10 minutes, le thread est considéré comme bloqué par Weblogic)

1339495698764 JOB[66] in 10000 ms on [[STUCK] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [default]

Exécutons maintenant ces mêmes traitements, mais via le WorkManager.

http://localhost:7001/CommonjWAR/ServletParallel

begin
1339501775295 : All jobs scheduled at :
1339501775283 JOB[17] in 10000 ms on [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[19] in 10000 ms on [[STANDBY] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[14] in 10001 ms on [[ACTIVE] ExecuteThread: '17' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[12] in 10001 ms on [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[1] in 10001 ms on [[ACTIVE] ExecuteThread: '9' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[10] in 10001 ms on [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[3] in 10001 ms on [[ACTIVE] ExecuteThread: '18' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775283 JOB[6] in 10001 ms on [[ACTIVE] ExecuteThread: '13' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]


1339501775295 JOB[94] in 10000 ms on [[STANDBY] ExecuteThread: '96' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775295 JOB[95] in 10000 ms on [[STANDBY] ExecuteThread: '97' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775295 JOB[99] in 10001 ms on [[STANDBY] ExecuteThread: '101' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775295 JOB[97] in 10001 ms on [[STANDBY] ExecuteThread: '99' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339501775295 JOB[98] in 10001 ms on [[STANDBY] ExecuteThread: '100' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
done in 10017

L’ensemble des traitements sont exécuté en même temps sur le WorkManager déclaré, et le retour apparaît au bout de 10s qui est le temps unitaire de traitement d’un job. On remarque que chaque traitement a un No de Thread différent.

En observant la taille du pool, on peut voir que la contrainte minimum du WorkManager de 100 Thread a été respectée et qu’il y a plus de 100 threads dans le pool global.


WORKMANAGER EMBEDED



On peut également déclarer le WorkManager dans les descripteurs JEE, ce qui évite une tâche administrative, mais le masque aux administrateurs. Supprimer l’entrée du WorkManager via la console est ajouter le weblogic.xml ci-dessous.

weblogic.xml

 <?xml version="1.0" encoding="UTF-8"?>  
 <wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.3/weblogic-web-app.xsd">  
   <wls:weblogic-version>10.3.6</wls:weblogic-version>  
   <wls:context-root>CommonjWAR</wls:context-root>  
   <wls:work-manager>  
     <wls:name>wm/MyWorkManager</wls:name>  
     <wls:min-threads-constraint>  
       <wls:name>myMinThreadsConstraint</wls:name>  
       <wls:count>100</wls:count>  
     </wls:min-threads-constraint>      
   </wls:work-manager>  
 </wls:weblogic-web-app>  

Re déployer l’application et redémarrer l’instance pour re exécuter la Servlet  ServletParallel

MIN THREADS CONSTRAINT



Regardons maintenant l’impact du paramètre MinThreadsConstraint en diminuant sa valeur de 100 à 10.


   <wls:work-manager>  
     <wls:name>wm/MyWorkManager</wls:name>  
     <wls:min-threads-constraint>  
       <wls:name>myMinThreadsConstraint</wls:name>  
       <wls:count>10</wls:count>  
     </wls:min-threads-constraint>      
   </wls:work-manager>  

En redémarrant et redéployant l’application et activant la Servlet ServletParallel, nous constatons que tous les traitements ne se font pas tous en parallèle et que le temps total d’exécution est supérieur à 10s.

La principale raison est que le WorkManager se base sur un historique pour prendre la décision d’utiliser un Thread du pool global pour exécuter la tâche demandée par l’application associée (éviter trop de traitement en parallèle qui pourrait écroulé la machine). Le fait de définir un minimum permet d’allouer tout de suite des Threads pour desservir la charge voulue.

begin
1339502663859 : All jobs scheduled at :
1339502663857 JOB[0] in 10000 ms on [[ACTIVE] ExecuteThread: '9' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339502663857 JOB[2] in 10000 ms on [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339502663857 JOB[1] in 10000 ms on [[ACTIVE] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]


1339502705721 JOB[97] in 10000 ms on [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339502705720 JOB[96] in 10002 ms on [[ACTIVE] ExecuteThread: '19' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339502705720 JOB[95] in 10002 ms on [[ACTIVE] ExecuteThread: '15' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339502705721 JOB[98] in 10002 ms on [[ACTIVE] ExecuteThread: '20' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
1339502705722 JOB[99] in 10001 ms on [[ACTIVE] ExecuteThread: '23' for queue: 'weblogic.kernel.Default (self-tuning)'] WorkManager [wm/MyWorkManager]
done in 51879

Afin de populer le pool de Threads dès le départ avec une valeur égale à la contrainte minimum, on peut également ajouter le paramètre suivant aux scriptes de démarrage des instances

-Dweblogic.threadpool.MinPoolSize=100

AUTEUR

Ma photo
Carrières Sur Sein, Yvelines, France
Consultant Oracle (Ancien consultant BEA depuis 2001), je m’occupe des expertises sur les produits Oracle : SOCLE (Weblogic, Coherence, JRockit) SOA (Service Bus, SOA Suite, BPM)
MON CV

LABEL 3D

Blogumulus by Roy Tanck and Amanda Fazani

LABEL CLOUD

MAP

Locations of visitors to this page

AUTRES BLOG

LIVRES

MEMBRES