본문으로 건너뛰기

실제 서비스 개발 중 몽고 DB Replication 으로 Write 직후 Read 데이터 불일치 현상

실제 서비스를 개발하다가 MongoDB 를 사용하다가 문제를 만난 적이 있습니다. Write 직후 동일한 데이터를 Read 하면 데이터가 확인되지 않는 현상이었습니다. 당시에는 해당 내용을 잘 몰라 시간을 꽤나 쓰고 애먹었었는데요. 이 문제점이 발생하게 된 상황과 원인에 대해서 적어보았습니다.

문제 상황

  • 당시 회사에서는 주로 많은 서비스에서 MongoDB 를 사용하는 환경
  • 글로벌 출시를 위하여 새로운 서비스를 만들고 런칭 준비를 하던 중 문제점 발견. stage 테스트 후, production 에 서비스를 올리니 이상 동작 발생
    • 간헐적으로 서버에 요청한 쿼리가 실패(Client 에서 호출한 서버 쿼리에서 내부적으로 mongodb write 후, 해당 데이터를 다시 read 하는 동작을 수행)
    • 정상 동작이라면 write 한 데이터를 다시 read 해서 다음 동작을 수행해야 되는데, 실패 시에는 클라이언트에서 에러를 만나게 됨
    • 쿼리는 아래와 같은 흐름으로 수행됨
      • Client 호출
      • 서버에서 aws 서비스 요청 후 결과 대기
      • aws 서비스 완료 시 mongodb 에 결과 write
      • write 후 다시 mongodb 에서 해당 데이터를 read 하여 다음 동작 수행
    • 서버에서 AWS 서비스를 조회하는 부분을 살펴보니, AWS 서비스에서는 정상적으로 동작완료
    • 서버의 write 부분을 살펴보기 위해 mongodb 를 직접 들어가서 확인해보면, 데이터가 실제 존재했음. 즉, write 동작에 이상이 없는 것으로 확인되었음.
    • 서버 쿼리의 read 부분이 실패헸는데, db 에는 write 한 데이터가 있음. 정확한 원인을 몰라 수정이 어려웠던 상황
  • 기존 테스트 환경에서 점검 했을 때는 이상 없음
    • 테스트 환경은 staging. 테스트 당시에는 전혀 발생하지 않던 현상이 product 에서 발생

해결방법

  • 처음에는 환경 차이라고 인식하지 못하고 코드상의 버그인 것으로 보아 로직을 확인. 여러번 확인해도 큰 문제점을 발견하지 못함.
  • 계속 확인하다가 해결책이 보이지 않아 더 많이 알고 있는 동료들에게 문의하여 같이 확인하게 됨
    • 동료돌도 잘 모르는 문제여서 해결에 다소 시간이 소요됨
  • 당시 분산 db 관련된 내용을 조금 습득했고, 문제점을 추론해보게 됨.
    • 문제점 인식을 위해 stage 와 production 에서 하나하나 어떤 차이점이 있는지 비교. 차이점을 비교해보니 하기와 같은 차이점을 가지고 있었음
    • stage 에서는 MongoDB 가 replication 없이 단일 노드에서 동작
    • production 에서는 MongoDB 가 replication 에서 2개의 Secondary 노드 보유
  • production 환경에서는 가용성을 위하여 replica set 이 구성되어 있었음
    • replication 에서는 production MongoDB 는 write 후, secondary 노드에 해당 데이터를 전파
    • 별도의 설정이 없었기 때문에, db 에서 write 하고 바로 읽으면 secondary 에 데이터가 전파되기 전에 read 동작을 수행. secondary 는 기존 데이터를 응답값으로 전달함
      • 전파 시간은 약 2~4 초 정도로 확인되었음.
    • 나중에 mongodb compass 에서 데이터를 확인할 때에는 전파 시간이 지나, read 시 write 한 데이터가 제대로 보였음
  • 위 이슈를 해결하기 위해 당시 떠오른 방법들은 아래와 같다.
    • client 에서 polling 하여 db 상태가 바뀔 때 까지 대기한다. 가장 간단해보이는 방법으로 보였음
    • server 에서 polling 하여 db 상태가 바뀔 때 까지 대기한다. client 입장에서는 변경 없이 기존 쿼리 사용 가능
    • mongodb 쿼리에 전파가 완료되는 것을 보장하고 읽을 수 있게, 쿼리나 컬렉션 등에 설정
  • 위 방법 중 2번째 방법을 사용해보았다. write 후 read 동작이 즉시 발생하는 것이 아닌, write 후 read 까지 delay 를 조금 넣어 줌
    • delay 를 추가하고 나서 정상적으로 동작하는 것을 확인
  • 이를 통해, CAP 이론에 대해 조금 더 알게 되었다.
    • 분산형 구조를 가진 경우 일관성(Consistency), 가용성(Availability), 분산 허용(Partitioning Tolerance) 이라는 3가지 특징을 가짐
    • 일관성와 가용성 중 1가지를 만족하려면 다른 1가지는 포기할 수 밖에 없게 됨.
      • 일관성을 만족할 시 : 분산된 노드 중 어느 노드로 접근하더라도 데이터 값이 같아야 한다. 일관성이 깨지면, 쿼리 요청할 때 다른 데이터 전달 가능
      • 가용성을 만족할 시 : 분산된 노드 중 하나 이상의 노드가 동기화에 실패(Fail)라도 정상적으로 요청을 처리할 수 있는 기능을 제공한다.
    • 현재 db 구조는 가용성을 만족하고 있어 일관성(Consistency)이 깨지는 케이스

정리

  • db 에 replication 설정이 되어 있으면, write 와 read 시점이 다를 때 주의하자
  • CAP 이론을 직접 눈으로 보고 느낄 수 있어 좋은 경험이었다.
  • 내가 개발하고 있는 서비스에 대해서 시간이 날 때마다 공부를 해보자. 모든 것을 다 알수는 없지만 많이 알수록 트러블 슈팅에 도움이 된다.
  • stage 와 production 간의 환경이 다를 수 있다는 것을 인지하자. 즉, 테스트 환경과 실제 운영 환경간의 차이가 있으면 문제가 생길 수 있고, 이를 사전에 생각해보면 더 좋을 것 같다.
    • 디버그 시간을 줄이기 위해서는 production 과 stage 환경을 거의 비슷하거나 동일하게 두는 것도 좋을 것 같음
    • 시간도 비용이다. 인건비, 서비스 오픈 지연 등 많은 것들이 지연되거나 추가로 소모될 수 있다. 서버 비용과 비교하여 너무 큰 비용이 아니면 stage 와 production 의 설정을 동일하게 해도 괜찮을 것 같다는 생각이 들었다.