Clustering di EJB

Dopo aver visto nella prima parte come configurare un cluster JBoss, in questo articolo analizziamo come clusterizzare gli Enterprise JavaBeans.

Session Bean Clustering

I session bean possono essere di due tipi: stateless e stateful. Entrambi possono essere clusterizzati ma con modalità diverse.

Stateless Session Beans

Il clustering di stateless session bean è semplice poiché non mantengono stato:

@Stateless
@Clustered
public class CalcoloBean implements Calcolo {
    public double somma(double a, double b) {
        return a + b;
    }
}

Il load balancer può distribuire le chiamate su qualsiasi nodo del cluster.

Stateful Session Beans

Per i stateful session bean è necessaria la replicazione dello stato:

@Stateful
@Clustered
@CacheConfig(maxSize=1000, idleTimeoutSeconds=300)
public class CarrelloBean implements Carrello {
    private List<Prodotto> prodotti = new ArrayList<>();

    public void aggiungi(Prodotto p) {
        prodotti.add(p);
    }

    public List<Prodotto> getProdotti() {
        return prodotti;
    }
}

Strategie di replicazione

JBoss supporta diverse strategie:

  • Session state replication: replica completa dello stato
  • Buddy replication: replica solo su nodi vicini
  • Database persistence: persistenza su DB condiviso

Entity Bean Clustering

Gli entity bean presentano sfide particolari per il clustering.

Cache distribuita

Per evitare inconsistenze, è necessaria una cache distribuita:

<cache-invalidation>true</cache-invalidation>
<cache-invalidation-config>
    <invalidation-manager-name>
        jboss.cache:service=InvalidationManager
    </invalidation-manager-name>
</cache-invalidation-config>

Commit options

Le diverse commit option hanno implicazioni diverse in cluster:

  • Option A: cache sempre valida (problematica in cluster)
  • Option B: rivalidazione ad ogni transazione
  • Option C: ricaricamento ad ogni invocazione

Lock management distribuito

Per garantire consistenza è necessario un meccanismo di lock distribuito:

@Entity
@Table(name="PRODOTTO")
@Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL)
public class Prodotto {
    @Id
    private Long id;
    private String nome;
    private double prezzo;
}

HA-JNDI

Per il lookup in ambiente cluster, JBoss fornisce HA-JNDI:

Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,
    "org.jboss.naming.NamingContextFactory");
props.put(Context.PROVIDER_URL, "jnp://node1:1100,node2:1100");
InitialContext ctx = new InitialContext(props);
Calcolo calcolo = (Calcolo)ctx.lookup("CalcoloBean/remote");

Load Balancing Policy

È possibile configurare diverse politiche di load balancing:

Round Robin

@Clustered(loadBalancePolicy="org.jboss.ha.client.loadbalance.RoundRobin")

First Available

@Clustered(loadBalancePolicy="org.jboss.ha.client.loadbalance.FirstAvailable")

Random

@Clustered(loadBalancePolicy="org.jboss.ha.client.loadbalance.RandomRobin")

Failover

In caso di guasto di un nodo, il client viene automaticamente reindirizzato:

1. Il client riceve un'eccezione 2. Lo stub consulta la lista dei nodi disponibili 3. La chiamata viene reinviata ad un altro nodo 4. Lo stato (per stateful) viene recuperato dalla replica

Best Practices

  • Minimizzare lo stato nei session bean stateful
  • Usare stateless quando possibile
  • Configurare timeout appropriati per le cache
  • Monitorare la replicazione
  • Testare il failover

Conclusioni

Il clustering di EJB richiede attenzione particolare alla gestione dello stato e alla configurazione della replicazione. JBoss fornisce strumenti potenti ma è necessario comprenderne il funzionamento per evitare problemi di performance e consistenza.