• Publicidad

Compartir memoria entre procesos

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

Notapor Moraita » 2009-02-04 06:45 @323

¡Uff, ahora sí que estoy hecha un lío!

Antes de nada expongo la situación concreta para que podamos llegar a la mejor solución.

La base de datos donde estarían las tablas de control del Perl es fija, ya existe y no es opcional: es una BD Oracle.
  • Un requerimiento es que el proceso Perl no realice accesos a esta BD para chequear si tiene trabajo o no porque según los arquitectos de la DB, esto no es óptimo.
  • Otro requerimiento es la mayor rapidez posible, ya que estamos real time y los datos vienen de lejos y van muy lejos (un montón de sistemas conectados, el Perl es enano al lado de toda la infraestructura montada) por lo tanto el tiempo es un handicap.
Tengo dos procesos.
  • Uno trabaja continuamente, non stop, me refiero a que está siempre activo con el objetivo de mantener una conexión con el servidor. Su función, entre otras cosas, es, "en el momento de ser avisado", conectarse a una base de datos (otra distinta a la primera) y ejecutar... lo que sea...
  • El otro proceso lo que tiene que hacer es "avisar" al primero para que trabaje, es decir, no queremos que el proceso primero acceda a la base de datos (la primera mencionada) continuamente para chequear ciertas cosas, sino que solo acceda cuando sea "avisado".
Otro detalle "sin importancia" es que ese primero, no es único, sino que son 8, los 8 estarán esperando su "aviso" para ponerse a trabajar.

En fin, para implementar este aviso tenemos 4 posibilidades(que yo vea):
  1. tabla control en BD ---> descartada por arquitectos (se aceptan comentarios que pueda yo exponer a estos arquitectos para rebatir su opinión)
  2. ficheros --> como tú, explorer, a mi me encanta esta solución en la que solo comprobar que se ha creado un fichero estaríamos "avisados"
  3. memoria compartida --> la verdad es que también me gusta pero para mi es una caja negra y tengo ¡¡¡TERROR!!!! ya que ¡¡¡¡no he conseguido encontrar comentarios positivos!!!!. Si esto funcionara bien creo que cumple los requisitos y sería en mi opinión la mejor opción.
  4. HTTP server --> me conecto a 8 diferentes HTTP addresses donde los 8 procesos estarán leyendo todo el rato (un thread que va leyendo el HTTP request) . En este caso El HTTP request lo lanza otro sistema cuando quiera "avisarme" de que hay trabajo, por lo tanto el segundo proceso que yo he mencionado anteriormente ("el avisador") desaparece. Y una vez avisado otro thread dentro del mismo proceso se pondrá a trabajar. Esta es la solución que inicialmente quieren implementar y que a mi NO ME GUSTA y que intento sustituir a toda costa y por lo que escribo este mail al foro... Por supuesto también podéis defenderla, soy todo oídos
¡¡¡¡Necesito vuestros comentarios!!!!

¡¡¡Gracias a todos!!!
Moraita
Perlero nuevo
Perlero nuevo
 
Mensajes: 36
Registrado: 2008-10-29 10:25 @475

Publicidad

Notapor explorer » 2009-02-04 07:31 @355

Lo bueno de Perl es que te permite probar, rapidamente, todas las posibilidades, y quedarte con la mejor.

De las soluciones comentadas, yo me quedaría con la cuarta. Convertiría los 8 procesos en 8 programas CGI: solo son ejecutados cuando desde fuera se solicita su intervención.

No necesitas crear hilos de ejecución, pues de eso se encargará el servidor web.

El problema es lo que comentas en el primer punto. ¿Por qué han de estar continuamente funcionando para mantener la conexión con el servidor? ¿Qué necesitan estar haciendo mientras no se les solicita nada?

Si solo están esperando el aviso externo para conectarse a la BD y ejecutar algo, con procesos CGI, vale: el servidor web es el proceso que está escuchando y manteniendo varios hilos de ejecución. Él se encargará de ejecutarlos. Y la respuesta del CGI se la enviará al solicitante, en el formato que queráis (no tiene porqué ser HTML).

Vamos, me parece lo más sencillo, rápido, y limpio de implementar, con los requerimientos que he leído, y salvo que se me haya pasado algo.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor salva » 2009-02-04 07:41 @362

Hay una cosa que no queda clara: ¿los 8 procesos hacen exactamente lo mismo o dependiendo del evento o de alguna otra cosa se tiene que dirigir el evento a uno o a otro?

Las tres primeras soluciones requieren hacer pooling ya sea de la BD, del sistema de ficheros o de la memoria compartida... así que, al menos en mi opinión, son malas soluciones.

La cuarta solución en cambio, se ajusta perfectamente a un modelo de eventos. Además, se basa en una infraestructura estándar, lo cual siempre es una ventaja porque tendrás que desarrollar menos y sera mas fácil de testear.

Las desventajas que le veo son:

Se va a crear una conexión TCP/IP para cada evento; esto puede introducir retardos considerables, la capa HTTP puede ser también innecesaria. Probablemente una solución similar basada en los sockets de Unix sería mucho más eficiente sin aumentar la complejidad del sistema (o sea, abrir socket, enviar mensaje con el evento sin utilizar ningún protocolo intermedio, cerrar socket).

Usar threads tampoco es generalmente una buena idea, porque en Perl los mismos no son precisamente ligeros; un fork es muchas veces más eficiente, así que si puedes, usa una solución más estándar como un servidor tipo prefork.
Avatar de Usuario
salva
Perlero nuevo
Perlero nuevo
 
Mensajes: 200
Registrado: 2008-01-03 15:19 @680

Notapor Moraita » 2009-02-04 10:49 @492

Tenemos una base de datos A que está en el servidor SA y una base de datos B que está en el servidor SB. Como recomendación de los DBAs se debe mantener una única conexión a ambos servidores.

Por otro lado yo tengo 8 procesos que hacen exactamente lo mismo pero atacando a bases datos en SB diferentes, es decir (B1, B2, B3..., B8).

En la base de datos A tengo las tablas de control que me indicarán que tengo qué hacer exactamente en las bases de datos B.

Implementando las soluciones comentadas CGI o sockets, yo me imagino un único proceso P1 para los ocho casos y 8 enlaces (E1, E2..., E8) apuntando a ese proceso.

Los 8 enlaces estarán siempre activos por lo tanto tendremos como 8 instancias de P1 continuamente ejecutándose.

Dentro de P1 me imagino lo siguiente:
#P1
  1. parametrizar puerto/socket según proceso origen
  2. abrir conexiones a SA y SB
  3. thread1/fork1 a la escucha del aviso
  4. thread2/fork2 ejecutándose siempre que reciba un aviso
  1. Una primera parte de parametrización dependiendo del enlace que ha disparado la instancia definiré qué base de datos atacar (B1 si E1, B2 si E2, B3 si E3….B8 si E8), de qué socket/memo/puerto (asumo que cada uno lee de un sitio diferente), etc...
  2. Una segunda parte de abrir conexiones a ambos servidores. Aquí el deseo es no cerrar nunca las conexiones, por indicación de los DBA´s, para evitar reconectar. No sé cómo será el mantener una conexión abierta for ever...
  3. Una tercera parte y aquí entra el thread/fork... que está continuamente escuchando en el puerto/socket correspondiente. Aquí no debemos perder los avisos, es decir, deberé utilizar una variable local que guarde un 1 conforme ha recibido un aviso
  4. Una cuarta parte que sería otro thread que ejecuta las tareas sobre la base de datos B correspondiente.
    Primero libera la variable local para recibir más avisos y luego ejecuta (puede estar de uno a 10 min. ejecutándose).
Respecto a los sockets de Unix, supongo que te refieres a ésto, ¿no? http://docstore.mik.ua/orelly/perl/cookbook/ch17_07.htm

Me lo miraré en detalle a ver qué tal....

Gracias,
Mercedes
Moraita
Perlero nuevo
Perlero nuevo
 
Mensajes: 36
Registrado: 2008-10-29 10:25 @475

Notapor salva » 2009-02-04 12:56 @581

(puede estar de uno a 10 min. ejecutándose).


¿Pero no estábamos hablando de tiempo real? Si tus tiempos de proceso son de varios minutos y no quieres perder las peticiones que llegan mientras procesas las anteriores entonces ¡lo que necesitas es un sistema de colas!

En CPAN hay varios módulos que te dan esa funcionalidad, también hay paquetes de software que no son específicos para Perl o también podrías utilizar un servidor SMTP donde cada evento llegaría en un correo.

En cuanto a lo de mantener conexiones permanentes a la base de datos, eso está bien cuando tienes muchas peticiones por segundo, pero para un proceso de varios minutos es totalmente innecesario. Puedes abrir una conexión por cada evento y la base de datos ni se va a enterar.
Avatar de Usuario
salva
Perlero nuevo
Perlero nuevo
 
Mensajes: 200
Registrado: 2008-01-03 15:19 @680

Notapor Moraita » 2009-02-05 02:57 @165

Sí, bueno, siento haberme explicado mal,
el 98% de las tareas tardarán o deberían tardar segundos pero pueden llegar tareas (una o dos veces al día) que pueden tardar minutos (de 1 a 10).

Con respecto a no perder el "aviso", es simplemente eso: no perder el aviso. No se trata de una cola de tareas; se trata de que algo me avisa y yo en caso de que esté ejecutando una tarea me debo guardar el aviso; cuantos avisos me llegan durante mi ejecución me da igual, lo que no debo perder es que al menos ha habido un aviso...

En fin, miraré lo de los sockets a ver...
Muchas gracias
Moraita
Perlero nuevo
Perlero nuevo
 
Mensajes: 36
Registrado: 2008-10-29 10:25 @475

Notapor Moraita » 2009-02-05 03:50 @201

Una cosa, la solución con la memoria compartida la probé y me funcionó sin problemas. Claro que está probado deprisa y corriendo, quizá cuando me meta a perfilar me encuentro con un montón de regalos y por lo que he entendido en este foro debo descartar esta opción porque en general da problemas, ¿no?
Moraita
Perlero nuevo
Perlero nuevo
 
Mensajes: 36
Registrado: 2008-10-29 10:25 @475

Notapor salva » 2009-02-05 04:06 @212

¡Ah!, pero si todo lo que necesitas es un flag, entonces la solución puede ser mucho más sencilla: usa señales para avisar al proceso.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
our $signaled = 1;

$SIG{USR1} = sub { $signaled = 1 };

while(1) {
  if ($signaled) {
    $signaled = 0;
    while (my $task = get_task_from_db()) {
      $signaled = 0;
      $task->process;
    }
  }
  else {
    select(undef, undef, undef, 1);
    # la señal termina el "select", pero
    # como hay una race-condition en el periodo desde
    # que se comprueba $signaled hasta que empieza el
    # select en el que podría llegar una señal, hay que
    # usar un timeout
  }
}
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


y desde el exterior avisas del evento...

Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
kill -USR1 $PID
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4
Avatar de Usuario
salva
Perlero nuevo
Perlero nuevo
 
Mensajes: 200
Registrado: 2008-01-03 15:19 @680

Notapor Moraita » 2009-02-05 05:06 @254

¡Esto va cogiendo color!

Si, seguro que es algo muy sencillo y creo que estás muy cerca, pero creo que sabes un montón y te olvidas de que yo no tengo ni idea :), bueno idea sí, pero...

¿Qué quieres decir con "... y desde el exterior avisas del evento... "?

y haces un kill y tal...

creo que me pierdo un poco aunque me gusta por donde estás tirando...
Moraita
Perlero nuevo
Perlero nuevo
 
Mensajes: 36
Registrado: 2008-10-29 10:25 @475

Notapor salva » 2009-02-05 05:19 @263

Lo que aparece en el primer bloque sería más o menos el bucle principal de los 8 procesos de los que hablabas.

Lo que aparece el final es un comando de shell pero que lo único que hace es llamar a la función kill() del sistema operativo. Es la forma en la que le dices al proceso desde el exterior que ha llegado un evento nuevo.

Si no sabes cómo funciona el tema de las señales te recomiendo que te lo mires porque en Unix/Linux es fundamental. Para empezar, leete las páginas man kill(1) y kill(2) y el perlipc. En cualquier libro que hable de IPC o de programación en Unix también te explicarán cómo funcionan.
Avatar de Usuario
salva
Perlero nuevo
Perlero nuevo
 
Mensajes: 200
Registrado: 2008-01-03 15:19 @680

AnteriorSiguiente

Volver a Intermedio

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados