2010-01-08 4 views
0

비즈니스 규칙에 따라 예약 된 시간에 데이터베이스에서 장기 실행 작업으로 처리 할 수있는 10,000 - 200,000 개의 행이 필요합니다. 각 행은 개별적으로 처리해야하며 (서로 의존하지는 않습니다) 비동기 적으로 발생하는 것이 좋습니다. 작업의 성공적인 완료는 문서화되어야합니다 (아마도 데이터베이스로).장기 실행 작업을위한 메시지 큐에 대량 데이터베이스 행

메시지 대기열을 사용하는 가장 좋은 방법은 내구성이므로 쉽게 확장 할 수 있습니다. 첫째, 이것이 최상의 솔루션입니까? 그렇다면 데이터베이스의 모든 행을 큐에 넣는 가장 효율적인 방법은 무엇입니까? 모든 행이 큐에 전달되도록 보장하는 방법은 무엇입니까?

참고 : 우리는 C# 3.5, WCF, MSMQ 및 SQL 2005를 사용하는 .Net 팀입니다. NServiceBus를 조사했으며이를 권장한다면이 기능을 기꺼이 사용할 수 있습니다.

데이타베이스가 병목 (처리 된 것으로 표시 할 각 행을 업데이트 중)이라는 걱정이 듭니다. 나는 또한 "트랜잭션 방식으로"메시지를 보내는 방법을 모른다.

  1. 어떻게 "트랜잭션 방식으로"메시지를 보내나요? 내가 의미하는 바는 다음과 같다 : db로부터 하나의 행을로드하고, 메시지를 보내고, db로 행을 업데이트한다. 업데이트가 실패하면 메시지를 보내지 않습니다.
  2. 이것은 일반적인 시나리오입니까, 아니면 다른 방식으로해야합니까?
  3. 내 걱정은 db의 개별 행을 업데이트하면 병목 현상이 발생한다는 것입니다. "트랜잭션 방식으로"여러 개의 메시지를 보낸 다음 데이터베이스를 일괄 적으로 업데이트 할 수 있습니까?

답변

2

예. 메시지 대기열은이 일을 위해 설계되었습니다. 그것이 바로 그들이 원하는 것입니다. 메시지 대기열 솔루션은 천문학적 크기로 확장 될 수 있습니다. 대기열 자체가 제한 요소가되기 전에 처리 능력이 부족합니다.

일반적으로 동시 개별 프로세스에서 이러한 작업을 실행해야합니다. 스레드 된 솔루션에서 단일 한 두뇌 칼로리를 낭비하지 마십시오. 당신이 적용 할 수있는만큼의 리소스를 원하고 OS 레벨의 리소스 할당이 이런 종류의 일에 가장 좋습니다.

다음을 수행 할 수있는 가장 간단한 방법이 필요합니다.

  1. 대기열을 만듭니다.

  2. 대기열에서 모두 읽는 여러 소비자 프로세스를 만듭니다.

  3. 생산 공정을 시작하십시오. 이렇게하면 쿼리가 실행되고 큐에 쓰여지며 프로세스에서 가능한 한 적게 수행됩니다.

각 소비자 프로세스는 대기열에있는 항목을 놓고 경쟁합니다. 유휴 소비자들 사이에서 Ice Hockey가 마주하고 있다고 생각하십시오. 일단 소비자가 행을 잡으면 기꺼이 그것을 할 수 있습니다.

쿼리가 비어 있으면 모든 작업을 닫아야합니다. 소비자를 폐쇄하는 것은 어렵지 않지만 불가능합니다. 쿼리 후에 큐에 넣는 특별한 "모든 완료"메시지를 갖는 것이 일반적입니다. n 소비자가있는 경우 n 복사본을 모두 대기열에 넣어 소비자가 모두 정상적으로 종료 할 수 있도록하십시오.

이것은 유닉스 파이프 라인과 매우 흡사합니다. 아주 좋은 이유로.


편집.

  1. 어떻게 "트랜잭션 방식으로"메시지를 보내나요? 내가 의미하는 바는 다음과 같다 : db로부터 하나의 행을로드하고, 메시지를 보내고, db로 행을 업데이트한다. 업데이트가 실패하면 메시지를 보내지 않습니다.

    하지 마십시오. 그것은 엉망입니다. 제작자가 메시지를 보냅니다. 대기열 자체는 완벽하게 신뢰할 수 있습니다. 메시지가 "잃어버린"또는 "어떻게 든"처리하지 못합니다. 큐는 파일 시스템과 함게 작동하도록 구성되어 메시지가 소비 될 때까지 지속되도록 할 수 있습니다.

    소비자는 작업을 완료하면 "완료"한 것으로 표시 할 수 있습니다. 이것은 많은 것을 느리게 할 것입니다.

    "처리 중"상태를 유지하려면 데이터웨어 하우징 기술을 사용하고 트랜잭션 데이터와 함께 보관하지 마십시오.

  2. 예, 이것은 일반적인 시나리오입니다. 모든 사람들은 이런 종류의 제작자 측에서 너무 많은 것을 시도합니다. 필요하다고 생각하는 모든 "트랜잭션"처리가 거의 필요하지 않습니다. 이를위한 최종 사용자 요구 사항을 자세히 설명해야합니다. 그 업데이트가 정말로 필요한가요? 아니면 처리 상태를 어딘가에 기록해야하는 것처럼 보이니까?

    대기열이 매우 안정적임을 기억하십시오. 데이터베이스에 영구 대기열을 다시 작성하지 마십시오.

    "트랜잭션 메시징"에서 http://www.microsoft.com/windowsserver2003/techinfo/overview/msmqfaq.mspx을 읽으십시오. 메시지가 큐에 들어갈 수 있도록 많은 구성 옵션이 있습니다.

  3. 내 걱정은 db의 개별 행을 업데이트하면 병목 현상이 발생한다는 것입니다.

    좋은 생각. 그러지 마라. 데이터베이스 업데이트의 질문은 항상 "왜?"입니다. 그것이 "완전성을 위해"있다면 그것은 전혀 이유가 아닙니다. "복구"또는 "재 처리 방지"인 경우 더 나은 디자인을 생각할 수 있습니다.

    로그에 삽입하는 것은 훨씬 빠르며 부분적으로 처리 된 기록을 복구해야하는 매우 드문 경우에 처리되지 않은 행을 찾기 위해 존재하지 않는 쿼리를 수행하는 것을 여전히 허용합니다.

가장 간단한 대기열이 가장 좋습니다. 당신은 거의 거래 재밌는 사업이 많이 필요합니다. 메시지를 큐에 넣고 소비자 측에서 작업하십시오.

+0

왜 소비자를 완전히 차단합니까? 프로세스가 주기적으로 보이고 소비자가 유휴 상태가되어 대기열에서 더 많은 데이터를 기다립니다. RecieveMessage에서 시간 제한을 사용하면 주기적으로 차단 된 상태를 벗어나 종료 할 제어 메시지를 수신했는지 확인하도록 할 수 있습니다. – GrayWizardx

+0

@GrayWizardx : 좋은 지적입니다. 우리는 Linux이고, 파이프 라인의 머리에서 소스를 닫으면 소비자에게 간단한 EOF가 전파되고 모든 것이 잘 닫힙니다. 저 클로저 다운 작전을 예상하고 있었어. 필요하지 않은 경우 복잡성을 줄입니다. –

+0

감사합니다. 이것은 또한 훌륭한 정보입니다.여러분 중 한 분이 저의 다른 요지를 도울 수 있다면, 좋을 것입니다. db의 병목 현상과 트랜잭션 방식으로 메시지를 보내는 방법에 대해 우려하고 있습니다. – JontyMC

2

NServiceBus는 대기열 설정 프로세스를 훨씬 쉽게 만듭니다. 이 작업 (msmq 디자인)은이 작업에 일반적으로 사용되는 패턴이지만 유일한 옵션은 아닙니다.

SQL Server Service Broker 및 이와 유사한 기술을 여러 가지 사용할 수 있습니다.

는주의의 몇 당신이 MSMQ에 알고 있어야 있습니다 그들이 Active Directory 도메인 큐 않는 한

  1. 트랜잭션 큐 는로드 밸런싱 할 수 없습니다 수 있습니다.여기서 큰 걸림돌은 이 단일 시스템에 있어야한다는 것입니다. 즉, 시스템이 손실되면 (영구적으로 또는 일시적으로) 손실의 위험이 있습니다. 이것은 큰 걱정거리가 아니지만 주목할만한 것입니다.
  2. MSMQ 대기열에는 트랜잭션 및 비 트랜잭션의 두 가지 "모드"가 있습니다. 트랜잭션 큐는 메시지 배달을 보장하는 유일한 큐입니다.
  3. MSMQ 메시지 자체는 기본적으로 4MB (또는 그 이상)로 제한되므로 직접 serialization을 관리해야합니다 (XML serializer로 기본 .NET 직렬화가 매우 쉽지만). 4MB보다 큰 메시지를 원할 경우 대기열 외부에서 메시지를 관리하거나 대기중인 여러 메시지를 직접 관리해야합니다 (BizTalk는 이와 같이 큰 문제는 아닙니다). 4MB는 사용자의 필요에 따라 충분히 커야합니다.
  4. 큐에서 메시지를 "수락"하면 즉시 제거되므로 디자인에 따라 문제가 될 수 있습니다. 고객이 메시지를 "수락"하고 실패 할 경우 이되고 메시지는 다시 대기열로 돌아 가지 않습니다. 당신이 당신의 구현을 계획하고 과정이 아닌 데이터 저장 부분의 메시징 부분을 사용하는 경우

는이 모든 것을 말해 두 겠는데, MSMQ은 매우 신뢰할 수 있고 안정적이다.

마지막으로 현재 제안에 대한 대안으로 (비교 대상이 있으므로) 설명 된 시나리오를 DB에서 직접 구현할 수 있습니다. 냅킨 스케치 :

  1. 프로세스가 DB에서 실행 및 처리 "보류"행이있는 테이블을 채 웁니다은, 각각에 고유 ID를 할당 (GUID 등)
  2. "N을 반환하는 SP 만들기 "를 호출자에게 보내고, db와 같은 행을"보류 중 "으로 표시합니다. 0 또는 -1 등을 반환하는 행이없는 경우
  3. 작업에 대한 행 ID 및 완료 (완료 정보) 목록을 수신하고 보류중인 테이블을 업데이트하는 SP를 작성하고 완료 또는 제거 표시 이들 및 로깅 완료 데이터
  4. 내 소비자
  5. 귀하 소비자
  6. 내 소비자 작업 완료 로그온 제 SP 전화 행 처리
  7. 작동하는 최초의 SP에 전화 행 세트를 요청

그러면 주기적으로 보고서를 실행하여 수행 한 작업과 sti를 확인할 수 있습니다 보류 중일 때, 필요하다면 대기 행렬에서 보류 중으로 행을 변경하십시오. 이것은 다른 솔루션과 거의 동일한 확장을 가지며, 간접 참조 계층을 제거하고 약간 더 선형적인 프로세스를 제공합니다. 이 프로세스는 본질적으로 Service Broker가 작동하는 방식입니다 (물론 매우 중요합니다).

이 모든 것은 가장 편안하게 구현하는 방법에 따라 다릅니다. 나는 그것을 두 가지 방법으로 모두 해냈고 두 가지 모두 장단점이있다.

+0

감사합니다. 훌륭한 정보입니다. 문제를 명확히하기 위해 질문을 업데이트했습니다. – JontyMC

관련 문제