Pregunta

Busco una buena estrategia de tratar con bloqueos de base de datos desde una aplicación Java 6; varios hilos paralelos podrían, potencialmente, escribir en la misma tabla al mismo tiempo. La base de datos (Ingres RDMBS) matará al azar una de las sesiones si detecta un callejón sin salida.

Lo que sería una técnica aceptable para hacer frente a la situación de bloqueo, teniendo en cuenta los siguientes requisitos?

  • el tiempo total transcurrido debe mantenerse tan pequeño como sea razonablemente posible
  • matando a una sesión incurrirá en una significativo (medible) rollback
  • hilos de tiempo no tienen manera de
    comunicarse entre sí es decir, el estrategia debe ser autónomo

Hasta el momento, la estrategia que se me ocurrió es algo a lo largo de estas líneas:

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
    try {
        //insert loads of records in table 'x'
        success = true;
    } catch (ConcurrencyFailureException e) {
        attempts++;
        success = false;
        delayMs = 1000*attempts+random.nextInt(1000*attempts);

        try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
        }
    }
} while (!success);

¿Se puede mejorar de alguna manera? p.ej. a la espera de una cantidad fija (número mágico) de segundos. ¿Hay una estrategia diferente que producirá mejores resultados?

Nota: Varias técnicas de nivel de base de datos serán utilizados para asegurar los puntos muertos son, en la práctica, muy raro. Además, la aplicación intentará evitar las discusiones de programación que escriben en la misma tabla al mismo tiempo. La situación anterior será sólo un “peor de los casos”.

Nota: La tabla en la que se insertan está organizado como una tabla de montón se repartió registros y no tiene índices; cada hilo se inserte registros en su propia partición.

¿Fue útil?

Solución

Un enfoque comúnmente utilizado es alguna forma de exponencial de back-off. En lugar de su aproach 1000*attempts+random, hacer que el retraso de una función exponencial del número de intentos. Esto garantiza una latencia mínima en los primeros uno o dos intentos, donde podría haber sido sólo mala suerte que en un punto muerto, pero le da mucho más grandes demoras más tarde, cuando está claro que la conexión realmente está congestionada.

Por supuesto, otra posibilidad sería tratar de organizar su base de datos accede a fin de que los puntos muertos son menos probable que ocurra. Pero sin saber lo que hacen sus consultas (y cómo, y cuando son ejecutados), es imposible decir si eso se puede hacer

Otros consejos

Esa es la manera que lo hicimos. Loop y vuelva a intentar la operación hasta que finalice.

No nos metan con retrasos aleatorios.

Además, hicimos la confirmación dentro del bloque try y el retroceso en el manejador de excepciones.

Cuando usted tiene múltiples recursos con cerradura y múltiples transacciones simultáneas, estancamiento es inevitable. Es una consecuencia lógica de la contención para las cerraduras.

Si evita la contención de bloqueos (es decir, pesimista tabla de nivel de bloqueo), entonces también tiende a evitar la concurrencia. Si se puede definir transacción que no contender por cerraduras, puede evitar un punto muerto. el acceso concurrente a la misma mesa, sin embargo, es más o menos la definición de punto muerto.

Al cargar, inserciones (especiales en una tabla de montón) pueden (a menudo) proceder en paralelo sin muchos problemas de contención. Si se demora la construcción de los índices, entonces no hay otros cambios que sucede durante la inserción.

Por lo tanto, es posible que pueda evitar al dejar caer los índices, el cambio de la organización a un montón, cargando con múltiples procesos concurrentes (o hilos, por lo general es más rápido para tener múltiples procesos), y luego construir sus índices (y posiblemente reorganizar la tabla), que puede ser capaz de evitar los puntos muertos.

Al hacer actualizaciones o eliminaciones, no hay mucha ayuda.

Si usted no necesita tener acceso simultáneo a la base de datos una solución simple podría ser la de quitarlo y utilizar una cola de procesamiento de la tarea de actualizar la base de datos en su lugar, serialising acceso a la base de datos a través de la cola. Sé que esto va a introducir un elemento asincrónica para su aplicación, por lo que no sería adecuado para la mayoría de las aplicaciones iniciadas por el usuario o web-aplicaciones en línea, pero valdría la pena considerar para una aplicación de tipo de lote / fuera de línea (me di cuenta, probablemente no es la respuesta que buscas pues aunque).

Con una base de datos Ingres como siempre obtendrá algunos callejones sin salida, así que hay que asumir que cualquier inserción, actualización o eliminación se producirá un error y tener una estrategia de reintento en su lugar (como en el ejemplo). Debe diseñar su base de datos para la contención se minimiza y los puntos muertos sólo ocurren raramente. Si usted está recibiendo continuamente las transacciones que fallan, incluso después de varios intentos, entonces esto es una señal de que usted tendrá que hacer algún reajuste importante base de datos (o mover a un sistema como Oracle, donde por lo general es posible diseñar aplicaciones para evitar los puntos muertos por el uso adecuado de bloqueo de fila).

¿cómo es esto?

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
try {
     synchronized(ClassName.class) {
         //insert loads of records in table 'x'
      }

    success = true;
} catch (ConcurrencyFailureException e) {
    attempts++;
    success = false;
    delayMs = 1000*attempts+random.nextInt(1000*attempts);

    try {
                    Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
    }
  }
} while (!success);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top