서비스를 운영하면서 가장 보수적으로 다뤄야 하는 컴포넌트를 하나 꼽자면 단연 데이터베이스다.
백엔드 서버는 문제가 생기면 다시 띄우거나 스케일링으로 복구할 수 있지만,
데이터베이스는 말처럼 쉽지 않다.
백업도 고려해야 하고 스토리지는 영속되어야 하며, 고려해야 할 것이 너무 많다.
게다가 데이터 손실이나 장시간 장애는 곧 서비스 신뢰도에 치명적인 영향을 준다.
이 글에서는 우리가 MongoDB를 사용하면서 서비스 성장 단계에 따라 데이터베이스 운영 방식을 어떻게 바꿔왔는지, 그리고 최종적으로 왜 Percona를 선택하게 되었는지를 정리해보려 한다.
서비스 완전 초기에는 MongoDB를 EC2 한 대에 docker-compose로 띄워서 사용했다.
이 구성은 실제 운영용으로 좋은 선택은 아니었지만, 초기 단계에서는 꽤 합리적인 선택이었다.
우선 매우 빠르게 띄울 수 있고, 모든 것을 직접 컨트롤할 수 있으며 디버깅과 운영이 직관적이었다.
초기에는 트래픽이 크지 않았고 데이터 규모도 작았으며 무엇보다 빠르게 서비스 검증이 필요했기 때문에 완벽한 구성보다는 지금 당장 잘 동작하는 구성이 더 중요했다.
하지만 서비스가 커지면서, 이 구조의 한계는 점점 명확해졌다.
단일 인스턴스기 때문에 DB에 문제가 있으면 서비스 전체가 먹통이 된다.
그리고 Docker-compose로 간단히 띄운 것이기 때문에 장애 시 복구 전략도 불분명하고 백업 / 복구 자동화도 안 되어 있으며 확장성도 부족했다.
“이 서버가 죽으면 서비스는 어떻게 되지?” 라는 생각보다는 “설마 죽겠어?” 라고 안일하게 생각했던 것 같다.
이 시점에서 우리는 데이터베이스를 조금 더 안전하게 운영해야 한다고 판단했다.
우리는 두 가지 선택지가 있었다.
- 데이터베이스를 클러스터에서 운영하기
- AWS 완전관리형 데이터베이스(DynamoDB) 쓰기
하지만 DynamoDB는 백업이나 관리 등 모두 AWS가 해준다는 점에서는 편리했지만 비용 문제가 있었기에 당장은 사용하지 않기로 했다.
그리고 이미 백엔드는 EKS에서 운영 중이었기 때문에, 자연스럽게 다음 선택지는 클러스터 안에서 데이터베이스를 운영하는 것이었다.
우리는 MongoDB를 ReplicaSet, Primary + Secondary 구조로 구성했다.
이를 통해 Primary 장애 시 Secondary 승격, 읽기 부하 분산, 그리고 가용성을 확보 할 수 있었다.
공식 Helm Chart를 참고해서 기본적인 ReplicaSet 구성으로 빠르게 마이그레이션을 진행했다.

이전 환경과 비교해서 스토리지 설정도 쿠버네티스 단에서 Persistent Volume으로 EBS와 통합되어 할 수 있었고, 가용성 측면에서도 발전시킬 수 있었다.
하지만 아직 해결 안 된 문제가 많았다.
ReplicaSet이 구성되었다고 해서 곧바로 안정적인 운영이 되는 것은 아니었다.
운영하면서 다음과 같은 고민이 계속 쌓였다.
- 백업은 어떻게 할 것인가?
- 복구 시나리오는 충분히 검증되었는가?
- 설정 변경은 어떻게 안전하게 반영할 것인가?
MongoDB를 띄운 것과 MongoDB를 운영하는 것은 완전히 다른 문제였다.
ReplicaSet, PV, Helm 설정, 백업 스크립트, 모니터링까지 모든 것을 직접 설계하고 관리하기에는 운영 부담이 점점 커지고 있었다.
이런 고민 끝에, 우리는 Percona MongoDB로 옮기기로 결정했다.

Percona는 여러 DB와 통합될 수 있고, 백업, 복구, 모니터링까지 포함한 운영 도구 제공해준다.
무엇보다 Kubernetes 환경을 전제로 한 Operator 제공해서 우리 기존 클러스터 환경과 통합하여 설정할 수 있었다.
즉, 데이터베이스를 직접 관리하는 부담을 줄이기 위한 선택이었다.
무엇보다 Percona로 데이터베이스를 운영한다면 DynamoDB가 가지는 큰 장점을 비용 때문에 사용하지 못 했는데 Percona면 어느 정도 그 장점을 가져올 수 있었다.
공식 문서와 유튜브 공식 영상이 너무 잘 되어 있어서 그대로만 따라가면 문제없이 구축할 수 있었다.
위 과정을 쭉 따라 구축하면 자동으로 Pod도 띄워지고 PV 설정 등도 알아서 된다.

everest-system 네임스페이스에서 Service 리소스를 보면 everest가 있을 것이다.
kubectl get svc -n everest-system으로 조회할 수 있다.

everest 서비스에서는 데이터베이스 관리를 위한 GUI 를 제공을 한다.
kubectl port-forward -n everest-system svc/everest 8080:8080
이 GUI에서 상태, 백업, 리소스 설정 등 매우 자세하게 할 수 있다.
사실상 GUI를 통한 관리 때문에 Percona를 쓴다고 생각해도 된다.
1. 메인 화면
메인 창에서는 현재 어떤 데이터베이스가 배포되어 있고, 현재 상태와 버전 등 정보를 확인할 수 있다.

2. 상세 화면
아래 사진에서 알 수 있듯이, 비밀번호, 스토리지, 리소스 등 여러 가지를 볼 수 있다.

아래와 같이 노드 당 리소스도 매우 세부적으로 조절할 수 있어서 매우매우 편리하다.

3. 컴포넌트 뷰
컴포넌트 뷰에서는 현재 실행 중인 Pod 상태와 Primary가 누군지 등을 알 수 있다.

4. 백업

즉시 백업을 할 수도 있고, 백업 스케줄을 지정할 수도 있다.
백업 관리를 직접 안 해도 된다는 것이 매우 강력한 기능인 거 같다.

우리는 매주 월요일/목요일에 자동 백업을 실시하도록 했다.
최신 N개의 백업본을 유지시켜서 어느 정도 최신 백업만 유지하도록 설정할 수도 있다.

5. 복구
우리는 다행히 사고가 터진적은 없어서 Restores를 쓸 기회는 없었는데, 백업본을 클릭만 하면 바로 복구를 할 수 있는 것으로 알고있다.
백업과 복구까지 원클릭으로 된다는 것이 너무 편리하다.

지금 되돌아보면, 각 선택은 모두 그 시점에서는 최선이었다.
Docker Compose로 배포할 때는 빠르고 간편한 배포가 중요했고, 클러스터로 들여오면서 가용성이 중요해졌으며, 서비스가 성장하니 안정성과 관리 부담이 핵심이 되었다.
결국 서비스가 어느 정도 성장하게 되고, 안정성과 관리 부담을 줄여야 하는 상황에서 나는 현재 상황을 유연하게 고려하여 Percona라는 해결책을 낸 것이다.
정답 하나가 있는 것이 아니라, 서비스 단계에 맞는 선택이 있을 뿐이라고 생각한다.
개발자는 처음부터 완벽한 구성을 만들기 위해 노력하는 것이 아닌, 서비스의 성장 단계에 따라 요구사항이 어떻게 변하는지를 인식하고, 그에 맞게 유연하게 선택을 조정해 나가야 한다고 생각한다.
지금까지 경험한 바로는 항상 완벽한 해결책은 없다.
서비스의 규모, 팀의 상황, 감당할 수 있는 운영 비용에 따라 그때그때 가장 적절한 선택이 있을 뿐이다.



답글 남기기