1 minute read

인과성은 중요한 개념이다. 하지만, 모든 인과관계를 파악하는 것은 비실용적이다.

인과관계를 파악하는 좋은 방법은 타임스탬프, 또는 순차번호를 사용하는 것이다. 여기서, 타임스탬프는 실제 시각 대신, 논리적으로 증가하는 순차적인 번호면 된다.

순차번호가 도움이 되는 이유는 전체 순서를 알 수 있고, 두 연산 사이의 선후 관계를 알 수 있기 때문이다.

단일 리더 복제 데이터베이스는 복제 로그를 통해 쓰기 작업의 순서를 정의한다. 리더는 각 작업에 대해 카운터를 증가시키기만 하면 되므로 복제 로그의 각 작업에 순차적으로 증가하는 시퀀스 번호를 할당할 수 있다. 팔로워가 복제 로그에 나타나는 순서대로 쓰기를 적용하면 팔로워의 상태는 리더보다 뒤처져 있더라도 항상 인과적으로 일관성을 유지한다.

비인과적 시퀀스 번호 생성기

리더가 하나도 없는 경우(다중 리더 데이터베이스를 사용하거나 데이터베이스가 분할되어 있기 때문일 수 있음) 연산에 대한 시퀀스 번호를 생성하는 방법이 명확하지 않을 수 있다.

실제로는 다양한 방법이 사용된다:

  • 각 노드는 자체적으로 독립적인 시퀀스 번호 집합을 생성할 수 있다. 예를 들어 두 개의 노드가 있는 경우 한 노드는 홀수만 생성하고 다른 노드는 짝수만 생성할 수 있습니다. 시퀀스 번호의 이진 표현에 고유한 노드 식별자를 포함하도록 일부 비트를 예약하여 서로 다른 두 노드가 동일한 시퀀스 번호를 생성하지 못하도록 할 수 있다.
  • 각 작업에 물리적 시계의 타임스탬프를 사용할 수 있다. 이러한 타임스탬프는 순차적이지는 않지만, 충분히 높은 해상도를 가진다면 연산 순서를 완전히 지정하기에 충분할 수 있다.
  • 시퀀스 번호 블록을 미리 할당할 수 있다. 예를 들어 노드 A는 1에서 1,000까지의 시퀀스 번호 블록을, 노드 B는 1,001에서 2,000까지의 블록을 주장할 수 있다. 그런 다음 각 노드는 자신의 블록에서 시퀀스 번호를 독립적으로 할당하고 시퀀스 번호 공급이 부족해지기 시작하면 새 블록을 할당할 수 있다.

이 세 가지 옵션은 모두 카운터를 증가시키는 단일 리더를 통해 모든 연산 작업을 푸시하는 것보다 성능이 더 우수하고 확장성이 뛰어나다. 그러나, 이 모든 연산에는 생성되는 시퀀스 번호가 인과관계와 일치하지 않는다는 문제가 있다.

인과성 문제는 이러한 시퀀스 번호 생성기가 여러 노드에 걸친 작업 순서를 올바르게 캡처하지 않기 때문에 발생한다:

  • 각 노드는 초당 처리하는 연산 수가 다를 수 있다. 따라서 한 노드가 짝수를 생성하고 다른 노드가 홀수를 생성하는 경우 짝수에 대한 카운터가 홀수에 대한 카운터보다 뒤처지거나 그 반대의 경우가 발생할 수 있다. 홀수 연산과 짝수 연산이 있는 경우 어느 것이 인과적으로 먼저 발생했는지 정확하게 알 수 없다.
  • 물리적 시계의 타임스탬프는 시계 왜곡의 영향을 받기 때문에 인과관계와 일치하지 않을 수 있다.
  • 블록 할당자의 경우, 한 연산에는 1,001에서 2,000 범위의 시퀀스 번호가 부여될 수 있고 인과적으로 나중에 발생한 연산에는 1에서 1,000 범위의 번호가 부여될 수 있습니다. 여기서도 시퀀스 번호는 인과관계와 일치하지 않는다.