문제

Java 6 응용 프로그램 내에서 데이터베이스 교착 상태를 다루는 좋은 전략을 찾고 있습니다. 몇 가지 병렬 스레드가 잠재적으로 동시에 같은 테이블에 쓸 수 있습니다. 데이터베이스 (Ingres RDMBS)는 교착 상태를 감지하면 세션 중 하나를 무작위로 죽입니다.

다음 요구 사항을 고려할 때 교착 상태 상황을 처리 할 수있는 수용 가능한 기술은 무엇입니까?

  • 총 경과 시간은 합리적으로 작은 상태로 유지되어야합니다.
  • 세션을 죽이는 것은 중요한 (측정 가능한) 롤백이 발생합니다.
  • 시간 스레드는 갈 수있는 방법이 없습니다
    서로 의사 소통을합니다. 즉, 전략은 자율적이어야합니다.

지금까지 제가 생각해 낸 전략은 다음과 같습니다.

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

어떤 식 으로든 개선 할 수 있습니까? 예를 들어 고정 된 양 (매직 번호)의 초를 기다리고 있습니다. 더 나은 결과를 얻을 수있는 다른 전략이 있습니까?

메모: 교착 상태가 실제로는 매우 드문 경우 여러 데이터베이스 수준 기술이 사용됩니다. 또한 응용 프로그램은 동시에 동일한 테이블에 쓰는 스레드 예약을 피하려고 시도합니다. 위의 상황은 단지 "최악의 시나리오"일뿐입니다.

메모: 레코드가 삽입되는 테이블은 힙 파티션 테이블로 구성되며 인덱스가 없습니다. 각 스레드는 자체 파티션에 레코드를 삽입합니다.

도움이 되었습니까?

해결책

일반적으로 사용되는 접근법은 어떤 형태의 지수 백 오프입니다. 당신보다 1000*attempts+random aproach, 지연을 시도 횟수의 지수 함수로 만듭니다. 이를 통해 첫 번째 또는 두 번의 시도에서 최소한의 대기 시간을 보장합니다. 여기서 교착 상태에 처한 불운이었을 수도 있지만 연결이 실제로 혼잡하다는 것이 분명 할 때 나중에 훨씬 더 큰 지연을 제공합니다.

물론, 또 다른 접근법은 교착 상태가 발생할 가능성이 적어 데이터베이스 액세스를 정리하려고 시도하는 것입니다. 그러나 쿼리가 무엇을하는지 (그리고 어떻게 실행되었는지)를 모르면, 그것이 할 수 있는지 말할 수 없습니다.

다른 팁

그것이 우리가 한 방식입니다. 트랜잭션이 완료 될 때까지 루프하고 다시 시도하십시오.

우리는 임의의 지연을 엉망으로 만들지 않았습니다.

또한, 우리는 내부에 커밋을했습니다 try 예외 핸들러의 블록 및 롤백.

잠금 식 자원이 여러 개 있고 동시 거래가 여러 번 있으면 교착 상태를 피할 수 없습니다. 자물쇠에 대한 논쟁의 논리적 결과입니다.

자물쇠 (즉, 비관적 테이블 레벨 잠금)에 대한 논쟁을 피하면 동시성을 방지하는 경향이 있습니다. 자물쇠에 맞지 않는 거래를 정의 할 수 있다면 교착 상태를 피할 수 있습니다. 그러나 같은 테이블에 동시에 액세스하는 것은 교착 상태의 정의입니다.

로딩 할 때 삽입 (특히 힙 테이블)은 많은 경합 문제없이 (종종) 병렬로 진행할 수 있습니다. 인덱스 구축을 지연 시키면 삽입 중에 다른 업데이트가 진행되지 않습니다.

따라서 인덱스를 삭제하고 조직을 힙으로 변경하고 여러 동시 프로세스 (또는 스레드, 일반적으로 여러 프로세스를 갖는 것이 더 빠르면)를로드 한 다음 지수를 구축하고 (테이블을 재구성 할 수 있음)를 피할 수 있습니다. 교착 상태를 피할 수 있습니다.

업데이트 또는 삭제를 수행 할 때는별로 도움이되지 않습니다.

데이터베이스에 동시에 액세스 할 필요가없는 경우 간단한 솔루션을 제거하고 작업 처리 큐를 사용하여 데이터베이스를 대신 업데이트하여 큐를 통해 데이터베이스에 대한 액세스를 일련링하는 것입니다. 나는 이것이 당신의 응용 프로그램에 비동기 요소를 소개한다는 것을 알고 있으므로 대부분의 사용자 시작 응용 프로그램이나 온라인 웹 애플에 적합하지는 않지만 배치/오프라인 유형 응용 프로그램을 고려할 가치가있을 수 있습니다 (아마도 당신이 찾고있는 답이 아님을 알 수 있습니다. 그래도).

Ingres와 같은 데이터베이스를 사용하면 항상 교착 상태를 얻을 수 있으므로 삽입, 업데이트 또는 삭제가 실패하고 (예에서와 같이) 재시도 전략이 있다고 가정해야합니다 (예제에서와 같이). 경합이 최소화되고 교착 상태가 거의 발생하지 않도록 데이터베이스를 설계해야합니다. 몇 번의 재료 후에도 지속적으로 트랜잭션이 실패하는 경우, 이는 일부 주요 데이터베이스 재 설계를 수행해야한다는 신호입니다 (또는 적절한 사용으로 교착 상태를 피하기 위해 응용 프로그램을 설계 할 수있는 Oracle과 같은 시스템으로 이동해야한다는 신호입니다. 줄 수준의 잠금).

방법이있다 ?

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);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top