Hola.

    Como ya he comentado estoy instalando un "cluster de replicacion" basado en PyReplica, creo que todo va bastante bien, ahora estoy ajustando algunos valores para mejorar la performance. El punto que busco solucionar ahora es el tiempo desde que ocurre un error, normalmente por concurrencia, hasta que se reintenta la ejecución.


   
    Buscando en los archivos de PyReplica encontre un valor que se pueden manejar para mejorar el tiempo de respuesta: time out entre selects, lo ajuste a 3 seg, funciona mucho mejor, por defecto viene con 60 segs,  pensando que estos servidores son exclusivos para el servicio de postgres, y atienden a 5 usuarios mas 2 esclavos de PyReplica. El problema principal sucede cuando dos nodos esclavos intentan leer el mismo registro de forma concurrente, es un error conocido y se acepta su condicion, pero el problema es el tiempo que demora en reintetar la ejecución del query, a pesar de mejorar el rendimiento con el cambio mencionado, creo que aun es lenta la reacción del servidor esclavo en reintentar la ejecución, demora mucho mas de tres segundos.

Ejemplo:

A    15:57:07 -  3 inserts a una tabla en replicación (con trigger py_log_replica),
son ejecutados sin errores, en el maestro y sin errores en el primer nodo, (el que leyo primero el cambio esta OK):
insert into sys_tablas (tab_codtabla,
tab_desctabla,tab_tipo,tab_codigo, tab_desc)
values (1,'Vend','U','0006','abcdef');
insert into sys_tablas (tab_codtabla,
tab_desctabla,tab_tipo,tab_codigo, tab_desc)
values (1,'Vend','U','0007','abcdef');
insert into sys_tablas (tab_codtabla,
tab_desctabla,tab_tipo,tab_codigo, tab_desc)
values (1,'Vend','U','0008','abcdef');

B    15:57:54 - Envia correo electronico avisando de error (Concurrencia)
C    15:59:06 - Reestablece replicación.
D    15:59:08 - Se completa la replicación, satisfactoriamente


Como puede apreciarse el tiempo que transcurre entre que se detecta el error "B" y  el inició de la replicación "C" es al rededor de 1 minuto. Pensando que solo se estan realizando 3 inserts, el tiempo tomado en la replicación es mucho.


Existe algun otro ajuste que pueda realizarse a los valores por defectos de PyReplica.


Otros:
Sevidores:
    Tengo 3 servidores iguales:
    CPU     :     Intel(R) Core(TM)2 Quad CPU    Q6600  @ 2.40GHz
     RAM   :4 Gb.
     HD      : 234 Gb.
Conexion:
    4Mbps, con telefonica. (nada es perfecto)

Javier Fritz Alsite wrote:
Saludos.

    Revisando en las entreñas de las tablas involucradas he decubierto lo que explica el problema. Los campos de tipo "serial" son creados como "integer" el problema es que los valores asinados a la sequence (MAXVALUE), no son soportador por este tipo de dato.


Valor por defecto para una sequence:
MAXVALUE 9223372036854775807

Maximo en un campo integer:
2147483647

Solucion: cambiar los campos afectado por la sequence a "bigint", o al crear la tabla usar "bigserial" en vez de "serial"


;)

Atento a sus comentarios.


Javier Fritz Alsite wrote:
Hola

    Con el cambio que propuso Mariano mejoro el panorama, con las indicaciones dadas el query generado si es correcto y al ejecutarse el query la "L" desaparece ;).

    El problema ahora esta en el trigger pero del esclavo, al hacer el cambio en el maestro, el trigger genera ok el query en el replica_log (maestro), este es capturado por el esclavo (que a su vez es maestro), lo ejecuta y el triger captura el cambio en la tabla, pero al insertar el registro en replica_log envia el siguiente mensaje:

Traceback (most recent call last):
  File "/usr/local/pyreplica/daemon.py", line 74, in run
    debug = self.debug)
  File "/usr/local/pyreplica/pyreplica.py", line 154, in main_loop
    replicate(cur0, cur1, skip_user, slave_field, debug)
  File "/usr/local/pyreplica/pyreplica.py", line 92, in replicate
    cur1.execute(sql)
DataError: el entero está fuera de rango
CONTEXT:  sentencia SQL: «INSERT INTO replica_log (sql) VALUES ($1)»

Buscando en el log de pyreplica en el esclavo encontre el query que se trae del maestro y al ejecutarlo manualmente sobre el esclavo envia:

WARNING:  plpython: in function py_log_replica:
DETAIL:  plpy.Error: Unknown error in PLy_spi_execute_plan

ERROR:  el entero está fuera de rango
CONTEXT:  sentencia SQL: «INSERT INTO replica_log (sql) VALUES ($1)»

********** Error **********

ERROR: el entero está fuera de rango
SQL state: 22003
Context: sentencia SQL: «INSERT INTO replica_log (sql) VALUES ($1)»


$1 corresponde al query que se ha ejecutado sobre una de las tablas del sistema, y segun la definición de la tabla el unico campo que puede dar este problema corresponde a "id" ya que es un serial. La seq. relacionada es

CREATE SEQUENCE replica_log_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 3223372036854776031
  CACHE 1;

el valor dudoso es start, pero fue dado en base a las recomendaciones del manejo de sequencias para pyreplica (no se excluyo a replica_log) a este esclavo le corresponderia trabajar en el segundo tercio del rango.

Por ahora se me ocurre vaciar el replica log del esclavo y restablecer la seq.

atento a sus comentarios.

Saludos.
  



Javier Fritz Alsite wrote:

lo estoy probando en este instante te cuento el resultado
Gracias :)



Mariano Reingart wrote:
2009/10/2 Javier Fritz Aliste <javier.fritz@lanix.cl>
Hola.

    Como estan, hace algun tiempo pedi ayuda sobre una solución de replicación, he optado por PyReplica , y tengo el siguiente problema.quizas de simple la solución,

    Tengo 3 servidores, cada uno tiene conexión con dos maestros remotos, funciona aceptablemente bien, esta montado en servidores con salida a internet con un trafico aun de prueba.

    Al grano, al  realizar una insercion en una tabla que posee un campo bigint, el triger esta capturando el query pero para el valor de este campo lo concatena con "L", no se si esto es correcto, ya que al ejectuar este query, se por el esclavo  pyreplica o extrayendolo manualmente y ejecutandolo sobre la base genera el error.


Hola Javier, parece ser un tema de conversión entre postgresql y python, una solucion podria ser modificar el código del disparador en plpython para que detecte los bigint de pg (long en python) y no le agregue la L al convertirlos para el query sql:

  # function to convert value from python to postgres representation
  def mogrify(v):
    if v is None: return 'NULL'
    if isinstance(v,long): return str(v) # no agregar L a long (bigint)
    if isinstance(v,basestring):
       r = repr(v)
       if not r.startswith('\"'):
          return r
       else:
          # postgres doesn't support ", replace and escape '
          return "'%s'" % r.replace("'","\\'")[1:-1]
    return "'%s'" % repr(v) # to get rid of bool that are passed as ints (solved in pg8.3)

Lo que hay que agregar es la linea verde despues de if v is None.. (respetando la identación):
if isinstance(v,long): return str(v)

No lo probé pero tendría que funcionar, cualquier cosa avisame
Sds
Mariano