Transparencias de RPCs/RMIs

Anuncio
RPC/RMI
LSUB
GSYC
20 de marzo de 2013
(cc) 2013 Laboratorio de Sistemas,
Algunos derechos reservados. Este trabajo se entrega bajo la licencia Creative Commons Reconocimiento NoComercial - SinObraDerivada (by-nc-nd). Para obtener la licencia completa, véase
http://creativecommons.org/licenses/. También puede solicitarse a Creative Commons, 559 Nathan Abbott Way,
Stanford, California 94305, USA.
Las imágenes de terceros conservan su licencia original.
RPC
• Llamada a un procedimiento que ejecuta en otro espacio de
direcciones.
• Sigue el modelo cliente/servidor, petición-respuesta.
• Al usuario se le ocultan los detalles de la comunicación y de la
distribución: transparencia de acceso y de distribución.
ecución de una RPC
RPC
PC involucra una serie de etapas que se ejecutan tanto en la máquina que realiza
omo en la máquina que ejecuta el procedimiento remoto (servidor).
Figura 2: Pasos en la ejecución de una RPC
RPC: fallos
¿Y si el servidor falla mientras se está haciendo? Hay distintas
semánticas:
• Exactly once: la operación se realiza una vez. Es caro.
• At most once: la operación se ejecuta como mucho una vez,
pero puede que ninguna. Se retorna error al cliente, que no
puede saber si se ha realizado la operación o no.
• At least once: la operacion se ejecuta al menos una vez, puede
que varias. Si la operación es idempotente no hay problema.
Serialización
• Las máquinas del sistema distribuido pueden ser homogéneas
o heterogéneas.
• En ambos casos, tiene que haber una representación canónica
para los datos.
• Cada extremo debe convertir los datos de su formato local al
formato canónico y viceversa: serialización (marshaling o
aplanado).
• Podemos definir nuestra propia serialización o usar uno de los
múltiples estándars: XDR (Sun rpc), JSON, ASN.1,
XML-RPC, etc.
Serialización
Para realizar nuestra propia serialización tenemos dos alternativas:
• Texto. Factores a tener en cuenta:
• Codificación (p. ej. UTF-8).
• Terminación de las cadenas.
• Binario. Factores a tener en cuenta:
• Longitud de los datos.
• Endianess.
• Formato (p. ej: coma flotante IEEE 754, IEEE 754-2008, etc.).
Serialización
Ejemplo: serializar un array de 3 enteros : 1, -2, 3.
• Texto (UTF-8):
"[[1], [-2], [3]]"
• Binario (little endian, 4 bytes por entero, complemento a 2):
0x03
0x01
0xfe
0x03
0x00
0x00
0xff
0x00
0x00
0x00
0xff
0x00
0x00
0x00
0xff
0x00
Ejemplo: JSON
• Es un formato de texto.
• Es independiente del lenguaje.
• Permite aplanar:
• Una colección de pares atributo/valor con el que se pueden
serializar objetos, records, diccionarios, etc.
• Lista de valores con el que se pueden aplanar arrays, listas,
conjuntos, etc.
Ejemplo: JSON
Objeto:
{
” rectangulo ” : {
” v i s i b l e ” : true ,
” color ” : ” verde ” ,
” supIzq ” : {
”x” : 34 ,
” y ” : 30
},
” infDer ” : {
”x” : 43 ,
” y ” : 10
}
}
}
Ejemplo: JSON
Lista:
{
”listaCoor”: [
{”x” : 0 , ”y” : 0} ,
{”x” : 2 , ”y” : 1} ,
{”x” : 4 , ”y” : 5} ,
{”x” : 0 , ”y” : 1} ,
{ ” x ” : −1 , ” y ” : 23}
]
}
Serialización en Java
• Cliente y servidor (ambos en Java) se pueden despreocupar
del formato de los datos.
• Una clase que cumpla con la interfaz Serializable se puede
serializar. Esa interfaz no tiene ningún método.
• Aplana el objeto y todos los objetos referenciados (web of
objects).
• Si un miembro es transient no forma parte del estado
persistente del objeto y por tanto no se serializa.
• Si un objeto no se puede serializar, se levanta la excepción
NotSerializableException.
Código
F i g u r e s = new S q u a r e ( p1 , p2 ) ;
ObjectOutputStream os =
new O b j e c t O u t p u t S t r e a m ( s o c k . g e t O u t p u t S t r e a m ( ) ) ;
os . w r i t e O b j e c t ( s ) ;
Serialización en Java
Las clases que necesitan personalizar la serialización deben definir
los métodos con estas cabeceras:
p r i v a t e void w r i t e O b j e c t ( j a v a . i o . ObjectOutputStream out )
throws IOException
private void readObject ( java . io . ObjectInputStream in )
throws IOException , ClassNotFoundException ;
p r i v a t e void readObjectNoData ( )
throws ObjectStreamException ;
Nombrado
• Necesitamos nombrar los recursos para poder acceder a ellos
(p. ej. hacer una RPC sobre un recurso concreto).
• Transparencia de localización: permite encontrar los recursos
con independencia de su localización fı́sica.
• El servicio puede ser centralizado o distribuido.
• El esquema de nombrado puede ser plano o estructurado.
Ejemplo: DHT
• Una tabla hash distribuida es un servicio de nombres planos.
Como en una tabla hash, a una clave le pertenece un valor
asociado.
Ejemplo: DNS
• El DNS es un servicio distribuido de nombres estructurados
para traducir nombres a direcciones IP.
(cc) George Shuklin
Nombres estructurados
• Los nombres estructurados forman un espacio de nombres
(name space)
• Generalmente se representan como un grafo dirigido con
nodos contenedores y nodos hoja,
• Los objetos se pueden nombrar con nombres absolutos o
relativos.
• La resolución puede ser iterativa o recursiva.
Resolución de nombres iterativa
(c) A. Tanenbaum
Resolución de nombres recursiva
• Reduce los mensajes en el cliente (puede afectar a la latencia
en gran medida) y facilita el caching.
(c) A. Tanenbaum
Java RMI
RMI
• OOM (Object Oriented Middleware) de Java.
• Permite:
• Localizar objetos remotos.
• Invocar métodos de objetos remotos.
• Cargar dinámicamente definiciones de clases remotas.
• El compilador genera los stubs.
• Usa la serialización de Java.
• El RMI registry se encarga del nombrado.
RMI
En resumen:
• La clase remota debe estar partida en una interfaz y una clase
que la implemente.
• Todos los métodos remotos deben estar especificados en la
interfaz.
• La interfaz debe extender java.rmi.remote.
• Todos los métodos remotos deben especificar que levantan
RemoteException.
• Si los métodos usan (argumentos, retorno) otro objeto remoto,
este objeto también debe ser definido por una interfaz.
Registry
• Es un servicio de nombrado sencillo para localizar los objetos
remotos.
• En la máquina en la que creamos el registro debemos ejecutar
el comando:
rmiregistry
RMI
Argumentos en RMI:
• Los objetos remotos se pasan por referencia. El objeto remoto
en realidad es una instancia del stub de cliente que le
representa.
• Los objetos locales se pasan por valor, se envı́a una copia del
objeto serializado. Se copian todos los miembros menos los
estáticos y transient.
RMI: servidor
• Si una interfaz exiende la interfaz Remote hace que los
métodos sean accesibles por RMI.
• Las excepciones extra provocadas por los mecanismos de de
RMI (el servidor no responde, error de aplanado, etc.) se
engloban en RemoteException (es checked).
p u b l i c i n t e r f a c e C l o c k S e r v e r e x t e n d s Remote {
p u b l i c Date getTime ( ) t h r o w s R e m o t e E x c e p t i o n ;
}
RMI: Exportar el objeto
• Hay que instanciar un objeto de la clase y exportarlo.
• El método estático exportObject() de
UnicastRemoteObject permite crear el stub de servidor para
aceptar peticiones. Su segundo argumento es el puerto TCP
que debe usar (0 significa que el puerto es anónimo).
• Dicho método retorna el stub de cliente para acceder a este
objeto, que debemos registrar.
C l o c k S e r v e r c = new C l o c k ( ) ;
ClockServer stub =
( ClockServer ) UnicastRemoteObject . exportObject ( c , 0 ) ;
RMI: Exportar el objeto (ii)
• Para registrar el stub de cliente tenemos que localizar el
registro. La clase LocateRegistry permite crear un registro
en esta JVM (método createRegistry()) o usar un registro
existente(método getRegistry()).
• El método rebind() registra el stub con un nombre dado.
Una aplicación sólo puede registrar objetos remotos en su
localhost.
Registry r e g i s t r y = LocateRegistry . createRegistry (9999);
r e g i s t r y . rebind ( ” MasterClock ” , stub ) ;
Código
p u b l i c c l a s s Clock implements C l o c k S e r v e r {
p u b l i c Clock ( ) throws RemoteException{
super ( ) ;
}
p u b l i c Date getTime ( ) t h r o w s R e m o t e E x c e p t i o n {
r e t u r n new Date ( ) ;
}
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
try {
C l o c k S e r v e r c = new C l o c k ( ) ;
ClockServer stub =
( ClockServer ) UnicastRemoteObject . exportObject ( c , 0 ) ;
Registry r e g i s t r y = LocateRegistry . createRegistry (9999);
r e g i s t r y . rebind ( ” MasterClock ” , stub ) ;
System . o u t . p r i n t l n ( ” C l o c k bound ” ) ;
} catch ( Exception e ) {
System . e r r . p r i n t l n ( ” C l o c k e x c e p t i o n : ” ) ;
e . printStackTrace ( ) ;
}
}
}
RMI: cliente
• Debe conseguir una referencia al registro:
Registry registry =
L o c a t e R e g i s t r y . g e t R e g i s t r y ( ” pc1 . e x a m p l e . o r g ” , 9 9 9 9 ) ;
RMI: cliente
• Después consigue el stub de cliente:
ClockServer c =
( ClockServer ) r e g i s t r y . lookup ( ” MasterClock ” ) ;
Código
import org . l s u b . c l o c k s e r v e r . C l oc k Se r ve r ;
public class Client {
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
try {
Registry r e g i s t r y = LocateRegistry . getRegistry ( args [0] ,
new I n t e g e r ( a r g s [ 1 ] ) ) ;
ClockServer c = ( ClockServer ) r e g i s t r y . lookup ( ” MasterClock ” ) ;
System . o u t . p r i n t l n ( ” M a s t e r C l o c k s a y s : ” + c . getTime ( ) ) ;
} catch ( Exception e ) {
System . e r r . p r i n t l n ( ” C l o c k e x c e p t i o n : ” ) ;
e . printStackTrace ( ) ;
}
}
}
Ejecución
1
Máquina servidora (omac.lsub.org):
rmiregistry&
2
Máquina servidora (omac.lsub.org):
java -cp rmiclock.jar org.lsub.clockserver.Clock
3
Máquina cliente (ignatz.lsub.org):
java -cp rmiclock.jar org.lsub.clockclient.Client
omac.lsub.org 9999
Salida:
MasterClock says: Fri Mar 15 13:23:18 CET 2013
RMI: descarga dinámica de clases
• RMI nos permite descargar clases dinámicamente si el cliente
o el servidor no tienen todas las clases necesarias.
• Este mecanismo no es imprescindible, lo más sencillo es
distribuir un jar con todas las clases.
• Complica la configuración y puede suponer un problema de
seguridad si no se configura con cuidado → no debemos
usarlo si realmente no lo necesitamos.
RMI: descarga dinámica de clases
(c) Oracle
RMI: descarga dinámica de clases
• java.rmi.server.codebase es la propiedad que indica la
URL que puede usar un cliente para conseguir las clases si no
están en su classpath local.
• La URL se puede especificar como argumento para la VM al
ejecutar:
-Djava.rmi.server.codebase=http://example.org/classes.jar
RMI: descarga dinámica de clases
Hay que instalar un Security Manager en el cliente y en el servidor:
• Determina los permisos (p. ej. el acceso al FS) del código
descargado dinámicamente.
• Es necesario instalar uno para descargar clases.
i f ( System . g e t S e c u r i t y M a n a g e r ( ) == n u l l ) {
System . s e t S e c u r i t y M a n a g e r ( new S e c u r i t y M a n a g e r ( ) ) ;
}
RMI: descarga dinámica de clases
• Por último, hay que generar ficheros de polı́ticas de seguridad
para que el SecurityManager autorice las acciones del código
descargado.
• El fichero de polı́ticas se puede especificar como argumento
para la VM al ejecutar:
-Djava.security.policy=file:/home/q/java/sec.policy
Descargar