들어가며
디지털 혁신의 시대에 접어들면서 데이터는 기업의 중요한 자산이 되었다.
데이터의 위상이 높아진 것만큼이나 IT 아키텍처에 대한 인식에도 많은 변화가 생겼다. 기업들이 기민한 고객 대응을 위해 MSA(Microservices Architecture, 마이크로서비스 아키텍처)를 선호하는 최근의 추세가 이를 증명한다. 그런데 MSA는 데이터를 분산시켜 정합성 유지에 어려움을 유발한다. 그렇다면 MSA 환경에서 데이터 관리를 어떻게 해야 할까?
본 아티클에서는 수년 간 MSA 구조의 시스템을 다루어 온 필자의 경험을 바탕으로 IT 개발자 및 운영관리자가 염두에 둬야 할 MSA에서의 데이터 관리 방안에 대해 살펴보겠다.
MSA로 시스템을 구축한 후 단위 서비스 별로 DB 간에 공유되어야 할 데이터가 일치하지 않는(틀어진) 경우를 꽤 발견할 수 있다. 수 년 전부터 일치하지 않은 상태로 관리되어 온 데이터를 우연히 발견하면 로그나 추적할 정보가 전혀 남아있지 않다 보니 상당한 고민거리로 작용한다. 불일치가 더 심해진 건 아닌지 파악해보고 싶은데 실시간 데이터 변경이 일어나는 상황에서 정합성을 맞춰보는 것도 쉬운 일이 아니다. 그렇다고 일치하지 않는 데이터가 발견될 때마다 수동으로 맞추는 것도 한계가 있다.
왜 이런 상황이 발생할까? 단순한 버그 문제일 수도 있고 아키텍처 설계가 잘못 되었기 때문일 수도 있다. 버그는 소프트웨어 품질 이슈로 고칠 수 있지만 한 번 구성한 시스템의 아키텍처를 손보는 것은 여간 어려운 일이 아니다. 결국 원인을 분석해보면 기본에 충실하지 않은 아키텍처 설계 때문인 것으로 나타나는 경우가 꽤 많다. 여기서 말하는 “기본에 충실하다”는 것은 “엔터프라이즈 시스템은 고가용성(High Availability, HA)을 전제로 해야 한다”는 사실이다. 99% 이상의 트랜잭션은 당연히 정상적으로 처리되어야 한다. 극히 일부분의 거래가 실패하는데 이의 처리에 얼마나 공을 들였느냐에 따라 서비스 안정성과 운영 비용이 크게 달라진다.
데이터베이스 고가용성
메인프레임(Mainframe)과 유닉스(Unix)로 고성능 대용량 서버를 몇 대 구성하여 모든 트랜잭션을 처리하는 모놀리식 아키텍처(Monolithic Architecture)가 유행했던 시절이 있었다. DB의 고가용성을 보장하기 위해서는 장애 발생 시 처리하던 데이터를 다른 장비에서 재빨리 이어 받아 처리할 수 있어야 했기에 스토리지와 파일시스템의 도움을 받아 장비 간에 데이터를 공유하게 하였다.
이와 같은 DB 고가용성은 클라우드나 MSA 환경에서도 당연히 보장되어야 한다. 클라우드 환경에서는 AWS RDS(Relational Database Service)와 같은 매니지드 서비스를 사용할 수 있고 오픈소스 SW를 활용해 자체 구축할 수도 있다. 페이스메이커(Pacemaker)와 DRBD(Distributed Replicated Storage System)를 조합하여 고가용 스토리지 클러스터를 구성하거나 MHA(Master High Availability)를 활용한 마스터-슬레이브(Master-Slave) 구조의 DB 간 고가용성 솔루션도 있다. 아래 [그림 1]은 인프라 환경에 따른 이중화 구성 방안 예시이다.
2PC(Two-Phase Commit)
서로 다른 DB 간에 완벽한 정합성을 보장하는 방법이다. 어느 순간에도 양쪽의 DB를 조회했을 때 합이 맞게 된다. 프로토콜의 기본 원리는 [그림 2]의 Phase #1과 같이 모든 DB에 반영할 수 있는지 물어봐서 합의가 되었을 때만 반영하고 그렇지 않으면 전체를 철회하는 방식이다. 이를 통해서 부분적으로 적용되는 일을 막을 수 있다. MSA 특성 상 개별 서비스의 패치 작업이 빈번하고 소규모 장애가 더 자주 발생할 가능성이 높다. 따라서 MSA 환경에서 2PC를 적용할 경우 전체 트랜잭션이 취소되어 오히려 단점으로 작용할 수 있으니 신중히 결정해야 한다.
[그림 2]의 Phase #2를 보면 각 DB에 커밋(Commit)이 수행되므로 어느 한 쪽이 먼저 커밋될 수 있다. 이 시점에 양쪽을 조회하더라도 커밋되지 않은 쪽은 락(Lock)이 잡혀 있어서 불일치된 상태로는 절대 조회되지 않는다. 락을 기반으로 정합성은 보장되지만 락이 풀리지 않으면 전역 장애를 유발할 수 있으므로 세밀한 주의가 필요하다.
‘Two-Phase’의 의미는 두 단계의 추가 통신(Prepare & Commit)을 한다는 것이다. SQL이 수행되면 락을 잡기 시작하고 각 DB별로 두 번의 추가 통신을 한 다음 락이 풀리면서 비로소 반영된다. DB별로 최소 세 번의 통신이 이루어져야 하고 락 구간도 길기 때문에 성능이 떨어지는 단점이 있다.
신용카드 회사에서 시스템을 포인트 서비스, 결제 서비스로 구성한 상황을 상정해보자. 포인트를 활용하여 결제 대금을 지불하는 서비스를 구성할 때 포인트는 금전에 준하는 것이라 일시적 불일치도 허용하지 않겠다고 하면 2PC로 보장해 줘야 한다. 다만 위에 언급한 단점들을 감수할 수 있는 경우에만 활용해야 할 것이다.
CDC(Change Data Capture)
지금부터 설명하는 방법은 최종 일관성(Eventual consistency)을 보장하는 방식이다. 일시적으로 양쪽의 합이 맞지 않을 수 있으나 궁극적으로 맞도록 하는 비동기 방식이다. 2PC의 성능이 도저히 감당이 되지 않을 때 전역 장애를 방지하기 위해 비동기 방식을 적용한다. CDC 솔루션은 [그림 3]과 같이 Source·Target DB 간에 비동기 복제 역할을 수행한다. 제품군을 CDC라도 통칭하는데 핵심 기술이 Source DB에서 데이터를 추출하는 것이기 때문이다. DB는 트랜잭션 변경 사항을 로그 파일로 남기는데 종류에 따라서 Oracle은 Redolog, MySQL·MariaDB는 Binlog, PostgreSQL은 WAL로 불린다. 해당 파일에서 변경된 트랜잭션을 뽑아내고 Target DB로는 Insert·Update·Delete SQL문을 수행하여 반영한다.
CDC는 2PC와 정반대로 Target DB에 장애가 발생하더라도 복구될 때까지 반복 수행하면서 기필코 반영시킨다. 2PC의 Phase #2만 수행한다고 보면 된다. Source DB는 이미 반영이 완료된 것으로 취소할 수 없기 때문에 Target DB에 반드시 반영시켜야만 하고 트랜잭션이 끊겨 있으므로 비동기 처리하는 것은 당연하다. 2PC와 반대의 방식이므로 빈번한 작업이 일어나는 MSA 환경에서 일시적인 오류를 잘 넘길 수 있다.
ETL(Extract, Transform, Load)과 CDC가 종종 비교된다. ETL은 주기적으로 SQL 쿼리를 수행하는 방식으로 활용이 가능하지만 서비스 단위로 실시간 동기화되는 CDC 방식이 더 적합하다. 메일·캘린더·미팅·문서 서비스를 제공하는 그룹웨어 시스템을 예로 들어 보겠다. 그룹웨어의 각 서비스에 계정 서비스가 기반 역할을 해줘야 한다. 계정을 처음 생성하면 자동으로 기본 메일함, 캘린더, 문서를 만들어 넣어줘야 한다. 이 때 일시적으로 메일 서비스 패치 작업을 하고 있었더라도 계정 생성에 영향을 주지 않아야 하니 [그림 4]처럼 CDC로 자동화하는 것이 좋은 방법이다. 실제 그룹웨어 시스템은 서비스 종류가 수십 개 이상이므로 이어서 설명할 SAGA 패턴으로 일일이 연계하고 보상 거래를 등록하기 어렵기 때문에 계정 초기화와 같이 반드시 성공해야 하는 경우라면 CDC가 유용하다.
SAGA 패턴
앞에서 언급한 방법들은 모두 시스템 소프트웨어가 보상 처리를 담당하는 방식이었는데 SAGA 패턴은 어플리케이션 개발자가 보상 트랜잭션을 잘 정의하고 누락되지 않도록 구성할 책임을 져야 한다.
구체적인 예를 다루기 전에 클라이언트와 서버 간의 통신에서 발생하는 근본적인 문제에 대해 짚고 넘어가겠다. 극단적인 사례로 생각될 수도 있지만 간과할 경우 찾아내기 어려운 데이터 불일치를 경험할 수도 있기에 언급하고자 한다. [그림 5]와 같이 클라이언트의 요청을 서버가 받아 데이터베이스에 반영하는 것까지는 성공했으나 그 후 클라이언트로 응답을 보내는 과정이 실패할 수 있다. 이 경우 서버는 성공한 상태로 남게 되지만 클라이언트는 오류 응답을 받게 되어 불일치 상태가 된다. 발생하지 않을 것 같지만 수 많은 트랜잭션을 수행하다 보면 이런 상황이 생길 가능성도 배제할 수 없다.
클라이언트는 통신 오류를 받게 되면 서버가 처리에 성공했는지 실패했는지 알 수가 없다. 보상 트랜잭션은 2PC처럼 즉시 취소를 하거나 CDC처럼 처리가 완료될 때까지 반복하는 방법을 써야 한다. 만약 간헐적으로 데이터 불일치가 발생하는데 그 원인을 도저히 모르겠다면 위와 같은 상황은 아닌 지 확인해 볼 필요가 있다.
2PC 설명 시 언급했던 카드 포인트로 결제 대금을 처리하는 경우를 예로 들어 설명해보겠다. [그림 6]과 같이 DB 상태는 단계적으로 변경되며 일시적으로 정합성이 맞지 않는 시점이 존재한다.
포인트 출금까지는 성공한 상태에서 그 이후 단계에 실패하면 포인트를 다시 복원해주거나 결제 대금을 제할 때까지 반복 수행을 해야 한다. 2단계 과정에서 포인트 서비스가 통신 오류 응답을 받았을 때 어떻게 처리하느냐가 중요하다. 다음과 같이 두 가지 방법을 고려할 수 있다.
첫 번째, 포인트를 복원 할 경우 [그림 7]과 같이 처리되어서 결제 대금은 차감되었으나 포인트는 여전히 남아 있어 회사에 손해를 입힐 수 있다. 이를 정상적으로 처리하기 위해서는 통신 오류 발생 시 결제 서비스를 재호출하여 정상 응답이 올 때까지 반복 수행해야 한다. 결제 서비스가 성공하였는데도 재시도될 경우 중복 감액이 되므로 결제 서비스에서는 트랜잭션 ID를 기반으로 중복을 방지해야 한다. 포인트 서비스와 DB 구간에도 마찬가지 이슈가 있으므로 포인트 서비스 역시 재시도 및 중복 방지를 해줘야 한다. 해당 방식은 2PC를 적용한 것과 결과적으로 동일하다.
두 번째, 포인트를 복원하지 않고 결제 대금이 감소될 때까지 재시도하는 방법이 있다. 이 경우는 결제 서비스만 국한해서 재시도와 중복 처리를 해주면 된다. 첫 번째 방식에 비해서 단순하며 CDC를 적용한 경우와 결과적으로 동일하다.
두 가지 방식 중 어떤 것을 선택할 지는 의사결정 사항인데 일반적으로 고객 입장에서는 포인트보다 결제 대금이 적은 것을 선호한다는 전제로 고객 친화적인 서비스를 제공한다면 구현하기가 수월한 두 번째 방식을 택하는 것이 낫다.
SAGA 패턴은 코레오그래피(Choreography)와 오케스트레이션(Orchestration) 방식으로 구현할 수 있다. 코레오그래피는 분산 구조로 서비스 간에 비동기 연계를 통한 이벤트 방식이고 오케스트레이션은 전체 트랜잭션을 관장하는 코디네이터(Coordinator)를 두고 이를 통해 보상 거래를 처리하는 방식이다. 스프링 부트(Spring Boot)와 카프카(Kafka)를 활용하여 각각의 방식을 구현할 수 있다.
SAGA 패턴은 애플리케이션 레벨에서 수행하고 2PC·CDC는 시스템 소프트웨어가 담당하느냐의 차이가 있을 뿐 궁극적인 실행 결과는 동일하다. SAGA 패턴은 표현력이 더 넓어서 보상 트랜잭션 구성 방식에 따라 2PC와 CDC의 효과를 모두 낼 수 있다. 다만 모든 보상 트랜잭션을 완벽하게 구성하는 것이 현실적으로 어려울 수 있으며 단계별 에러 케이스를 다 검증해야 하는 부담이 있다. 강한 정합성(Strong consistency)은 2PC만 보장할 수 있다. 반드시 반영되어야 하는 케이스인데 SAGA 패턴으로 보상 거래를 기술하기 복잡하다면 CDC가 구성이 단순하고 안정적이므로 더 적합하다고 할 수 있다.
마치며
지금까지 분산 시스템 간의 데이터 동기화 방법에 대해 기본 원리와 간단한 사례를 들어 살펴 보았다. SAGA 패턴이 MSA 사상에 가장 부합하는 방식이기는 하나 맹목적으로 따라서는 안 된다. 서비스와 시스템이 추구하는 가장 중요한 목표는 무엇이고 이에 부합하는 최적의 방법이 어떤 것인지를 면밀하게 검토한 후 결정하기 바란다. 장단점을 충분히 이해한 상태에서 기술적으로 감당할 수 있는 방안을 골랐다면 틀에 얽매일 필요는 없다. 잘 발생하지 않을 것 같은 케이스도 고려해야 나중에 이를 해결하기 위한 운영 비용을 절감할 수 있으니 이 점도 꼭 염두에 두기 바란다. 앞서 서술한 내용은 필자의 실제 경험을 단순화하여 정리한 것으로 이 글을 읽는 개발자 및 시스템 운영관리자가 유사한 상황에 놓였을 때 도움이 되기를 바란다.
본문에서 다루지 않았지만 클라우드와 MSA는 리눅스 OS부터 풀스택(Full stack)을 오픈소스 소프트웨어로 전환하는 것을 전제로 하고 있다. 전통적인 상용 소프트웨어(Proprietary software)의 시대는 저물고 있지만 그렇다고 주위 평판만 믿고 오픈소스를 도입했다가는 낭패를 보기 십상이다. 특히 미션 크리티컬한 엔터프라이즈 시스템에 오픈소스를 적용할 때에는 사전에 전문가의 조언을 구해야 한다.
오픈소스를 잘 다루면 IT 역량이 무궁무진해진다. 에스코어는 글로벌 시장에서 검증 받은 주요 오픈소스 소프트웨어에 대한 기술 커버리지를 확보하고 필요 시 소스코드 레벨까지 파고 들어 분석한다. CDC와 같이 운영 환경에 쓸 만큼 성숙한 오픈소스가 없는 경우에는 자체 개발하여 적용하기도 한다. 이러한 오픈소스 전문성을 바탕으로 기업들이 엔터프라이즈 플랫폼을 견고하게 구축·운영할 수 있도록 지원하고 있다.
# References
- DB 이중화 구성방안 MariaDB Korea Conference 발표 https://www.youtube.com/watch?v=yxDHw75SVSs&form=MY01SV&OCID=MY01SV
- Pacemaker https://wiki.clusterlabs.org/wiki/Pacemaker
- DRBD(Distributed Replicated Storage System) https://linbit.com/drbd/
- MHA(Master High Availability) https://github.com/yoshinorim/mha4mysql-manager
- 2PC(Two-Phase Commit) https://en.wikipedia.org/wiki/X/Open_XA
- Consistency Model https://en.wikipedia.org/wiki/Consistency_model
- Data Integration(CDC/ETL 등) https://en.wikipedia.org/wiki/Data_integration
- SAGA pattern https://microservices.io/patterns/data/saga.html
- Choreography Saga Pattern https://www.vinsguru.com/choreography-saga-pattern-with-spring-boot/
- Orchestration Saga Pattern http://www.vinsguru.com/architectural-pattern-orchestration-saga-pattern-implementation-using-kafka/
- 서비스 경량화를 위한 MSA 설계 시 고려사항 https://www.s-core.co.kr/insight/view/%ec%84%9c%eb%b9%84%ec%8a%a4-%ea%b2%bd%eb%9f%89%ed%99%94%eb%a5%bc-%ec%9c%84%ed%95%9c-msa-%ec%84%a4%ea%b3%84-%ec%8b%9c-%ea%b3%a0%eb%a0%a4%ec%82%ac%ed%95%ad
서성한 프로
에스코어(주) 소프트웨어사업부 컨버전스SW그룹
시스템SW 및 오픈소스SW 전문 아키텍트로서 미들웨어, OS kernel, 메일엔진 등을 개발하였습니다. 현재는 오픈소스SW와 엔터프라이즈 플랫폼을 담당하고 있습니다.
Register for Download Contents
- 이메일 주소를 제출해 주시면 콘텐츠를 다운로드 받을 수 있으며, 자동으로 뉴스레터 신청 서비스에 가입됩니다.
- 뉴스레터 서비스 가입 거부 시 콘텐츠 다운로드 서비스가 제한될 수 있습니다.
- 파일 다운로드가 되지 않을 경우 s-core_mktg@samsung.com으로 문의해주십시오.