DevOps/사고실험

MSA에서 데이터베이스 아키텍처 설계해보기 (RDBMS)

마늘냄새폴폴 2025. 6. 21. 18:14

가트너의 MSA 아키텍처에서 보면 MSA를 3티어 아키텍처로 두고 여러개의 파트로 분리해놓은 것을 보고 일단 데이터베이스부터 설계를 해야겠다는 생각을 했습니다. 

 

MSA에서 데이터베이스를 설계할 때 제가 중요하게 생각한 관점은 다음과 같습니다. 

 

  1. RDBMS는 거대한 상태 덩어리이므로 stateless 애플리케이션에 적합한 k8s에 적합하지 않다. 때문에 데이터베이스는 클러스터 외부 베어메탈 머신에서 돌아가야한다. 이런 상황에서 쿠버네티스 클러스터 내부에 있는 애플리케이션과 상호작용 해야한다. 
  2. 마스터 - 슬레이브 아키텍처로 마스터 노드에선 쓰기 작업을, 슬레이브 노드에선 읽기 작업을 해야하며 마스터 노드의 장애시 슬레이브 노드가 마스터 노드로 승격되어야한다. 되도록이면 Automatic Failover를 지향한다. 
  3. 반드시 수평 확장이 가능해야한다. 

 

이 전제 조건을 바탕으로 한번 본격적으로 시작해보겠습니다. 

 

MSA 에서 데이터베이스 아키텍처

 

우선 제가 설계한 아키텍처 먼저 살펴보고 왜 선택하게 되었는지를 첨언하도록 하겠습니다. 

 

  1. 앞에 전제조건대로 쿠버네티스 클러스터 내부엔 데이터베이스를 넣지 않습니다. 앞서 언급했듯이 거대한 상태 덩어리인 데이터베이스 (특히 RDBMS) 를 stateless 애플리케이션에 최적화된 쿠버네티스 클러스터에 넣지 않기로 결정했습니다. 베어메탈 머신에서 데이터베이스를 직접 설치해서 사용하는걸로 정했습니다. 
  2. 데이터베이스는 MySQL (혹은 MariaDB) 을 선택했습니다. 이건 그냥 제가 MySQL을 많이 써봐서 생태계도 잘 알고 있고 친숙해서 사용했습니다. 
  3. 데이터베이스 HA 솔루션으로는 VTOrc를 선택했습니다. Vitess와 Orchestrator를 결합한 VTOrc는 서로의 단점을 보완하는 관계이기에 제가 생각하는 아키텍처에 잘 맞을거라고 생각했습니다. 
  4. 쿠버네티스 클러스터 내부에 있는 파드에서 MySQL 클러스터에 연결하기 위해 라우터를 하나 두어야하는데 맨 처음엔 ProxySQL을 생각했으나 조금 더 찾아보니 VTOrc에 VTGate라는 비슷한 기능이 있어서 Vitess와 통합을 생각해서 VTGate를 사용했습너ㅣ다. 
  5. VTGate는 etcd에 등록된 MySQL 프록시인 VTTablet을 찾아가는 라우터이기에 Write / Read 쿼리에 따라서 마스터, 슬레이브로 요청을 나눠줄 수 있고 지금 누가 마스터고 누가 슬레이브인지 상태를 관리하기위해 etcd를 적극 활용합니다. 이 etcd는 절대 죽으면 안되기 때문에 3중화를 진행했습니다. 

 

하나씩 풀어보겠습니다. 

 

쿠버네티스 클러스터에 RDB 넣어 말아 논쟁

쿠버네티스 커뮤니티에선 이 논쟁이 아직도 뜨거운 감자입니다. 누구는 galera 클러스터를 10개씩 (3중화가 기본인 galera를 10개 넣는다는건 30개의 파드를 띄운다는것) 쿠버네티스에 띄워서 사용했다느니 누구는 도커로 데이터베이스를 띄우는것도 반대인데 쿠버네티스 클러스터에 어떻게 띄우냐느니 말이 많습니다. 

 

저도 마땅한 답을 찾지 못했기에 선배님들 의견을 따라가려고 합니다. 컨퍼런스에서 연사자로 나오셨던 여러 분들과 대화해보고 제 멘토분도 아직은 쿠버네티스 클러스터에 RDB를 띄우는건 이르다. 라는 판단이기에 저도 그 판단에 따르도록 하겠습니다. 

 

이에 대해서 쓴 블로그 글이 있으니 그걸 참고해보시는 것도 괜찮을 것 같습니다. 

 

https://coding-review.tistory.com/562

 

쿠버네티스 클러스터에 RDB배포 해? 말어? 에 대한 논쟁

요즘 사이드 프로젝트 때문에 실습만 주구장창 했는데 오랜만에 이론 포스팅입니다. 쿠버네티스를 공부하다보면, 그리고 DevOps에 대해 공부하다보면 한번쯤은 보게 되는 논쟁 바로 "쿠버네티스

coding-review.tistory.com

 

InnoDB 진영 HA 솔루션 VTOrc

InnoDB 진영에선 HA 솔루션으로 Vitess와 Orchestrator를 조합한 VTOrc를 주로 사용합니다. 실전에서 한번도 사용해본적은 없지만 그래도 대세를 따르려합니다. 

 

Vitess, Orchestrator를 단독으로 사용할 수도 있지만 VTOrc가 서로의 단점을 잘 보완해주어 장점만 뽑아먹을 수 있게 설계되어있어서 VTOrc를 선택했습니다. 

 

Orchestrator만 단독으로 사용한다면 레플리카 토폴로지에 등록된 노드들의 정확한 메타데이터를 알지 못하는 경우가 있고 Vitess만 사용하는 경우 마스터 - 마스터 레플리카를 절대 금지하고 있는 상황이라 Write 연산의 부하를 분산시켜주기 위해서 Orchestrator를 사용합니다. 

 

이 덕분에 Orchestrator는 Vitess로 인해 더 정확한 메타데이터를 확보해 마스터 - 슬레이브 아키텍처에서 승격에 필요한 확실한 정보를 알게 되었고 샤딩까지 가능하게 되었습니다. Vitess는 Orchestrator의 마스터 슬레이브 승격 매커니즘과 마스터 - 마스터 레플리카 전략도 가져갈 수 있게 되었죠. 

 

물론 둘 다 누가 지금 마스터고 누가 슬레이브인지에 대한 상태정보를 알아야하는데 가끔 Automatic Failover를 Orchestrator가 진행하는 과정에서 순식간에 끝나거나 정상적으로 종료되지 않으면 Orchestrator가 마스터라고 인식하고 있지만 Vitess는 슬레이브로 인식하는 경우가 있긴합니다. 

 

하지만 이 경우 Orchestrator가 지속적으로 싱크를 맞춰주기 때문에 큰 문제는 없다고 판단하였습니다. 

 

Orchestrator와 Vitess의 합작에 대한 포스팅도 준비되어있으니 아래의 링크를 참고해주시면 감사하겠습니다. 

 

https://coding-review.tistory.com/543

 

Orchestrator를 이용한 MySQL 레플리케이션 그리고 장애회복

MySQL은 다양한 레플리케이션 전략을 가지고 있습니다. 동기, 반동기, 비동기 이렇게 세 가지 전략을 가지고 있죠. 그 중에서 Orchestrator는 비동기 레플리케이션을 구현할 수 있게 해주는 서드파티

coding-review.tistory.com

 

쿼리 라우터 VTGate

쿼리가 읽기면 슬레이브로 쓰기면 마스터로 이동시키는 VTGate를 앞에두고 모든 파드들이 VTGate를 바라보게 하였습니다. 일단 기본적으로 MySQL 클러스터가 이리저리 흩어져있는데 이를 한군데 모아줄 라우터가 필요하다고 판단했기 때문이죠. 

 

처음에 바로 떠오른 것은 ProxySQL이었습니다. 왜냐하면 ProxySQL이 MySQL 전용 라우터이고 복잡한 라우팅도 가능하고 자체적으로 데이터베이스 커넥션을 관리해주기 때문에 MySQL진영에서 많이 사용한다고 들었습니다. 

 

그럼에도 제가 VTGate를 채택한 이유는 Orchestrator와 통합하기 위해서였습니다. 

 

Orchestrator의 마스터 - 슬레이브 아키텍처가 마스터 노드 장애시 슬레이브 노드의 승격으로 HA솔루션을 제공하는만큼 꼭 필요하다고 생각했고 Orchestrator를 사용하려니 Vitess를 사용하는것이 맞겠다고 판단하였습니다. 

 

처음엔 ProxySQL - Galera cluster - Orchestrator 로 이어지는 아키텍처를 구상했는데 ProxySQL의 문제가 뭐였냐면 만약 마스터 노드의 장애로 슬레이브 노드가 승격시 ProxySQL이 이를 직접적으로 알 수 있는 방법이 없다는 것이었습니다. 

 

때문에 이를 알기 위해선 Orchestrator에서 제공하는 API로 현재 마스터 - 슬레이브 정보를 가져왔어야했고 이를 crontab으로 확인해야했죠. 

 

하지만 쿼리가 쏟아지는 와중에 crontab과 마스터 - 슬레이브 승격간에 시간차이가 생겨버리면 데이터 유실이 심히 우려되어 이 방법은 사용하지 않았습니다. 

 

etcd 삼중화

etcd가 VTGate의 상태관리 역할을 하는데 단일 노드로는 잘 활용하지 않습니다. 때문에 노드를 세개 두어 삼중화 작업을 진행했습니다. 또한 etcd는 내부적으로 HA 솔루션을 가지고 있는데 Raft라는 분산 합의 알고리즘을 이용해서 마스터가 죽어도 정상적으로 작동할 수 있기 때문에 안전하다고 판단했습니다. 

 

etcd는 비교적 삼중화 작업이 간단하고 Raft 덕분에 잘 죽지도 않아서 매우 만족스러운 설계라고 생각했습니다. 

 

Raft에 대한 내용도 작성한 포스팅이 있으니 아래의 링크를 참고해주시면 감사하겠습니다. 

 

https://coding-review.tistory.com/590

 

쿠버네티스의 분산 합의 알고리즘 (Raft 알고리즘)

최근에 사이드 프로젝트를 하느라 코딩을 많이해서 그런가 요즘은 이론 공부에 집중하게 되더군요. 조금 딴소리지만 처음 공식문서를 읽게 된게 Baeldung의 로컬 트랜잭션과 글로벌 트랜잭션인데

coding-review.tistory.com

 

마치며

MSA 사고실험은 일단 3 tier 에서 가장 뒤쪽부터 시작할 생각입니다. 왜냐하면 기반이 튼튼해야 뒤에서 설계할 아키텍처에도 힘이 실리기 때문이죠. 일단 사용자로부터 가장 멀리 떨어져있는 Data Access Tier 부터 처리하고 천천히 앞으로 나아가보겠습니다. 

 

이번 데이터베이스 아키텍처는 제가 평소에 꾸준하게 공부하던 데이터베이스 관련 지식들이 많은 도움이 되었습니다. 딱히 공부할게 많지 않아서 금방 끝난 것도 있는 것 같습니다. 

 

다음 포스팅은 애플리케이션 레벨에서 이 데이터베이스에 어떻게 접근할 것인지 설계해보려고합니다. 다음 포스팅도 많은 기대 부탁드립니다. 

 

긴 글 읽어주셔서 감사합니다. 오늘도 즐거운 하루 되세요~