Está en la página 1de 117

c David Vallejo Fern ndez.

Se permite la copia, distribuci n y/o modicaci n de este documento a o o bajo los t rminos de la licencia de documentaci n libre GNU, versi n 2 o cualquier versi n posterior e o o o publicada por la Free Software Foundation, sin secciones invariantes. Puede consultar esta licencia en http://www.gnu.org.
A Este documento fue compuesto con LTEX. Im genes generadas con OpenOfce. a

Indice general
1. Introducci n o 1.1. Introducci n general a los middlewares o 1.1.1. Conceptos . . . . . . . . . . . . 1.1.2. Fundamentos b sicos . . . . . . a 1.2. Caractersticas generales de ICE . . . . 1.3. Organizaci n de este documento . . . . o 1 1 1 2 3 4

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

Un vistazo a ICE
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5
6 6 6 19 19 19 21 22 22 23 23 24 24 24 24 26 26 26 27 30 32 33

2. Toma de contacto con ICE 2.1. La arquitectura de ICE . . . . . . . . . . . . . . . 2.1.1. Terminologa . . . . . . . . . . . . . . . . 2.1.2. Slice (Lenguaje de especicaci n para ICE) o 2.1.3. Mappings de lenguajes . . . . . . . . . . . 2.1.4. Estructura cliente-servidor . . . . . . . . . 2.1.5. El protocolo ICE . . . . . . . . . . . . . . 2.1.6. Persistencia de objetos . . . . . . . . . . . 2.2. Servicios ofrecidos por ICE . . . . . . . . . . . . . 2.2.1. IceGrid . . . . . . . . . . . . . . . . . . . 2.2.2. IceBox . . . . . . . . . . . . . . . . . . . 2.2.3. IceStorm . . . . . . . . . . . . . . . . . . 2.2.4. IcePatch2 . . . . . . . . . . . . . . . . . . 2.2.5. Glacier2 . . . . . . . . . . . . . . . . . . . 2.3. Benecios arquitect nicos de ICE . . . . . . . . . o

3. Un ejemplo sencillo de aplicaci n con ICE o 3.1. Hola mundo! con ICE . . . . . . . . . . . . . . . . . . . . 3.1.1. Escribiendo la denici n en Slice . . . . . . . . . . o 3.1.2. Escribiendo la aplicaci n en Python . . . . . . . . . o 3.1.3. Escribiendo la aplicaci n en C++ . . . . . . . . . . o 3.1.4. Escribiendo la aplicaci n en Java . . . . . . . . . . o 3.1.5. Escribiendo la parte cliente de la aplicaci n en Ruby o

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

INDICE GENERAL

II

Slice
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35
36 36 37 37 38 39 40 40 41 42 46 46

4. El lenguaje Slice 4.1. Introducci n . . . . . . . . . . . . . . . . . . o 4.2. Aspectos b sicos . . . . . . . . . . . . . . . a 4.2.1. Compilaci n . . . . . . . . . . . . . o 4.2.2. Ficheros fuente . . . . . . . . . . . . 4.2.3. Reglas l xicas . . . . . . . . . . . . . e 4.2.4. M dulos . . . . . . . . . . . . . . . o 4.2.5. Tipos b sicos en Slice . . . . . . . . a 4.2.6. Tipos denidos por el usuario . . . . 4.2.7. Interfaces, operaciones, y excepciones 4.3. Aspectos avanzados . . . . . . . . . . . . . . 4.3.1. Clases . . . . . . . . . . . . . . . . .

III

ICE avanzado
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47
48 48 48 49 49 50 50 51 52 53 54 54 54 56 57 58 59 59 60 61 63 63 64

5. Propiedades de ICE y conguraci n o 5.1. Introducci n . . . . . . . . . . . o 5.2. Propiedades . . . . . . . . . . . 5.3. Archivos de conguraci n . . . o 5.4. La propiedad Ice.Cong . . . .

6. Programaci n asncrona o 6.1. Introducci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 6.1.1. Invocaci n de m todos asncrona o AMI (Asynchronous Method Ino e vocation) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.1.2. Tratamiento de m todos asncrono o AMD (Asynchronous Method e Dispatch) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.1.3. Controlando la generaci n de c digo utilizando metadatos . . . . . . o o 6.1.4. Transparencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2. AMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.1. Simulando AMI utilizando invocaciones oneway . . . . . . . . . . . 6.2.2. Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.3. Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.4. Cuestiones asociadas a la concurrencia . . . . . . . . . . . . . . . . 6.2.5. Timeouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3. AMD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.1. Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.2. Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7. Transferencia eciente de cheros 7.1. Introducci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 7.2. Versi n inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o

7.3. 7.4. 7.5. 7.6. 7.7. 7.8.

Usando AMI . . . . . . . . . . . . . . . . . . . . . Incrementando la eciencia con dos llamadas AMI . Uso de la caracterstica zero-copy del mapping a C++ Utilizando AMD en el servidor . . . . . . . . . . . . A n m s eciente . . . . . . . . . . . . . . . . . . . u a Conclusiones . . . . . . . . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

66 69 71 72 73 76

IV

Servicios en ICE

77
78 78 80 86 86 87 87 88 89 92 92 95 95 99

8. IceGrid 8.1. Introducci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 8.2. Ejemplo de aplicaci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 9. Freeze 9.1. Introducci n . . . . . . . . . . o 9.2. Freeze map . . . . . . . . . . 9.2.1. Ejemplo de aplicaci n o 9.3. Freeze evictor . . . . . . . . . 9.3.1. Ejemplo de aplicaci n o 10. Glacier2 10.1. Introducci n . . . . . . . . o 10.2. Ejemplos de aplicaciones . 10.2.1. Ejemplo b sico . . a 10.2.2. Ejemplo avanzado

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

11. IceBox 101 11.1. Introducci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 o 11.2. Ejemplo de aplicaci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 o 12. IceStorm 104 12.1. Introducci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 o 12.2. Ejemplo de aplicaci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 o 13. IcePatch2 110 13.1. Introducci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 o 13.2. Ejemplo de aplicaci n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 o Bibliografa 113

Captulo 1 Introducci n o
1.1. Introducci n general a los middlewares o 1.1.1. Conceptos 1.1.2. Fundamentos b sicos a 1.2. Caractersticas generales de ICE 1.3. Organizaci n de este documento o

1.1.
1.1.1.

Introducci n general a los middlewares o


Conceptos

Se puede entender un middleware como un software de conectividad que hace posible que aplicaciones distribuidas pueden ejecutarse sobre distintas plataformas heterog neas, es decir, e sobre plataformas con distintos sistemas operativos, que usan distintos protocolos de red y, que incluso, involucran distintos lenguajes de programaci n en la aplicaci n distribuida. o o Desde otro punto de vista distinto, un middleware se puede entender como una abstracci n en la complejidad y en la heterogeneidad que las redes de comunicaciones imponen. o De hecho, uno de los objetivos de un middleware es ofrecer un acuerdo en las interfaces y en los mecanismos de interoperabilidad, como contrapartida de los distintos desacuerdos en hardware, sistemas operativos, protocolos de red, y lenguajes de programaci n. o

1.1. Introducci n general a los middlewares o

Aplicacin

Aplicacin

APIs Middleware Serviciosdesistemas distribuidos


Interfaz plataforma Interfaz plataforma

Plataforma Sistema operativo

Plataforma Sistema operativo

Figura 1.1: Esquema general de un middleware

1.1.2.

Fundamentos b sicos a

La mayora de los middlewares tratan de acercar el modelo de programaci n a un punto o de vista local, es decir, enmascarando la llamada a los procedimientos remotos. Por otra parte, el enfoque m s extendido es el de la generaci n de un proxy en la parte del cliente y a o de un esqueleto en la parte del servidor. Para ello, el cliente utiliza un objeto proxy con la misma interfaz denida en la parte del servidor, y que act a como intermediario. El servidor, u por otro lado, utiliza un esqueleto encargado de traducir los eventos de la red a invocaciones sobre el objeto en cuesti n. Como se puede apreciar, existe un gran acercamiento de la versi n o o distribuida a la versi n centralizada. o Las principales responsabilidades de un proxy son las siguientes: Codicar la invocaci n y los argumentos en un mensaje. o Esperar la respuesta y decodicar el valor o los valores de retorno. Por otra parte, las principales responsabilidades de un esqueleto son las siguientes: Esperar una invocaci n y decodicar el mensaje y los argumentos. o

1.2. Caractersticas generales de ICE Invocar el m todo real. e Codicar el valor o los valores de retorno en un mensaje de respuesta.

Una cuesti n importante a tener en cuenta es la codicaci n de los datos en la red. Por o o ejemplo, es posible tener distintas representaciones de un mismo tipo de datos dependiendo del computador empleado. Para solucionar este problema, se suele denir una representaci n o externa can nica, y transformar a y desde un formato binario a partir de la representaci n o o externa. Este proceso es conocido como proceso de marshalling y unmarshalling. Por otra parte, el middleware tambi n ha de gestionar problemas inherentes a las comue nicaciones, como por ejemplo la identicaci n de mensajes, la gesti n de retransmisiones, la o o gesti n de conexiones, y la identicaci n de objetos. Por todo ello, la soluci n m s extendida o o o a se basa en un n cleo de comunicaciones gen rico y de un generador autom tico de proxies y u e a esqueletos.

1.2.

Caractersticas generales de ICE

ICE (Internet Communication Engine) [4] es un middleware orientado a objetos, es decir, ICE proporciona herramientas, APIs, y soporte de bibliotecas para construir aplicaciones cliente-servidor orientadas a objetos. Una aplicaci n ICE se puede usar en entornos o heterog neos: los clientes y los servidores pueden escribirse en diferentes lenguajes de proe gramaci n, pueden ejecutarse en distintos sistemas operativos y en distintas arquitecturas, o y pueden comunicarse empleando diferentes tecnologas de red. Adem s, el c digo fuente a o de estas aplicaciones puede portarse de manera independiente al entorno de desarrollo. Los principales objetivos de diseno de ICE son los siguientes: Proporcionar un middleware listo para usarse en sistemas heterog neos. e Proveer un conjunto completo de caractersticas que soporten el desarrollo de aplica ciones distribuidas reales en un amplio rango de dominios. Evitar una complejidad innecesaria, haciendo que ICE sea f cil de aprender y de usar. a

1.3. Organizaci n de este documento o

Proporcionar una implementaci n eciente en ancho de banda, en uso de memoria, y o en carga de CPU. Proporcionar una implementaci n basada en la seguridad, de forma que se pueda usar o sobre redes no seguras. Se puede decir que la losofa de ICE se basa en construir una plataforma tan potente como CORBA, pero sin cometer todos los fallos de esta y evitando una complejidad innecesaria.

1.3.

Organizaci n de este documento o

Este documento est estructurado en cuatro partes: a Parte I, Un vistazo a ICE, realiza una toma de contacto con el middleware ZeroC ICE y expone un ejemplo sencillo de aplicaci n en ICE. o Parte II, Slice, alude al lenguaje de denici n de interfaces de ZeroC ICE, comentando o los aspectos b sicos por un lado y algunos de los aspectos m s avanzados por otro. a a Parte III, ICE avanzado, expone ciertos aspectos avanzados de ZeroC ICE. Parte IV, Servicios en ICE, realiza un estudio de los servicios propuestos por el middleware ZeroC ICE desde una perspectiva eminentemente pr ctica. a

Parte I Un vistazo a ICE

Captulo 2 Toma de contacto con ICE


2.1. La arquitectura de ICE 2.1.1. Terminologa 2.1.2. Slice (Lenguaje de especicaci n para ICE) o 2.1.3. Mappings de lenguajes 2.1.4. Estructura cliente-servidor 2.1.5. El protocolo ICE 2.1.6. Persistencia de objetos 2.2. Servicios ofrecidos por ICE 2.2.1. IceGrid 2.2.2. IceBox 2.2.3. IceStorm 2.2.4. IcePatch2 2.2.5. Glacier2 2.3. Benecios arquitect nicos de ICE o

2.1.
2.1.1.

La arquitectura de ICE
Terminologa

ICE introduce una serie de conceptos t cnicos que componen su propio vocabulario, como e ocurre con cualquier nueva tecnologa. Sin embargo, el objetivo perseguido fue reutilizar la

2.1. La arquitectura de ICE

mayor parte de terminologa existente en sistemas de este tipo, de forma que la cantidad de t rminos introducidos fuera mnima. De hecho, si el lector ha trabajado con tecnologas e relacionadas como CORBA, la terminologa aqu descrita le ser muy familiar. a 2.1.1.1. Clientes y servidores

Los t rminos cliente y servidor no est n directamente asociados a dos partes distintas de e a una aplicaci n, sino que m s bien hacen referencia a los roles que las diferentes partes de una o a aplicaci n pueden asumir durante una petici n: o o Los clientes son entidades activas, es decir, emiten solicitudes de servicio a un servidor. Los servidores son entidades pasivas, es decir, proporcionan un servicio en respuesta a las solicitudes de los clientes. Normalmente, los clientes no son clientes puros en el sentido de que s lo solicitan peticioo nes. En su lugar, los clientes suelen ser entidades hbridas que asumen tanto el rol de cliente como el de servidor. De hecho, los sistemas cliente-servidor suelen describirse de una forma m s eciente como sistemas peer-to-peer. a 2.1.1.2. Objetos ICE

Un objeto ICE es una entidad conceptual o una abstracci n que mantiene una serie de o caractersticas: Un objeto ICE es una entidad en el espacio de direcciones remoto o local que es capaz de responder a las peticiones de los clientes. Un unico objeto ICE puede instanciarse en un unico servidor o, de manera redundante, en m ltiples servidores. Si un objeto tienes varias instancias simult neamente, todava u a sigue siendo un unico objeto ICE. Cada objeto ICE tiene una o m s interfaces. Una interfaz es una colecci n de operaa o ciones soportadas por un objeto. Los clientes emiten sus peticiones invocando dichas operaciones.

2.1. La arquitectura de ICE

Una operaci n tiene cero o m s par metros y un valor de retorno. Los par metros y o a a a los valores de retorno tienen un tipo especco. Adem s, los par metros tienen una a a determinada direcci n: los par metros de entrada se inicializan en la parte del cliente y o a se pasan al servidor, y los par metros de salida se inicializan en el servidor y se pasan a a la parte del servidor. (El valor de retorno es simplemente un par metro de salida a especial). Un objeto ICE tiene una interfaz distinguida del resto y conocida como la interfaz principal. Adem s, un objeto ICE puede proporcionar cero o m s interfaces alternativas, a a conocidas como facetas o facets. De esta forma, un cliente puede seleccionar entre las distintas facetas de un objeto para elegir la interfaz con la que quiere trabajar. Cada objeto ICE tiene una identidad de objeto unica. La identidad de un objeto es un valor identicativo que distingue a un objeto del resto de objetos. El modelo de objetos denido por ICE asume que las identidades de los objetos son unicas de forma global, es decir, dos objetos no pueden tener la misma identidad dentro de un dominio de comunicaci n en ICE. o 2.1.1.3. Proxies Para que un cliente sea capaz de comunicarse con un objeto ICE ha de tener acceso a un proxy para el objeto ICE. Un proxy es un componente local al espacio de direcciones del cliente, y representa al (posiblemente remoto) objeto ICE para el cliente. Adem s, act a como a u el embajador local de un objeto ICE, de forma que cuando un cliente invoca una operaci n o en el proxy, el n cleo de ejecuci n de ICE: u o 1. Localiza al objeto ICE. 2. Activa el servidor del objeto ICE si no est en ejecuci n. a o 3. Activa el objeto ICE dentro del servidor. 4. Transmite los par metros de entrada al objeto ICE. a 5. Espera a que la operaci n se complete. o

2.1. La arquitectura de ICE

6. Devuelve los par metros de salida y el valor de retorno al cliente (o una excepci n en a o caso de error). Un proxy encapsula toda la informaci n necesaria para que tenga lugar todo este proceso. o En particular, un proxy contiene informaci n asociada a diversas cuestiones: o Informaci n de direccionamiento que permite al n cleo de ejecuci n de la parte del o u o cliente contactar con el servidor correcto. Informaci n asociada a la identidad del objeto que identica qu objeto particular es el o e destino de la petici n en el servidor. o Informaci n sobre el identicador de faceta opcional que determina a qu faceta del o e objeto en concreto se reere el proxy. 2.1.1.4. Proxies textuales (stringed proxies)

La informaci n asociada a un proxy se puede representar como una cadena. Por ejemplo, o la cadena SimplePrinter:default -p 10000 es una representaci n legible de un proxy. El n cleo de ejecuci n de ICE proporciona o u o llamadas a su API para convertir proxies en cadenas y viceversa. Sin embargo, este tipo de representaci n se utiliza para aplicaciones b sicas y con prop sitos did cticos, ya que su o a o a tratamiento requiere de operaciones adicionales que se pueden evitar utilizando otro tipo de representaciones expuestas a continuaci n. o 2.1.1.5. Proxies directos (direct proxies)

Un proxy directo es un proxy que encapsula una identidad de objeto junto con la direcci n asociada a su servidor. Dicha direcci n est completamente especicada por los siguieno o a tes componentes: Un identicador de protocolo (como TCP/IP o UDP).

2.1. La arquitectura de ICE

10

Una direcci n especca de un protocolo (como el nombre y el puerto de una m quina). o a Con el objetivo de contactar con el objeto asociado a un proxy directo, el n cleo de ejeu cuci n de ICE utiliza la informaci n de direccionamiento vinculada al proxy para contactar o o con el servidor, de forma que la identidad del objeto se enva al servidor con cada petici n o realizada por el cliente. 2.1.1.6. Proxies indirectos (indirect proxies)

Un proxy indirecto tiene dos formas. Puede proporcionar s lo la identidad de un objeto, o o puede especicar una identidad junto con un identicador de adaptador de objetos. Un objeto que es accesible utilizando s lo su identidad se denomina objeto bien conocido. Por ejemplo, o la cadena SimplePrinter es un proxy v lido para un objeto bien conocido con la identidad a SimplePrinter. Un proxy indirecto que incluye un identicador de adaptador de objetos tiene la forma textual SimplePrinter@PrinterAdapter. Cualquier objeto del adaptador de objetos puede ser accedido utilizando dicho proxy sin importar si ese objeto tambi n es un objeto e bien conocido. Se puede apreciar que un proxy indirecto no contiene informaci n de direccionamiento. o Para determinar el servidor correcto, el n cleo de ejecuci n de la parte del cliente pasa la u o informaci n del proxy a un servicio de localizaci n. Posteriormente, el servicio de localizao o ci n utiliza la identidad del objeto o el identicador del adaptador de objetos como clave en o una tabla de b squeda que contiene la direcci n del servidor y que devuelve la direcci n del u o o servidor actual al cliente. El n cleo de ejecuci n de la parte del cliente es capaz ahora de u o contactar con el servidor y de enviar la solicitud del cliente de la manera habitual. El proceso completo es similar a la traducci n de los nombres de dominio en Internet a direcciones IP, o es decir, similar al DNS. 2.1.1.7. Binding directo y binding indirecto El proceso de convertir la informaci n de un proxy en una pareja protocolo-direcci n se o o conoce como binding. De forma intuitiva, la resoluci n directa se usa para los proxies directos o y la resoluci n indirecta para los proxies indirectos. o

2.1. La arquitectura de ICE

11

La principal ventaja de la resoluci n indirecta es que permita movilidad de servidores o (es decir, cambiar su direcci n) sin tener que invalidar los proxies existentes asociados a o los clientes. De hecho, los proxies indirectos siguen trabajando aunque haya migraci n del o servidor a otro lugar. 2.1.1.8. Proxies jos (xed proxies)

Un proxy jo es un proxy que est asociado a una conexi n en particular: en lugar de a o contener informaci n de direccionamiento o de un nombre de adaptador, el proxy contiene o un manejador de conexi n. Dicho manejador de conexi n permanece en un estado v lido o o a siempre que la conexi n permanezca abierta. Si la conexi n se cierra, el proxy no funciona o o (y no volver a funcionar m s). Los proxies jos no pueden pasarse como par metros a la a a a hora de invocar operaciones, y son utilizados para permitir comunicaciones bidireccionales, de forma que un servidor puede efectuar retrollamadas a un cliente sin tener que abrir una nueva conexi n. o 2.1.1.9. Replicaci n o

En ICE, la replicaci n implica hacer disponibles en m ltiples direcciones a los adaptadoo u res de objetos (y a sus objetos). El principal objetivo de la replicaci n es el de proporcionar o redundancia ejecutando el mismo servidor en distintas m quinas. Si en una de ellas se produce a un error, el servidor permanece disponible en el resto. Utilizar la replicaci n tambi n implica que las aplicaciones est n dise adas teniendo en o e e n cuenta dicho concepto. En particular, signica que un cliente pueda acceder a un objeto a trav s de una direcci n y que obtenga el mismo resultado si hubiera accedido a trav s de otra. e o e ICE soporta una forma limitada de replicaci n cuando un proxy especica m ltiples dio u recciones para un objeto. El n cleo de ejecuci n de ICE selecciona una de esas direcciones de u o manera aleatoria para su intento de conexi n inicial, e intenta contactar con el resto en caso o de fallo. Por ejemplo, considere este proxy: SimplePrinter:tcp -h server1 -p 10001:tcp -h server 2 -p 10002

2.1. La arquitectura de ICE

12

El proxy indica que el objeto identicado por SimplePrinter est disponible utilizando dos a direcciones TCP, una en la m quina server1 y otra en la m quina server2. Se supone que los a a administradores del sistema garantizan que el servidor est en ejecuci n tanto en la m quina a o a server1 como en la m quina server2. a 2.1.1.10. Grupos de r plica e

Adem s de la replicaci n basada en proxies comentada en la secci n anterior, ICE soporta a o o una forma m s util de replicaci n conocida como grupos de r plica que requiren el uso de un a o e servicio de localizaci n. o Un grupo de r plica tiene un identicador unico y consiste en un n mero determinado de e u adaptadores de objetos. Un adaptador de objetos puede ser miembro de al menos un grupo de r plica. Dicho adaptador se considera como un adaptador de objetos replicado. e Despu s de haber establecido un grupo de r plica, su identicador puede utilizarse como e e un proxy indirecto en lugar de un identicador de adaptador. Por ejemplo, un grupo de r plica e identicado por PrinterAdapters puede utilizarse como un proxy de la siguiente forma: SimplePrinter@PrinterAdapters Un grupo de r plica es tratado por el servicio de localizaci n como un adaptador de objee o tos virtual. El comportamiento del servicio de localizaci n cuando resuelve un proxy indirecto o que contiene el identicador de un grupo de r plica es un aspecto relacionado con la implee mentaci n. Por ejemplo, el servicio de localizaci n podra tomar la decisi n de devolver las o o o direcciones de todos los adaptadores de objetos del grupo, en cuyo caso el n cleo de ejecuu ci n de la parte del cliente podra seleccionar una de esas direcciones de manera aleatoria o utilizando la forma limitada de replicaci n comentada en la anterior secci n. Otra posibilio o dad para el servicio de localizaci n sera la de devolver una unica direcci n seleccionada en o o funci n de una determinada heurstica. o Sin tener en cuenta c mo el servicio de localizaci n resuelve un grupo de r plica, el o o e principal benecio es la indirecci n: el servicio de localizaci n puede a adir m s inteligencia o o n a al proceso de resoluci n actuando como intermediario. o

2.1. La arquitectura de ICE 2.1.1.11. Sirvientes (Servants)

13

Como se coment anteriormente, un objeto ICE es una entidad conceptual que tiene un o tipo, una identidad, e informaci n de direccionamiento. Sin embargo, las peticiones de los o clientes deben terminar en una entidad de procesamiento en el lado del servidor que proporcione el comportamiento para la invocaci n de una operaci n. En otras palabras, una petici n o o o de un cliente ha de terminar en la ejecuci n de un determinado c digo en el servidor, el cual o o estar escrito en un determinado lenguaje de programaci n y ejecutado en un determinado a o procesador. El componente en la parte del servidor que proporciona el comportamiento asociado a la invocaci n de operaciones se denomina sirviente. Un sirviente encarna a uno o m s objetos o a ICE. En la pr ctica, un sirviente es simplemente una instancia de una clase escrita por un el a desarrollador de la aplicaci n y que est registrada en el n cleo de ejecuci n de la parte del o a u o servidor como el sirviente para uno o m s objetos ICE. Los m todos de esa clase se correspona e deran con las operaciones de la interfaz del objeto ICE y proporcionaran el comportamiento para dichas operaciones. Un unico sirviente puede encarnar a un unico objeto ICE en un determinado momento o a varios objetos ICE de manera simult nea. En el primer caso, la identidad del objeto ICE a encarnado por el sirviente est implcita en el sirviente. En el segundo caso, el sirviente mana tiene la identidad del objeto ICE con cada solicitud, de forma que pueda decidir qu objeto e encarnar mientras dure dicha solicitud. En cambio, un unico objeto ICE puede tener m ltiples sirvientes. Por ejemplo, podramos u tomar la decisi n de crear un proxy para un objeto ICE con dos direcciones distintas para o distintas m quinas. En ese caso, tendramos dos servidores, en los que cada servidor cona tendra un sirviente para el mismo objeto ICE. Cuando un cliente invoca una operaci n en o dicho objeto, el n cleo de ejecuci n de la parte del cliente enva la petici n a un servidor. u o o En otras palabras, tener varios sirvientes para un unico objeto ICE permite la construcci n de o sistemas redundantes: el n cleo de ejecuci n de la parte del cliente trata de enviar la petici n u o o a un servidor y, si dicho servidor falla, enva la petici n al segundo servidor. S lo en el caso o o de que el segundo servidor falle, el error se enva para que sea tratado por el c digo de la o

2.1. La arquitectura de ICE aplicaci n de la parte del cliente. o 2.1.1.12. Sem ntica at-most-once a

14

Las solicitudes ICE tienen una sem ntica at-most-once: el n cleo de ejecuci n de ICE a u o hace todo lo posible para entregar una solicitud al destino correcto y, dependiendo de las circunstancias, puede volver a intentar una solicitud en caso de fallo. ICE garantiza que entregar la solicitud o, en caso de que no pueda hacerlo, informar al cliente con una determinada a a excepci n. Bajo ninguna circunstancia una solicitud se entregar dos veces, es decir, los reino a tentos se llevar n a cabo s lo si se conoce con certeza que un intento previo fall . a o o Esta sem ntica es importante porque asegura que las operaciones que no son idempotena tes puedan usarse con seguridad. Una operaci n es idempotente es una operaci n que, si se o o ejecuta dos veces, provoca el mismo efecto que si se ejecut una vez. Por ejemplo, x = 1; es o una operaci n idempotente, mientras que x++; no es una operaci n idempotente. o o Sin este tipo de sem nticas se pueden construir sistemas distribuidos robustos ante la prea sencia de fallos en la red. Sin embargo, los sistemas reales requieren operaciones no idempotentes, por lo que la sem ntica at-most-once es una necesidad, incluso aunque implique tener a un sistema menos robusto ante la presencia de fallos. ICE permite marcar a una determinada operaci n como idempotente. Para tales operaciones, el n cleo de ejecuci n de ICE utiliza un o u o mecanismo de recuperaci n de error m s agresivo que para las operaciones no idempotentes. o a 2.1.1.13. Invocaci n de m todos sncrona o e

Por defecto, el modelo de envo de peticiones utilizado por ICE est basado en la llama a da sncrona a procedimientos remotos: una invocaci n de operaci n se comporta como una o o llamada local a un procedimiento, es decir, el hilo del cliente se suspende mientras dure la llamada y se vuelve activar cuando la llamada se ha completado (y todos los resultados est n a disponibles).

2.1. La arquitectura de ICE 2.1.1.14. Invocaci n de m todos asncrona o e

15

ICE tambi n proporciona invocaci n de m todos asncrona (asynchronous method invoe o e cation) o AMI: un cliente puede invocar operaciones de manera asncrona, es decir, el cliente utiliza un proxy de la manera habitual para invocar una operaci n pero, adem s de pasar los o a par metros necesarios, tambi n pasa un objeto de retrollamada (callback object) y retorna a e de la invocaci n inmediatamente. Una vez que la operaci n se ha completado, el n cleo de o o u ejecuci n de la parte del cliente invoca a un m todo en el objeto de retrollamada pasado inio e cialmente, proporcionando los resultados de la operaci n a dicho objeto (o en caso de error, o proporcionando la informaci n sobre la excepci n asociada). o o El servidor no es capaz de diferenciar una invocaci n asncrona de una sncrona. De heo cho, en ambos casos el servidor simplemente aprecia que un cliente ha invocado una operaci n en un objeto. o 2.1.1.15. Tratamiento de m todos asncrono e

El tratamiento de m todos asncrono (asynchronous method dispatch) o AMD es el equie valente a AMI en el lado del servidor. En el tratamiento sncrono por defecto el n cleo de u ejecuci n de la parte del servidor y mientras la operaci n se est ejecutando (o durmiendo o o a debido a que espera para obtener un dato), el hilo de ejecuci n asociado al servidor s lo se o o libera cuando la operaci n se ha completado. o Con AMD se informa de la llegada de la invocaci n de una operaci n al c digo de la o o o aplicaci n de la parte del servidor. Sin embargo, en lugar de forzar al proceso a atender la o petici n inmediatamente, la aplicaci n de la parte del servidor puede retrasar el procesamiento o o de dicha petici n y liberar el hilo de ejecuci n asociado a la misma. El c digo de aplicaci n o o o o de la parte del servidor es ahora libre de hacer lo que quiera. Eventualmente, una vez que los resultados de la aplicaci n est n disponibles, el c digo de aplicaci n de la parte del servidor o a o o realiza una llamada al API para informar al n cleo de ejecuci n de la parte del servidor de u o que la petici n que se realiz con anterioridad ha sido completada. En este momento, los o o resultados de la ooperaci n invocada se envan al cliente. o AMD es util, por ejemplo, si un servidor ofrece operaciones que bloquean a los clientes

2.1. La arquitectura de ICE

16

por un periodo largo de tiempo. Por ejemplo, el servidor puede tener un objeto con una operaci n get que devuelva los datos de una fuente de datos externa y asncrona, lo cual bloqueara o al cliente hasta que los datos estuvieran disponibles. Con el tratamiento sncrono, cada cliente que esperara unos determinados datos estara vinculado a un hilo de ejecuci n del servidor. Claramente, este enfoque no es escalable con o una docena de clientes. Con AMD, centenas o incluso miles de clientes podran bloquearse en la misma invocaci n sin estar vinculados a los hilos del servidor. o El tratamiento sncrono y asncrono de m todos son transparentes al cliente, es decir, el e cliente es incapaz de saber si un determinado servidor realiza un tratamiento sncrono o, por el contrario, un tratamiento asncrono. 2.1.1.16. Invocaci n de m todos en una direcci n (Oneway Method Invocation) o e o

Los clientes pueden invocar una operaci n como una operaci n en una direcci n (oneway). o o o Dicha invocaci n mantiene una sem ntica best-effort. Para este tipo de invocaciones, el n cleo o a u de ejecuci n de la parte del cliente entrega la invocaci n al transporte local, y la invocaci n se o o o completa en la parte del cliente tan pronto como el transporte local almacene la invocaci n. o La invocaci n actual se enva de forma transparente por el sistema operativo. El servidor no o responde a invocaciones de este tipo, es decir, el ujo de tr co es s lo del cliente al servidor, a o pero no al rev s. e Este tipo de invocaciones no son reales. Por ejemplo, el objeto destino puede no existir, por lo que la invocaci n simplemente se perdera. De forma similar, la operaci n podra ser o o tratada por un sirviente en el servidor, pero dicha operaci n podra fallar (por ejemplo, porque o los valores de los par metros no fuesen correctos). En este caso, el cliente no recibira ning n a u tipo de noticaci n al respecto. o Las invocaciones oneway son s lo posibles en operaciones que no tienen ning n tipo de o u valor de retorno, no tienen par metros de salidad, y no arrojan ning n tipo de excepci n de a u o usuario. En lo que se reere al c digo de aplicaci n de la parte del servidor estas invocaciones son o o transparentes, es decir, no existe ninguna forma de distinguir una invocaci n twoway de una o oneway.

2.1. La arquitectura de ICE

17

Las invocaciones oneway est n disponibles s lo si el objeto destino ofrece un transporte a o orientado a ujo, como TCP/IP o SSL. 2.1.1.17. Invocaci n de m todos en una direcci n y por lotes (batched oneway method o e o invocation) Cada invocaci n oneway enva un mensaje al servidor. En una serie de mensajes cortos, la o sobrecarga es considerable: los n cleos de ejecuci n del cliente y del servidor deben cambiar u o entre el modo usuario y el modo n cleo para cada mensaje y, a nivel de red, se incrementa la u sobrecarga debido a la auencia de paquetes de control y de conrmaci n. o Las invocaciones batched oneway permiten enviar una serie de invocaciones oneway en un unico mensaje: cada vez que se invoca una operaci n batched oneway, dicha invocaci n o o se almacena en un buffer en la parte del cliente. Una vez que se han acumulado todas las invocaciones a enviar, se lleva a cabo una llamada al API para enviar todas las invocaciones a la vez. A continuaci n, el n cleo de ejecuci n de la parte del cliente enva todas las invocao u o ciones almacenadas en un unico mensaje, y el servidor recibe todas esas invocaciones en un unico mensaje. Este enfoque evita los inconvenientes descritos anteriormente. Las invocaciones individuales en este tipo de mensajes se procesan por un unico hilo en el orden en el que fueron colocadas en el buffer. De este modo se garantiza que las operaciones individuales sean procesadas en orden en el servidor. Las invocaciones batched oneway son particularmente utiles para servicios de mensajes como IceStorm, y para las interfaces de grano no que ofrecen operaciones set para atributos peque os. n 2.1.1.18. Datagram invocations Este tipo de invocaciones mantienen una sem ntica best-effort similar a las invocaciones a oneway. Sin embargo, requieren que el mecanismo de transporte empleado sea UDP. Estas invocaciones tienen las mismas caractersticas que las invocaciones oneway, pero abarcan un mayor n mero de escenarios de error: u Las invocaciones pueden perderse en la red debido a la naturaleza del protocolo UDP.

2.1. La arquitectura de ICE

18

Las invocaciones pueden llegar fuera de orden debido a la naturaleza del protocolo UPD. Este tipo de invocaciones cobr n m s sentido en el ambito de las redes locales, en las a a que la posibilidad de p rdida es peque a, y en situaciones en las que la baja latencia es m s e n a importante que la abilidad, como por ejemplo en aplicaciones interactivas en Internet. 2.1.1.19. Batched datagram invocations Este tipo de invocaciones son an logas a las batched oneway invocations, pero en el ambia to del protocolo UDP. 2.1.1.20. Excepciones en tiempo de ejecuci n o

Cualquier invocaci n a una operaci n puede lanzar una excepci n en tiempo de ejecuci n. o o o o Las excepciones en tiempo de ejecuci n est n predenidas por el n cleo de ejecuci n de ICE o a u o y cubren condiciones de error comunes, como fallos de conexi n, timeouts, o fallo en la o asignaci n de recursos. Dichas excepciones se presentan a la aplicaci n como excepciones o o propias a C++, Java, o C#, por ejemplo, y se integran en la forma de tratar las excepciones de estos lenguajes de programaci n. o 2.1.1.21. Excepciones denidas por el usuario

Las excepciones denidas por el usuario se utilizan para indicar condiciones de error especcas a la aplicaci n a los clientes. Dichas excepciones pueden llevar asociadas una o determinada cantidad de datos complejos y pueden integrarse en jerarquas de herencia, lo cual permite que la aplicaci n cliente maneje diversas categoras de errores generales. o 2.1.1.22. Propiedades

La mayor parte del n cleo de ejecuci n de ICE se puede congurar a trav s de las propieu o e dades. Estos elementos son parejas clave-valor , como por ejemplo Ice.Default.Protocol=tcp. Dichas propiedades est n normalmente almacenadas en cheros de texto y son trasladadas al a

2.1. La arquitectura de ICE

19

n cleo de ejecuci n de ICE para congurar diversas opciones, como el tama o del pool de u o n hilos, el nivel de traceado, y muchos otros par metros de conguraci n. a o

2.1.2.

Slice (Lenguaje de especicaci n para ICE) o

Como se mencion anteriormente, cada objeto ICE tiene una interfaz con un determinado o n mero de operaciones. Las interfaces, las operaciones, y los tipos de datos intercambiados u entre el cliente y el servidor se denen utilizando el lenguaje Slice. Slice permite denir el contrato entre el cliente y el servidor de forma independiente del lenguaje de programaci n o empleado. Las deniciones Slice se compilan por un compilador a una API para un lenguaje de programaci n especco, es decir, la parte de la API que es especca a las interfaces y los o tipos que previamente han sido denidos y que consisten en c digo generado. o

2.1.3.

Mappings de lenguajes

Las reglas que rigen c mo se traslada cada construcci n Slice en un lenguaje de prograo o maci n especco se conocen como mappings de lenguajes. Por ejemplo, para el mapping a o C++, una secuencia en Slice aparece como un vector STL, mientras que para el mapping a Java, una secuencia en Slice aparece como un array. Con el objetivo de determinar qu aspecto e tiene la API generada para un determinado lenguaje, s lo se necesita conocer la especicaci n o o en Slice y las reglas de mapping hacia dicho lenguaje. Actualmente, ICE proporciona mappings para los lenguajes C++, Java, C#, Visual Basic .NET, Python, y, para el lado del cliente, PHP y Ruby.

2.1.4.

Estructura cliente-servidor

Los clientes y los servidores ICE tienen la estructura l gica interna mostrada en la gura o 2.1. Tanto el cliente como el servidor se pueden entender como una mezcla de c digo de o aplicaci n, c digo de bibliotecas, y c digo generado a partir de las deniciones Slice: o o o El n cleo de ICE contiene el soporte de ejecuci n para las comunicaciones remotas u o

2.1. La arquitectura de ICE

20

Aplicacincliente

Aplicacinservidora

Cdigo proxy

APIIce

APIIce

Esqueleto

Adaptador objetos

NcleoclienteIce Red

NcleoservidorIce

Figura 2.1: Estructura cliente-servidor

en el lado del cliente y en el del servidor. De cara al desarrollador, dicho n cleo se u corresponde con un determinado n mero de bibliotecas con las que la aplicaci n puede u o enlazar. La parte gen rica del n cleo de ICE, a la cual se accede a trav s del API de ICE. e u e El desarrollador utiliza esta API para la gesti n de tareas administrativas, como por o ejemplo la inicializaci n y nalizaci n del n cleo de ejecuci n de ICE. o o u o El c digo de los proxies se genera a partir de las deniciones en Slice y, por lo tanto, es o especco a los tipos de objetos y de datos denidos en Slice. Dicho c digo tiene dos o funciones principales: proporciona una interfaz para el cliente y proporciona c digo de o marshaling y unmarshaling. Marshaling es el proceso de serializar una estructura de datos compleja, como una secuencia o un diccionario, para la transmisi n por la red. o Este c digo convierte los datos en una forma est ndar para la transmisi n de forma o a o independiente de la arquitectura de las m quinas involucradas (como por ejemplo biga endian) y de las reglas de relleno. Unmarshaling es el proceso contrario.

2.1. La arquitectura de ICE

21

El c digo del esqueleto tambi n se genera a partir de la denici n en Slice y, por lo o e o tanto, es especco a los tipos de objetos y datos denidos en Slice. Dicho c digo es el o equivalente al generado para el proxy pero en la parte del servidor. El adaptador de objetos es una parte de la API de ICE especco al lado del servidor: s lo los servidores utilizan los adaptadores de objetos. Un adaptador de objetos tiene o varios funciones, como traducir las peticiones de los clientes a los m todos espece cos al lenguaje de programaci n empleado, asociarse a uno o m s puntos nales de o a transporte, o crear los proxies que pueden pasarse a los clientes.

2.1.5.

El protocolo ICE

ICE proporciona un protocolo RPC que puede utilizar tanto TCP/IP como UPD como capa de transporte subyacente. Adem s, ICE permite utilizar SSL, de forma que todas las a comunicaciones entre el cliente y el servidor est n encriptadas. e El protocolo ICE dene: Un determinado n mero de tipos de mensajes, como por ejemplo de solicitud y resu puesta. Una m quina de estados que determina qu secuencia siguen los distintos tipos de mena e sajes que se intercambian el cliente y el servidor, junto con el establecimiento de conexi n asociado. o Reglas de codicicaci n que determinan c mo se representa cada tipo de datos en la o o red. Una cabecera para cada tipo de mensaje que contiene detalles como el tipo del mensaje, el tama o del mensaje, y el protocolo y la versi n de codiciaci n empleados. n o o ICE tambi n soporta compresi n en la red: ajustando un par metro de conguraci n se e o a o pueden comprimir todos los datos asociados al tr co de red cara reducir el ancho de banda a utilizado. Esta propiedad resulta util si la aplicaci n intercambia grandes cantidades de datos o entre el cliente y el servidor.

2.2. Servicios ofrecidos por ICE

22

El protocolo ICE tambi n soporta operaciones bidireccionales: si un servidor quiere enviar e un mensaje a un objeto de retrollamada proporcionado por el cliente, la retrollamada puede efectuarse a partir de la conexi n establecida inicialmente por el cliente. Esta caracterstio ca es especialmente importante cuando el cliente est detr s de un cortafuegos que permite a a conexiones de salida pero no de entrada.

2.1.6.

Persistencia de objetos

ICE dispone de un servicio de persistencia que se denomina Freeze. Freeze facilita el almacenamiento del estado de un objeto en una base de datos, de forma que el desarrollador dene en Slice el estado almacenado para los objetos y el compilador Freeze genera c digo o que permite almacenar y recuperar el estado de los objetos en y desde una base de datos, respectivamente. Por defecto, ICE utiliza Berkeley DB y su base de datos asociada. ICE tambi n proporciona herramientas que facilitan el mantenimiento de bases de datos e y la migraci n del contenido de las bases de datos existentes a un nuevo esquema si las o deniciones de los objetos cambian.

2.2.

Servicios ofrecidos por ICE

El n cleo de ICE proporciona una sosticada plataforma cliente-servidor para el desarrou llo de aplicaciones distribuidas. Sin embargo, las aplicaciones reales necesitan normalmente algo m s que las capacidades remotas, como por ejemplo la activaci n de servidores bajo a o demanda, la distribuci n de proxies a los clientes, la distribuci n de eventos asncronos, la o o conguraci n de aplicaciones, etc. o ICE maneja una serie de servicios que gestionan estas caractersticas y otras. Dichos ser vicios se implementan como servidores ICE de forma que la aplicaci n desarrollada act e o u como un cliente. Ninguno de estos servicios utilizan caractersticas internas a ICE ocultas a la aplicaci n en cuesti n, por lo que en teora es posible desarrollar servicios equivalentes o o por parte del desarrollador. Sin embargo, manteniendo estos servicios disponibles como parte de la plataforma permite al desarrollador centrarse en el desarrollo de la aplicaci n en lugar o de construir la infraestructura necesaria en primer lugar. Adem s, la construcci n de dichos a o

2.2. Servicios ofrecidos por ICE

23

servicios no es un esfuerzo trivial, por lo que es aconsejable conocer y usar los servicios disponibles en lugar de reinventar la rueda en cada aplicaci n. o

2.2.1.

IceGrid

IceGrid es la implementaci n de un servicio de localizaci n ICE que transforma la ino o formaci n simb lica en un proxy indirecto asociado a una pareja protocolo-direcci n en lo o o o que se reere a resoluci n indirecta. Adem s de ser un servicio de localizaci n, IceGrid tiene o a o muchas otras caractersticas: IceGrid permite el registro de servidores para un arranque autom tico, es decir, habilita a la activaci n de servidores bajo demanda (servidores que se activan cuando el cliente o emite una solicitud). IceGrid proporciona herramientas que facilitan la conguraci n de aplicaciones como plejas que contienen ciertos servidores. IceGrid soporta la replicaci n y el balanceado de carga. o IceGrid automatiza la distribuci n de los ejecutables asociados a los servidores y de sus o archivos vinculados. IceGrid proporciona un servicio que permite a los clientes obtener proxies para los objetos en los que est n interesados. a

2.2.2.

IceBox

IceBox es un unico servidor de aplicaciones que permite gestionar el arranque y la parada de un determinado n mero de componentes de aplicaci n. Dichos componentes se pueden u o desplegar como una biblioteca din mica en lugar de un proceso. Esto hecho reduce la sobrea carga global del sistema, por ejemplo, permitiendo ejecutar varios componentes en una unica m quina virtual Java en lugar de tener m ltiples procesos, cada uno con su propia m quina a u a virtual.

2.3. Benecios arquitect nicos de ICE o

24

2.2.3.

IceStorm

IceStorm es un servicio de publicaci n-subscripci n que act a como un distribuidor de o o u eventos entre servidores y clientes. Los publicadores envan eventos al servicio IceBox, el cual los notica a los subscriptores. De esta forma, un unico evento publicado por el publicador se puede enviar a m ltiples subscriptores. Los eventos est n categorizados en funci n de un u a o tema, y los subscriptores especican los temas en los que est n interesados. IceBox permite a seleccionar entre distintos criterios de calidad de servicio para que las aplicaciones puedan obtener una relaci n abilidad-rendimiento apropiada. o

2.2.4.

IcePatch2

IcePatch2 es un servicio que permite la f cil distribuci n de actualizaciones de software a o a los clientes. Estos simplemente han de conectarse al servidor IcePatch2 y solicitar actualizaciones para una determinada aplicaci n. El servicio chequea autom ticamente la versi n o a o de los clientes y enva cualquier actualizaci n disponible en un formato comprimido para o gestionar ecientemente el ancho de banda. Estas actualizaciones pueden ser seguras utilizando el servicio Glacier2, de forma que s lo los clientes autorizados puedan descargarse o actualizaciones.

2.2.5.

Glacier2

Glacier2 es el servicio de cortafuegos de ICE, el cual permite que tanto los clientes como los servidores se comuniquen de forma segura a trav s de un cortafuegos sin comprometer la e seguridad. El tr co entre el cliente y el servidor queda completamente encriptado utilizando a certicados de clave p blica y es bidireccional. Glacier2 tambi n proporciona soporte para la u e autenticaci n mutua y para la gesti n segura de sesiones. o o

2.3.

Benecios arquitect nicos de ICE o

La arquitectura propuesta por ICE proporciona un serie de benecios a los desarrolladores de aplicaciones:

2.3. Benecios arquitect nicos de ICE o Mantiene una sem ntica orientada a objetos. a Proporciona un manejo sncrono y asncrono de mensajes. Soporta m ltiples interfaces. u Es independiente de la m quina. a Es independiente del lenguaje de programaci n. o

25

Es independiente de la implementaci n, es decir, el cliente no necesita conocer c mo o o el servidor implementa sus objetos. Es independiente del sistema operativo. Soporta el manejo de hilos. Es independiente del protocolo de transporte empleado. Mantiene transparencia en lo que a localizaci n y servicios se reere (IceGrid). o Es seguro (SSL y Glacier2). Permite hacer persistentes las aplicaciones (Freeze). Tiene disponible el c digo fuente. o

Captulo 3 Un ejemplo sencillo de aplicaci n con ICE o


3.1. Hola mundo! con ICE 3.1.1. Escribiendo la denici n en Slice o 3.1.2. Escribiendo la aplicaci n en Python o 3.1.3. Escribiendo la aplicaci n en C++ o 3.1.4. Escribiendo la aplicaci n en Java o 3.1.5. Escribiendo la parte cliente de la aplicaci n en Ruby o

3.1.

Hola mundo! con ICE

En esta secci n se estudiar como crear una sencilla aplicaci n cliente-servidor utilizando o a o los lenguajes Python, C++, Java, y Ruby para la parte cliente. Dicha aplicaci n en cuesti n o o ser una versi n remota del cl sico Hola mundo!. El objetivo de esta secci n es establecer a o a o una primera toma de contacto en lo que a desarrollo con ICE se reere.

3.1.1.

Escribiendo la denici n en Slice o

El primer paso en lo que al desarrollo de aplicaciones ICE se reere consiste en la denici n de un chero que especique las interfaces utilizadas por la aplicaci n. Para el sencillo o o ejemplo que se presenta a continuaci n, dicha denici n sera la siguiente: o o
module Demo {

26

3.1. Hola mundo! con ICE

27

interface HolaMundo { void saludar (); }; };

La denici n en Slice consiste en un m dulo Demo, el cual contiene una unica interfaz o o denominada HolaMundo. Dicha interfaz es muy simple y s lo proporciona una operaci n: o o saludar. Esta operaci n no acepta par metros de entrada y no devuelve ning n valor. o a u

3.1.2.

Escribiendo la aplicaci n en Python o

Esta secci n muestra c mo crear la aplicaci n Hola Mundo! en Python. o o o 3.1.2.1. Escribiendo el servidor

El servidor, cuyo c digo se explicar a continuaci n es el siguiente: o a o


import sys, traceback, Ice Ice.loadSlice(../slice/holaMundo.ice, [-I /usr/share/slice]) import Demo class HolaMundoI (Demo.HolaMundo): def saludar (self, current = None): print Hola Mundo! class Server (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() adapter = self.communicator().createObjectAdapterWithEndpoints( HolaMundoAdapter, default -p 10000) adapter.add(HolaMundoI(), Ice.stringToIdentity(HolaMundo)) adapter.activate() self.communicator().waitForShutdown() return 0 Server().main(sys.argv)

Como se puede apreciar, el c digo es muy sencillo gracias a la potencia que nos ofreo ce Python. De hecho, s lo necesitaremos utilizar las mnimas instrucciones de cara a poner o nuestra aplicaci n en funcionamiento. o La primera parte del programa est vinculada a la importanci n de m dulos y a la carga a o o del archivo en el que previamente denimos nuestras especicaciones en Slice. Es importante resaltar que es necesario incluir el m dulo Ice en todas nuestras aplicaciones ICE. As mismo, o

3.1. Hola mundo! con ICE

28

merece la pena hablar sobre la operaci n loadSlice, la cual nos permite generar el c digo asoo o ciado al archivo denido en Slice de forma din mica, es decir, permitiendo que los archivos a Slice se carguen en tiempo de ejecuci n y se traduzcan din micamente en c digo Python, el o a o cual es inmediatamente compilado y queda disponible para la aplicaci n del usuario. En el o caso especco del cliente, la interfaz HolaMundo se traduce en una clase que representa el esqueleto asociado a dicha interfaz. Como se ver posteriormente, su h mologo en la parte a o del cliente est representado por el proxy. a A continuaci n se dene la clase HolaMundoI, la cual es una especializaci n de la clase o o Demo.HolaMundo, que a su vez representa al esqueleto generado por ICE a partir de la interfaz HolaMundo. Ahora simplemente se han de implementar las operaciones denidas en dicha interfaz. En este caso, se propone una implementaci n de la operaci n saludar, la cual o o imprime por pantalla un mensaje. El siguiente paso consiste en escribir el c digo asociado a la aplicaci n servidora en cueso o ti n. Para ello, y como se observa en el c digo expuesto, se dene la clase Server. Esta clase o o contiene todo el c digo asociado a la instanciaci n de los recursos necesarios para obtener o o la parte servidora de la aplicaci n. En primer lugar, se observa c mo la clase Server hereda o o de la clase Ice.Application, proporcionada por ICE para encapsular todo el c digo asociado o a las actividades de inicializaci n y nalizaci n. El idea de esta clase es que el desarrollador o o cree una especializaci n de la misma y que implemente el m todo abstracto run en la clase o e derivada. El aspecto que se obtiene al utilizar esta clase es el siguiente:
class Server (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() .... # Server code. .... self.communicator().waitForShutdown() return 0 Server().main(sys.argv)

Utilizar la clase Ice.Application hace m s sencilla la creaci n de aplicaciones ICE. a o Finalmente, quedan por ejecutar tres instrucciones para completar la parte servidora: 1. Crear un adaptador de objetos: para ello se utiliza la operaci n createObjectAdapterWito hEndpoints, especicando el nombre del adaptador de objetos (HolaMundoAdapter) y

3.1. Hola mundo! con ICE

29

la direcci n en la que escuchar dicho adaptador de objetos (default -p 10000). En este o a caso, dicha direcci n utiliza el protocolo TCP/IP por defecto y el puerto 10000. o 2. Informar al adaptador de objetos de la existencia de un nuevo sirviente: para ello se utiliza la operaci n add, especicando la instancia especca del sirviente (HolaMundoI()) o y el identicador asociado a dicha instancia (Ice.stringToIdentity(HolaMundo)). En este caso, la cadena HolaMundo es el nombre del sirviente. 3. Activar el adaptador de objetos: para ello se utiliza la operaci n activate. o Ya s lo se necesita instanciar la clase Server y el servidor quedar a la escucha para o a atender las peticiones de los clientes. Llegados a este punto, es importante resaltar que el c digo comentado anteriormente es o esencialmente el mismo para todos los servidores. As mismo, se puede comprobar que Pyt hon minimiza la cantidad de c digo necesaria para el desarrollo de aplicaciones ICE, lo cual o lo hace especialmente util para temas de prototipado. 3.1.2.2. Escribiendo el cliente

La parte asociada al cliente, la cual es m s sencilla a n si cabe que la del servidor y que a u se explicar a continuaci n, se expone a continuaci n: a o o
import sys, traceback, Ice Ice.loadSlice(../slice/holaMundo.ice, [-I /usr/share/slice]) import Demo class Client (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() basePrx = self.communicator().stringToProxy( HolaMundo:default -p 10000) holaMundoPrx = Demo.HolaMundoPrx.checkedCast(basePrx) holaMundoPrx.saludar() self.communicator().waitForShutdown() return 0 Client().main(sys.argv)

El c digo del cliente es id ntico al del servidor a excepci n del c digo asociado al m todo o e o o e run. En este caso, la aplicaci n s lo ha de crear un proxy al objeto registrado en la parte del o o

3.1. Hola mundo! con ICE

30

servidor y ejecutar la operaci n saludar en dicho proxy, ya que este act a como embajador o u de dicho objeto. Para ello se han de llevar a cabo los siguientes pasos: 1. Obtener un proxy al objeto remoto: para ello se utiliza la operaci n stringToProxy, o pas ndole como par metro la cadena HolaMundo:default -p 10000, la cual contiene a a la identidad del objeto y el puerto usado por el servidor. 2. Realizar una conversi n del proxy obtenido en el paso anterior (el cual es del tipo o Ice::ObjectPrx) a un proxy del tipo Demo::HolaMundoPrx: para ello se utiliza la operaci n Demo.HolaMundoPrx.checkedCast, la cual enva un mensaje al servidor para o comprobar que realmente est asociado a la interfaz Demo::HolaMundo. En ese caa so, la llamada devuelve un proxy del tipo Demo.HolaMundoPrx. En caso contrario, la llamada devuelve None.

3.1.3.

Escribiendo la aplicaci n en C++ o

El sencillo ejemplo Hola Mundo! es pr cticamente id ntico a su hom logo en Python, a e o pero con la salvedad del cambio de sintaxis asociado. 3.1.3.1. Escribiendo el servidor

El servidor, cuyo c digo se explicar a continuaci n es el siguiente: o a o


#include <Ice/Application.h> #include <HolaMundo.h> using namespace std; using namespace Demo; class HolaMundoI : public HolaMundo { public: virtual void saludar (const Ice::Current&); }; void HolaMundoI:: saludar (const Ice::Current&) { cout << "Hola Mundo!" << endl; }

3.1. Hola mundo! con ICE

31

class Server : virtual public Ice::Application { virtual int run (int, char*[]) { Ice::ObjectAdapterPtr adapter = communicator()-> createObjectAdapterWithEndpoints("HolaMundoAdapter", "default -p 10000"); Ice::ObjectPtr object = new HolaMundoI; adapter->add(object, communicator()->stringToIdentity("HolaMundo")); adapter->activate(); communicator()->waitForShutdown(); return 0; } }; int main (int argc, char *argv[]) { Server server; return server.main(argc, argv); }

Como se puede apreciar, la funcionalidad del c digo mostrado es la misma que para el o lenguaje Python. En primer lugar, se incluyen los archivos de cabecera necesarios para hacer funcionar la aplicaci n servidora. Estos son el archivo Ice/Application.h, para hacer uso de la funcionao lidad denida en la clase Application, y el archivo HolaMundo.h, el cual se genera a partir de compilar el archivo HolaMundo.ice para el lenguaje C++. Posteriormente, se importan los contenidos de los espacios de nombrado std y Demo. A continuaci n, se implementa la clase HolaMundoI, la cual deriva de la clase HolaMuno do y, que a su vez, fue generada a partir de las deniciones Slice del archivo HolaMundo.ice. El resto del c digo es similar que para el ejemplo en Python: o 1. Se crea el adaptador de objetos. 2. Se informa al adaptador de objetos de la existencia del sirviente. 3. Se activa el adaptador de objetos. 3.1.3.2. Escribiendo el cliente

La parte cliente es an loga a la denido con el lenguaje Python y se expone a continuaa ci n: o

3.1. Hola mundo! con ICE

32

#include <Ice/Application.h> #include <HolaMundo.h> using namespace std; using namespace Demo; class Client : virtual public Ice::Application { virtual int run (int, char*[]) { Ice::ObjectPrx base = communicator()-> stringToProxy("HolaMundo:default -p 10000"); HolaMundoPrx holaMundoPrx = HolaMundoPrx::checkedCast(base); holaMundoPrx->saludar(); communicator()->waitForShutdown(); return 0; } }; int main (int argc, char *argv[]) { Client client; return client.main(argc, argv); }

3.1.4.

Escribiendo la aplicaci n en Java o

El primer paso para crear la aplicaci n en Java consiste en compilar la deni n Slice o o para generar los proxies y esqueletos asociados. Para ello, se pueden ejecutar los siguientes comandos:
mkdir generated slice2java --output-dir generated HolaMundo.ice

El siguiente paso es implementar la interfaz denida para el ejemplo b sico: a


public class HolaMundoI extends Demo._HolaMundoDisp { public void printString (String s, Ice.Current current) { System.out.println("Hola Mundo!"); } }

3.1.4.1.

Escribiendo el servidor

A continuaci n se presenta el c digo del servidor: o o


public class Server extends Ice.Application { public int run (String[] args) { Ice.ObjectAdapter adapter = communicator(). createObjectAdapterWithEndpoints("HolaMundoAdapter", "default -p 10000");

3.1. Hola mundo! con ICE

33

Ice.Object object = new HolaMundoI(); adapter.add(object, Ice.Util.stringToIdentity("HolaMundo")); adapter.activate(); communicator().waitForShutdown(); return 0; } }

3.1.4.2.

Escribiendo el cliente

A continuaci n se presenta el c digo del cliente: o o


public class Client extends Ice.Application { public int run (String[] args) { Ice.Objectprx base = communicator().stringToProxy( "HolaMundo:default -p 10000"); Demo.HolaMundoPrx prx = Demo.HolaMundoPrxHelper. checkedCast(base); if (prx == null) a throw new Error("Proxy no vlido"); prx.saludar(); communicator().waitForShutdown(); return 0; } }

Como se puede apreciar, tanto el cliente como el servidor son id nticos a los especicados e en otros lenguajes.

3.1.5.

Escribiendo la parte cliente de la aplicaci n en Ruby o

La parte cliente de la aplicaci n escrita en Ruby es pr cticamente id ntica a la denida en o a e Python:


require Ice Ice::loadSlice(../slice/HolaMundo.ice) class Client < Ice::Application def run (args) comm = Ice::Application::communicator() basePrx = comm.stringToProxy( HolaMundo:default -p 10000) holaMundoPrx = HolaMundoPrx.checkedCast(basePrx) holaMundoPrx.saludar() return 0 end end

3.1. Hola mundo! con ICE

34

app = Client.new() exit(app.main(ARGV))

Parte II Slice

35

Captulo 4 El lenguaje Slice


4.1. Introducci n o 4.2. Aspectos b sicos a 4.2.1. Compilaci n o 4.2.2. Ficheros fuente 4.2.3. Reglas l xicas e 4.2.4. M dulos o 4.2.5. Tipos b sicos en Slice a 4.2.6. Tipos denidos por el usuario 4.2.7. Interfaces, operaciones, y excepciones 4.3. Aspectos avanzados 4.3.1. Clases

4.1.

Introducci n o

Slice (Specication Language for Ice) es el mecanismo de abstracci n fundamental para o separar las interfaces de los objetos de su implementaci n. Slice establece un contrato entre o el cliente y el servidor que describe los tipos y las interfaces de los objetos utilizados por la aplicaci n. Esta descripci n es independiente del lenguaje de implementaci n, por lo que no o o o importa que el cliente est implementado utilizando el mismo lenguaje que en el servidor. e Las deniciones en Slice se compilan para un determinado lenguaje de implementaci n o a trav s de un compilador. Dicho compilador se encarga de traducir las deniciones indee 36

4.2. Aspectos b sicos a

37

pendiente del lenguaje en deniciones de tipos especcas del lenguaje y en APIs. Son estos tipos y estas deniciones los que ser n utilizados por el desarrollador de cara a proporcionar a la funcionalidad de la aplicaci n y a interactuar con ICE. Los algoritmos de traducci n para o o los distintos lenguajes de implementaci n se conocen como mappings de lenguajes. Actualo mente, ICE dene mappings para C++, Java, C#, Visual Basic .NET, Python, PHP, y Ruby (estos dos ultimos en lo que a la parte del cliente se reere).

4.2.
4.2.1.

a Aspectos b sicos
Compilaci n o

El compilador de Slice produce archivos fuente que han de ser combinados con el c digo o de la aplicaci n para generar los ejecutables asociados al cliente y al servidor. o En la gura 4.1 se muestra la situaci n en la que tanto el cliente como el servidor est n o a implementados utilizando C++. El compilador Slice genera dos archivos a partir de una denici n Slice en un archivo fuente Printer.ice: un chero de cabecera (Printer.h) y un chero o fuente (Printer.cpp). El chero de cabecera Printer.h contiene deniciones que se corresponden a los tipos utilizados en la denici n Slice. Este archivo se incluye tanto en el c digo del cliente o o como en el del servidor para asegurar que ambos est n de acuerdo con los tipos y las a interfaces utilizadas por la aplicaci n. o El chero fuente Printer.cpp proporciona un API al cliente para enviar los mensajes a los objetos remotos. El c digo fuente del cliente (Client.cpp) contiene la l gica de o o la aplicaci n del lado del cliente. El c digo fuente generado y el c digo del cliente se o o o compilan y se enlazan para obtener el ejecutable asociado al cliente. Por otra parte, el chero fuente asociado al servidor (Server.cpp) contiene la l gica de la o aplicaci n de la parte del servidor (la implementaci n de los objetos, es decir, los sirvientes). o o El proceso de compilaci n y enlazado es hom logo al de la parte del cliente. o o

4.2. Aspectos b sicos a

38

Figura 4.1: Proceso de desarrollo si el cliente y el servidor comparten el mismo lenguaje de programaci n o

El proceso asociado a la utilizaci n de distintos lenguajes de programaci n en el lado del o o cliente y en el del servidor es pr cticamente id ntico al comentado anteriormente. En la gura a e 4.2 se muestra un ejemplo.

4.2.2.

Ficheros fuente

Los archivos que contiene deniciones Slice han de terminar con la extensi n .ice, como o por ejemplo Printer.ice. Slice es un lenguaje libre de forma, es decir, se pueden utilizar espacios, tabulaciones verticales y horizontales, o retornos de carro para formatear el c digo de la manera deseada. o Por otra parte, Slice es preprocesado por el preprocesador C++, de forma que se pueden utilizar las directivas de preprocesado comunes, como por ejemplo #include. Sin embargo, estas sentencias han de indicarse al principio del archivo, justo antes de cualquier denici n o Slice.

4.2. Aspectos b sicos a

39

Figura 4.2: Proceso de desarrollo si el cliente y el servidor no comparten el mismo lenguaje de programaci n o

4.2.3.

Reglas l xicas e

Las reglas l xicas de Slice son muy parecidas a las de los lenguajes C++ y Java, a excepe ci n de algunas diferencias en lo que a identicadores se reere. o Los comentarios permitidos por Slice son de los tipos utilizados en C y en C++:
/* * Comentario estilo C. */ // Comentario estilo C++.

Los identicadores han de comenzar por un car cter alfab tico seguido de cualquier sea e cuencia de caracteres alfanum ricos. Los identicadores Slice est n restringidos al rango de e a caracteres alfab ticos ASCII. Por otra parte, Slice no permite el uso de guiones de subrayado e en los identicadores. Adem s, no son sensibles a may sculas. Para profundizar m s sobre a u a las reglas l xicas de Slice ver [4]. e

4.2. Aspectos b sicos a

40

4.2.4.

M dulos o

Un problema com n en grandes sistemas son los conictos de nombres conforme estos u crecen. Slice proporciona el constructor module para solventar este problema:
module Demo { module Client { // Definiciones aqu... }; module Server { // Definiciones aqu... }; };

Un m dulo pueden contener cualquier construcci n denida en Slice, incluso otros m duo o o los. Adem s, Slice necesita que cualquier denici n est incluida dentro de un m dulo, es a o e o decir, no se pueden tener deniciones globales. Los m dulos pueden abrirse y cerrarse en cualquier lugar, lo cual resulta muy util en o proyectos grandes, de forma que se puede estructurar el contenido de un m dulo en varios o archivos fuente. Adem s, cuando se produce un cambio en uno de estos cheros, s lo se a o necesita recompilar el chero que ha cambiado.

4.2.5.

Tipos b sicos en Slice a

Slice proporciona los siguientes tipos de datos b sicos: a bool byte short int long oat double

4.2. Aspectos b sicos a string Para una informaci n m s detallada sobre los mismos consultar [4]. o a

41

4.2.6.

Tipos denidos por el usuario

Adem s de los tipos b sicos comentados previamente, Slice proporciona los siguientes a a tipos de datos denidos por el usuario: Enumeraciones. Estructuras. Secuencias. Diccionarios. Una enumeraci n en Slice es parecida a la denida en C++: o
enum Fruta{Pera, Manzana, Naranja};

Una estructura en Slice contiene uno o m s miembros de un determinado tipo, incluyendo a tipos complejos denidos por el usuario:
struct Hora { short hora; short minute; short second; };

Una secuencia es un vector de elementos de longitud variable:


sequence<Fruta> BandejaDeFruta;

Un diccionario es un conjunto de parejas clave-valor:


struct Empleado { long numero; string primerApellido; string segundoApellido; }; dictionary<long, Empleado> Empleados;

4.2. Aspectos b sicos a

42

Aunque los diccionarios se podran implementar como una secuencia de estructuras, re sulta m s adecuado utilizar diccionarios por dos motivos principalmente: a Un diccionario hace explcito el dise o del desarrollador de la aplicaci n. n o A nivel de lenguaje de programaci n, las secuencias se implementan como vectores y o requieren una b squeda linear para localizar un elemento. Por otra parte, los diccionau rios est n implementados de acuerdo a una estructura de datos eciente en tiempos de a b squeda. u Para una informaci n m s detallada sobre los tipos de datos denidos por el usuario cono a sultar [4]. Slice tambi n soporta la denici n de constantes a trav s de uno de los siguientes tipos e o e de datos: Un tipo integral (bool, byte, short, int, long, o un tipo enumerado). oat o double. string.

4.2.7.

Interfaces, operaciones, y excepciones

El principal objetivo de Slice es la denici n de interfaces, por ejemplo: o


struct Hora { short hora; short minute; short second; }; interface Reloj { Hora obtenerHora(); void establecerHora(Hora h); };

La denici n anterior especica un tipo de interfaz denominado Reloj. Dicha interfaz o soporta dos operaciones: obtenerHora y establecerHora. Los clientes acceden a un objeto que soporta la interfaz Reloj invocando una operaci n en un proxy para dicho objeto: para o

4.2. Aspectos b sicos a

43

obtener la hora actual el cliente invoca a la hora operaci n obtenerHora, y para establecerla o invoca a la operaci n establecerHora, especicando un par metro del tipo Hora. o a La denici n de una operaci n ha de tener un tipo de retorno y cero o m s deniciones o o a de param tros. Por defecto, los par metros enviados del cliente al servidor son par metros de e a a entrada. Para pasar un par metro del servidor al cliente se pueden emplear los par metros de a a salida, utilizando para ello el modicador out:
void obtenerHora(out Hora h);

En cuanto a las operaciones que devuelven varios par metros de salida existen distintas a opciones, como por ejemplo especicar que todos esos par metros sean de salida o asociar el a valor de retorno al par metro de salida m s importante y utilizar el modicador out para el a a resto:
bool siguiente(out Registro r);

Slice no soporta ning n tipo de sobrecarga de operaciones. Todas las operaciones de una u interfaz han de tener un nombre distinto entre s. Este hecho se debe a que existen ciertos lenguajes que no soportan esta caracterstica. Existen distintos modicadores que se pueden aplicar a la denici n de las operaciones o en funci n de su naturaleza. Algunas operaciones no modican el estado del objeto sobre o el que operan, mientras que otras son idempotentes, es decir, se obtiene el mismo resultado tanto si se invocan una vez como si se invocan varias. El desarrollador puede informar a ICE sobre estos hechos de cara a que este utilice mecanismos m s agresivos con el objetivo de a ahorrar recursos y proporcionar una implementaci n m s eciente. Para ello, se utilizan los o a modicadores nonmutating e idempotent, respectivamente:
struct Hora { short hora; short minute; short second; }; interface Reloj { nonmutating Hora obtenerHora(); idempotent void establecerHora(Hora h); };

4.2. Aspectos b sicos a

44

En lo relativo a excepciones, ICE permite la denici n de excepciones de usuario para o indicar al cliente las condiciones de error que se produzcan:
exception Error {}; exception RangeError { Hora errorEnLaHora; Hora tiempoMin; Hora tiempoMax; }; interface Reloj { nonmutating Hora obtenerHora(); idempotent void establecerHora(Hora h) throws RangeError, Error; };

Las excepciones en Slice son parecidas a las estructuras en el sentido de que pueden tener un n mero arbitrario de miembros, pero con la salvedad de que las excepciones pueden no u tener miembros. Adem s, Slice soporta la herencia de excepciones. De hecho, mantiene un a arbol de herencia en el que se especican las excepciones propias al entorno de ejecuci n de o ICE. Es importante tener en cuenta que una operaci n s lo puede lanzar una excepci n que o o o previamente fue especicada en su denici n en Slice. Adem s, las excepciones no se consio a deran tipos de datos de primera clase, por lo que no pueden pasarse como par metros en las a operaciones ni utilizarlos como miembros en la denici n de estructuras, entre otras restrico ciones. Siguiendo con el ejemplo del reloj se podra denir un servidor en el que estuvieran pre sentas las zonas horarias de todo el mundo:
exception ErrorGenerico { string razon; }; struct Hora { short hora; short minute; short second; }; exception ValorHoraErroneo extends ErrorGenerico {}; interface Reloj { nonmutating Hora obtenerHora();

4.2. Aspectos b sicos a

45

idempotent void establecerHora(Hora h) throws ValorHoraErroneo; }; dictionary<string, Reloj*> MapaZonas; exception NombreZonaErroneo extends ErrorGenerico {}; interface RelojMundial { idempotent void aadirZona(string nombre, Reloj* relojZona); n void eliminarZona(string nombre) throws NombreZonaErroneo; nonmutating Reloj* encontrarZona(string nombre) throws NombreZonaErroneo; nonmutating MapaZonas listaZonas(); idempotent void establecerZonas(MapaZonas zonas); };

La interfaz RelojMundial act a como un gestor de zonas, es decir, un gestor de parejas u nombre de la zona y reloj. Dicha interfaz proporciona operaciones para a adir zonas, eliminar n zonas, encontrar zonas, obtener la lista completa de zonas, y establecer la lista de zonas. El concepto m s importante de este ejemplo reside en que las propias interfaces son tipos de a datos por s mismas y, por lo tanto, se pueden pasar como par metros y pueden ser devueltas, a como se aprecia en las operaciones a adirZona y eliminarZona, respectivamente. El operador n se conoce como operador proxy. Su argumento m s a la izquierda ha de ser una interfaz (o a una clase), y su tipo de retorno es un proxy. Un proxy se puede entender como un puntero que referencia a un objeto. La sem ntica de los proxies es muy parecida a los punteros asociados a a una instancia de clase en C++. Cuando un cliente pasa un proxy Reloj a la operaci n a adirZona, el proxy hace refeo n rencia al objeto de tipo Reloj real en el servidor. El objeto ICE Reloj referenciado por ese proxy puede estar implementado en el mismo proceso servidor que la interfaz RelojMundial o en un proceso de servidor distinto. Desde el punto de vista del cliente, la localizaci n fsica o de dicho objeto no importa. En otras palabras, el proxy act a como el embajador local del u objeto remoto: invocar una operaci n en el proxy se traduce en invocar la operaci n en la o o implementaci n del objeto real. Si el objeto est implementado en un espacio de direcciones o a distinto al del cliente, ICE realiza una llamada a procedimiento remoto. Si el objeto est ima plementado en el mismo espacio de direcciones, ICE realiza una llamada local desde el proxy a la implementaci n del objeto. o Al igual que ocurre con las excepciones, las interfaces tambi n soportan el concepto de e

4.3. Aspectos avanzados herencia.

46

4.3.

Aspectos avanzados

En esta secci n se comentar n algunos aspectos avanzados de Slice. Sin embargo, para o a obtener una informaci n m s completa y detallada se recomienda estudiar [4]. o a

4.3.1.

Clases

Adem s de las interfaces, Slice permite la denici n de clases. Las clases son como las a o interfaces en el sentido de que tienen operaciones, y se parecen a las estructuras debido a que pueden incluir atributos. El resultado son unos objetos hbridos que pueden tratarse al igual que las interfaces y pasarse por referencia, o pueden tratarse como atributos y pasarse por valor. El benecio de las clases es una mayor exibilidad a la hora de desarrollar aplicaciones: las clases permiten modelar el comportamiento a implementar en el lado del cliente y las interfaces permiten representar el comportamiento a implementar en el lado del servidor. Las clases soportan la herencia y, por lo tanto, el polimorsmo. El utilizar clases en ciertos contextos, como por ejemplo denir una clase con operaciones, implica reexionar sobre ciertos aspectos asociados a la arquitectura de la aplicaci n. El tener o una clase con operaciones denidas en ellas implica utilizar c digo nativo del lado del cliente o y, por lo tanto, elimina la transparencia de implementaci n proporcionada por las interfaces. o Una clase Slice tambi n puede utilizarse como un sirviente en un servidor, es decir, una e instancia de una clase se puede utilizar para proporcionar el comportamiento de un interfaz:
interface Tiempo { nonmutating Hora obtenerHora(); idempotent void establecerHora(Hora h); }; class Reloj implements Tiempo { Hora hora; };

Parte III ICE avanzado

47

Captulo 5 Propiedades de ICE y conguraci n o


5.1. Introducci n o 5.2. Propiedades 5.3. Archivos de conguraci n o 5.4. La propiedad Ice.Cong

5.1.

Introducci n o

ICE utiliza un mecanismo de conguraci n que permite controlar muchos aspectos del o comportamiento de las aplicaciones ICE en tiempo de ejecuci n, como el tama o m ximo de o n a los mensajes, el n mero de hilos, o si generar mensajes de trazas de red. Dicho mecanismo u de conguraci n no s lo es util para congurar ICE, sino que tambi n se puede utilizar para o o e proporcionar par metros de conguraci n a las propias aplicaciones. Este mecanismo es muy a o simple en el sentido de que se puede utilizar con una sencilla API, y escalable en el sentido de que se adapta a la necesidades de la mayora de aplicaciones.

5.2.

Propiedades

ICE y sus distintos subsistemas se conguran a trav s de las propiedades. Una propiedad e es un par nombre-valor, por ejemplo:

48

5.3. Archivos de conguraci n o

49

Ice.UDP.SndSize=65535

En este ejemplo, el nombre de la propiedad es Ice.UPD.SndSize y su valor es 65535.

5.3.

Archivos de conguraci n o

Los valores de las propiedades se establecen normalmente en archivos de conguraci n. o Un archivo de conguraci n contiene un determinado n mero de parejas nombre-valor, cada o u uno en una lnea del mismo. El car cter # se utiliza para introducir comentarios que se extien a den para la lnea actual en la que se introduce dicho car cter. Un ejemplo es el siguiente: a
# Ejemplo de archivo de configuracin para ICE. o Ice.MessageSizeMax = 2048 # Tamao mximo de 2MB. n a Ice.Trace.Network = 3 # Mximo nivel de traza de red. a Ice.Trace.Protocol = # Desactivada la traza de protocolo.

Para C++, Python, y .NET, ICE lee los contenidos del archivo de conguraci n cuando o se crea el communicator. Por defecto, el nombre del archivo de conguraci n se determina o leyendo el contenido de la variable de entorno ICE CONFIG.

5.4.

La propiedad Ice.Cong

La propiedad Ice.Cong tiene un signicado especial para ICE: determina la ruta del archivo de conguraci n a partir del cual leer los valores de las distintas propiedades. Por o a ejemplo:
$ ./server --Ice.Config=/usr/local/holaMundo/config

Para aspectos m s detallados como acceder y establecer los valores de las propiedades a desde una aplicaci n se recomienda consultar [4]. o

Captulo 6 Programaci n asncrona o


6.1. Introducci n o o e 6.1.1. Invocaci n de m todos asncrona o AMI (Asynchronous Method Invocation) 6.1.2. Tratamiento de m todos asncrono o AMD (Asynchronous Method Dispatch) e 6.1.3. Controlando la generaci n de c digo utilizando metadatos o o 6.1.4. Transparencia 6.2. AMI 6.2.1. Simulando AMI utilizando invocaciones oneway 6.2.2. Mappings 6.2.3. Ejemplo 6.2.4. Cuestiones asociadas a la concurrencia 6.2.5. Timeouts 6.3. AMD 6.3.1. Mappings 6.3.2. Ejemplo

6.1.

Introducci n o

La mayora de las tecnologas middleware m s modernas tratan de facilitar la transici n a o de los programadores al desarrollo de aplicaciones distribuidas. Para ello, lo que hacen es acercar el modelo de programaci n tradicional a los entornos distribuidos, de forma que las o llamadas a procedimientos remotos sean pr cticamente id nticas a las llamadas locales. Sin a e

50

6.1. Introducci n o

51

embargo, la implementaci n de un objeto en una aplicaci n distribuida puede estar impleo o mentado en otra m quina distinta a la que invoca una operaci n suya, por lo que existen a o ciertas diferencias sem nticas que el programador ha de tener en cuenta, como por ejemplo a la sobrecarga derivada de la invocaci n a operaciones remotas o los errores derivados de la o propia red. A pesar de estas cuestiones, la experiencia del programador con la programaci n o orientada a objetos es a n relevante, y este modelo de programaci n sncrona, en el que el u o hilo que invoca una operaci n se queda bloqueado hasta que esta naliza, es familiar y f cil o a de entender. ICE es inherentemente un plataforma middleware asncrona que simula el comportamien to sncrono para el benecio de las aplicaciones (y de sus programadores). Cuando una apli caci n ICE ejecuta una operaci n sncrona en un proxy vinculado a un objeto remoto, los o o par metros de entrada de la operaci n se codican junto con el mensaje a transportar, y el a o hilo de ejecuci n que lleva a cabo esa invocaci n se bloquea con el objetivo de simular la llao o mada sncrona. Mientras tanto, ICE opera en un segundo plano procesando los mensajes hasta que se recibe la respuesta y el hilo que ejecut la llamada queda bloqueado para decodicar o los resultados. Existen muchas situaciones en las que la naturaleza bloqueante de la programaci n sncroo na resulta muy restrictiva. Por ejemplo, la aplicaci n puede disponer de trabajo util para ejecuo tar mientras est a la espera de una invocaci n remota. De esta forma, utilizar una invocaci n a o o sncrona fuerza a la aplicaci n a posponer ese trabajo hasta que se reciba la respuesta asociada o o a desarrollarlo en otro hilo de ejecuci n distinto. Cuando ninguna de estas alternativas reo sulta aceptable, la facilidades asncronas proporcionadas por ICE suponen una soluci n ecaz o para mejorar el rendimiento y la escalabilidad, o para simplicar ciertas tareas complejas.

6.1.1.

Invocaci n de m todos asncrona o AMI (Asynchronous Method o e Invocation)

AMI es el t rmino empleado para describir el soporte del lado del cliente en el modelo e de programaci n asncrono. Utilizando AMI, una invocaci n remota no bloquea el hilo de o o ejecuci n asociado mientras se espera la respuesta asociada a dicha invocaci n. En su lugar, o o

6.1. Introducci n o

52

dicho hilo puede continuar sus actividades y ICE notica a la aplicaci n cuando la respuesta o llega. Esta noticaci n se efect a a trav s de una retrollamada de un objeto proporcionado o u e por la aplicaci n desarrollada. o

6.1.2.

Tratamiento de m todos asncrono o AMD (Asynchronous Mete hod Dispatch)

El n mero de solicitudes sncronas simult neas que un servidor es capaz de soportar queda u a determinado por el modelo de concurrencia del servidor. Si todos los hilos est n ocupados a atendiendo a operaciones que requieren mucho tiempo, entonces no existen hilos disponibles con los que procesar nuevas peticiones y, por lo tanto, es posible que los clientes experimenten una inaceptable p rdida de respuesta. e AMD, el equivalente en el lado del servidor de AMI, trata este problema de escalabilidad. Utilizando AMD, un servidor es capaz de recibir una solicitud y entonces suspender su procesamiento para liberar el hilo asociado tan pronto como sea posible. Cuando dicho procesamiento se reanuda y los resultados est n disponibles, el servidor enva una respuesta a explcita utilizando un objeto de retrollamada proporcionado por el n cleo de ejecuci n de u o ICE. En t rminos pr cticos, una operaci n AMD tpicamente encola los datos de la solicitud e a o (como por ejemplo el objeto de retrollamada y los argumentos de la operaci n) para proceo sarlos posteriormente por un hilo de la aplicaci n (o un conjunto de hilos). De esta forma, el o servidor minimiza el n mero de hilos asociados al tratamiento de operaciones y es capaz de u soportar miles de clientes de manera simult nea y eciente. a Un caso de uso alternativo para AMD es una operaci n que requiere una mayor cantidad o de procesamiento despu s de completar una solicitud del cliente. Con el objetivo de minimie zar el tiempo de espera del cliente, la operaci n devuelve los resultados mientras en el hilo o asociado al tratamiento de dicha solicitud espera, y entonces contin a utilizando dicho hilo u para el trabajo adicional.

6.1. Introducci n o

53

6.1.3.

Controlando la generaci n de c digo utilizando metadatos o o

Para indicar el uso de un modelo de programaci n asncrono (AMI, AMD, o ambos) se o utilizan metadatos en las deniciones Slice. El programador puede especicar estos metadatos a dos niveles: a nivel de interfaz o de clase, o a nivel de operaci n individual. Si se o especica para una interfaz o una clase, entonces el soporte asncrono se genera para todas sus operaciones. De forma alternativa, si el soporte asncrono se necesitas lo para ciertas ope o raciones, entonces el c digo generado puede minimizarse especicando los metadatos s lo o o para los operaciones que as lo requieran. Los m todos de invocaci n sncronos se generan siempre en un proxy, de forma que ese o pecicando los metadatos AMI simplemente se a aden los m todos de invocaci n asncron e o nos. Por otra parte, especicar los metadatos AMD implica que los m todos de tratamiento e sncrono sean reemplazados por sus hom logos asncronos. o Un ejemplo en Slice es el siguiente:
[ami] interface I { bool esValido(); float calcularMedia(); }; interface J { [amd] void comenzarProceso(); [ami, amd] int finalizarProceso(); };

En este ejemplo, todos los m todos asociados a la interfaz I se generan con soporte para e invocaciones sncronas y asncronas. En la interfaz J, la operaci n comenzarProceso utiliza o un tratamiento asncrono, mientras que la operaci n nalizarProceso soporta una invocaci n o o y un tratamiento asncronos. Especicar metadatos a nivel de operaci n, en lugar de a nivel de interfaz o de clase, o no s lo minimiza la cantidad de c digo generado, sino lo que es m s importante, tambi n o o a e minimiza la complejidad. Aunque el modelo asncrono es m s exible, tambi n resulta m s a e a complejo de utilizar. Por lo tanto, es decisi n del desarrollador limitar el uso del modelo o asncrono para aquellas operaciones en las que proporcione determinadas ventajas, utilizando el modelo sncrono para el resto, el cual resulta m s sencillo. a

6.2. AMI

54

6.1.4.

Transparencia

El uso del modelo asncrono no afecta a lo que se enva por el medio. De hecho, el modelo de invocaci n utilizado por el cliente es transparente al servidor, mientras que el modelo de o tratamiento utilizado por el servidor es transparente para el cliente. Por lo tanto, un servidor es incapaz de distinguir si el modelo de invocaci n del cliente es sncrono o asncrono, mientras o que el cliente es incapaz de distinguir un tratamiento sncrono o asncrono del servidor.

6.2.

AMI

En esta secci n se describe la implementaci n de ICE para AMI y c mo utilizarla. El o o o primer paso ser discutir una forma parcial de c mo implementar AMI utilizando invocacioa o nes en un unico sentido. Este estudio tiene como objetivo mostrar los benecios de AMI. Posteriormente se comentar el mapping a Python y algunos ejemplos relacionados. a

6.2.1.

Simulando AMI utilizando invocaciones oneway

Como se coment anteriormente, las invocaciones sncronas no resultan apropiadas para o cierto tipo de aplicaciones. Un ejemplo son las interfaces gr cas de usuario, en las que no a resulta aceptable que un usuario quede a la espera de la nalizaci n de una tarea tras haber o provocado un evento en la interfaz. Dicha aplicaci n podra evitarse utilizando invocaciones en un unico sentido, las cuales o por denici n no pueden devolver un valor de retorno ni manejar par metros de salida. Deo a bido a que el n cleo de ejecuci n de ICE no espera respuesta alguna, la invocaci n bloquea u o o el hilo de ejecuci n asociado mientras se lleva a cabo la codicaci n de los par metros y o o a la copia del mensaje al buffer de transporte local. Sin embargo, el uso de invocaciones en un unico sentido puede requerir cambios inaceptables en la denici n de las interfaces. Por o ejemplo, una invocaci n en dos sentidos que devuelva valores de retorno o lance excepciones o debe convertirse en dos operaciones al menos: una para el cliente de forma que al invocarla utilice una sem ntica oneway y que contenga s lo los par metros de entrada, y otra (o m s) a o a a para que el servidor notique al cliente los resultados pertinentes.

6.2. AMI Para ilustrar estos cambios se presenta el siguiente ejemplo:


interface I { int op (string s, out long l); };

55

Como se puede apreciar, la operaci n op no es adecuada para invocaciones en un unico o sentido, ya que tiene un par metro de salida y especica un valor de retorno no nulo. Para a amoldar la anterior denici n a una invocaci n oneway de la operaci n op se podran efectuar o o o los siguientes cambios:
interface IRetroLlamada { void resultados (int retorno, long l); }; interface I { void op (IRetroLlamada* rl, string s); };

Los cambios con respecto a la denici n original son los siguientes: o Se ha a adido una interfaz IRetroLlamada, la cual contiene la operaci n resultados cun o yos par metros representan a los resultados de la operaci n original. El servidor invoca a o esta operaci n para noticar al cliente que la operaci n ha terminado. o o Se ha modicado la operaci n I::op para adecuarse a la sem ntica oneway: ahora tiene o a un tipo de retorno nulo y s lo toma par metros de entrada. o a Se ha a adido un par metro a la interfaz I::op que permite al cliente proporcionar un n a proxy para su objeto de retrollamada. Como se puede apreciar, se han llevado a cabo cambios substanciales en relaci n a la deo nici n de la interfaz original para obtener la implementaci n requerida por el cliente. Ahora o o el cliente act a tambi n como servidor, debido a que ha de crear una instancia de IRetroLlau e mada y registrarla en un adaptador de objetos con el objetivo de recibir las noticaciones asociadas a la nalizaci n de operaciones. o Una repercusi n m s relevante est asociada al impacto de estos cambios sobre el servidor. o a a El hecho de que un cliente invoque a una operaci n de forma sncrona o asncrona debera o

6.2. AMI

56

ser irrelevante para el servidor, pero en este caso se ha generado una gran acoplaci n entre o el servidor y el cliente. De hecho, la situaci n podra ser incluso peor si se hubiera incluido o alguna excepci n en la operaci n inicial. o o El hecho de describir esta simulaci n AMI sirve para explicar la estrategia utilizada por o ICE internamente, la cual es bastante similar a la aqu expuesta pero con algunas diferencias: 1. No se requiere cambiar el tipo de sistema para utilizar AMI. La representaci n de los o datos en la red es id ntica y, por lo tanto, clientes y servidores sncronos y asncronos e pueden coexistir en un mismo sistema, utilizando las mismas operaciones. 2. La soluci n proporcionada por AMI acomoda el manejo de excepciones de una manera o razonable. 3. Utilizar AMI no requiere que el cliente act e tambi n de servidor. u e

6.2.2. Mappings
Una operaci n para la cual se ha especicado el metadato AMI soporta los modelos de o invocaci n sncrono y asncrono. Adem s del m todo del proxy para la invocaci n sncrona, o a e o el generador de c digo crea un m todo para la invocaci n asncrona, junto con una clase de o e o retrollamada. El c digo generado sigue un patr n similar al expuesto en la anterior secci n, o o o el cual se apreciar mucho mejor al observar el siguiente caso especco. a 6.2.2.1. Mapping a Python Para cada operaci n AMI, el mapping a Python genera un m todo adicional en el proxy o e con el mismo nombre de la operaci n especicada en la interfaz Slice m s el sujo async. o a Este m todo tiene un valor de retorno nulo. El primer par metro es una referencia al objeto e a de retrollamada, como se describe a continuaci n. El resto de par metros hace referencia a o a los par metros de entrada de la operaci n, los cuales se especican en el orden de declaraci n a o o denido. El m todo asncrono del proxy requiere que su objeto de retrollamada dena dos operae ciones:

6.2. AMI

57

def ice response(self, <par metros>): indica que la operaci n ha nalizado con exito. a o Los par metros representan el valor de retorno y los par metros de salida de la operaa a ci n. o def ice exception(self, ex): indica que se ha lanzado una excepci n de usuario o una o excepci n local. o Se puede suponer, por ejemplo, la siguiente denici n: o
interface I { [ami] int op (short s, out long l); };

Los prototipos de las operaciones requeridas para el objeto de retrollamada de la operaci n o op son los siguientes:
class ... # # Prototipos de las operaciones: # # def ice_response(self, _resultado, l) # def ice_exception(self, ex)

La operaci n del proxy para la invocaci n asncrona de la operaci n op se genera de la o o o siguiente forma:
def op_async(self, __cb, s);

6.2.3.

Ejemplo

Para demostrar el uso de AMI en ICE se dene la siguiente interfaz asociada a un sencillo motor de computaci n: o
module Demo { sequence<float> Row; sequence<Row> Grid; exception ErrorDeRango {}; interface Model { [ami] Grid interpolar(Grid datos, float factor) throws ErrorDeRango; }; };

6.2. AMI

58

Dado un elemento de dos dimensiones de valores en punto otante y un factor, la operaci n interpolar devuelve un nuevo elemento del mismo tama o con los valores interpolados o n de una determinada manera. La implementaci n asociada a la parte del cliente para la invoo caci n asncrona en Python podra estar basada en el siguiente c digo: o o
class AMI_Model_interpolarI(object): def ice_response(self, resultado): print Datos recibidos # ... post-procesado ... def ice_exception(self, ex): try: raise ex except Demo.ErrorDeRango, e: print Interpolacin fallida: Error de rango. o except Ice.LocalException, e: print Interpolacin fallida: + str(e) o

La implementaci n de la operaci n ice response informa de un resultado correcto, mieno o tras que la operaci n ice exception muestra el diagn stico asociado a la excepci n lanzada. o o o El c digo para invocar a la operaci n interpolar es muy sencillo: o o
modelo = ... cb = AMI_Model_interpolarI() grid = ... inicializarGrid(grid) modelo.interpolar_async(cb, grid, 0.5)

6.2.4.

Cuestiones asociadas a la concurrencia

El conjunto de hilos del cliente es el encargado de habilitar en ICE el soporte para las invocaciones asncronas. Esos hilos tienen como principal responsabilidad procesar los mensajes de respuesta. Es importante tener en cuenta ciertos factores: Un objeto de retrollamada no debe utilizarse para varias invocaciones simult neas. a Las llamadas a los objetos de retrollamada se efect an a trav s de los hilos de la parte u e del n cleo de ejecuci n de ICE asociada al cliente. Por lo tanto, la sincronizaci n puede u o o ser necesaria en el caso de que la aplicaci n interact e con el objeto de retrollamada al o u mismo tiempo que llega la respuesta.

6.3. AMD

59

El n mero de hijos en el cliente determina el m ximo n mero posible de retrollamadas u a u simult neas para las invocaciones asncronas. a

6.2.5.

Timeouts

Soportar el uso de timeouts para invocaciones asncronas presenta un reto especial para ICE. El problema surge debido a que tras una invocaci n asncrona, ICE devuelve el control o al hilo que efectu la llamada tan pronto como sea posible. o Consecuentemente, el n cleo de ejecuci n de ICE ha de utilizar otro mecanismo: un hilo u o dedicado que, entre otras tareas, revisa peri dicamente las invocaciones asncronas pendieno tes. De esta forma, si una invocaci n mantiene un timeout que ha espirado, dicho hilo termina o la invocaci n informando con una excepci n del tipo Ice::TimeoutException a la operaci n o o o ice exception del objeto de retrollamada asociado a la invocaci n asncrona. o Para todo este proceso se puede utilizar la propiedad de conguraci n Ice.MonitorConnections, o cuyo valor se especica en segundos, que determina la frecuencia con la que el hilo dedicado lleva a cabo dichas revisiones.

6.3.

AMD

Como se discuti en la secci n anterior, los mappings para AMI permiten que las aplicao o ciones puedan utilizar tanto el modelo de invocaci n sncrono como el modelo de invocaci n o o asncrono. Sin embargo, y en el caso de una operaci n AMD, la implementaci n asociada o o a este modelo de tratamiento asncrono en el servidor no permite utilizar los dos modelos. De hecho, especicar el metadato AMD en una operaci n implica que dicha operaci n, la o o cual mantena un modelo de tratamiento sncrono, pase a utilizar un modelo de tratamiento asncrono. La operaci n de tratamiento asncrono tiene un prototipo similar al utilizado en AMI: el o tipo de retorno es nulo, y los argumentos consisten en un objeto de retrollamada y en los par metros de entrada de la operaci n. En AMI, el objeto de retrollamada lo proporciona a o la aplicaci n, mientras que en AMD dicho objeto lo proporciona el n cleo de ejecuci n de o u o

6.3. AMD

60

ICE, el cual proporciona los m todos necesarios para devolver los par metros asociados a la e a operaci n y lanzar las excepciones correspondientes en su caso. o

6.3.1. Mappings
6.3.1.1. Mapping a Python Para cada operaci n AMD, el mapping a Python genera un m todo de tratamiento con el o e mismo nombre que la operaci n y con el sujo async. Este m todo devuelve None. El primer o e par metro es la referencia al objeto de retrollamada, como se mostrar posteriormente. El a a resto de par metros hacen referencia a los par metros de entrada de la operaci n, siguiendo a a o el orden en el que se declararon. El objeto de retrollamada dene dos operaciones: def ice response(self, <par metros>): indica que la operaci n ha nalizado con exito. a o Los par metros representan el valor de retorno y los par metros de salida de la operaa a ci n. o def ice exception(self, ex): indica que se ha lanzado una excepci n de usuario o una o excepci n local. o Se puede suponer, por ejemplo, la siguiente denici n: o
interface I { [amd] int op (short s, out long l); };

Los prototipos de las operaciones requeridas para el objeto de retrollamada de la operaci n o op son los siguientes:
class ... # # Prototipos de las operaciones: # # def ice_response(self, _resultado, l) # def ice_exception(self, ex)

El m todo de tratamiento para la invocaci n asncrona de la operaci n op es el siguiente: e o o


def op_async(self, __cb, s);

6.3. AMD

61

6.3.2.

Ejemplo

Para demostrar el uso de AMD en ICE se contin a con el ejemplo comentado anterioru mente, pero primero es necesario a adir a la operaci n el metadato AMD: n o
module Demo { sequence<float> Row; sequence<Row> Grid; exception ErrorDeRango {}; interface Model { [ami, amd] Grid interpolar(Grid datos, float factor) throws ErrorDeRango; }; };

La implementaci n asociada en Python tendra una clase sirviente que derivara de Deo mo.Model y que proporcionara una denici n para el m todo interpolar async que creara un o e Trabajo para gestionar el objeto de retrollamada y los argumentos, y a adira dicho Trabajo n a una cola. El m todo utiliza un candado para gestionar el acceso concurrente a la cola: e
class ModelI(Demo.Model): def __init__(self): self._mutex = threading.Lock() self._jobs = [] def interpolate_async(self, cb, data, factor, current=None): self._mutex.acquire() try: self._jobs.append(Job(cb, data, factor)) finally: self._mutex.release()

Una vez que se ha almacenado la informaci n en una cola, la operaci n devuelve el control o o al n cleo de ejecuci n de ICE, de forma que el hilo de tratamiento asociado quede disponible u o para procesar otra solicitud. Un hilo de la aplicaci n elimina el siguiente Trabajo de la cola o e invoca a la operaci n ejecutar, la cual utiliza a interpolarGrid para llevar a cabo el trabajo o computacional asociado:
class Trabajo(object): def __init__(self, cb, grid, factor): self._cb = cb self._grid = grid self._factor = factor

6.3. AMD

62

def execute(self): if not self.interpolateGrid(): self._cb.ice_exception(Demo.ErrorDeRango()) return self._cb.ice_response(self.grid) def interpolarGrid(self): # ...

Si interpolarGrid devuelve falso, entonces se invoca a la operaci n ice exception pao ra indicar que ha ocurrido un error de rango. La sentencia return que sigue a la llamada ice exception es necesaria porque esta llamada no arroja una excepci n, sino que simplemeno te codica el argumento de la excepci n y se lo enva la cliente. o Si la interpolaci n tuvo exito, se invoca a la operaci n ice response para enviar los datos o o modicados al cliente.

Captulo 7 Transferencia eciente de cheros


7.1. Introducci n o 7.2. Versi n inicial o 7.3. Usando AMI 7.4. Incrementando la eciencia con dos llamadas AMI 7.5. Uso de la caracterstica zero-copy del mapping a C++ 7.6. Utilizando AMD en el servidor 7.7. Aun m s eciente a 7.8. Conclusiones

7.1.

Introducci n o

La transferecia de cheros entre una aplicaci n cliente y una servidora puede ser tratada o de distintas formas seg n la naturaleza de la aplicaci n. Por ejemplo, si el cliente tiene que u o obtener un chero de un tama o relativamente grande parece razonable que transferir todo el n contenido del mismo en una unica llamada remota no es una alternativa viable. Adem s, dicha a transferencia puede manejarse de una forma m s eciente utilizando ciertas caractersticas a que ICE proporciona. En Slice tendramos la siguiente denici n: o
#include <Ice/BuiltinSequences.ice> module FileTransfer { interface FileStore { Ice::ByteSeq read(string name);

63

7.2. Versi n inicial o

64

void write(string name, Ice::ByteSeq bytes); }; };

Como se puede apreciar, esta interfaz transere el contenido de un chero utilizando una unica llamada a procedimiento remoto. Si la aplicaci n reside en una red local con m quinas o a con suciente memoria, estas operaciones simplemente funcionaran estableciendo la propie dad Ice.MessageSizeMax a un valor lo sucientemente grande. Sin embargo, y cuanto m s a grande es el chero a transferir, generalmente es mejor segmentar dicho chero y transferirlo utilizando varias llamadas remotas en lugar de una sola. En las sucesivas secciones se ir n presentando distintas aproximaciones para realizar a de forma eciente la transferencia de cheros, comenzando por una versi n sencilla y meo jor ndola de forma paralela a la eciencia de dicha transferencia. a

7.2.

Versi n inicial o

Como se coment en la anterior secci n, un prototipo de interfaz inicial permitira transo o ferir un chero en varios bloques de datos:
#include <Ice/BuiltinSequences.ice> module FileTransfer { exception FileAccessException { string reason; }; interface FileStore { Ice::ByteSeq read(string name, int offset, int num) throws FileAccessException; void write(string name, int offset, Ice::ByteSeq bytes); }; };

La operaci n read solicita un determinado n mero de bytes comenzando en el valor indio u cado por offset. Dicha operaci n devuelve como mucho num bytes. De este modo, el cliente o estara recibiendo el chero en bloques hasta que recibiese un bloque vaco que indicase el n de la transferencia. Esta interfaz, sin embargo, introduce un problema de eciencia debido a que una unica invocaci n remota se divide en varias invocaciones remotas, lo cual incrementa la latencia. No o

7.2. Versi n inicial o

65

obstante, si el chero es lo sucientemente grande no hay forma de evitar dichas invocaciones, especialmente si el cliente o el servidor no tienen mucha memoria. Por ejemplo, para transferir un chero de 1 GB en una unica invocaci n, el cliente necesita tener 2 GB de memoria: o 1 GB asociado al chero en cuesti n y 1 GB para que Ice cree un buffer de marshalling o internamente. En el lado del servidor ocurrira lo mismo. Teniendo en cuenta la interfaz previamente denida, el cliente operara de la siguiente forma para obtener el contenido de un chero:
// C++ Ice::ObjectPrx base = communicator()-> stringToProxy("FileStore:tcp -h host -p port"); FileStorePrx fileStorePrx = FileStorePrx::checkedCast(base); string name = argv[1]; FILE* fp = fopen(name.c_str(), "wb"); Ice::ByteSeq data; int offset = 0; int len = 1000 * 1024; for (;;) { try { data = fileStorePrx-> read(name, offset, len); } catch (FileAccessException ex) { cout << ex.reason << endl; break; } if (data.size() == 0) { break; } if (fwrite(&data[0], 1, data.size(), fp) != data.size()) { cerr << "error writing: " << strerror(errno) << endl; break; } offset += data.size(); } fclose(fp);

Como se puede apreciar, el cliente lee datos del almac n y los escribe directamente en e el chero de salida. En la parte del servidor, la operaci n read leera y transferira los bytes o especicados por dicha operaci n: o
// C++ ::Ice::ByteSeq FileStoreI::read(const ::std::string& name,

7.3. Usando AMI

66

::Ice::Int offset, ::Ice::Int num, const ::Ice::Current&) const { FILE* fp = fopen(name.c_str(), "rb"); if (fp == 0) { FileAccessException ex; ex.reason = "cannot open " + name + " for reading: " + strerror(errno); throw ex; } if (fseek(fp, offset, SEEK_SET) != 0) { fclose(fp); return Ice::ByteSeq(); } Ice::ByteSeq data(num); ssize_t r = fread(&data[0], 1, num, fp); fclose(fp); if (r!= num) data.resize(r); return data; }

7.3.

Usando AMI

La implementaci n propuesta en la anterior secci n presenta dos problemas de eciencia. o o El primero es la latencia de red. El segundo, y m s serio a n, es el tiempo empleado en a u escribir los datos asociados al chero, en el que toda la actividad de red cesa. Idealmente, se persigue explotar el paralelismo de forma que el servidor entregue el siguiente bloque de datos mientras que el cliente todava est escribiendo el bloque anterior. Para ello, se puede a utilizar AMI enviando una solicitud para el siguiente bloque antes de escribir los datos en el disco. El primer paso consiste en modicar la denici n de la interfaz en Slice: o
#include <Ice/BuiltinSequences.ice> module FileTransfer { exception FileAccessException { string reason; };

7.3. Usando AMI

67

interface FileStore { ["ami"] Ice::ByteSeq read(string name, int offset, int num) throws FileAccessException; void write(string name, int offset, Ice::ByteSeq bytes); }; };

A continuaci n, es preciso reescribir parte del bucle principal del cliente: o


// C++ ... FileStore_readIPtr cb = new FileStore_readI; fileStorePrx->read_async(cb, name, offset, len); for (;;) { cb->getData(bytes); if (bytes.empty()) { break; } offset += bytes.size(); fileStorePrx->read_async(cb, name, offset, len); if (fwrite(&bytes[0], 1, bytes.size(), fp) != bytes.size()) { cerr << "error writing: " << strerror(errno) << endl; break; } } fclose(fp);

El cliente comienza el proceso enviando de forma asncrona una solicitud de lectura uti lizando la operaci n read async y, posteriormente, entrando en el bucle de lectura-escritura. o En dicho bucle, el cliente invoca a getData en el objeto de retrollamada, bloque ndose hasta a que los datos est n disponibles. Una vez que getData retorna, el cliente emite una solicitud a para el siguiente bloque de datos de forma inmediata. De esta manera, mientras est escria biendo los datos en el disco, el hilo de la parte del cliente puede leer la siguiente respuesta. En teora, esta aproximaci n debera proporcionar m s paralelismo y mejorar la eciencia de o a la aplicaci n. o La implementaci n del objeto de retrollamada AMI es sencilla: o
// C++ class FileStore_readI : public AMI_FileStore_read, public IceUtil::Monitor<IceUtil::Mutex> {

7.3. Usando AMI

68

public: FileStore_readI() : _done(false) { } virtual void ice_response(const ::Ice::ByteSeq&); virtual void ice_exception(const ::Ice::Exception&); void getData(::Ice::ByteSeq&); private: bool _done; auto_ptr<Ice::Exception> _exception; Ice::ByteSeq _bytes; }; typedef IceUtil::Handle<FileStore_readI> FileStore_readIPtr;

La variable done se utiliza para esperar a que una invocaci n pendiente est completada, o e mientras que exception y bytes almacenan los resultados de la invocaci n. o La implementaci n de ice response sera la siguiente: o
// C++ void FileStore_readI :: ice_response(const ::Ice::ByteSeq& bytes) { Lock sync(*this); _bytes = bytes; _done = true; notify(); }

Esta operaci n se invoca cuando un hilo de la parte cliente recibe la respuesta de una o invocaci n asncrona. De esta forma, la secuencia de bytes se pasa como argumento a esta o operaci n y se almacena en la variable bytes, pudiendo noticar al monitor que la respuesta o ha llegado. La implementaci n de ice exception sera la siguiente: o
// C++ void FileStore_readI :: ice_exception(const ::Ice::Exception& ex) { Lock sync(*this); _exception.reset(ex.ice_clone()); _done = true; notify(); }

Dicha operaci n se ejecuta en el caso de que una invocaci n desemboque en una excepo o ci n. En tal caso, se almacenan los resultados en la variable exception y se notica al monitor o de que ha llegado una respuesta.

7.4. Incrementando la eciencia con dos llamadas AMI Finalmente, getData espera a que se complete una invocaci n asncrona: o
// C++ void FileStore_readI :: getData(::Ice::ByteSeq& bytes) { Lock sync(*this); while (!_done) { wait(); } _done = false; if (_exception.get()) { auto_ptr<Ice::Exception> ex = _exception; _bytes.clear(); ex->ice_throw(); } bytes.swap(_bytes); }

69

La operaci n espera una noticaci n de ice response o de ice exception, utilizando para o o ello la variable done. En caso de que no se produzca una excepci n, se intercambia el conteo nido de las variables bytes y bytes (se utiliza swap para evitar una copia extra de la secuencia de bytes).

7.4.

Incrementando la eciencia con dos llamadas AMI

De cara a seguir mejorando la eciencia en la transferencia de archivos se deben considerar tres variables: La cantidad de tiempo empleado en realizar el marshalling y enviar la petici n AMI, es o decir, el tiempo empleado por read async. El tiempo empleado para esperar la respuesta de la invocaci n asncrona, es decir, el o tiempo empleado por getData. El tiempo empleado en escribir los datos al disco, es decir, el tiempo empleado en fwrite. Tanto el tiempo empleado por la operaci n read async como el tiempo empleado en la o escritura de datos en el disco no puede reducirse. Sin embargo, s que se puede gestionar de

7.4. Incrementando la eciencia con dos llamadas AMI

70

una manera m s eciente el tiempo empleado mientras se espera que la operaci n getData a o termine. Se pueden reducir los efectos de la latencia de red mantiendo m s de una llamada a AMI activa. Si se utilizan dos, la primera puede obtener el resultado actual mientras que la segunda emite una solicitud para obtener el siguiente bloque del chero. De esta forma, el servidor est permanentemente ocupado debido a que tan pronto como enva la respuesta de a la primera invocaci n, la segunda ya est disponible para ser procesada. De manera similar se o a mejora el comportamiento del cliente. Sin embargo, hay que tener en cuenta que este enfoque es apropiado si el cuello de botella del sistema es la latencia de red, ya que si el problema estuviese en el disco este enfoque no mejorara apenas la eciencia. El bucle principal del cliente quedara de la siguiente forma:
// C++ ... FileStore_readIPtr curr, next; for (;;) { if (!curr) { curr = new FileStore_readI; next = new FileStore_readI; fileStorePrx->read_async(curr, name, offset, len); } else { swap(curr, next); } fileStorePrx->read_async(next, name, offset + len, len); curr->getData(bytes); if (bytes.empty()) { break; } if (fwrite(&bytes[0], 1, bytes.size(), fp) != bytes.size()) { cerr << "error writing: " << strerror(errno) << endl; rc = EXIT_FAILURE; } offset += bytes.size(); } fclose(fp);

En este enfoque se tienen dos objetos de retrollamada, next y curr, que se intercambian en cada iteraci n del bucle. El resto del mismo es igual al de la anterior aproximaci n. o o

7.5. Uso de la caracterstica zero-copy del mapping a C++

71

7.5.

Uso de la caracterstica zero-copy del mapping a C++

Otra de las posibles mejoras a aplicar a este sistema de transferencia de cheros est relaa cionada con la implementaci n de la operaci n ice response: o o
// C++ void FileStore_readI :: ice_response(const ::Ice::ByteSeq& bytes) { Lock sync(*this); _bytes = bytes; _done = true; notify(); }

En el anterior c digo se puede apreciar c mo el contenido de bytes se almacena en la o o variable de clase bytes. Adem s, y como se coment en anteriores secciones, Ice copia estos a o datos a un buffer interno. Como resultado, 1 GB de datos enviados a la aplicaci n ocupan 3 o GB de memoria: 1 GB para el buffer, 1 GB para bytes, y 1 GB para bytes. Este hecho se puede gestionar de forma m s eciente si utilizamos la caracterstica zero-copy del mapping a a C++ para evitar la copia del buffer al vector. El primer paso consiste en a adir la directiva correspondiente a la operaci n de la interfaz: n o
interface FileStore { ["ami", "cpp:array"] Ice::ByteSeq read(string name, int offset, int num) throws FileAccessException; ... };

De esta forma, la operaci n ice response pasa a tener la signatura siguiente: o


// C++ void FileStore_readI:: ice_response(const ::std::pair<const ::Ice::Byte*, const ::Ice::Byte*>& bytes);

Ahora Ice pasa una pareja de const Ice::Byte* a la operaci n. El primer puntero apunta o al comienzo de la secuencia y el segundo puntero apunta al nal (misma sem ntica que las a operaciones begin y end de los iteradores STL). Dichos punteros se reeren directamente a posiciones del buffer de marshalling de Ice, de forma que se puede evitar una copia de datos cuando se almacenan en la variable bytes:

7.6. Utilizando AMD en el servidor

72

// C++ void FileStore_readI:: ice_response(const ::std::pair<const ::Ice::Byte*, const ::Ice::Byte*>& bytes) { Lock sync(*this); Ice::ByteSeq(bytes.first, bytes.second).swap(_bytes); _done = true; notify(); }

Con esta aproximaci n, el cliente requiere 2 GB de memoria para recibir un chero de 1 o GB de capacidad: 1 GB para el buffer de Ice y 1 GB para la variable de clase bytes.

7.6.

Utilizando AMD en el servidor

La operaci n read de la parte del servidor era la siguiente: o


// C++ ::Ice::ByteSeq FileStoreI::read(const ::std::string& name, ::Ice::Int offset, ::Ice::Int num, const ::Ice::Current&) const { FILE* fp = fopen(name.c_str(), "rb"); if (fp == 0) { FileAccessException ex; ex.reason = "cannot open " + name + " for reading: " + strerror(errno); throw ex; } if (fseek(fp, offset, SEEK_SET) != 0) { fclose(fp); return Ice::ByteSeq(); } Ice::ByteSeq data(num); ssize_t r = fread(&data[0], 1, num, fp); fclose(fp); if (r!= num) data.resize(r); return data; }

7.7. Aun m s eciente a

73

La implementaci n es sencilla: se abre el chero, se posiciona en la localizaci n correcta, o o se asigna el n mero correcto de bytes, se leen los datos, y se devuelve el buffer. De nuevo, se u necesita 1 GB para el buffer usado por Ice y 1 GB para los datos. Adem s, y en funci n del a o soporte del compilador empleado para NRVO (Named Return Value Optimization), el valor de retorno podra requerir una copia adicional. Utilizando AMD, Ice posibilita enviar los datos en lugar de devolver el valor de retorno. De esta forma, la implementaci n de read async o quedara de la siguiente forma:
// C++ void FileStoreI::read_async(const ::FileTransfer::AMD_FileStore_readPtr& cb, const ::std::string& name , ::Ice::Int offset, ::Ice::Int num, const ::Ice::Current&) { ... Ice::ByteSeq bytes(num); ssize_t r = fread(&bytes[0], 1, num, fp); fclose(fp); pair<const Ice::Byte*, const Ice::Byte*> ret; ret.first = &bytes[0]; ret.second = &bytes[r]; cb->ice_response(ret); }

7.7.

Aun m s eciente a

En las anteriores secciones se han presentado mejoras signicativas, pero todava existen problemas de eciencia. Para cada petici n el servidor realiza varias acciones: o Abrir y cerrar el chero. Posicionarse en la localizaci n correcta del chero. o Asignar el buffer de lectura para cada petici n. o Si se hacen ciertas suposiciones sobre c mo el cliente utiliza el interfaz, se pueden proo porcionar ciertas mejoras en la eciencia. Para llevarlas a cabo se a ade una nueva interfaz n File:

7.7. Aun m s eciente a

74

#include <Ice/BuiltinSequences.ice> module FileTransfer { exception FileAccessException { string reason; }; interface File { ["ami", "amd", "cpp:array"] Ice::ByteSeq next(); }; interface FileStore { File* read(string name, int num); throws FileAccessException; void write(string name, int offset, Ice::ByteSeq bytes); }; };

Para leer el contenido de un chero, el cliente efect a una llamada a FileStore::read y u recibe un proxy a un objeto File. Entonces, el cliente invoca repetidamente a la operaci n o next de dicho objeto hasta que recibe una secuencia vaca, la cual indica el nal del archivo. El servidor destruye autom ticamente el objeto File cuando el cliente obtiene EOF. Con esta a inferfaz, los distintos bloques de datos se almacenan secuencialmente por el cliente, es decir, el cliente no especica un determinado desplazamiento asociado al chero. A su vez, este hecho permite al objeto File mantener en cach el manejador asociado al archivo, evitando abrir e y cerrar el chero para cada bloque de datos. Adem s, la implementaci n de next no necesita a o ejecutar la operaci n fseek para establecer explcitamente el desplazamiento del chero cada o vez. La implementaci n inicial de File sera la siguiente: o
// C++ class FileI : public File { public: FileI(FILE* fp, int num) : _fp(fp), _num(num), _bytes(new Ice::Byte[num]) { } FileI() { delete[] _bytes;

7.7. Aun m s eciente a

75

virtual void next_async(const ::FileTransfer::AMD_File_nextPtr&, const ::Ice::Current private: FILE* _fp; const int _num; Ice::Byte* _bytes; }; void FileI::next_async(const ::FileTransfer::AMD_File_nextPtr& cb, const ::Ice::Current& current) { pair <const Ice::Byte*, const Ice::Byte*> ret(0, 0); ssize_t r = fread(_bytes, 1, _num, _fp); if (r == 0) { fclose(_fp); current.adapter->remove(current.id); } else { ret.first = _bytes; ret.second = _bytes + r; } cb->ice_response(ret); }

El servidor no soporta llamadas concurrentes desde el mismo cliente como una decisi n o de implementaci n. De hecho, no existe benecio para un unico cliente en invocar al servidor o de forma concurrente, y a adir protecci n para la concurrencia implicara un descenso de la n o eciencia (esto es distinto de que distintos clientes utilicen el servidor concurrentemente). Para forzar esta restricci n se puede congurar al servidor para que utilice el modelo de o concurrencia thread-per-connection (hilo por conexi n): o
# config.server Ice.ThreadPerConnection=1

La parte del cliente necesita adaptarse a esta nueva interfaz:


... try { int num = 1000 * 1024; FilePrx file = fileStorePrx->read(name, num); int offset = 0; File_nextIPtr curr, next;

7.8. Conclusiones

76

Ice::ByteSeq bytes; for (;;) { if (!curr) { curr = new File_nextI; next = new File_nextI; file->next_async(curr); } else { swap(curr, next); } file->next_async(next); curr->getData(bytes); if (bytes.empty()) { break; } if (fwrite(&bytes[0], 1, bytes.size(), fp) != bytes.size()) { cerr << "error writing: " << strerror(errno) << endl; rc = EXIT_FAILURE; } offset += bytes.size(); } } catch (const FileAccessException& e) { cerr << "FileAccessException: " << e.reason << endl; rc = EXIT_FAILURE; } ...

7.8.

Conclusiones

En este captulo se ha presentado un enfoque dirigido a mejorar la eciencia en la transfe rencia de archivos. Es muy importante dise ar las aplicaciones teniendo en cuenta las capacin dades de una m quina para manejar distintos hilos de ejecuci n. Por fortuna, Ice proporciona a o mecanismos para aprovechar estas posibilidades, mejorando la eciencia en la transferencia de cheros.

Parte IV Servicios en ICE

77

Captulo 8 IceGrid
8.1. Introducci n o 8.2. Ejemplo de aplicaci n o

8.1.

o Introducci n

IceGrid es el servicio de activaci n y localizaci n de aplicaciones ICE. Dada la creciente o o importancia de la computaci n grid, IceGrid se introdujo en la versi n 3.0 de ICE para soporo o tar todas las responsabilidades asociadas a la activaci n y localizaci n de aplicaciones con el o o objetivo de desarrollar y administrar las mismas en entornos grid. Una posible conguraci n grid sera una colecci n homog nea de computadores que ejeo o e cutaran programas parecidos. Cada computador en el grid sera un clon del resto, y todos seran capaces de llevar a cabo una tarea. Por lo tanto, el propio desarrollador tendra que escribir c digo que se ejecutara en las distintas m quinas, y ICE proporcionara la infraeso a tructura necesaria que permitira que los distintos componentes del grid se comunicaran entre s. Sin embargo, escribir dicho c digo es s lo una parte del problema. Algunas otras son las o o siguientes: C mo instalar y actualizar una aplicaci n en todos los componentes de un grid? o o C mo mantener los servidores en ejecuci n? o o

78

8.1. Introducci n o C mo distribuir la carga entre los servidores? o C mo migrar un servidor de una m quina a otra? o a C mo a adir una nueva m quina al grid? o n a

79

Todos estos temas est n directamente relacionados con un grid. IceGrid proporciona soa luciones a todas estas preguntas utilizando ciertas caractersticas: Servicio de localizaci n: IceGrid permite que los clientes contacten con los servidoo res de forma indirecta, haciendo que las aplicaciones sean m s exibles en lo que a a requerimientos se reere. Activaci n de servidores bajo demanda: IceGrid puede asumir la responsabilidad de o activar un servidor bajo demanda, es decir, cuando un cliente intenta contactar con un objeto situado en dicho servidor. Esta acci n es completamente transparente para el o cliente. Distribuci n de aplicaciones: IceGrid proporciona un mecanismo para la distribuci n o o de aplicaciones en un conjunto de m quinas, sin la necesidad de utilizar un sistema de a archivos compartidos o complicados scripts. Balanceado de carga y replicaci n: IceGrid soporta la replicaci n agrupando los adapo o tadores de objetos de determinados servidores en un unico adaptador de objetos virtual. Durante la resoluci n indirecta, el cliente puede ser asociado a cualquiera de estos o adaptadores. Adem s, IceGrid monitoriza la carga de cada m quina y puede utilizar a a esa informaci n para decidir qu endpoint devolver al cliente. o e Asignaci n de recursos y sesiones: un cliente IceGrid establece una sesi n con el obo o jetivo de asignar un recurso, como un objeto o un servidor. IceGrid evita que otros clientes utilicen ese recurso hasta que el cliente inicial lo libere o expire la sesi n. Las o sesiones pueden ser seguras utilizando el servicio Glacier2. Tolerancia a fallos autom tica: ICE soporta los reintentos autom ticos y la tolerana a cia a fallos en cualquier proxy que contenga m ltiples puntos de transporte asociados. u

8.2. Ejemplo de aplicaci n o

80

Combinado con el soporte de IceGrid para la replicaci n y el balanceado de carga, eso ta caracterstica permite que una solicitud fallida se reenve de forma transparente al cliente en el siguiente punto de transporte. Preguntas din micas: las aplicaciones pueden interactuar directamente con IceGrid para a localizar objetos de numerosas formas. Monitorizaci n del estado: IceGrid soporta que las interfaces Slice permitan monitorio zar sus actividades y recibir noticaciones sobre eventos signicativos, habilitando el desarrollo de herramientas para la integraci n de los eventos de estado de IceGrid en o alg n framework existente. u Administraci n: IceGrid incluye herramientas de administraci n tanto desde la lnea de o o ordenes como gr cas. a Despliegue: utilizando cheros XML, el desarrollador puede describir los servidores a desplegar en cada m quina. Tambi n permite el uso de plantillas para simplicar la a e descripci n de servidores id nticos. o e

8.2.

Ejemplo de aplicaci n o

En esta secci n se presenta una aplicaci n sencilla que demuestra las principales capacio o dades de IceGrid. La aplicaci n consiste en un codicador de pistas de m sica en archivos con o u formato mp3. Este proceso suele ser largo y consumir bastantes ciclos de CPU, por la aplicaci n distribuida aqu presentada acelerar el proceso haciendo uso de los distintos servidores o a utilizados por la misma, de forma que se puedan procesar varias canciones en paralelo. La denici n en Slice de la interfaz es muy sencilla: o
module Ripper { exception EncodingFailException { string reason; }; sequence<byte> ByteSeq; sequence<short> Samples;

8.2. Ejemplo de aplicaci n o

81

interface Mp3Encoder { // Input: PCM samples for left and right channels. // Output: MP3 frame(s). ByteSeq encode (Samples leftSamples, Samples rightSamples) throws EncodingFailException; // You must flush to get the last frame(s). // Flush also destroys the encoder object. ByteSeq flush() throws EncodingFailException; }; interface Mp3EncoderFactory { Mp3Encoder* createEncoder(); }; };

La implementaci n del algoritmo de codicaci n no es relevante para el prop sito de o o o este manual, por lo que el objetivo perseguido ser mostrar las capacidades de IceGrid que a permiten desarrollar una aplicaci n eciente. o La arquitectura inicial de la aplicaci n se puede observar en la gura 8.1. Como se puede o apreciar, esta consiste en un sencillo nodo IceGrid responsable del servidor de codicaci n y o que se ejecuta en la m quina ComputeServer. Adem s, tambi n se puede comprobar c mo el a a e o cliente invoca a la operaci n createEncoder y las acciones que IceGrid lleva a cabo. o Por lo tanto, el c digo del cliente es muy sencillo: o
class Client (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() obj = self.communicator().stringToProxy(EncoderFactory) ripper = Ripper.Mp3EncoderFactoryPrx.checkedCast(obj) encoder = ripper.createEncoder() encoder.encode(None, None) self.communicator().waitForShutdown() return 0 Client().main(sys.argv, client.cfg)

El cliente utiliza un proxy indirecto para el objeto EncoderFactory, en concreto un proxy bien-conocido. Este tipo de proxies se reeren a objetos bien-conocidos, es decir, cuya identidad es suciente para permitir que un cliente los localice. El descriptor asociado a la aplicaci n es el siguiente: o
<icegrid>

8.2. Ejemplo de aplicaci n o

82

Figura 8.1: Arquitectura b sica de la aplicaci n a o

<application name="Ripper"> <replica-group id="EncoderAdapters"> <load-balancing type="adaptive"/> <object identity="EncoderFactory" type="::Ripper::MP3EncoderFactory"/> </replica-group> <server-template id="EncoderServerTemplate"> <parameter name="index"/> <parameter name="exepath" default="./Server.py"/> <server id="EncoderServer${index}" exe="${exepath}" activation="on-demand"> <adapter name="EncoderAdapter" replica-group="EncoderAdapters" register-process="true" endpoints="tcp"/> </server> </server-template> <node name="Node1"> <server-instance template="EncoderServerTemplate" index="1"/> </node> <node name="Node2"> <server-instance template="EncoderServerTemplate" index="2"/> </node>

8.2. Ejemplo de aplicaci n o

83

</application> </icegrid>

Este descriptor permite la descripci n de la aplicaci n estudiada. Dicho descriptor est bao o a sado en el uso de una plantilla, de forma que se denir una instancia de esa plantilla para a cada uno de los nodos de nuestra aplicaci n. En este caso existen dos nodos, los cuales se o diferencian por el par metro index. Mediante esta descripci n, tenemos dos objetos del tipo a o EncoderFactory que se tratan como un unico objeto virtual gracias a la replicaci n que se hao ce explcita mediante los grupos de r plica. En la plantilla tambi n se especica el sirviente e e asociado a cada uno de los objetos y el tipo de activaci n, que en este caso es bajo demanda. o As mismo, tambi n se hace uso de otro concepto de IceGrid: el balanceado de carga. IceGrid e permite distintos tipos de balanceado de carga, pero el elegido para esta aplicaci n ha sido o adaptativo, es decir, IceGrid utilizar la informaci n del sistema para elegir el adaptador de a o objetos menos cargado cuando se efect a una solicitud. u Como se coment anteriormente, la arquitectura de IceGrid consiste en un registro y un o n mero determinado de nodos. En este caso, la aplicaci n contiene dos nodos. Es com n u o u hacer que el registro corra en el mismo proceso que uno de los nodos. Para ello se expone la conguraci n asociada al registro y al node Node1: o
#Registry properties IceGrid.Registry.Client.Endpoints=default -p 10000 IceGrid.Registry.Server.Endpoints=default IceGrid.Registry.Admin.Endpoints=default IceGrid.Registry.Internal.Endpoints=default IceGrid.Registry.Data=registry #Node properties IceGrid.Node.Name=Node1 IceGrid.Node.Endpoints=default IceGrid.Node.Data=node IceGrid.Node.CollocateRegistry=1 IceGrid.Node.Trace.Activator=3 Ice.Default.Locator=IceGrid/Locator:tcp -h 127.0.0.1 -p 10000

Para la conguraci n del nodo Node2 tenemos que denir otro nombre y otro directorio o de datos en el caso de que corra en la misma m quina que el primer nodo: a
#Node properties IceGrid.Node.Endpoints=default

8.2. Ejemplo de aplicaci n o

84

IceGrid.Node.Name=Node2 IceGrid.Node.Data=node2 IceGrid.Node.Trace.Activator=3 Ice.Default.Locator=IceGrid/Locator:tcp -h <mquina_registro> -p 10000 a

Como se puede apreciar, con la propiedad Ice.Default.Locator se especica la direcci n o en la que se est ejecutando el registro. Adem s, esta misma propiedad habr que especicarla a a a en el archivo de conguraci n del cliente: o
Ice.Default.Locator=IceGrid/Locator:tcp -h <mquina_registro> -p 10000 a

Por ultimo, queda por especicar el c digo del servidor: o


class Mp3EncoderI (Ripper.Mp3Encoder): def encode (self, leftSamples, rightSamples, current): print Encoding... return None def flush (self, current): print Flushing... return None class Mp3EncoderFactoryI (Ripper.Mp3EncoderFactory): def createEncoder (self, current): prx = current.adapter.addWithUUID(Mp3EncoderI()) adapterId = current.adapter.getCommunicator().getProperties(). getProperty(current.adapter.getName() + ".AdapterId") return Ripper.Mp3EncoderPrx.uncheckedCast(prx.ice_adapterId(adapterId)) class Server (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() adapter = self.communicator().createObjectAdapter(EncoderAdapter) adapter.add(Mp3EncoderFactoryI(), Ice.stringToIdentity(EncoderFactory)) adapter.activate() self.communicator().waitForShutdown() return 0 Server().main(sys.argv)

Para ejecutar la aplicaci n es necesario seguir los siguientes pasos: o 1. Arrancar el registro. 2. Arrancar los nodos. 3. Desplegar la aplicaci n. o

8.2. Ejemplo de aplicaci n o 4. Ejecutar el cliente. En Unix se pueden ejecutar las siguientes operaciones: 1. icegridnode Ice.Cong=<registro nodo1.cfg> 2. icegridnode Ice.Cong=<nodo2.cfg> 3. icegridadmin Ice.Cong=<icegridadmin.cfg> -e application add Ripper.xml 4. ./Client.py

85

Captulo 9 Freeze
9.1. Introducci n o 9.2. Freeze map 9.2.1. Ejemplo de aplicaci n o 9.3. Freeze evictor 9.3.1. Ejemplo de aplicaci n o

9.1.

Introducci n o

Freeze representa el conjunto de servicios persistentes de ICE: Freeze evictor es una implementaci n altamente escalable de un servicio de localizao ci n de ICE que proporciona persistencia autom tica y desalojo de objetos ICE con un o a c digo de aplicaci n mnimo. o o Freeze map es un contenedor asociativo gen rico. Las aplicaciones interact an con e u Freeze map como cualquier otro contenedor asociativo, excepto que las claves y los valores de Freeze map son persistentes. Como se podr comprobar posteriormente, integrar Freeze map o Freeze evictor en una a aplicaci n ICE es muy sencillo: una vez denidos los datos persistentes en Slice, Freeze o se encarga de los detalles concretos de persistencia. Freeze est implementado utilizando a Berkeley DB, una base de datos compacta de alto rendimiento. 86

9.2. Freeze map

87

9.2.

Freeze map

Un Freeze map es un contenedor asociativo y persistente en el que tanto la clave como el valor pueden ser tipos primitivos o tipos denidos por el usuario en Slice. Para cada pareja clave-valor, el desarrollador utiliza una herramienta de generaci n de c digo para obtener una o o clase especca del lenguaje que se ajusta a las convenciones especcas de ese lenguaje. Por ejemplo, en C++ la clase generada est vinculada a std:map, y en Java implementa la interfaz a java.util.SortedMap. La mayorad de la l gica asociada al almacenamiento y recuperaci n o o del estado a y desde una base de datos, respectivamente, est implementada en una clase base a Freeze. Las clases generadas derivan de esta clase, por lo que contienen poco c digo y, por lo o tanto, son ecientes en cuanto al tama o del mismo. n

9.2.1.

Ejemplo de aplicaci n o

A continuaci n se presenta un sencillo ejemplo de uso de Freeze map en C++, en el que o primero se genera un contenedor y, posteriormente, se realizan operaciones b sicas sobre el: a
#include <Freeze/Freeze.h> #include <StringIntMap.h> int main(int argc, char *argv[]) { Ice::CommunicatorPtr communicator = Ice::initialize(argc, argv); Freeze::ConnectionPtr connection = Freeze::createConnection(communicator, "db"); StringIntMap map(connection, "simple"); map.clear(); Ice::Int i; StringIntMap::iterator p; // Poblar... for (i = 0; i < 26; i++) { std::string key(1, a + i); map.insert(make_pair(key, i)); } // Iterar y cambiar valores... for (p = map.begin(); p != map.end(); ++p)

9.3. Freeze evictor

88

p.set(p->second + 1); // Encontrar y eliminar el ltimo elemento... u p = map.find("z"); assert(p != map.end()); map.erase(p); // Limpieza... connection->close(); communicator->destroy(); return 0; }

El primer paso consiste en generar el contenedor utilizando el siguiente comando:


slice2freeze --dict StringIntMap,string,int StringIntMap

El compilador slice2freeze crea las clases necesarias en C++ para el Freeze map. En este caso, se crea un contenedor denominado StringIntMap con un tipo de clave string y un valor int. El ultimo argumento hace referencia al nombre de los archivos de salida, que en este caso son StringIntMap.h y StringIntMap.cpp.

9.3.

Freeze evictor

Freeze evictor combina la persistencia y la escalabilidad en una unica facilidad, la cual se puede integrar de una manera sencilla en aplicaciones ICE. Como implementaci n de la interfaz ServantLocator, el Freeze evictor toma ventaja de o la separaci n b sica entre objeto ICE y sirviente para activar los sirvientes bajo demanda o a desde un almac n persistente y desactivarlos de nuevo utilizando las restricciones de desalojo e seleccionadas. Aunque una aplicaci n puede tener miles de objetos ICE en su base de datos, o no resulta pr ctico tener sirvientes para todos esos objetos residiendo en memoria de forma a simult nea. La aplicaci n puede conservar recursos y ganar en escalabilidad estableciendo un a o lmite m ximo para el n mero de sirvientes activos, permitiendo al Freeze evictor manejar a u los detalles asociados a la activaci n, persistencia, y desactivaci n de sirvientes. o o Freeze evictor mantiene una cola de servidores activos, utilizando un algoritmo de desalojo menos recientemente usado: si la cola est llena, el sirviente menos recientemente usado a deja su puesto a un nuevo sirviente.

9.3. Freeze evictor

89

9.3.1.

Ejemplo de aplicaci n o

En general, incorporar un Freeze evictor en una aplicaci n requiere los siguientes pasos: o 1. Evaluar si las deniciones Slice actuales son adecuados para manejar los tipos de datos persistentes. 2. Si no es as, tpicamente se denir una nueva clase derivada que reejar las restriccio a a nes asociadas al estado persistente. Es buena pr ctica denir estos datos en un archivo a distinto al vinculado a la interfaz p blica mostrada al cliente y utilizando otro m dulo u o distinto. 3. Generar el c digo (utilizando slice2freeze o slice2freezej) para las nuevas deniciones. o 4. Crear un evictor y registrarlo como un localizador de sirvientes con un adaptador de objetos. 5. Crear instancias de los tipos persistentes de la aplicaci n y registrarlos con el evictor. o El ejemplo aqu presentado es el conocido Hola mundo!, cuya especicaci n Slice es la o siguiente:
module Demo { interface Hello { void puts(string str); }; class HelloPersistent implements Hello { int useCount; }; };

En este caso, la persistencia viene reejada por la clase HelloPersistent, la cual a ade n persistencia para reejar el n mero de veces que se invoca a la operaci n puts. u o La parte de la aplicaci n encargada de crear el evictor sera la siguiente: o
#include <Freeze/Freeze.h> #include <IceUtil/IceUtil.h> #include <Hello.h> using namespace std; using namespace Demo;

9.3. Freeze evictor

90

class Server: public Ice::Application { public: virtual int run (int argc, char* argv[]) { shutdownOnInterrupt(); // Crear la fbrica de objetos ICE HelloFactory. a communicator() ->addObjectFactory(new HelloFactory(), Demo::HelloPersistent::ice_staticId()); // Crear el adaptador de objetos. Ice::ObjectAdapterPtr oa = communicator() ->createObjectAdapterWithEndpoints("HelloOA", "tcp -p 8888"); // Inicializar el evictor. Freeze::EvictorPtr e = Freeze::createEvictor(oa, "db", "hello", new HelloInitializer()); oa->addServantLocator(e, ""); // Creacin de los objetos si no estaban gestionados por el evictor. o for (int i=0; i<5; ++i) { char str[] = "hello?"; str[5]=0 + i; Ice::Identity ident = communicator()->stringToIdentity(str); if (e->hasObject(ident)) { cout << ident.name << " ya estaba en este evictor" << endl; } else { Ice::ObjectPrx obj = e->add(new HelloI(), ident); cout << communicator()->proxyToString(obj) << endl; } } oa->activate(); communicator()->waitForShutdown(); cout << "Done" << endl; return 0; } }; int main(int argc, char* argv[]) { Server* app = new Server(); app->main(argc, argv); exit(0); }

9.3. Freeze evictor

91

El sirviente ha heredar de Demo::HelloPersistent (clase generada por el compilador de Slice) y de IceUtil::AbstractMutex (por cuestiones asociadas a la sincronizaci n): o
class HelloI: public Demo::HelloPersistent, public IceUtil::AbstractMutexI<IceUtil::Mutex> { friend class HelloInitializer; public: HelloI() { useCount = 0; } virtual void puts(const string& str, const Ice::Current& current) { cout << current.id.name << " (" << useCount << "): " << str << endl; useCount += 1; } };

Tambi n es necesario denir clases asociadas a las implementaciones de la f brica de e a objetos y a la inicializaci n del sirviente: o
class HelloFactory: public Ice::ObjectFactory { public: virtual Ice::ObjectPtr create(const string& type) { return new HelloI(); } virtual void destroy() {} }; class HelloInitializer: public Freeze::ServantInitializer { public: virtual void initialize(const Ice::ObjectAdapterPtr& oa, const Ice::Identity& ident, const string& str, const Ice::ObjectPtr& obj) { HelloIPtr ptr = HelloIPtr::dynamicCast(obj); cout << ident.name << " Inicial: " << ptr->useCount << endl; } };

Captulo 10 Glacier2
10.1. Introducci n o 10.2. Ejemplos de aplicaciones 10.2.1. Ejemplo b sico a 10.2.2. Ejemplo avanzado

10.1.

Introducci n o

En las distintas aplicaciones ICE con prop sitos docentes tanto el cliente como el servio dor suelen ejecutarse en la misma m quina. Sin embargo, en entornos de red m s reales la a a situaci n es mucho m s complicada: las m quinas en las que se ejecutan los clientes y los o a a servidores suelen estar detr s de un router o cortafuegos que no s lo restringe las conexiones a o entrantes, sino que tambi n hace que dichas m quinas se sit en en un espacio de direcciones e a u privado utilizando NAT. Dentro de este marco, Glacier2 es una soluci n de cortafuegos ligera para aplicaciones o ICE, que permite a los clientes y a los servidores comunicarse a rav s de un cortafuegos de una e manera segura. El tr co cliente-servidor queda totalmente encriptado usando certicados de a clave p blica de forma bidireccional. Adem s, Glacier2 proporciona soporte para autenticau a ci n y gesti n de sesiones. El escenario virtual creado por Glacier2 se puede observar en la o o gura 10.2.

92

10.1. Introducci n o

93

ClienteA Firewall ClienteB Glacier2

ServidorA

ServidorB

Figura 10.1: Escenario creado por Glacier2

El uso de Glacier2 proporciona las siguientes ventajas: Los clientes requieren un cambio mnimo. S lo es necesario un puerto para soportar cualquier n mero de servidores. o u El n mero de conexiones a los servidores es reducido. u Los servidores no se dan cuenta de la presencia de Glacier2, ya que este act a como un u cliente m s. Adem s, IceGrid puede seguir us ndose de forma transparente. a a a Las retrollamadas de los servidores se envan sobre la conexi n establecida entre el o cliente y el servidor. Glacier2 no requiere conocimiento de la aplicaci n. o Glacier2 ofrece servicios de gesti n y autenticaci n de sesiones. o o El n cleo de ICE proporciona un router gen rico, representado por la interfaz Ice::Router, u e que permite a un tercer servicio interceptar las peticiones a un proxy congurado correcta-

10.1. Introducci n o

94

ClienteA Firewall ClienteB Glacier2

ServidorA

ServidorB

Figura 10.2: Escenario creado por Glacier2

mente y las entrega al servidor previsto. Glacier2 es una implementaci n de este servicio, o aunque sera posible llevar a cabo otras implementaciones. Glacier2 normalmente se ejecuta en una m quina de la red privada detr s de un cortafuegos, pero tambi n puede operar en una a a e m quina con acceso a redes p blicas y privadas. a u En la parte del cliente, los proxies deben congurarse para utilizar Glacier2 como router. Dicha conguraci n puede llevarse a cabo de una forma est tica para todos los proxies o a creados o especic ndola en el c digo para un proxy en concreto. Un proxy congurado paa o ra utilizar Glacier2 se denomina routed proxy. De forma resumida, Glacier2 act a como un u cliente local en nombre de un cliente remoto.

10.2. Ejemplos de aplicaciones

95

10.2.
10.2.1.

Ejemplos de aplicaciones
Ejemplo b sico a

A continuaci n, se presenta el cl sico ejemplo del Hola mundo! utilizando Glacier2 y o a IceGrid. Para utilizar Glacier2 y una conguraci n mnima es necesario desarrollar las sio guientes tareas: Escribir un archivo de conguraci n para el router. o Escribir un archivo de contrase as para el router 1 . n Decidir si utilizar el gestor de sesiones interno del router o utilizar uno propio. Arrancar el router en una m quina con acceso a redes privadas y p blicas. a u Modicar la conguraci n del cliente para utilizar el router. o Modicar el cliente para crear una sesi n hacia el router. o Para congurar el router se utiliza el siguiente archivo de conguraci n: o
Glacier2.Client.Endpoints=tcp -h localhost -p 8000 Glacier2.SessionTimeout=60

El endpoint denido por Glacier2.Client.Endpoints por el n cleo de ejecuci n de ICE en u o un cliente para interactuar directamente con el router, el cual se dene en la interfaz de red p blica porque debe ser accesible para los clientes. u La propiedad Glacier2.SessionTimeout est vinculada a la duraci n de una sesi n. Esta a o o puede terminar en caso de que un cliente lo haga de forma explcita, o puede expirar en el caso de que el n mero de segundos denidos en dicha propiedad se haya cumplido. Es u recomendable establecer siempre un valor para esta propiedad. El siguiente paso es denir un archivo de contrase as e informar al router de ello: n
Glacier2.CryptPasswords=passwords.cfg
1

En el siguiente ejemplo se propondr n m todos de autenticaci n de usuarios alternativos. a e o

10.2. Ejemplos de aplicaciones

96

El formato de este archivo se corresponde a una serie de parejas nombre-contrase a, con n cada pareja en una lnea distinta del archivo y un espacio en blanco entre ambos campos:
david QupfJsB7qmL4E

Se puede utilizar la utilidad openssl para generar las contrase as: n


openssl OpenSSL> passwd Password: Verifying - Password: QupfJsB7qmL4E

El siguiente paso consiste en arrancar el router pero, como en este ejemplo se ha utilizado IceGrid tambi n, antes es necesario indicar a Glacier2 c mo puede contactar con el servicio e o de localizaci n IceGrid. Para ello se a ade lo siguiente al archivo de conguraci n del router: o n o
Ice.Trace.Network=2 Ice.Default.Locator=IceGrid/Locator:tcp -h 127.0.0.1 -p 10000

La aplicaci n a desplegar se especica en el archivo app.xml: o


<icegrid> <application name="DemoGlacier2"> <node name="localhost"> <server id="HolaMundo" exe="./Server.py" activation="on-demand"> <adapter name="HolaMundoAdapter" id="HolaMundoAdapter" register-process="true" endpoints="tcp"> <object identity="holaMundo" type="::Demo::HolaMundo"/> </adapter> </server> </node> </application> </icegrid>

Luego ya se pueden ejecutar los siguientes comandos:


icegridnode --Ice.Config=icegrid.cfg icegridadmin --Ice.Config=icegridadmin.cfg -e application add app.xml glacier2router --Ice.Config=router.cfg

El contenido del archivo icegrid.cfg es el siguiente:

10.2. Ejemplos de aplicaciones

97

#Registry properties IceGrid.Registry.Client.Endpoints=default -p 10000 IceGrid.Registry.Server.Endpoints=default IceGrid.Registry.Admin.Endpoints=default IceGrid.Registry.Internal.Endpoints=default IceGrid.Registry.Data=registry #Node properties IceGrid.Node.Name=localhost IceGrid.Node.Endpoints=default IceGrid.Node.Data=node IceGrid.Node.CollocateRegistry=1 IceGrid.Node.Trace.Activator=3 Ice.Default.Locator=IceGrid/Locator:tcp -h 127.0.0.1 -p 10000

El contenido del archivo icegridadmin.cfg es el siguiente:


Ice.Default.Locator=IceGrid/Locator:tcp -h 127.0.0.1 -p 10000

El siguiente paso es crear el cliente y especicar su archivo de conguraci n: o


import Ice, Glacier2, sys Ice.loadSlice(HolaMundo.ice, [-I /usr/share/slice]) import Demo

class Client (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() router = Glacier2.RouterPrx.checkedCast(self.communicator().getDefaultRouter()) session = router.createSession(david, david) obj = self.communicator().stringToProxy(holaMundo) prx = Demo.HolaMundoPrx.uncheckedCast(obj) prx.saludar(david) self.communicator().waitForShutdown() return 0 Client().main(sys.argv, client.cfg)

En el c digo se puede apreciar c mo el cliente crea una sesi n hacia el router, indicando o o o el nombre del usuario y su contrase a. Como se puede apreciar, no resulta deseable exponer n la contrase a en dicho c digo, por lo que en el pr ximo ejemplo se estudiar n m todos de n o o a e autenticaci n adicionales. o El archivo de conguraci n client.cfg es el siguiente: o
Ice.Default.Router=Glacier2/router:tcp -h localhost -p 8000 Ice.ACM.Client=0 Ice.MonitorConnections=60 Ice.RetryIntervals=-1

10.2. Ejemplos de aplicaciones

98

La propiedad Ice.Default.Router permite que el cliente conozca la ubicaci n de Glacier2. o La propiedad Ice.ACM.Client gobierna el comportamiento de la gesti n de conexiones activas o (active connection management o ACM), la cual permite ahorrar recursos cerrando conexiones ociosas de forma peri dica. Esta caracterstica ha de ser desabilitada en un cliente que o utiliza un router Glacier2, ya que de otra forma ACM nalizara las sesiones de forma pre matura. Para los clientes que utilizan AMI se establece la propiedad Ice.MonitorConnections de manera que los timeouts se gestionen correctamente. Si esta propiedad no se dene, toma por defecto el valor de la propiedad Ice.ACM.Client, que en este caso tiene el valor 0. Por lo tanto, siempre que se desactiva ACM es necesario especicar un valor para Ice.ACM.Client. Finalmente, estableciendo Ice.RetryIntervals a -1 se desactivan los reintentos autom ticos, los a cuales no son utiles para los proxies congurados para usar un router Glacier2. Por ultimo, queda por denir el servidor, el cual es muy sencillo e implementa la interfaz HolaMundo denida en otras secciones:
import Ice, Glacier2, sys Ice.loadSlice(HolaMundo.ice, [-I /usr/share/slice]) import Demo class HolaMundoI (Demo.HolaMundo): def saludar (self, nombre, current): print Hola + nombre + ! class Server (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() adapter = self.communicator().createObjectAdapter(HolaMundoAdapter) adapter.add(HolaMundoI(), Ice.stringToIdentity(holaMundo)) adapter.activate() self.communicator().waitForShutdown() return 0 Server().main(sys.argv)

El archivo de conguraci n asociado es el siguiente: o


Ice.Default.Router=IceGrid/Locator:tcp -h 127.0.0.1 -p 10000

10.2. Ejemplos de aplicaciones

99

10.2.2.

Ejemplo avanzado

En esta secci n se presenta un ejemplo que permite validar la identidad de los usuarios o a trav s de la interfaz Glacier2.PermissionsVerier. Es un ejemplo sencillo porque lo que e pretende es ilustrar al lector con la funcionalidad de esta intefaz. El servidor en Python es el siguiente:
import sys, traceback, Ice, Glacier2 class PermissionsVerifierI (Glacier2.PermissionsVerifier): def checkPermissions (self, usuario, password, current): # Validacin de permisos... o return (True, ) class Server (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() adapter = self.communicator().createObjectAdapterWithEndpoints( VerifierAdapter, default -p 10000) adapter.add(PermissionsVerifierI(), Ice.stringToIdentity(verifier)) adapter.activate() self.communicator().waitForShutdown() return 0 Server().main(sys.argv)

Como se puede apreciar, hay que implementar la operaci n checkPermissions del sirviente o asociado a la interfaz PermissionsVerier. En este caso, se validara a cualquier usuario. El cliente tambi n es muy b sico: e a
import sys, traceback, Ice, Glacier2 class Client (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() obj = self.communicator().stringToProxy(verifier:default -p 10000) prx = Glacier2.PermissionsVerifierPrx.checkedCast(obj) ret, err = prx.checkPermissions(usuario, password) if ret: print Usuario validado. else: print Usuario no validado. self.communicator().waitForShutdown() return 0 Client().main(sys.argv)

10.2. Ejemplos de aplicaciones

100

Aunque en este ejemplo se ha utilizado TCP como mecanismo de transporte, este m todo e no es seguro debido a que la contrase a del usuario viaja en claro por la red. Por ello, resultara n m s apropiado utilizar SSL como mecanismo de transporte. a

Captulo 11 IceBox
11.1. Introducci n o 11.2. Ejemplo de aplicaci n o

11.1.

Introducci n o

IceBox es un framework para servicios de aplicaciones ICE f cil de usar. Este elemento se a puede entender como una implementaci n del patr n congurador de servicios en lo relativo o o a servicios ICE. Este patr n es una t cnica util para la conguraci n de servicios de forma o e o que su administraci n queda centralizada. En t rminos pr cticos, este hecho signica que o e a los servicios se desarrollan como componentes que se cargan din micamente y que pueden a congurarse a trav s de un servidor de prop sito general seg n sea necesario. e o u Existen distintas ventajas a la hora de utilizar IceBox: Los servicios cargados por un mismo servidor IceBox pueden congurarse para obtener las ventajas derivadas de las optimizaciones de asignaci n de ICE. o La composici n de una aplicaci n consistente en varios servicios se lleva a cabo a trav s o o e de la conguraci n, sin la necesidad de compilar o enlazar. o Varios servicios Java se pueden activar en una unica instancia de la m quina virtual de a Java (JVM). 101

11.2. Ejemplo de aplicaci n o

102

Los servicios implementan una interfaz del servicio IceBox, obteniendo un framework com n para los desarrolladores y utilidades de administraci n centralizadas. u o IceBox soporta la integraci n con IceGrid. o Para crear un servicio IceBox es necesario implementar una de las interfaces de IceBox. La implementaci n que se expondr en la siguiente secci n implementa la interfaz o a o IceBox::Service:
module IceBox { local interface Service { void start (string name, Ice::Communicator communicator, Ice::StringSeq args); void stop (); }; };

Como se puede apreciar, un servicio s lo necesita implementar dos operaciones, las cuales o son invocadas por el gestor del servicio. start es invocada despu s de que arranque el servicio, e y stop cuando el servidor IceBox naliza su ejecuci n. o

11.2.

Ejemplo de aplicaci n o

El ejemplo aqu presentado est basado en el cl sico Hola mundo!, y en este caso se a a presentar utilizando el lenguaje Java. La clase asociada a la denici n del servicio es muy a o sencilla:
public class HelloServiceI extends Ice.LocalObjectImpl implements IceBox.Service { public void start(String name, Ice.Communicator communicator, String[] args) { _adapter = communicator.createObjectAdapter(name); Ice.Object object = new HelloI(communicator); _adapter.add(object, Ice.Util.stringToIdentity("hello")); _adapter.activate(); }

11.2. Ejemplo de aplicaci n o

103

public void stop() { _adapter.deactivate(); } private Ice.ObjectAdapter _adapter; }

Como se puede apreciar la clase es muy sencilla, y b sicamente se resume en la implea mentaci n del m todo start, en la que se crea el adaptador de objetos con el mismo nombre o e del servicio, se activa el sirviente del tipo HelloI, y se activa el adaptador de objetos. Para congurar un servicio en un servidor IceBox se utiliza una unica propiedad con distintos prop sitos: dene el nombre del servicio, proporciona el punto de entrada a ese o servicio al gestor de servicios, y dene las propiedades y los argumentos para el servicio:
IceBox.Service.\textit{name}=\textit{punto_entrada} [argumentos]

Para la aplicaci n descrita anteriormente podramos tener la siguiente propiedad: o


IceBox.Service.Hello=HelloServiceI

Para congurar IceBox se puede utilizar el siguiente archivo de conguraci n: o


IceBox.InstanceName=DemoIceBox IceBox.ServiceManager.Endpoints=tcp -p 9998 IceBox.Service.Hello=HelloServiceI Hello.Endpoints=tcp -p 10000:udp -p 10000 Ice.Warn.Connections=1

Para arrancarlo se puede utilizar el siguiente comando:


java IceBox.Server --Ice.Config=config.icebox

Captulo 12 IceStorm
12.1. Introducci n o 12.2. Ejemplo de aplicaci n o

12.1.

o Introducci n

IceStorm es un eciente servicio de publicaci n-subscripci n para aplicaciones ICE. o o Act a de mediador entre el publicador y el subscriptor, ofreciendo varias ventajas: u Para distribuir informaci n a los subscriptores s lo es necesaria una simple llamada al o o servicio IceStorm. Los monitores interact an con el servidor IceStorm para llevar a cabo la subscripci n. u o Los cambios de la aplicaci n para incluir IceStorm son mnimos. o Una aplicaci n indica su inter s en recibir mensajes subscribi ndose a un topic. Un sero e e vidor IceStorm soporta cualquier n mero de topics, los cuales son creados din micamente u a y distinguidos por un nombre unico. Cada topic puede tener varios publicadores y subscriptores. Un topic es equivalente a una interfaz Slice: las operaciones del interfaz denen los tipos de mensajes soportados por el topic. Un publicador usa un proxy al interfaz topic para enviar sus mensajes, y un subscriptor implementa la interfaz topic (o derivada) para recibir

104

12.2. Ejemplo de aplicaci n o

105

Monitor

Monitor Colector IceStorm Monitor

Monitor

Figura 12.1: Ejemplo de aplicaci n con IceStorm o

los mensajes. Realmente dicha interfaz representa el contrato entre el publicador (cliente) y el subscriptor (servidor), excepto que IceStorm encamina cada mensaje a m ltiples receptores u de forma transparente.

12.2. Ejemplo de aplicaci n o


En esta secci n se presentar el ejemplo asociado a la aplicaci n mostrada en la gura o a o 12.1, la cual est basada en un monitor de medida de condiciones meteorol gicas. En este a o ejemplo se mostrar c mo crear, suscribirse, y publicar mensajes en un topic. a o Las deniciones en Slice de esta aplicaci n son las siguientes: o
module Demo { struct Measurement { string tower; float windSpeed; short windDirection; float temperature; };

// // // //

Tower id. Knots. Degrees. Degrees Celsius.

12.2. Ejemplo de aplicaci n o

106

interface Monitor { void report(Measurement m); }; };

Monitor representa la interfaz topic, y s lo tiene una operaci n (report). o o Para implementar un publicador, que en este caso se reere a la parte de la aplicaci n que o toma la condici n clim tica, se han de seguir una serie de sencillos pasos: o a 1. Obtener un proxy para el TopicManager. Este es el principal objeto IceStorm, utilizado tanto por los publicadores como por los subscriptores. 2. Obtener un proxy para el topic Weather, creando el topic si no existe o recuper ndolo. a 3. Obtener un proxy para el objeto publicador del topic Weather. El objetivo de este proxy es el de publicar mensajes, por lo que deber hacerse una conversi n a una interfaz a o Monitor. 4. Recoger y publicar las medidas. El publicador en Python tendra un aspecto parecido al siguiente c digo: o
import sys, traceback, time, Ice, IceStorm Ice.loadSlice(WeatherMonitor.ice, [-I /usr/share/slice]) import Demo class Publisher (Ice.Application): def run (self, argv): self.shutdownOnInterrupt() properties = self.communicator().getProperties() proxy = properties.getProperty(IceStorm.TopicManager.Proxy) obj = self.communicator().stringToProxy(proxy) topicManager = IceStorm.TopicManagerPrx.checkedCast(obj) try: topic = topicManager.retrieve(Weather) except IceStorm.NoSuchTopic: topic = topicManager.create(Weather) pub = topic.getPublisher() if (pub.ice_isDatagram()): pub = pub.ice_oneway() monitor = Demo.MonitorPrx.uncheckedCast(pub) for i in range (1, 10): m = Demo.Measurement() # Get the measurement...

12.2. Ejemplo de aplicaci n o

107

monitor.report(m) time.sleep(1) self.communicator().waitForShutdown() return 0 Publisher().main(sys.argv, publisher.cfg)

B sicamente, lo que se hace es obtener un proxy al topic manager, para despu s obtener a e un proxy al topic Weather. El siguiente paso es obtener un proxy al publicador, el cual se convierte a un proxy del tipo Monitor, es decir, a un proxy de la interfaz denida en el archivo de deniciones. Por ultimo, y a modo de ejemplo, el publicador realiza 10 publicaciones utilizando la operaci n report. o El archivo de conguraci n asociado al publicador es el siguiente: o
IceStorm.TopicManager.Proxy=DemoIceStorm/TopicManager:default -p 10000

El siguiente paso consiste en denir el suscriptor, a partir de una serie de pasos: 1. Obtener un proxy para el TopicManager. 2. Crear un adaptador de objetos que albergue al sirviente asociado a la interfaz Monitor. 3. Instanciar y activar dicho sirviente en el adaptador de objetos. 4. Suscripci n al topic Weather. o 5. Procesas los mensajes recibidos hasta el momento de su nalizaci n. o 6. Eliminar la suscripci n al topic Weather. o El c digo en Python sera parecido al siguiente: o
import sys, traceback, Ice, IceStorm Ice.loadSlice(WeatherMonitor.ice, [-I /usr/share/slice]) import Demo class MonitorI (Demo.Monitor): def report (self, measurement, current): # Process the measurement... print Obtaining a new measurement class Subscriber (Ice.Application): def run (self, argv):

12.2. Ejemplo de aplicaci n o

108

self.shutdownOnInterrupt() properties = self.communicator().getProperties() proxy = properties.getProperty(IceStorm.TopicManager.Proxy) obj = self.communicator().stringToProxy(proxy) topicManager = IceStorm.TopicManagerPrx.checkedCast(obj) adapter = self.communicator().createObjectAdapter(MonitorAdapter) monitorPrx = adapter.addWithUUID(MonitorI()) try: topic = topicManager.retrieve(Weather) topic.subscribe(None, monitorPrx) except IceStorm.NoSuchTopic: # Process error... print Topic not found! adapter.activate() self.communicator().waitForShutdown() topic.unsubscribe(monitorPrx) return 0 Subscriber().main(sys.argv, subscriber.cfg)

El archivo de conguraci n del suscriptor sera el siguiente: o


MonitorAdapter.Endpoints=tcp IceStorm.TopicManager.Proxy=DemoIceStorm/TopicManager:default -p 10000

Para probar la aplicaci n hay que tener en cuenta que IceStorm es un servicio relativameno te ligero y que se implementa como un servicio IceBox. Luego el primer paso sera arrancar IceStorm:
icebox --Ice.Config=icebox.cfg

El contenido de dicho archivo de conguraci n tendra un aspecto parecido al siguiente: o


IceBox.ServiceManager.Endpoints=tcp -p 9998 IceBox.Service.IceStorm=IceStormService,31:createIceStorm --Ice.Config=icestorm.cfg

El siguiente paso sera utilizar la herramienta administrativa icestormadmin para indicar las propiedades asociadas a la instancia de IceStorm:
icestoradmin --Ice.Config=icestorm.cfg

Donde dicho archivo de conguraci n1 tendra un aspecto parecido a: o


1

Para m s informaci n estudiar la parte de conguraci n de IceStorm en [4]. a o o

12.2. Ejemplo de aplicaci n o

109

IceStorm.TopicManager.Proxy=DemoIceStorm/TopicManager:default -p 10000 IceStorm.TopicManager.Endpoints=default -p 10000 IceStorm.InstanceName=DemoIceStorm IceStorm.Publish.Endpoints=default IceStorm.Trace.TopicManager=2 IceStorm.Trace.Topic=1 IceStorm.Trace.Subscriber=1 IceStorm.Trace.Flush=1 IceStorm.Flush.Timeout=2000 Freeze.DbEnv.IceStorm.DbHome=db

Y por ultimo, ya s lo quedara arrancar los distintos subscriptores y el publicador de o eventos.

Captulo 13 IcePatch2
13.1. Introducci n o 13.2. Ejemplo de aplicaci n o

13.1.

Introducci n o

IcePatch2 es un eciente servicio de actualizaci n de archivos, f cil de congurar y f cil o a a de usar. Incluye los siguientes componentes: El servidor IcePatch (icepatch2server). Un cliente IcePatch basado en texto (icepatch2client). Una herramienta basada en texto para comprimir archivos y calcular las sumas de comprobaci n (icepatch2calc). o Una API Slice y una biblioteca C++ para el desarrollo de clientes IcePatch2. Como ocurre con el resto de servicios de ICE, IcePatch2 puede congurarse para utilizar facilidades de ICE como Glacier2 o IceSSL. Conceptualmente, IcePatch2 es muy simple. El servidor tiene la responsabilidad asociada a un directorio de archivos (el directorio de datos), el cual contiene los directorios y archivos a distribuir entre los distintos clientes IcePatch2. El desarrollador puede utilizar icepatch2calc 110

13.2. Ejemplo de aplicaci n o

111

para comprimir estos archivos y crear un archivo que contenga una suma de comprobaci n o para cada uno de ellos. El servidor transmite estos archivos al cliente, el cual obtiene el directorio de datos y su contenido, actualizando cualquier archivo que haya cambiado desde su ultima ejecuci n. o

13.2.

Ejemplo de aplicaci n o

A adir la distribuci n de aplicaciones al ejemplo comentado en la secci n de IceGrid es n o o muy simple, ya que requiere s lo unos cambios en el descriptor de la aplicaci n: o o
<icegrid> <application name="Ripper"> <server-template id="IcePatch2"> <parameter name="instance-name" default="${application}.IcePatch2"/> <parameter name="endpoints" default="default"/> <parameter name="directory"/> <server id="${instance-name}" exe="icepatch2server" application-distrib="false" activation="on-demand"> <adapter name="IcePatch2" endpoints="${endpoints}"> <object identity="${instance-name}/server" type="::IcePatch2::FileServer"/> </adapter> <properties> <property name="IcePatch2.Admin.Endpoints" value="tcp -h 127.0.0.1"/> <property name="IcePatch2.Admin.RegisterProcess" value="1"/> <property name="IcePatch2.InstanceName" value="${instance-name}"/> <property name="IcePatch2.Directory" value="${directory}"/> </properties> </server> </server-template> <replica-group id="EncoderAdapters"> <load-balancing type="round-robin"/> <object identity="EncoderFactory" type="::Ripper::MP3EncoderFactory"/> </replica-group> <server-template id="EncoderServerTemplate">

13.2. Ejemplo de aplicaci n o

112

<parameter name="index"/> <parameter name="exepath" default="./Server.py"/> <server id="EncoderServer${index}" exe="${exepath}" activation="on-demand"> <adapter name="EncoderAdapter" replica-group="EncoderAdapters" register-process="true" endpoints="tcp"/> </server> </server-template> <distrib/> <node name="Node1"> <server-instance template="EncoderServerTemplate" index="1"/> <server-instance template="IcePatch2" directory="./distrib.simple"/> </node> <node name="Node2"> <server-instance template="EncoderServerTemplate" index="2"/> </node> </application> </icegrid>

Debido a que cada nodo IceGrid es en realidad un cliente IcePatch2, cada nodo lleva a cabo la actualizaci n como si se tratara de un cliente IcePatch2: descarga todo lo necesario si o no tiene una copia local de la distribuci n o realiza una actualizaci n incremental de aquellos o o archivos que han cambiado.

Bibliografa
[1] Benoit Foucher. Grid Computing with IceGrid. Connections, pages 27, December 2005. [2] Michi Henning. Teach Yourself IceGrid in 10 Minutes. Connections, pages 1115, November 2006. [3] Michi Henning. The Rise and Fall of Corba. 2006. [4] Henning M. and Spruiell M. Distributed Programming with Ice. Technical report, ZeroC ICE, October 2006. [5] Matthew Newhook. Advanced Use of Glacier2. Connections, pages 711, May 2005. [6] Matthew Newhook. An Introduction to IceStorm. Connections, pages 27, June 2005. [7] Matthew Newhook. Session Management with Glacier2. Connections, pages 26, April 2005. [8] Matthew Newhook. IceGrid Security. Connections, pages 217, September 2006. [9] Matthew Newhook. Session Management with IceGrid. Connections, pages 29, October 2006. [10] Mark Spruiell. Ice for Ruby. Connections, pages 211, December 2006.

113

También podría gustarte