Pergunta

Eu estou procurando uma boa estratégia de lidar com bloqueios de banco de dados a partir de um aplicativo Java 6; vários threads paralelas poderia, potencialmente, escrever na mesma tabela ao mesmo tempo. O banco de dados (Ingres RDMBS) vai matar aleatoriamente uma das sessões se detectar um impasse.

O que seria uma técnica aceitável para lidar com a situação de impasse, dada aos seguintes requisitos?

  • o tempo total deve ser mantido tão pequeno quanto razoavelmente possível
  • matando uma sessão terã uma significativa (mensurável) rollback
  • tópicos tempo não tem como
    comunicar uns com os outros ou seja, o estratégia deve ser autônomo

Até agora, a estratégia que eu vim com algo ao longo destas linhas:

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);

Pode ser melhorado de alguma forma? por exemplo. à espera de uma quantia fixa (número mágico) de segundos. Existe uma estratégia diferente que irá produzir melhores resultados?

Nota: Várias técnicas de nível de banco de dados será usado para garantir impasses são, na prática, muito raros. Além disso, a aplicação tentará evitar tópicos de agendamento que escreve na mesma tabela ao mesmo tempo. A situação acima será apenas um “pior cenário”.

Nota: A tabela na qual são inseridos registos é organizada como uma pilha tabela particionada e não tem índices; cada thread irá inserir registros em sua própria partição.

Foi útil?

Solução

Uma abordagem comumente utilizada é uma forma de back-off exponencial. Ao invés de seu aproach 1000*attempts+random, faça o atraso uma função exponencial do número de tentativas. Isso garante latência mínima no primeiro uma ou duas tentativas, onde ele poderia ter sido apenas má sorte que você impasse, mas dá-lhe atrasos muito maiores mais tarde, quando é evidente que a conexão realmente está congestionado.

Claro, outra abordagem seria tentar organizar seu banco de dados acessa para que os impasses são menos prováveis ??de ocorrer. Mas sem saber o que suas consultas fazer (e como e quando eles são executados), é impossível dizer se isso pode ser feito

Outras dicas

Essa é a maneira que o fizemos. Circuito e repita a operação até que ele termine.

Nós não mexer com atrasos aleatórios.

Além disso, nós fizemos a cometer dentro do bloco try ea reversão no manipulador de exceção.

Quando você tem vários recursos bloqueáveis ??e múltiplas transações simultâneas, o impasse é inevitável. É uma consequência lógica da disputa por bloqueios.

Se evitar contenção para fechaduras (isto é, bloqueio de tabelas de nível pessimista), em seguida, também tendem a evitar a simultaneidade. Se você pode definir a transação que não lutar por bloqueios, você pode evitar impasse. acesso simultâneo à mesma mesa, no entanto, é praticamente a definição de impasse.

Ao carregar, inserções (Especial em uma tabela HEAP) pode (muitas vezes) proceder em paralelo sem muitos problemas de contenção. Se você atrasar a construção dos índices, então não há nenhuma outra atualização acontecendo durante a inserção.

Assim, você pode ser capaz de evitar soltando os índices, alterando a organização para uma pilha, carregamento com vários processos simultâneos (ou tópicos, geralmente é mais rápido para ter vários processos), em seguida, construir seus índices (e, possivelmente, reorganizar o tabela), você pode ser capaz de impasses a evitar.

Ao fazer atualizações ou exclusões, não muito ajuda.

Se você não precisa ter acesso simultâneo ao banco de dados uma solução simples pode ser para removê-lo e usar uma fila de processamento tarefa para atualizar o banco de dados em vez disso, serializadas acesso ao banco de dados através da fila. Sei que isso vai introduzir um elemento assíncrona para a sua aplicação, e por isso não seria adequado para a maioria das aplicações iniciado pelo usuário ou web-apps on-line, mas pode valer a pena considerar para uma aplicação tipo de lote / off-line (eu percebo provavelmente não a resposta a sua procura pois embora).

Com um banco de dados como Ingres você sempre vai ter alguns impasses, então você tem que assumir que qualquer inserção, atualização ou excluir irá falhar e ter uma estratégia de repetição no lugar (como no seu exemplo). Você deve projetar seu banco de dados para que a contenção é minimizada e impasses só acontecem raramente. Se você está continuamente recebendo transações falhando mesmo depois de várias tentativas, então este é um sinal de que você vai ter que fazer alguma grande reformulação de banco de dados (ou passar para um sistema como a Oracle, onde geralmente é possível projetar aplicações para impasses evitar, uso adequado de bloqueio ao nível de linha).

Como é isso?

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top