Alcune note su “A Note on Distributed Computing”

L’articolo
è del ’94. La tesi, in breve, è che non è praticamente possibile rendere
trasparente (invisibile) la differenza fra oggetti locali e remoti, in un
sistema di programmazione ad oggetti. La qual cosa, detta così, può anche
apparire ovvia; ma in quegli anni si faceva un gran parlare di DCOM, Corba,
RMI, EJB e altri sistemi che promettevano al programmatore di “sviluppare
un’applicazione ad oggetti, e preoccuparsi dopo di come distribuire gli
oggetti su diverse macchine.”

Il tono dell’articolo è accademico-scassapalle. Ciononostante hanno ragione. Alcune degli argomenti che citano sono abbastanza banali; altri un po’ meno, soprattutto quello che dicono dei fallimenti parziali.

Quali sono, dunque, i motivi per cui un oggetto remoto non può essere trattato come un’oggetto locale?

  1. Latenza. L’invocazione di un metodo locale costa pochissimo, invocare un metodo remoto no. Finchè si tratta di invocarlo una volta è un conto, ma in pratica un sistema distribuito deve essere progettato per minimizzare il numero di network round-trip (chiamate remote). Questo dovrebbe essere abbastanza ovvio.
  2. Modello della memoria. Chiamare un metodo significa passare parametri, e magari ricevere dei risultati. Se questi dati sono value objects (semplici strutture dati autocontenute) non c’è nessun problema. Ma se contengono risorse a strutture date esterne, tipo connessioni a database o a file aperti, questi oggetti non si possono serializzare. Così come sono problematiche strutture dati che contengono puntatori ad altre zone di memoria. Anche questo mi pare abbastanza ovvio.
  3. Fallimenti parziali. Quando una chiamata remota fallisce, non è dato sapere se il fallimento è totale o parziale. Per esempio: supponiamo di avere una chiamata remota il cui effetto è aggiungere un record ad un database. Se invoco questo metodo, e dopo un po’ di tempo non ho avuto risposta, i casi sono due: o la chiamata è andata persa, e il record non è stato aggiunto; oppure la risposta è andata persa, e il record è stato aggiunto. Il mio problema è che non posso sapere in quale dei due casi mi trovo.

Quest’ultimo caso è il più difficile e interessante. Così su due piedi, l’unica cosa che posso fare è attendere fino a un certo tempo e poi arrendermi. Ma non so se il record è stato aggiunto o no. Tutto quello che posso fare è aspettare un po’ e provare ad aggiungerlo di nuovo, correndo il rischio di aggiungere il record due volte!

La soluzione è semplice, mi dirai. Basta interrogare il server per sapere se il record è stato aggiunto. Oppure aggiungere un identificatore alla mia richiesta; ad esempio, se ho ricevuto una timeout sulla richiesta n. 456, riprovo a mandare la richiesta 456. Il server può così distinguere il caso di una richiesta che ha già visto, nel qual caso la ignora.

Aha! Ma in entrambi i casi, abbiamo modificato l’interfaccia remota per tenere conto del fatto che l’invocazione è, appunto remota.
Nel caso di una invocazione locale non abbiamo i fallimenti parziali: se la mia richiesta di aggiungere un record fallisce, lo so e basta.

Qui sta il succo dell’articolo: per progettare un interfaccia da usare in remoto, occorrono accorgimenti specifici per il caso remoto. Il che può apparire ovvio, detto così! Ma quando ci si prova, è difficile tenere conto dei fallimenti parziali che possiamo avere in un sistema distribuito.

Tutto sommato, è valsa la pena di leggerlo.

PS. Jim Waldo, uno degli autori di “A Note” e in seguito inventore di Jini, tiene un corso ad Harvard la cui pagina è una bella bibliografia di articoli sui sistemi distribuiti

]]>

Leave a Reply