WebLogic EJB y balanceo de carga

Autor
Damian
Terlecki
5 minutos de lectura
JEE

Recientemente me preguntaron sobre el balanceo de carga de interfaces @Remote @EJB en WebLogic. ¿Se balancean las interfaces remotas? ¿Depende del contexto? ¿El balanceo ocurre en la invocación o solo en el lookup? ¿Desde el cliente se puede saber qué nodo del clúster procesó la petición? Entender estos conceptos es clave para implementar procesos escalables y eficientes.

Características de balanceo de carga para EJB stateless remotos

Para responder, primero consultemos la documentación de WebLogic 14.1.1.0 (aunque en versiones anteriores es similar). Describe el balanceo de carga para EJB stateless remotos. En resumen, hay dos tipos de conexión:

  1. cliente-servidor;
  2. servidor-servidor.

Las conexiones e invocaciones cliente-servidor se balancean usando una de tres estrategias: round-robin (por defecto), basada en peso o aleatoria. También se puede desactivar el balanceo en favor de la afinidad de servidor. Con afinidad, sigues sujeto a balanceo solo si usas un URI de clúster en vez de un managed server, y solo al crear un nuevo contexto inicial. Todas estas opciones soportan failover.

Para conexiones servidor-servidor, la afinidad no afecta el balanceo entre servidores. Además, dentro de un clúster, WLS siempre usará el EJB que reside en el mismo nodo que recibió la petición, ya que es más eficiente. Esta "colocación de objetos" hace que usar interfaces @Remote dentro de @EJB sea subóptimo (serialización innecesaria). Algo similar ocurre con UserTransaction y opcionalmente con XA.

WebLogic Remote EJB Load Balancing Chart (simplificado)

No hay colocación (al contrario: sí hay balanceo) entre clústeres separados, por ejemplo en una configuración multi-tier. Si no quieres colocación, puedes procesar usando destinos JMS balanceados. Otra opción sería hacer proxy del lookup con un classloader personalizado actuando como cliente WLS, pero no es algo probado ni recomendado.

Saber qué servidor procesó mi petición (cliente)

A veces quieres saber qué servidores procesan ciertas peticiones. Una vez me encontré con un despliegue desincronizado de una nueva versión en un clúster, lo que resultó en respuestas distintas en round-robin. Saber cómo vincular la respuesta con un servidor concreto me permitió resolverlo sin redeploy ni apagar todo el clúster.

Una forma es implementar logs identificables de request/response. ¿Hay algo ad-hoc? Si has trabajado con WLS, sabrás que esa información puede estar en los objetos de la librería wlthint3client.jar, usada para conectar a WLS y que contiene la lógica de balanceo para el protocolo t3.

Pero hay más. Para el balanceo, hay un logger específico que puedes usar. Sin él, tendrías que crear un wrapper personalizado alrededor de las llamadas EJB stub que acceda al estado interno del balanceador.

Captura de IntelliJ evaluando el nombre WLS que procesó la invocación EJB

El logging de Wlthint3client usa JUL (Java Util Logging). Para integrarlo con otros frameworks, busca un bridge como jul-to-slf4j. Para activarlo, arranca la app con la propiedad JVM -Dweblogic.debug.DebugLoadBalancing o hazlo por código para el logger compartido:

WebLogic DebugLoadBalancing debugger
weblogic.diagnostics.debug.DebugLogger
        .getDebugLogger("DebugLoadBalancing")
        .setDebugEnabled(false);

Luego configura el nivel de logging y el appender según tu framework. Aquí, el displayName es el nombre del logger sin el prefijo Debug, es decir, el logger JUL se llama LoadBalancing. Así verás logs como:

JUL|FINE|my-exampl-earmy-ejb_jarcom_example_MyBean_MyRemoteBean request routing from 8754691235748961325S:10.90.0.4:[7001,7001,-1,-1,-1,-1,-1]:mydomain:wls1 to 6654312976543210890S:10.90.0.5:[7001,7001,-1,-1,-1,-1,-1]:mydomain:wls2
JUL|FINE|my-exampl-earmy-ejb_jarcom_example_MyBean_MyRemoteBean request routing from 6654312976543210890S:10.90.0.5:[7001,7001,-1,-1,-1,-1,-1]:mydomain:wls2 to 7890564123879561234S:10.90.0.6:[7001,7001,-1,-1,-1,-1,-1]:mydomain:wls3
JUL|FINE|my-exampl-earmy-ejb_jarcom_example_MyBean_MyRemoteBean request routing from 7890564123879561234S:10.90.0.6:[7001,7001,-1,-1,-1,-1,-1]:mydomain:wls3 to 8754691235748961325S:10.90.0.4:[7001,7001,-1,-1,-1,-1,-1]:mydomain:wls1

Combinado con el nombre del thread y la hora (formato de logging), o cualquier otro contexto, puedes vincular cada request con un proceso de negocio y nodo EJB concreto. Otro logger útil es DebugFailOver y, en menor medida, DebugMessaging. Este último suele funcionar tras añadir -Dweblogic.kernel.debug=true y saca mensajes en consola en formato byte-pretty.