병합 복제를 사용하면 여러 노드에서 자율적인 데이터를 변경할 수 있으므로 한 노드에서 변경한 내용이 다른 노드의 동일한 데이터에 대한 변경 내용과 충돌할 수 있는 상황이 존재합니다. 다른 상황에서 병합 에이전트는 제약 조건 위반과 같은 오류가 발생하고 특정 노드에서 변경한 내용을 다른 노드로 전파할 수 없습니다. 이 문서에서는 충돌 유형, 충돌을 감지 및 해결하는 방법, 감지 및 해결에 영향을 주는 요인에 대해 설명합니다.
충돌 검색 및 해결
병합 에이전트는 시스템 테이블의 MSmerge_contents 열을 사용하여 lineage 충돌을 감지합니다. 아티클에 대해 열 수준 추적이 설정된 경우, COLV1 열도 사용됩니다. 이러한 열에는 행 또는 열이 삽입되거나 업데이트되는 시기와 병합 복제 토폴로지에서 행 또는 열을 변경한 노드에 대한 메타데이터가 포함됩니다.
sp_showrowreplicainfo 시스템 저장 프로시저를 사용하여 이 메타데이터를 볼 수 있습니다.
병합 에이전트는 동기화 중에 적용할 변경 내용을 열거할 때 게시자와 구독자의 각 행에 대한 메타데이터를 비교합니다. 병합 에이전트는 이 메타데이터를 사용하여 토폴로지의 둘 이상의 노드에서 행 또는 열이 변경되었는지 확인합니다. 이는 잠재적 충돌을 나타냅니다. 충돌이 감지되면 병합 에이전트는 충돌이 있는 아티클에 지정된 충돌 해결 프로그램을 시작하고 해결 프로그램을 사용하여 충돌 승자를 확인합니다. 승리한 행은 게시자 및 구독자에 적용되며, 패배한 행의 데이터는 충돌 테이블에 기록됩니다.
문서에 대한 대화형 충돌 해결을 선택하지 않은 경우 병합 에이전트에서 충돌을 자동으로 즉시 해결합니다. 자세한 내용은 Microsoft 복제 대화형 충돌 해결 프로그램을 참조하세요. 병합 복제 충돌 뷰어를 사용하여 충돌의 승리 행을 수동으로 변경하는 경우 병합 에이전트는 다음 동기화 중에 손실된 서버에 행의 승리 버전을 적용합니다.
해결된 충돌 로그
병합 에이전트가 충돌 해결 프로그램의 논리에 따라 충돌을 해결한 후 충돌 유형에 따라 충돌 데이터를 기록합니다.
UPDATE및INSERT충돌의 경우, 손실된 행 버전을 아티클의 충돌 테이블에 씁니다. 이 테이블의 이름은conflict_<PublicationName>_<ArticleName>형식으로 지정됩니다. 충돌 유형과 같은 일반적인 충돌 정보가 테이블에MSmerge_conflicts_info기록됩니다.충돌이 발생하면,
DELETE테이블에 손실된 버전의 행을MSmerge_conflicts_info에 씁니다. 업데이트에 대해 삭제가 손실되면, 삭제이기 때문에 손실된 행에 대한 데이터가 없으므로conflict_<PublicationName>_<ArticleName>에 아무 것도 기록되지 않습니다.
각 아티클의 충돌 테이블은 매개 변수sp_addmergepublication에 지정된 @conflict_logging 값에 따라 게시 데이터베이스, 구독 데이터베이스 또는 둘 다(기본값)에 만들어집니다. 각 충돌 테이블은 origin_datasource_id 열이 추가된 상태로 그것이 기반이 되는 아티클과 동일한 구조를 가집니다. 병합 에이전트는 게시의 충돌 보존 기간보다 오래된 경우 충돌 테이블에서 데이터를 삭제합니다. 이 기간은 매개 변수 sp_addmergepublication 를 사용하여 @conflict_retention 지정됩니다(기본값은 14일).
복제는 충돌 데이터를 볼 수 있는 복제 충돌 뷰어 및 저장 프로시저(sp_helpmergearticleconflicts및sp_helpmergeconflictrowssp_helpmergedeleteconflictrows)를 제공합니다. 자세한 내용은 병합 복제에 대한 충돌 해결을 참조하세요.
충돌 해결에 영향을 주는 요소
병합 에이전트가 검색한 충돌을 해결하는 방법에 영향을 주는 두 가지 요소가 있습니다.
구독 유형: 클라이언트 또는 서버(구독이 끌어오기 구독인지 푸시 구독인지는 충돌 해결에 영향을 주지 않음).
사용되는 충돌 추적 유형: 행 수준, 열 수준 또는 논리적 레코드 수준입니다.
구독 유형
구독을 만들 때 밀어넣기 또는 끌어오기 구독인지 여부를 지정하는 것 외에도 클라이언트 또는 서버 구독인지 지정합니다. 구독을 만든 후에는 형식을 변경할 수 없습니다(이전 버전의 SQL Server에서는 클라이언트 및 서버 구독이 각각 로컬 및 글로벌 구독으로 참조됨).
우선 순위 값이 할당된 구독(0.00에서 99.99까지)을 서버 구독이라고 합니다. 게시자의 우선 순위 값을 사용하는 구독을 클라이언트 구독이라고 합니다. 또한 서버 구독이 있는 구독자는 다른 구독자에게 데이터를 다시 게시할 수 있습니다. 다음 표에는 각 구독자 유형의 주요 차이점과 용도가 요약되어 있습니다.
| 유형 | 우선 순위 값 | 사용됨 |
|---|---|---|
| 서버 | 사용자에 의해 할당됨 | 다른 구독자가 다른 우선 순위를 가지도록 하려는 경우 |
| 클라이언트 | 0.00이지만 데이터 변경은 동기화 후 게시자의 우선 순위 값을 가정합니다. | 모든 구독자의 우선 순위가 같도록 하고 첫 번째 구독자가 게시자와 병합하여 충돌을 이겨 내도록 하려는 경우 |
클라이언트 구독에서 행이 변경된 경우 구독이 동기화될 때까지 변경에 우선 순위가 할당되지 않습니다. 동기화하는 동안 구독자의 변경 내용에 게시자의 우선 순위가 할당되고 후속 동기화에 대한 우선 순위가 유지됩니다. 어떤 의미에서 게시자는 변경 내용의 소유권을 가정합니다. 이 동작을 사용하면 첫 번째 구독자가 게시자와 동기화하여 지정된 행 또는 열에 대한 다른 구독자와의 후속 충돌을 이길 수 있습니다.
서버 구독에서 행을 변경하면 변경에 대한 메타데이터에 구독 우선 순위가 저장됩니다. 이 우선 순위 값은 다른 구독자의 변경 내용과 병합될 때 변경된 행과 함께 이동합니다. 이렇게 하면 우선 순위가 높은 구독에서 변경한 내용이 우선 순위가 낮은 구독의 후속 변경으로 손실되지 않습니다.
구독은 게시자보다 높은 명시적 우선 순위 값을 가질 수 없습니다. 병합 복제 토폴로지의 최상위 게시자에는 항상 명시적 우선 순위 값이 100.00입니다. 해당 게시에 대한 모든 구독의 우선 순위 값이 이 값보다 작아야 합니다. 다시 게시되는 토폴로지에서:
구독자가 데이터를 다시 게시하는 경우 구독은 구독자 위에 있는 게시자보다 우선 순위 값이 작은 서버 구독이어야 합니다.
구독자가 데이터를 다시 게시하지 않는 경우(다시 게시 트리의 리프 수준에 있기 때문에) 구독은 클라이언트 구독이어야 합니다.
서버 구독 및 우선 순위에 대한 자세한 내용은 구독 유형 및 할당된 우선 순위에 따라 병합 충돌 해결의 예를 참조하세요.
지연된 충돌 알림
충돌 우선 순위가 다른 서버 구독에서 지연된 충돌 알림이 발생할 수 있습니다. 다음 시나리오를 고려하세요. 이 시나리오에서는 게시자와 우선순위가 낮은 구독자 간에 충돌하지 않는 변경 내용이 교환되지만, 우선순위가 높은 구독자가 게시자와 동기화를 시도할 때 변경 내용이 충돌하게 됩니다.
LowPrioritySub라는 게시자 및 우선 순위가 낮은 구독자는 충돌 없이 여러 동기화를 통해 변경 내용을 교환합니다.
HighPrioritySub라는 우선 순위가 높은 구독자는 일정 시간 동안 게시자와 동기화되지 않았으며 LowPrioritySub 구독자가 만든 것과 동일한 행을 변경했습니다.
HighPrioritySub 구독자는 게시자와 동기화되며 LowPrioritySub 구독자보다 우선 순위가 높기 때문에 변경 내용과 LowPrioritySub 구독자 간의 충돌을 이깁니다. 이제 게시자에 HighPrioritySub 구독자가 변경한 내용이 포함됩니다.
LowPrioritySub 구독자가 게시자와 병합된 후 HighPrioritySub 구독자와의 충돌 때문에 많은 변경 내용이 다운로드됩니다.
우선 순위가 낮은 구독자가 충돌에서 패배한 동일한 행을 변경한 경우 이 상황은 문제가 될 수 있습니다. 이로 인해 이 구독자가 변경한 모든 내용이 손실될 수 있습니다. 이 문제에 대한 잠재적 해결 방법은 비즈니스 논리가 달리 지시하지 않는 한 모든 구독자의 우선 순위가 동일한지 확인하는 것입니다.
추적 수준
데이터 변경이 충돌로 한정되는지 여부는 문서에 대해 설정한 충돌 추적 유형(행 수준, 열 수준 또는 논리적 레코드 수준)에 따라 달라집니다. 논리적 레코드 수준 추적에 대한 자세한 내용은 고급 병합 복제 충돌 - 논리 레코드에서 해결을 참조하세요.
행 수준에서 충돌이 인식되면 해당 행에 대한 변경 내용이 동일한 열에 대한 변경 내용인지 여부에 관계없이 충돌로 판단됩니다. 예를 들어 게시자 행의 주소 열이 한 번 변경되고 해당 구독자 행의 전화 번호 열(동일한 테이블)이 두 번째로 변경된 경우를 가정해 보겠습니다. 행 수준 추적을 사용하면 동일한 행이 변경되었으므로 충돌이 감지됩니다. 열 수준 추적을 사용하면 동일한 행의 다른 열이 변경되었으므로 충돌이 감지되지 않습니다.
행 수준 및 열 수준 추적의 경우 충돌 해결은 동일합니다. 전체 데이터 행은 충돌 발생자의 데이터로 덮어씁니다(논리적 레코드 수준 추적의 경우 해결 방법은 아티클 속성 logical_record_level_conflict_resolution에 따라 다름).
애플리케이션 의미 체계는 일반적으로 사용할 추적 옵션을 결정합니다. 예를 들어 주소 및 전화 번호와 같이 일반적으로 동시에 입력되는 고객 데이터를 업데이트하는 경우 행 수준 추적을 선택해야 합니다. 이 상황에서 열 수준 추적을 선택한 경우 한 위치의 고객 주소와 다른 위치의 고객 전화 번호에 대한 변경 내용은 충돌로 감지되지 않습니다. 동기화 시 데이터가 병합되고 오류가 누락됩니다. 다른 상황에서는 여러 사이트에서 개별 열을 업데이트하는 것이 가장 논리적인 선택일 수 있습니다. 예를 들어 두 사이트는 소득 수준 및 총 달러 금액의 신용 카드 구매와 같은 고객에 대한 다양한 유형의 통계 정보에 액세스할 수 있습니다. 열 수준 추적을 선택하면 두 사이트가 불필요한 충돌을 생성하지 않고도 서로 다른 열에 대한 통계 데이터를 입력할 수 있습니다.
비고
애플리케이션에 열 수준 추적이 필요하지 않은 경우 일반적으로 동기화 성능이 향상되므로 행 수준 추적(기본값)을 사용하는 것이 좋습니다. 행 추적을 사용하는 경우 기본 테이블에는 최대 1,024개의 열이 포함될 수 있지만, 최대 246개의 열이 게시되도록 아티클에서 열을 필터링해야 합니다. 열 추적을 사용하는 경우 기본 테이블에는 최대 246개의 열이 포함될 수 있습니다.
충돌 유형
대부분의 충돌은 업데이트와 관련이 있지만(한 노드의 업데이트가 다른 노드에서 업데이트 또는 삭제와 충돌함) 다른 충돌 유형이 있습니다. 이 섹션에서 설명하는 각 충돌 유형은 업로드 단계 또는 병합 처리의 다운로드 단계에서 발생할 수 있습니다. 업로드 처리는 특정 병합 세션에서 수행되는 변경 내용의 첫 번째 조정이며 병합 에이전트가 구독자에서 게시자까지 변경 내용을 복제하는 단계입니다. 이 처리 중에 검색된 충돌을 업로드 충돌이라고 합니다. 다운로드 처리에는 게시자에서 구독자로의 변경 내용 이동이 포함되며 업로드 처리 후에 발생합니다. 이 처리 단계의 충돌을 다운로드 충돌이라고 합니다.
충돌 유형에 대한 자세한 내용은 MSmerge_conflicts_info, 특히 conflict_type 열과 reason_code 열을 참조하세요.
업데이트-업데이트 충돌
병합 에이전트는 한 노드의 행(또는 열 또는 논리 레코드)에 대한 업데이트가 다른 노드의 동일한 행에 대한 다른 업데이트와 충돌할 때 업데이트-업데이트 충돌을 감지합니다. 이 경우 기본 해결 프로그램의 동작은 손실된 노드에 행의 승리 버전을 보내고 아티클 충돌 테이블에서 손실된 행 버전을 기록하는 것입니다.
업데이트 삭제 충돌
병합 에이전트는 한 노드의 데이터 업데이트가 다른 노드의 삭제와 충돌할 때 업데이트-삭제 충돌을 감지합니다. 이 경우 병합 에이전트는 행을 업데이트합니다. 그러나 병합 에이전트가 대상에서 해당 행을 검색하는 경우 삭제되었기 때문에 행을 찾을 수 없습니다. 승자가 행을 업데이트한 노드인 경우 손실된 노드의 삭제는 삭제되고 병합 에이전트는 새로 업데이트된 행을 충돌 손실자로 보냅니다. 병합 에이전트는 손실된 행 버전에 대한 정보를 테이블에 기록합니다 MSmerge_conflicts_info .
변경 실패에 따른 충돌
병합 에이전트는 특정 변경 내용을 적용할 수 없는 경우 이러한 충돌을 발생합니다. 이 문제는 일반적으로 게시자와 구독자 간의 제약 조건 정의 차이와 제약 조건에서 NFR(NFR) 속성의 NOT FOR REPLICATION 사용으로 인해 발생합니다. 예를 들면 다음과 같습니다.
구독자 측 제약 조건이 NFR로 표시되지 않을 때 발생할 수 있는 외래 키 충돌입니다.
게시자와 구독자 간의 제약 조건 차이와 제약 조건은 NFR로 표시되지 않습니다.
구독자에서 종속 개체를 사용할 수 없음 예를 들어 뷰를 게시하지만 해당 뷰가 의존하는 테이블이 아닌 경우 구독자에서 해당 보기를 통해 삽입하려고 하면 오류가 발생합니다.
기본 키 및 외래 키 제약 조건과 일치하지 않는 게시물에 대한 조인 필터링 논리입니다. SQL Server 관계형 엔진이 제약 조건을 적용하려고 하지만 병합 에이전트가 아티클 간의 조인 필터 정의를 적용하는 경우 충돌이 발생할 수 있습니다. 병합 에이전트는 테이블 수준 제약 조건으로 인해 대상 노드에서 변경 사항을 적용할 수 없으므로 충돌이 발생합니다.
고유 인덱스 또는 고유 제약 조건 위반 또는 기본 키 위반으로 인한 충돌은 아티클에 대해 ID 열이 정의되고 자동화된 ID 관리가 사용되지 않는 경우 발생할 수 있습니다. 두 구독자가 새로 삽입된 행에 동일한 ID 값을 사용하는 경우 문제가 될 수 있습니다. ID 범위 관리에 대한 자세한 내용은 ID 열 복제를 참조하세요.
병합 에이전트가 대상 테이블에 행을 삽입하지 못하도록 하는 트리거 논리로 인해 충돌이 발생합니다. 구독자에서 정의된 업데이트 트리거를 고려하십시오. 이 트리거는 NFR로 표시되지 않으며 그 논리에는
ROLLBACK가 포함됩니다. 오류가 발생하면 트리거가 트랜잭션에 대해ROLLBACK를 실행하여 병합 에이전트가 실패한 변경 충돌을 감지합니다.