Ho modificato un'applicazione per avere una divisione client / server più pulita per consentire la suddivisione del carico e la condivisione delle risorse, ecc. Tutto è scritto su un'interfaccia, quindi è stato semplice aggiungere un livello remoto all'interfaccia usando un proxy. Tutto ha funzionato bene. La fase successiva consisteva nell'aggiungere un livello di caching all'interfaccia e ancora una volta questo ha funzionato bene e la velocità è stata migliorata, ma non tanto quanto mi sarei aspettato. All'ispezione è diventato molto chiaro cosa stava succedendo.
Sono certo che questo comportamento è stato visto molte volte in passato e probabilmente c'è un modello di progettazione per risolvere il problema ma sfugge a me e non sono nemmeno sicuro di come descriverlo.
È più facile spiegarlo con un esempio. Immaginiamo che l'interfaccia sia
interface IMyCode {
List<IThing> getLots( List<String> );
IThing getOne( String id );
}
Il metodo getLots () chiama getOne () e riempie l'elenco prima di tornare.
L'interfaccia è implementata sul client che è inoltrata a un client remoto che chiama quindi il server remoto che a sua volta chiama l'implementazione sul server. Al livello client e server esiste anche una cache.
Quindi abbiamo: -
Client interface
|
Client cache
|
Remote client
|
Remote server
|
Server cache
|
Server interface
Se chiamiamo getOne ("A") sull'interfaccia client, la chiamata viene passata alla cache del client che presenta dei guasti. Questo quindi chiama il client remoto che passa la chiamata al server remoto. Questo quindi chiama la cache del server che fa anche il guasto e quindi la chiamata viene passata all'interfaccia del server che in effetti riceve l'IThing. A sua volta la cache del server viene riempita e infine anche la cache del client.
Se getOne ("A") viene nuovamente chiamato nell'interfaccia client, la cache del client ha i dati e viene restituito immediatamente. Se un secondo client chiamato getOne ("B") riempirebbe la cache del server con "B" così come la propria cache client. Quindi, quando il primo client chiama getOne ("B"), la cache del client fa un errore ma la cache del server ha i dati.
Questo è tutto come ci si aspetterebbe e funziona bene.
Ora consente di chiamare get get (["C", "D"]). Funziona come ci si aspetterebbe chiamando getOne () due volte, ma qui c'è una sottigliezza. La chiamata a getLots () non può fare direttamente uso della cache. Pertanto la sequenza consiste nel chiamare l'interfaccia client che a sua volta chiama il client remoto, quindi il server remoto e infine l'interfaccia del server. Questo quindi chiama getOne () per riempire l'elenco prima di tornare.
Il problema è che le chiamate getOne () sono soddisfatte sul server quando idealmente dovrebbero essere soddisfatte sul client. Se si immagina che il collegamento client / server sia molto lento, allora diventa chiaro il motivo per cui la chiamata del client è più efficiente della chiamata del server una volta che la cache del client ha i dati.
Questo esempio è ideato per illustrare il punto. Il problema più generale è che non è possibile continuare ad aggiungere layer proxy a un'interfaccia e aspettarsi che funzioni come si potrebbe immaginare. Non appena la chiamata passa "attraverso" il proxy, tutte le chiamate successive sono sul lato proxy invece che sul lato "self".
Non ho imparato o non ho imparato qualcosa correttamente?
Tutto questo è implementato in Java e non ho usato EJB.
Sembra che l'esempio possa essere fonte di confusione. Il problema non ha nulla a che fare con l'efficienza della cache. Ha più a che fare con un'illusione creata dall'uso di proxy o tecniche AOP in generale.
Quando si ha un oggetto la cui classe implementa un'interfaccia, si presume che una chiamata su quell'oggetto possa effettuare ulteriori chiamate sullo stesso oggetto. Ad esempio,
public String getInternalString() {
return InetAddress.getLocalHost().toString();
}
public String getString() {
return getInternalString();
}
Se ottieni un oggetto e chiama getString () il risultato dipende da dove il codice è in esecuzione. Se si aggiunge un proxy remoto alla classe, il risultato potrebbe essere diverso per le chiamate a getString () e getInternalString () sullo stesso oggetto. Questo perché la chiamata iniziale viene "deproxied" prima che venga chiamato il metodo effettivo.
Trovo questo non solo confuso, ma mi chiedo come posso controllare questo comportamento, specialmente perché l'uso del proxy può essere di terze parti.
Il concetto va bene, ma la pratica non è certamente quella che mi aspettavo.
Ho perso il punto da qualche parte?