Ir al contenido principal

Modelo de transacción fiable en sistemas intercomunicados

Los embedded systems utilizan los protocolos de comunicación para enviar y recibir información crítica, tanto entre procesadores internos, como con actores externos. Dentro del mismo sistema, algunos mensajes pueden ser más críticos que otros, requiriendo un alto nivel de fiabilidad en su transferencia al medio. Para aumentar este factor en un medio poco fiable o cuando se requiere una fiabilidad extraordinaria, puede recurrise al mecanismo de transacción, el cual disminuye la probabilidad de ocurrencia de ciertos problemas, que en determinados sistemas, como los médicos, pueden incurrir en fallas muy severas.

El presente artículo describe la aplicación del mecanismo de transacción "exactamente una vez" (EO - exactly once) [3], sobre un sistema que controla un motor, monitorea su velocidad de salida, su temperatura y su presión de aceite, y provee una interfaz al usuario. El sistema en cuestión intercambia información entre sus actores, utilizando el paradigma maestro-esclavo o cliente-servidor, y los principios de un protocolo RPC (Remote Procedure Call) [3].

La implementación propuesta se basa en el paradigma de la programación gobernada por eventos [4], el modelo computacional objeto activo, los Statecharts [2,3,4,5], los diagramas de secuencias [3] y el framework RKH [1,5].



Modelo de ejemplo

La siguiente figura muestra un sistema de dos procesadores. El cual controla un motor, monitorea su velocidad de salida, su temperatura y su presión de aceite, y provee una interfaz al usuario. Desde esta última, y por medio de una perilla y botones, el usuario puede controlar la velocidad del motor e inclusive puede visualizar en un display los parámetros de funcionamiento del mismo.


El ejemplo propuesto es meramente ilustrativo.

Mensajes y respuestas en modelo cliente-servidor

En la figura anterior, el cliente User Control se comunica con un servidor Motor Unit. Donde este último, (esclavo de la comunicación) espera órdenes del cliente (maestro) para actuar en consecuencia. En este modelo el cliente siempre inicia la comunicación, envía una solicitud de operación (solicitud de procedimiento remoto) y espera hasta que la misma se complete, una vez recibida la respuesta desde el servidor. Este mecanismo es similar a invocar un servicio localmente, por ejemplo: llamar a una función en lenguaje C, pasándole parámetros y esperando el retorno de la misma.

Para el caso en cuestión, las órdenes (también conocidas como solicitudes, comandos o mensajes) que envía el cliente, invocan servicios del servidor, por ejemplo: "enviar un SMS", "solicitar el nivel de señal", "incrementar la velocidad del motor", etc. Estos mensajes tiene argumentos y respuestas, de forma similar a una llamada a función.

Durante el proceso de definición de los mensajes y sus respuestas, es una buena práctica de diseño listarlos en una tabla, la cual resume básicamente los mensajes, las respuestas, su formato y posiblemente una breve descripción. Inclusive, dependiendo del nivel de detalle adoptado, la tabla se utiliza fundamentalmente durante la implementación. A modo ilustrativo se muestra un ejemplo, el cual detalla la información que transporta el protocolo de comunicación. Generalmente, dicha información forma parte del campo de datos (payload) de una trama de datos.





donde:
  • Command:contiene los mensajes (comandos) que envía el cliente. Generalmente, esto son tipificados como un simple enumerado. Por ejemplo, {RPC_HEARTBEAT = 0, RPC_INC, ..., RPC_SET_ALARM, RPC_NUM_MSG}
  • Byte Ix: indica el órden (índice) de los bytes que componen el payload de un mensaje particular. También indica lo mismo para las respuestas al mensaje en cuestión. Aquellos campos que se codifican en bits se los representa entre corchetes.
  • Contents: contiene los campos de información de un mensaje particular y de su respuesta.
  • Size: indica el tamaño de los campos de datos de un mensaje, como así también el de los campos de información recibidos. B: indica bytes, mientras qye b: indica bits.
  • Description: breve descripción de los mensajes, de sus campos de información y del contenido de las respuestas.
La siguiente figura muestra la codificación en bytes, en formato HEX, de los mensajes RPC_INC y RPC_SET, de acuerdo con la tabla anterior. Ver la enumeración de los campos dataID, infotype y dataunits. Es importante observar, que el ejemplo adopta el formato big-endian, representando los bytes en el orden "natural".


Transmisor y receptor de mensajes

La siguiente figura ilustra los Statecharts del transmisor y receptor de mensajes de ambos extremos de la comunicación, estos son el modelo de comportamiento de los objetos activos "pmc" (protocol manager client) y "pms" (protocol manager server). El primero de ellos es el encargado de recibir las solicitudes desde la aplicación User Control, enviarlas como mensajes al servidor (Motor Unit), recibir la respuesta de este último y enviarla de regreso a User Control. Este es el cliente y maestro durante las comunicaciones. Por su lado, pms reside en la aplicación Motor Unit, el cual actúa como servidor, recibiendo los mensajes desde User Control, procesándolos acordemente y devolviendo una respuesta a este último. Tanto pmc, como pms interactúan con el resto de la aplicación por medio eventos.



(1-2) Puede activarse/desactivarse mediante los eventos ENABLE, DISABLE respectivamente.
(3) Acepta las solicitudes (eventos) REQ_INC, REQ_DEC, REQ_SET, REQ_GET, REQ_CONTROL, REQ_SET_ALARM, que concuerdan con los mensajes especificados en la tabla anterior. Adicionalmente, estos eventos incorporan el parámetro src para indicar el objeto activo de la aplicación User Control que solicita el envío del mensaje y que por lo tanto espera la respuesta desde el servidor.
(4) Recibida la respuesta, esta se notifica al objeto activo correspondiente. Estas se reciben como eventos desde el protocolo de comunicaciones subyacente. RPY_ALARM (RPC_ALARM) indica la recepción de un evento de alarma, RPY_VALUE (RPC_VALUE) indica la respuesta a la solicitud REQ_GET (RPC_GET).
(5,7) En estado de reposo (pmc_ready_to_send), permite programar el envío periódico de un mensaje, por ejemplo, para mantener "viva" la comunicación entre cliente-servidor, para la encuesta de alarmas, eventos y cambios de estados, como watchdog, otros. Esto se realiza mediante el SET_PERIODIC( msg, target, period), en donde msg indica el mensaje a enviar, target indica el objeto activo destino de la respuesta recibida, y period indica el periodo de tiempo para el envío.
(6) Por su parte, BLOCK_PERIOD bloquea la característica descripta. En el ejemplo en cuestión, el mensaje periodico es RPC_HEARTBEAT, el cual se utiliza, como su nombre lo sugiere, como una señal de "vida". La misma permite que el servidor reporte las alarmas que hayan ocurrido desde el último "hearbeat" recibido.
(8-9) Luego de enviar un mensaje, espera una respuesta, transitando hacia el estado pmc_waiting. Dicho estado indica que el pmc se encuentra ocupado, y por lo tanto, si se reciben nuevas solicitudes, estas se almacenan, para luego ser enviadas una vez que finalice dicha espera. Esto evita rechazar las solicitudes.
(10-11) Si no recibe respuesta desde el servidor, pmc renvía el mensaje las veces que indique MAX_RETRIES.
(12) Alcanzado la cantidad MAX_RETRIES, se notifica dicha situación al objeto activo que dió origen al mensaje. pmc vuelve a su estado de reposo. En caso que esta ocurra con el mensaje periódico, se notifica al objeto activo destino mediante el evento PERMSG_TOUT, si ocurre con el resto de los mensajes se notifica al objeto activo originante mediante el evento MSG_TOUT. Mientras tanto, el envío periodico continua, para detectar el reestablecimiento del servidor, si ocurre dicha situación, la misma se notifica al objeto activo destino mediante el evento ESTABLISHED.
(13) Inicializa la máquina de estados.


 
(1)  Inicializa la máquina de estados.
(2-3) Puede activarse/desactivarse mediante los eventos ENABLE, DISABLE respectivamente.
(4) La recepción del mensaje RPC_HEARTBEAT indica que debe reportarse la alarma más antigua reportada por la aplicación. En caso que no exista ninguna, responde con RPC_OK, en concordancia con lo detallado en la tabla de mensajes.
(5) Los mensajes recibidos desde el cliente se procesan y responden inmediatamente, en concordancia con lo detallado en la tabla de mensajes.
(6) El mensaje REQ_CONTROL se envía al objeto activo registrado de la aplicación Motor Unit, para que procese la solicitud y envie el resultado una vez finalizada. Durante este proceso pms aguarda en el estado pms_wait_reply.
(7) El resultado de la solicitud REQ_CONTROL se indica por medio de los eventos ON y OFF.
(8) Si pms recibe nuevos mensajes durante la espera de la respuesta a REQ_CONTROL, estos se descartan, provocando una situación de error.
(9-10) La situación (8) puede mantenerse por un tiempo determinado. Si se alcanza este tiempo, pms vuelve a su estado de reposo.
(11) Las alarmas que ocurran durante la operación activa de pms se almacenan hasta que este reciba el evento REQ_HEARTBEAT.


Transacción fiable

En un sistema que intercambia información, ciertos mensajes pueden ser más críticos que otros y por lo tanto requieren un alto nivel de fiabilidad, en su transferencia al medio. Para aumentar este factor en un medio poco fiableo o cuando se requiere una fiabilidad extraordinaria, puede recurrise al concepto de transacción, el cual disminuye la probabilidad de ocurrencia de ciertos problemas, que en determinados sistemas, como los médicos, pueden incurrir en fallas muy severas.

Las transacciones pueden ser del tipo:
  • Tal vez o At Most Once (AMO): un mensaje se transmite una única. Si el mensaje se pierde o está corrupto, se descarta.
  • Al menos una vez o At Least Once (ALO): un mensaje se transmite repetidamente hasta que se reciba una respuesta válida como confirmación del envío, o se exceda la cantidad máxima de reintentos. En este caso, se soporta la recepción de un mismo mensaje.
  • Exactamente una vez o Exactly Once (EO): el mensaje se trata como una transacción ALO, excepto que, si se recibe un mensaje más de una vez debido a los reintentos, sólo será procesada la primera instancia del mensaje. Esta se utiliza cuando la fiabilidad de la transferencia del mensaje es relativamente baja, no obstante es importante que el mensaje se procese una única vez, por ejemplo para los mensajes del tipo "incrementar" o "toggle", es decir, si el mensaje fuera "incrementar la dosis" y no se empleará la transacción EO, ¡el paciente recibiría dos dosis en lugar de una!.

Los modelos mostrados adoptan la transacción EO, detallada más abajo. La cual debe aplicar el protocolo de comunicación subyacente. La siguiente figura muestra un diagrama de secuencia [3] que describe un escenario particular, en donde puede apreciarse el funcionamiento del protocolo de comunicaciones RPC soportando la transacción EO.



donde:
  • controller: es un objeto activo perteneciente a User Control que requiere enviar el mensaje RPC_INC.
  • pmc es el objeto activo perteneciente a User Control encargado de enviar y recibir los mensajes hacia y desde el servidor.
  • comm_stack client: es el protocolo de comunicaciones, perteneciente a User Control , establecido como cliente o master en las comunicaiones.
  • comm_stack server: es el protocolo de comunicaciones, perteneciente a Motor Unit,  establecido como servidor o slave en las comunicaiones.
  • pms: es el objeto activo encargado de recibir las solicitudes y enviar las respuestas desde el cliente y hacia el servidor.
  • speed_controller: es un objeto activo perteneciente a Motor Unit que finalmente recibe la solicitud (evento) REQ_INC.
En este escenario, la respuesta RPC_OK se pierde, y por lo tanto, el lado transmisor (comm_stack_client) no puede determinar si se perdió el mensaje original o su respuesta, en cuyo caso debe retransmitirlo luego del tiempo RETRY_TIME. El lado receptor (comm_stack_server), mientras tanto, recibió el mensaje y lo notificó al speed_controller. Luego, recibe nuevamente el mismo mensaje, el cual descarta, no obstante envía la respuesta anterior inmediata. Cada vez que recibe un mensaje, el receptor dispara el temporizador de duración TIME_TO_LIVE. Durante el cual, descarta los comandos repetidos. Sin embargo, uan vez que alcance su cuenta final, el lado receptor vuelve a su estado de reposo. Por su parte, el lado transmisor finalmente recibe la respuesta, enviando la notificación corrspondiente a controller, en este caso el evento RPY_OK. En caso que el lado transmisor no reciba respuesta alguna, es decir, se alcance la cantidad máxima de reintentos (MAX_RETRIES), se notifica dicha situación al objeto activo que dió origen al mensaje, en este caso controller.
El mecanismo empleado durante la transmisión y recepción del mensaje REQ_INC, evitó que speed_controller incremente dos veces la velocidad del motor, cuando no era lo requerido. Si el mensaje fuera "incrementar la dosis" y no se empleará la transacción EO, ¡el paciente recibiría dos dósis en lugar de una!.

Si el protocolo subyacente no posee el mecanismo de transacción EO, y la aplicación lo requiere, el mismo puede implementarse agregando un número (msgid o nseq) que se asocie al mensaje, este debe ser tal que permita identificarlo de forma unívoca durante la transacción. Este número debe generarlo y asignarlo el protocolo de comunicación subyacente del lado transmisor. La figura anterior lo denomina nseq (número de secuencia), y lo asigna con valor N. Luego, el lado receptor recibe el mensaje con nseq = N, este número lo  compara con el valor inmediato anterior, si coincide,  automáticamente descarta el mensaje; si es diferente, actualiza el valor almacenado con el valor recientemente recibido. Una vez procesado el mensaje recibido, el lado receptor envía la respuesta con el nseq almacenado, es decir, con el número recibido recientemente, en este caso nseq = N. Ahora, el lado transmisor recibe la respuesta, de la cual extrae su nseq y lo compara con el enviado recientemente, si coinciden entonces notifica la recepción, como lo indica la figura. De forma contraria, si no coincide, lo descarta, en cuyo caso, se alcanzaría el tiempo RETRY_TIME, retransmitiendo el mensaje.

Para analizar gráficamente el párrafo anterior, se incorporan las siguientes figuras, las cuales ilustran diferentes escenarios, relacionados con el número de identificación de mensaje y su rol en la transacción EO.



Protocolo en operación

La siguiente figura muestra el sistema en funcionamiento mediante un diagrama de secuencias, el cual permite analizar y divisar visualmente tanto el pasaje de mensajes entre el cliente y el servidor, como el intercambio de eventos entre objetos activos del sistema. Para lo cual, puede obviarse la participación de los actores comm_stack_client y comm_stack_server.

Es importante observar que la representación de la figura no distingue el hecho que el cliente y servidor son entidades remotas y por lo tantto el pasaje de mensajes también lo es. Por lo tanto, el modelo cliente-servidor puede aplicarse entre objetos activos del mismo sistema como entre entidades externas.

En primera instancia, la figura indica como controller envía el evento REQ_INC a pmc para incrementar la velocidad del motor, el cual envía el mensaje RPC_INC, por medio del protocolo de comunicaciones, una vez recibido pms finalmente genera y envía el evento REQ_INC speed_controller para que realiza la operación correspondiente. Lo mismo ocurre con el envío del evento REQ_SET.
Ambos procesos destacan el hecho que un evento se convierte en mensaje del protocolo para luego convertirse nuevamente en evento del otro extremo de la comunicación.

Asimismo, controller configura el envío periódico de mensaje, específicamente RPC_HEARTBEAT, cuyo período lo especifica HB_TIME. En el segundo envío, sensors reporta dos alarmas. Las cuales fueron configuradas previamente por el mensaje RPC_SET_ALARM.


Implementación

Las implementación de los Statecharts se realiza mediante el framework RKH [1,5], la cual será incluída en un artículo posterior para mantener la simpleza del presente.

Conclusiones


La transacción EO es realmente útil en aquellos sistemas que intercambian información crítica, que requiere un nivel alto de fiabilidad. Si el protocolo de comunicaciones subyacente no soporta transacción EO nativa, la misma puede implementarse fácilmente, con sólo agregar un número de indentificación al mensaje y obviamente la lógica necesaria tanto en el lado transmisor como en receptor. Por otro lado, el modelo cliente-servidor y el protocolo RPC es sumamente importante en sistemas como el descripto.

Junto con los Statecharts, los diagramas de secuencias son una de las herramientas fundamentales para el desarrollo de software, en especial el relacionado con la programación gobernada por eventos. Ya que permiten visualizar rápidamente en diferentes escenarios, el pasaje de eventos entre los diferentes actores del sistema.

Referencias


[1] RKH, “RKH Sourceforge download site,”, http://sourceforge.net/projects/rkh-reactivesys/
[2] D. Harel, "Statecharts: A Visual Formalism for Complex Systems", Sci. Comput. Programming 8 (1987), pp. 231–274.
[3] B. P. Douglass, “Real Time UML Advances in The UML for Real-Time Systems", Third Edition,  February 27, 2004.
[4] M. Samek, “Practical UML Statecharts in C/C++, Second Edition: Event-Driven Programming for Embedded Systems,” Elsevier, October 1, 2008.
[5] RKH, “Reference Manual,”, http://rkh-reactivesys.sourceforge.net/
 

Comentarios