1. 서비스 요구사항


데이터 정합성 문제


<aside>

커플 서비스 글에서 메시지 큐 사용 시 데이터 정합성 문제가 발생할 수 있음 을 이야기 했다

문제상황


  1. 유저 A가 일정을 생성하고 이 데이터를 유저 B의 메시지 큐에 삽입한다.
  2. 유저 B가 데이터를 동기화 하기 위해 백엔드 서버로 요청을 보냈다.
  3. 백엔드 서버는 동기화를 위한 데이터를 레디스에서 조회함과 동시에 데이터를 삭제한 후 이를 응답한다
  4. 만약 여기서 B가 데이터를 처리하다가 예상치 못한 상황으로 데이터를 처리하지 못한다면 데이터 정합성 문제가 발생한다

이 문제를 해결하기 위해 TCP/IP 의 ACK 패턴을 도입했다.

</aside>

2. 아키텍처 개선


1️⃣ ACK 패턴이란


<aside>

ACK 패턴은 말 그대로 데이터 처리를 완료했다는 것을 확인 시켜주기 위한 요청이다.

즉 사용자가 데이터 동기화를 마치고 마쳤다는 요청을 다시 보내므로 이 데이터를 삭제하는 것이다.

프로세스


  1. 유저 B는 데이터를 동기화하기 위해 벡엔드 서버로 요청을 보낸다.
  2. 백엔드 서버는 메시지 큐에서 데이터를 조회한 후 유저 B에게 반환한다.
  3. 유저 B는 데이터를 처리하고 완료했다는 것을 다시 백엔드 서버로 보낸다.
  4. 백엔드 서버는 처리 완료 신호를 받으면 유저 B의 메시지 큐를 초기화한다. </aside>

ACK 패턴에서 발생하는 문제


<aside>

ACK 패턴을 통해 데이터 정합성을 높일 수 있었지만 100%는 아니었다.

아래 같은 문제 상황이 존재할 수 있다.

문제상황


  1. 유저 B는 데이터를 동기화하기 위해 벡엔드 서버로 요청을 보낸다.
  2. 백엔드 서버는 메시지 큐에서 데이터를 조회한 후 유저 B에게 반환한다.
  3. 유저 B는 데이터를 처리하고 완료했다는 것을 다시 백엔드 서버로 보낸다.
  4. 유저 B가 데이터를 처리하는 동안 유저 A가 새로운 일정을 등록하고 유저 B의 큐에 추가된다.
  5. 백엔드 서버는 처리 완료 신호를 받으면 유저 B의 메시지 큐를 초기화한다.

문제 상황 정리


위와 같이 유저 B가 데이터를 처리하는 와중에 유저 B의 메시지 큐에 새로운 데이터가 추가될 수있다.

이렇게 되면 유저 B가 메시지 큐를 초기화할때, 새로 등록된 일정에 대한 메시지도 같이 사라지는 것이다.

즉, 유저 A가 새로 등록한 일정을 유저 B는 볼 수 없게 된다.

</aside>

2️⃣ Sequence Number를 부여


<aside>

문제 해결


ACK 패턴의 문제를 해결하기 위해 메시지를 선별적으로 삭제하기로 했다. 즉 각 메시지에 고유한 시퀀스 넘버를 주어 이 숫자까지의 메시지를 삭제하는 것이다.

프로세스


  1. 메시지를 큐에 삽입할 때 시퀀스 번호를 원자적으로 증가시키고, 이 번호를 점수로 하여 메시지를 정렬된 집합(ZSET)에 저장한다
  2. 사용자가 ACK 신호를 보낼때 처리한 데이터의 마지막 번호를 같이 보내고 이 번호까지의 메시지를 안전하게 삭제하여 데이터 처리 중 발생할 수 있는 정합성 이슈를 없앤다. </aside>

시퀀스 번호를 점수로 하여 ZSET에 저장하는 이유


<aside>

ZET 셋이 내부적으로 각 메시지를 (메시지, 시퀀스 번호) 형태로 저장하고, 점수(시퀀스 번호)에 따라 자동으로 정렬하기 때문이다.

프로세스


  1. 메시지 큐에 사용자로부터 받은 메시지들을 저장하면 각 메시지마다 순차적으로 증가하는 시퀀스 번호를 부여받는다
  1. 이 메시지들을 Redis의 ZSET에 저장되므로 점수(시퀀스 번호)에 따라 자동으로 정렬된다.
  2. 사용자의 ACK 신호가 오면 점수(시퀀스 번호)에 맞춰 메시지를 삭제해준다.