2010-01-05 14 views
12

L'applicazione ha un processo lungo intensivo della CPU attualmente eseguito su un server (un metodo EJB) in modo seriale quando il client lo richiede.In che modo un EJB può parallelizzare un processo lungo e ad alta intensità di CPU?

È teoricamente possibile (da un punto di vista concettuale) dividere quel processo in N blocchi ed eseguirli in parallelo, purché l'output di tutti i lavori paralleli possa essere raccolto e unito insieme prima di inviarlo al client che ha avviato il processo. Mi piacerebbe utilizzare questa parallelizzazione per ottimizzare le prestazioni.

Come posso implementare questa parallelizzazione con EJB? So che non dovremmo creare thread in un metodo EJB. Invece, dovremmo pubblicare messaggi (uno per lavoro) da consumare da message driven bean (MDB). Ma allora non sarebbe più una chiamata sincrona. Ed essere sincrono sembra essere un requisito in questo caso poiché ho bisogno di raccogliere l'output di tutti i lavori prima di inviarlo al client.

C'è una soluzione per questo?

risposta

6

Questa domanda particolare è emersa in più occasioni e riassumo che ci sono diverse soluzioni possibili, solo una delle quali raccomanderei.

Utilizzare un WorkManager dall'AP comune. Permette thread gestiti in un contenitore Java EE ed è progettato specificamente per adattarsi al caso d'uso. Se si utilizza WebSphere o WebLogic, queste API sono già disponibili nel server. Per gli altri la tua volontà dovrà mettere una soluzione di terze parti in te stesso.

WorkManager info

Domande correlate Why Spawning threads is discouraged

+0

Sembra che 'WorkManager' sia specifico di WebSphere, quindi inadatto in generale: http://stackoverflow.com/questions/9026516/replacing-webspheres-workmanager-in-jboss – Raedwald

+1

Questo non si riferisce al commonj WorkManager, ma a una soluzione specifica IBM che lo precede. Come ho già detto, commonj non è specifico di IBM ed è disponibile nella maggior parte delle piattaforme. – Robin

1

Una volta ho partecipato a un progetto in cui le transazioni EJB venivano eseguite per un massimo di 5 ore alla volta. Aargh!

Questa stessa applicazione disponeva anche di un consulente specializzato BEA che ha approvato l'avvio di ulteriori thread dalle transazioni. Anche se è sconsigliato nelle specifiche e altrove, non comporta automaticamente un errore. Devi essere consapevole del fatto che i tuoi thread extra sono fuori dal controllo del contenitore e quindi se qualcosa va storto è colpa tua. Ma se si può assicurare che il numero di thread iniziati nel caso peggiore non superi i limiti ragionevoli e che tutti si concludano in modo pulito in tempi ragionevoli, allora è del tutto possibile lavorare in questo modo. In effetti, nel tuo caso sembra la soluzione quasi-unica.

Esistono alcune soluzioni leggermente esoteriche in cui l'app EJB raggiunge un'altra app per un servizio, che quindi esegue il multithreading in sé stesso prima di tornare al chiamante EJB. Ma questo è essenzialmente solo spostando il problema.

Si può, tuttavia, considerare una soluzione di pool di thread per mantenere un limite superiore al numero di thread generati. Se hai troppi thread la tua applicazione si comporterà in modo orribile.

+0

Not "disrecommended", flat out non ammessi: http://stackoverflow.com/ a/9739300/545127 – Raedwald

1

Hai analizzato abbastanza bene la situazione, e no, non c'è patern per questo che corrisponda al modello EJB.

Creazione di thread è principalmente vietato perché aggira l'app . strategia di gestione dei thread del server e anche a causa delle transazioni .

Ho lavorato a un progetto con requisiti simili e ho deciso di generare thread aggiuntivi (andando contro il sepc quindi). L'operazione di parallelizzazione era di sola lettura, quindi ha funzionato per quanto riguarda la transazione (il thread non avrebbe praticamente nessuna transazione associata ad essi). Sapevo anche che non avrei generato troppi thread per chiamate EJB, quindi il numero di thread non era un problema. Ma se i tuoi thread dovrebbero modificare i dati, allora rompi il modello transazionale dell'EJB sul serio. Ma se la tua operazione nel puro computing, potrebbe essere ok.

Speranza che aiuta ...

+0

Cerca t lui WorkManager dall'API CommonJ. Ti permette di farlo in thread gestiti. – Robin

4

Un EJB è un ultima analisi, un componente di transazione per un sistema client-server che fornisce richiesta/risposta semantica. Se ti trovi nella posizione in cui hai bisogno di classificare una transazione di lunga durata entro i limiti di un ciclo di richiesta/risposta, allora da qualche parte l'architetto di sistema (ure) ha preso la svolta sbagliata.

La situazione descritta è gestita in modo pulito e corretto da un'architettura basata su eventi con un back-end di messaggistica. L'evento iniziale avvia il processo (che può quindi essere banalmente parallelo facendo in modo che gli operai si iscrivano all'argomento dell'evento) e il processo di aggregazione solleva un evento al suo completamento. Puoi ancora spremere questa sequenza entro i limiti di un ciclo di richiesta/risposta, ma dovrai necessariamente violare la lettera e lo spirito delle specifiche di architettura del sistema Java EE.

+0

Questa è una visione del mondo molto in bianco e nero, la maggior parte di noi ha a che fare con sfumature di grigio. Non si vorrebbe rearchitect un intero sistema solo per fornire questa funzionalità. Per non parlare del fatto che non c'è nulla di intrinsecamente sbagliato nell'avere una chiamata sincrona che esegue più operazioni parallele prima di tornare al termine. Questo da solo non giustifica un'architettura basata su eventi su una semplice richiesta/risposta basata su di essa. – Robin

+0

Non c'è niente di sbagliato in ciò che descrivi nel contesto di un framework o piattaforma che è stato specificato e progettato pensando a tali operazioni. Ma questa non è la piattaforma JEE. L'intero punto di JEE è l'adozione di vincoli per promuovere la distribuzione e la disponibilità (e l'obiettivo ormai dimenticato dell'orientamento dei componenti). Una volta che si iniziano a rompere i vincoli, si sta effettivamente seguendo un percorso controproducente. Quindi non dobbiamo essere d'accordo sul punto di respingere l'uso improprio della tecnologia come un caso di punto di vista dogmatico ("bianco e nero"). – alphazero

+0

"semantica richiesta/risposta ... un'architettura basata su eventi con un back-end di messaggistica" Vedo il tuo punto se la semantica della richiesta è "eseguire un processo a lungo termine" e la risposta è "processo a lungo termine finito". Ma si inserirà nel modello JEE se la richiesta significa "avviare un processo a lungo termine" e la risposta è "processo a lungo termine in coda"? Quindi, come suggerisce un'altra risposta, l'EJB può semplicemente inviare un messaggio usando JMS per portare a termine il lavoro da un MDB (o anche da un utente non-JEE del messaggio). – Raedwald

10

Ci sono tutti i tipi di modi per farlo.

Uno, è possibile utilizzare un timer EJB per creare un processo run-once che verrà avviato immediatamente. Questa è una buona tecnica per generare processi in background. Un timer EJB è associato a un'implementazione Session Bean specifica. È possibile aggiungere un Timer EJB a ogni Session Bean che si desidera essere in grado di fare, oppure si può avere un singolo Session Bean che può quindi chiamare la logica dell'applicazione attraverso un meccanismo di invio.

Per me, passo un blob serializzabile di parametri insieme a un nome di classe che soddisfa un'interfaccia specifica a un Session Bean generico che esegue quindi la classe. In questo modo posso facilmente fare da sfondo a qualsiasi cosa.

Un avvertimento sul timer EJB è che i timer EJB sono persistenti. Una volta creato un Timer EJB, rimane nel contenitore fino a quando il suo lavoro non è terminato o cancellato. Il problema è che se si ha un lungo processo in esecuzione e il server non funziona, al riavvio il processo continuerà e riprenderà. Ricorda che può essere una buona cosa, ma solo se il tuo processo è pronto per essere riavviato. Ma se hai un processo semplice che esegue iterazione di "10.000 elementi", se il server scende sull'articolo 9999, quando viene ripristinato puoi facilmente vederlo semplicemente ricominciare dall'articolo 1. È tutto praticabile, solo un avvertimento da tenere presente di.

Un altro modo per fare uno sfondo è utilizzare una coda JMS. Metti un messaggio in coda e il gestore viene eseguito in modo asincrono dal resto dell'applicazione.

La parte intelligente qui e qualcosa che ho fatto anche sfruttando il lavoro con Timer Bean, è possibile controllare quanti "lavori" verranno eseguiti in base a quante istanze MDB si configurano il sistema.

Quindi, per lo specifico compito di eseguire un processo in più blocchi paralleli, prendo il compito, lo suddivido in "pezzi", quindi invio ogni pezzo nella Coda messaggi, dove vengono eseguiti dagli MDB. Se consento 10 istanze di MDB, posso avere 10 "parti" di qualsiasi attività in esecuzione simultaneamente.

In realtà funziona sorprendentemente bene. C'è un po 'di overhead che divide il processo e lo indirizza attraverso la coda JMS, ma questo è tutto fondamentalmente "tempo di avvio". Una volta che si ottiene, si ottiene un vantaggio reale.

Un altro vantaggio dell'utilizzo della coda messaggi è che è possibile eseguire i processi in esecuzione lunghi su una macchina separata oppure creare facilmente un cluster di macchine per gestire questi processi. Tuttavia, l'interfaccia è la stessa e il codice non conosce la differenza.

Ho scoperto che una volta retrocesso un processo di lunga durata in background, è possibile pagare il prezzo di un accesso meno immediato a tale processo. Cioè, non c'è motivo di monitorare direttamente le classi di esecuzione stesse, basta che pubblichino informazioni interessanti e statistiche sul database, o JMX, o qualsiasi cosa invece di avere qualcosa che possa monitorare direttamente l'oggetto perché condivide lo stesso spazio di memoria.

sono stato facilmente in grado di creare un quadro che lascia esecuzione dell'attività sia sul timer EJB o sulla coda dispersione MDB, i compiti sono gli stessi, e ho potuto monitorare i loro progressi, fermarli, ecc

È possibile combinare la tecnica scatter per creare diversi lavori EJB Timer. Uno dei vantaggi gratuiti di MDB è che agisce come un pool di thread che può limitare i lavori (in modo da non saturare improvvisamente il sistema con troppi processi in background). Ottieni questo "gratuitamente" semplicemente sfruttando le funzionalità di gestione EJB nel contenitore.

Infine, Java EE 6 ha un nuovo qualificatore "asincrono" (o qualcosa) per i metodi Session Bean. Non conosco i dettagli su come funziona, dato che devo ancora giocare con un nuovo contenitore Java EE 6. Ma immagino che probabilmente non vorrai cambiare contenitore solo per questa struttura.

2

Ritorno al futuro - Java EE 7 ha molto di più sostegno Concurrency via ManagedThreadFactory, servizio ManagedExecutor ecc (JSR 236: Concorrenza Utilità per Java EE) con cui è possibile creare i propri 'managed'Threads .E non è più un tabù in EE AS ​​lo sostengono (? wildfly) tramite il usining ManagedThread * API

Maggiori dettagli

https://jcp.org/aboutJava/communityprocess/ec-public/materials/2013-01-1516/JSR236-EC-F2F-Jan2013.pdf http://docs.oracle.com/javaee/7/tutorial/doc/concurrency-utilities002.htm

+0

Alla fine, dovendo lavorare con JBoss AS 7.1 e con l'esecuzione parallela senza thread, ho seguito automaticamente l'architettura basata su messaggi contenente una suddivisione dell'attività principale in attività secondarie; utilizzando il clustering e il bilanciamento del carico di Jboss e HorneQ; pubblicato in GitHub il framework –

+0

JBoss AS 7.1 implementa già le specifiche EJB 3.1. È possibile utilizzare la chiamata al metodo asincrono per casi d'uso semplici. Non dimenticare di configurare il pool di thread sul server delle applicazioni in base alle proprie esigenze. – JanM

Problemi correlati