DocumentDB Version Upgrade

Beaver Lee
Spoon Radio
Published in
13 min readDec 12, 2023

안녕하세요. SpoonRadio SRE 팀에서 DBA 업무를 담당하고 있는 Beaver(이선영)입니다. SpoonRadio에서는 다양한 데이터베이스를 사용하여 운영하고 있습니다. 그중에서도 NoSQL 데이터베이스로는 AWS DocumentDB를 사용합니다. 최근에 DocumentDB 3.6 버전이 EOS (End Of Service)가 되면서 5.0 버전으로의 업그레이드가 필요했습니다. SpoonRadio에서는 다국가 서비스를 하고 있으며 이에 따라 DocumentDB와 EC2 위에 MongoDB 사용을 혼용하여 서비스를 운영하고 있었습니다. 이번 작업시 모든 서비스의 안정적인 운영을 위해 MongoDB를 DocumentDB로 전환을 추가적으로 진행하였습니다.

작업 절차

작업 절차를 결정하기 위해서 DocumentDB 3.6의 데이터 용량 및 이동할 데이터양을 확인했습니다. 먼저, 사용되지 않는 데이터베이스는 제외하였습니다. 나머지 데이터베이스 중에서는 배치가 실행된 결과 값이 저장되고 있는 데이터베이스가 가장 큰 용량을 차지하고 있음을 확인하였습니다.

그에 따라서 배치성 데이터베이스에 대해서 이동을 하지 않는다면 작업 시간을 최소화할 수 있어서 무중단으로 작업을 진행할 수 있을 것이라고 판단하였습니다. 해당 데이터베이스를 이동하지 않기 위해서 우리는 DocumentDB 3.6 과 5.0 버전에 양쪽에 데이터를 쓰도록 미리 변경을 진행하였습니다.

Document DB 3.6 데이터 용량

DocumentDB를 사용중인 환경에서의 작업 절차는 다음과 같습니다. 먼저, DocumentDB Parameter Group 에서 audit_log를 활성화하고 모든 쿼리문에 대한 로그를 dml_write로 변경하여 남기도록 설정하였습니다. 해당 파라미터는 Amazon CloudWatch audit logs가 활성화되었음을 나타내며, dml_write는 DML 쓰기 이벤트에 대한 감사 기록을 활성화하고, ddl은 DDL 이벤트에 대한 감사 기록을 활성화한다는 것을 의미합니다.

Defines whether Amazon CloudWatch audit logs are enabled.

enabled—CloudWatch audit logs are enabled.

dml_write—auditing for DML write events is enabled.

ddl—auditing for DDL events is enabled.

데이터 이동 작업은 Backup, Restore, Resync로 나누어 진행했습니다. Backup은 Mongodump를 활용하여 진행하고, Restore는 MongoRestore를 이용하여 진행했습니다. 특히 Restore 과정에서는 불필요한 컬렉션을 제외하고 진행하여 작업 시간을 단축하였습니다.

데이터 Backup과 Restore가 완료된 후에는 사용자에게 데이터베이스 권한부여, Batch 실행, DocumentDB 5.0의 정보를 확인하였습니다. 그리고 CloudWatch Logs를 통해 변경 내용을 확인하고 Resync를 통해 데이터 이동을 완료하였습니다.

모든 데이터 검증이 완료된 이후에는 DocumentDB Parameter Group에서 변경한 audit_log를 dml_write로 그대로 유지하기에는 불필요한 로그가 많이 발생하게 되어 ddl로 변경하여 운영하고 있습니다.

DocumentDB 3.6 → DocumentDB 5.0 작업 절차

DocumentDB를 사용 중이었던 환경 외에 MongoDB로 유지되고 있는 환경에 대한 추가적인 준비가 필요했습니다. 변경 내용을 확인하고 Resync를 진행하기 위해 Cloudwatch Logs를 통한 정보 수집이 어려웠습니다.

이 문제를 해결하기 위해 데이터베이스의 Profile Level을 변경하여 관련 내용들을 syste.profile 컬렉션을 통해 확인할 수 있도록 설정하였습니다. 이를 통해 변경 내용을 추적하고 필요한 데이터를 안정적으로 Resync할 수 있게 되었습니다.

MongoDB 3.6 → DocumentDB 5.0 작업 절차

저희는 다국가 서비스를 하고 있음에 따라서 동일한 작업을 각 서비스에 맞춰서 진행해야 합니다. 하나의 환경의 작업을 완료했을때 DocumentDB 5.0의 Pending Maintenace가 발생했습니다. 다음 Maintenance 진행 시 작업 절차를 간소화하기 위해 남아있는 환경의 작업시 함께 진행하게 되었습니다.

다만, 이전에 배치에 대해서 Document DB 3.6과 5.0을 모두 데이터를 쓰기 위해 미리 생성되어 있어 새롭게 생성할 수 있는 상황이 아니었습니다. 따라서, 3개의 Instance 중에서 Replica Instance 2개에 대해서 먼저 진행했습니다. 나머지 Primary Instance에 대해서는 Failover를 이용하여 진행 후 다시 Failover를 진행함으로써 다시 Primary로 승격시켜 주었습니다.

이슈 사항

작업 준비시 발생한 이슈

DocumentDB 5.0으로 변경 후, 관련 API로 기능 테스트를 진행했을때 삭제 관련 기능에서 “Retryable writes are not supported” 관련 처리가 안되는 오류가 발생했습니다. 해당 이슈는 DocumentDB 5.0에서 retryWrites에 대한 Option이 변경되면서 발생한 것으로 , API에서 connection시 retryWrites=False 조건을 추가하여 해결했습니다.

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/opt/spooncast/webapp/SpoonCast/mongo.py", line 363, in delete_one
self.get_collection(coll_name).delete_one(doc)
File "/usr/lib64/python3.8/site-packages/pymongo/collection.py", line 1199, in delete_one
self._delete_retryable(
File "/usr/lib64/python3.8/site-packages/pymongo/collection.py", line 1163, in _delete_retryable
return self.__database.client._retryable_write(
File "/usr/lib64/python3.8/site-packages/pymongo/mongo_client.py", line 1492, in _retryable_write
return self._retry_with_session(retryable, func, s, None)
File "/usr/lib64/python3.8/site-packages/pymongo/mongo_client.py", line 1385, in _retry_with_session
return func(session, sock_info, retryable)
File "/usr/lib64/python3.8/site-packages/pymongo/collection.py", line 1157, in _delete
return self._delete(
File "/usr/lib64/python3.8/site-packages/pymongo/collection.py", line 1140, in _delete
result = sock_info.command(
File "/usr/local/lib64/python3.8/site-packages/ddtrace/contrib/pymongo/client.py", line 192, in command
return self.__wrapped__.command(dbname, spec, *args, **kwargs)
File "/usr/lib64/python3.8/site-packages/pymongo/pool.py", line 603, in command
return command(self.sock, dbname, spec, slave_ok,
File "/usr/lib64/python3.8/site-packages/pymongo/network.py", line 165, in command
helpers._check_command_response(
File "/usr/lib64/python3.8/site-packages/pymongo/helpers.py", line 159, in _check_command_response
raise OperationFailure(msg % errmsg, code, response)
pymongo.errors.OperationFailure: Retryable writes are not supported

또한, Resync 작업을 진행할 때 insert 문을 실행하면서 int 형 데이터가 float으로 저장되는 현상이 있었습니다. 이를 해결하기 위해서는 int 형에 대해서 NumberInt 함수를 사용하여 명시적으로 형변환을 진행하였습니다. 이를 통해 데이터의 일관성을 유지하고 정확한 형식으로 저장되도록 조치하였습니다.

  • Before : db.test.insert({id: 0})
  • After : db.test.insert({id: NumberInt(0)})

작업 진행 이후 발생했던 문제

작업 이후 PRD 환경에서 DocumentDB의 connection이 계속해서 늘어나고 있었으며, 이전에는 발생하지 않았던 pymongo endsession 관련 이슈가 발생했습니다.

Database Connections

우선, pymongo의 버전 이슈일 것으로 추측하여 개발 환경의 버전을 변경해 보았습니다. 그러나 변경 후에도 문제가 계속되어 원복 후 다른 해결책을 찾아 보았습니다. 다른 대안으로는 mongo close 함수 호출을 제거하는 것이었습니다. 해당 함수 제거로 해결할 수 있었던 이유는 DocumentDB는 endSession을 모든 버전에서 지원하지 않고 있었고 DB Connection을 위해서 사용한 pymongo는 3.6버전에서만 지원하고 있었기 때문입니다.

이를 테스트하고 문제가 발생하지 않았기 때문에 이 변경을 운영 환경에 반영했고, 해당 에러가 더 이상 발생하지 않았습니다. 또한, connection이 감소한 것을 확인했습니다.

다음 환경의 작업에서는 이러한 문제를 예방하기 위해 Datadog Dashboard를 통해 pymongo의 에러 로그를 추가로 모니터링하도록 설정했습니다.

Datadog pymongo error monitoring

또 다른 이슈로는 Database Load가 증가하였습니다. 이러한 현상은 특정 사용자의 정보가 int를 double로 변환하여 10000.0으로 조회되는 것으로 확인되었으며, pymongo의 이슈로 확인 되었습니다. 이 문제는 이전에도 존재했지만, DocumentDB 5.0으로 업그레이드하면서 Performance Insights를 활성화하여 확인할 수 있게 되었습니다.

Amazon DocumentDB Performance Insights

해결책으로는 해당 이슈가 발생하지 않도록 아래의 쿼리를 사용하여 bson datatype No 16. (32bit Int)을 확인했습니다. 또한, 문제가 발생하는 시점에 Host가 unknown으로 표시되는 현상이 있었는데, 이는 Amazon DocumentDB Performance Insights에서의 버그임을 확인했습니다.

db.collection_name.find({ "_id": { $not: { $type: 16 } } })

Terminate

작업이 완료되고 DocumentDB 5.0이 안정적으로 운영되기 시작한 시점에 Terminate 작업을 진행했습니다. DocumentDB 3.6에서는 connection을 확인한 후, 용량이 큰 데이터베이스를 제외한 모든 데이터베이스를 MongoDump CLI를 활용하여 마지막 백업을 진행했습니다. 이후, 백업된 데이터는 AWS S3에 업로드하여 안전하게 보관하였습니다. Terminate 작업은 DocumentDB 3.6과 연관된 모든 리소스를 제거했습니다. 이에는 Secrets Manager, Route 53, DocumentDB 또는 MongoEC2와 같은 모든 구성 요소가 포함되었습니다. 이를 통해 DocumentDB 3.6과 관련된 모든 환경을 정리하고 종료를 완료했습니다.

마치며

SpoonRadio에 입사하여 처음으로 진행한 Maintenance로 Document Version Upgrade를 진행하면서 많이 배울 수 있었습니다. 작업 절차에 대해서 Python을 활용하여 자동화 하고 진행 전 수많은 테스트로 작업시 발생할 수 있는 이슈들을 최소화 할 수 있었습니다. 그럼에도 발생한 pymongo 관련 이슈들과 DocumentDB의 Data Type의 이슈들에 대해서는 해당 작업을 진행할 분들이라면 한번씩 확인해보시면 좋을 것 같습니다.

또한, 다른 서비스의 환경을 고려해서 DocumentDB와 MongoDB의 특성을 고려하는 것이 중요했습니다. 하지만 해당 부분에 대한 준비가 미흡하여 작업 절차를 마지막까지 수정해야 했습니다. 앞으로는 모든 환경에 맞춰 더 신중한 고려를 통해 작업을 진행할 예정입니다.

마지막으로, 작업이 무사히 완료될 수 있도록 함께 테스트를 진행해주시고 작업에 참여하신 모든 분들에게 감사 인사를 전하고 싶습니다.😀

--

--