7.7.3. Mettre en place une politique d'équilibrage des charges presonnalisée pour les appels EJB
AllClusterNodeSelector pour les appels EJB. Le comportement de sélection de noeud de AllClusterNodeSelector ressemble à celui du sélecteur par défaut, sauf que AllClusterNodeSelector utilise tous les noeuds de cluster disponibles, même pour les clusters de grande taille (nombre de noeuds>20). Si un noeud de cluster non connecté est renvoyé, il s'ouvre automatiquement. L'exemple suivant montre une implémentation de AllClusterNodeSelector :
package org.jboss.as.quickstarts.ejb.clients.selector;
import java.util.Arrays;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.ejb.client.ClusterNodeSelector;
public class AllClusterNodeSelector implements ClusterNodeSelector {
private static final Logger LOGGER = Logger.getLogger(AllClusterNodeSelector.class.getName());
@Override
public String selectNode(final String clusterName, final String[] connectedNodes, final String[] availableNodes) {
if(LOGGER.isLoggable(Level.FINER)) {
LOGGER.finer("INSTANCE "+this+ " : cluster:"+clusterName+" connected:"+Arrays.deepToString(connectedNodes)+" available:"+Arrays.deepToString(availableNodes));
}
if (availableNodes.length == 1) {
return availableNodes[0];
}
final Random random = new Random();
final int randomSelection = random.nextInt(availableNodes.length);
return availableNodes[randomSelection];
}
}
SimpleLoadFactorNodeSelector pour les appels EJB. L'équilibrage des charges dans SimpleLoadFactorNodeSelector a lieu sur la base d'un facteur de charge. Le facteur de charge (2/3/4) est calculé sur la base des noms de noeuds (A/B/C) irrespectivement de la charge qui pèse sur chaque noeud. L'exemple suivant vous montre une implémentation de SimpleLoadFactorNodeSelector :
package org.jboss.as.quickstarts.ejb.clients.selector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.ejb.client.DeploymentNodeSelector;
public class SimpleLoadFactorNodeSelector implements DeploymentNodeSelector {
private static final Logger LOGGER = Logger.getLogger(SimpleLoadFactorNodeSelector.class.getName());
private final Map<String, List<String>[]> nodes = new HashMap<String, List<String>[]>();
private final Map<String, Integer> cursor = new HashMap<String, Integer>();
private ArrayList<String> calculateNodes(Collection<String> eligibleNodes) {
ArrayList<String> nodeList = new ArrayList<String>();
for (String string : eligibleNodes) {
if(string.contains("A") || string.contains("2")) {
nodeList.add(string);
nodeList.add(string);
} else if(string.contains("B") || string.contains("3")) {
nodeList.add(string);
nodeList.add(string);
nodeList.add(string);
} else if(string.contains("C") || string.contains("4")) {
nodeList.add(string);
nodeList.add(string);
nodeList.add(string);
nodeList.add(string);
}
}
return nodeList;
}
@SuppressWarnings("unchecked")
private void checkNodeNames(String[] eligibleNodes, String key) {
if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) {
// must be synchronized as the client might call it concurrent
synchronized (nodes) {
if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) {
ArrayList<String> nodeList = new ArrayList<String>();
nodeList.addAll(Arrays.asList(eligibleNodes));
nodes.put(key, new List[] { nodeList, calculateNodes(nodeList) });
}
}
}
}
private synchronized String nextNode(String key) {
Integer c = cursor.get(key);
List<String> nodeList = nodes.get(key)[1];
if(c == null || c >= nodeList.size()) {
c = Integer.valueOf(0);
}
String node = nodeList.get(c);
cursor.put(key, Integer.valueOf(c + 1));
return node;
}
@Override
public String selectNode(String[] eligibleNodes, String appName, String moduleName, String distinctName) {
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.finer("INSTANCE " + this + " : nodes:" + Arrays.deepToString(eligibleNodes) + " appName:" + appName + " moduleName:" + moduleName
+ " distinctName:" + distinctName);
}
// if there is only one there is no sense to choice
if (eligibleNodes.length == 1) {
return eligibleNodes[0];
}
final String key = appName + "|" + moduleName + "|" + distinctName;
checkNodeNames(eligibleNodes, key);
return nextNode(key);
}
}
jboss-ejb-client.properties
Vous devrez ajouter la propriété remote.cluster.ejb.clusternode.selector au nom de votre classe d'implémentation (AllClusterNodeSelector ou SimpleLoadFactorNodeSelector). Le sélecteur vérifiera les serveurs configurés disponibles au moment de l'invocation. l'exemple suivant utilise AllClusterNodeSelector comme sélecteur de noeud de déploiement :
remote.clusters=ejb
remote.cluster.ejb.clusternode.selector=org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false
remote.cluster.ejb.username=test
remote.cluster.ejb.password=password
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=one,two
remote.connection.one.host=localhost
remote.connection.one.port = 4447
remote.connection.one.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.one.username=user
remote.connection.one.password=user123
remote.connection.two.host=localhost
remote.connection.two.port = 4547
remote.connection.two.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
Vous devrez ajouter la propriété remote.cluster.ejb.clusternode.selector à la liste de constructeur PropertiesBasedEJBClientConfiguration. L'exemple suivant utilise AllClusterNodeSelector comme sélecteur de noeud de déploiement :
Properties p = new Properties();
p.put("remote.clusters", "ejb");
p.put("remote.cluster.ejb.clusternode.selector", "org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector");
p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED", "false");
p.put("remote.cluster.ejb.username", "test");
p.put("remote.cluster.ejb.password", "password");
p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
p.put("remote.connections", "one,two");
p.put("remote.connection.one.port", "4447");
p.put("remote.connection.one.host", "localhost");
p.put("remote.connection.two.port", "4547");
p.put("remote.connection.two.host", "localhost");
EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);
p = new Properties();
p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(p);
jboss-ejb-client.xml
Pour pouvoir utiliser la politique d'équilibrage des charges pour la communication d'un serveur à un autre, empaquetez la classe avec l'application et configurez-là dans les paramètres de jboss-ejb-client.xml (qui se trouvent dans le dossier META-INF). L'exemple suivant utilise AllClusterNodeSelector comme sélecteur de noeud de déploiement :
<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd">
<client-context>
<ejb-receivers>
<!-- this is the connection to access the app -->
<remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" />
</ejb-receivers>
<!-- if an outbound connection connect to a cluster a list of members is provided after successful connection.
To connect to this node this cluster element must be defined.
-->
<clusters>
<!-- cluster of remote-ejb-connection-1 -->
<cluster name="ejb" security-realm="ejb-security-realm-1" username="test" cluster-node-selector="org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector">
<connection-creation-options>
<property name="org.xnio.Options.SSL_ENABLED" value="false" />
<property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" />
</connection-creation-options>
</cluster>
</clusters>
</client-context>
</jboss-ejb-client>
ejb-security-realm-1 à la configuration côté serveur. L'exemple suivant vous montre les commandes CLI pour ajouter un domaine de sécurité (ejb-security-realm-1). La valeur correspond au mot de passe base64 codifié pour l'utilisateur "test" :
core-service=management/security-realm=ejb-security-realm-1:add()
core-service=management/security-realm=ejb-security-realm-1/server-identity=secret:add(value=cXVpY2sxMjMr)
Note
-Djboss.node.name= ou le fichier de configuration du serveur standalone.xml pour configurer le nom du serveur (server name=""). Veillez à ce que le nom de serveur soit unique. En mode de domaine, le contrôleur valide automatiquement le fait que les noms soient uniques.