본문 바로가기
개발/Spring

[스프링 캠프 2024] MSA 실전 가이드

by 윤호 2024. 5. 26.

2024 스프링캠프에서 삼성SDS 김용욱 연사님의 "실전 MSA 개발 가이드" 강연에 대한 내용입니다.

인용 부분은 연사님의 말씀이고 그외 내용은 강연과 제 생각을 추가한 것입니다.

 

실무에서 MSA를 사용했던 경험이 있는데, 두루뭉술하게 생각했던 해법이나 사수의 조언이나 서치로 알아냈던 해법을 정리해볼 수 있었던 시간이었습니다. 뿐만 아니라 고민되었던 부분의 해답도 말씀해주셔서 MSA를 사용해봤다면 얻을게 많았던 유익한 시간이었습니다.

MSA에서 조회

MSA환경에선 분산 데이터베이스를 사용하므로 조인이 필요한 경우 네트워크 통신을 하게된다. 실제 유저가 판단할 만큼의 성능 저하는 발생하지 않는다. 다만, N+1 문제에는 주의가 필요하다.

 

업무환경에선 MSA환경에서 조회 서비스로 graphql을 사용했는데, graphq 데이터로더의 미성숙한 사용으로 N+1 문제가 발생했었다. 기능 추가에 따라 여러 조인을 추가하다 보니 어느 순간 특정 페이지에서 로딩이 28초나 걸리는 상황이 발생했다. 확인해 보니 조회서비스에서 N+1 문제가 있었고, 이를 고치니 1초 대로 성능이 회복됐다.

이처럼 MSA환경에서는 N+1 문제가 더 심각한 성능저하를 발생시키므로 각별한 주의와 성능테스트가 필수적이다.

 

MSA에서 쓰기 - 트랜잭션

MSA 환경에서 가장 불편하고 치명적인 부분이 트랜잭션이다. 분산 환경에서 데이터베이스의 정합성과 무결성을 지키기 위한 여러 작업이 있다. 이런 작업에 대해 정리하고 어떤 방법이 성숙한 방법인지 환인해 볼 수 있었다.

 

트랜잭션 보장이 안되는 환경에서 정합성을 맞추기 위해 기본적으로 대사 작업이 필요하다.

 

대사 작업이란 회계에서 매출금액과 정산금액 따위가 일치하는지 대조하는 작업인데, 여기선 데이터의 정합성을 확인하고 맞추는 일 정도로 생각하면 된다. 

 

이 부분에서 강연을 듣는 많은 사람들이 반응을 보였는데, 아마 나 처럼 대사 작업으로 고생을 많이 한 사람이 아닐까 싶다.

내가 업무에서 운영했던 서비스 또한 시스템 장애, 동시성 문제, 메시지 유실 등으로 정합성이 깨지는 일이 많았다. 주기적으로 발생하는 간단한 이슈들은 직접 원인을 해결하거나 스케줄링을 통해 개발자 손을 거칠 필요가 없게 할 수 있었다. 하지만, 원인을 간단하게 파악할 수 없는 이슈와 스케줄링이 성능에 큰 영향을 미치는 경우 개발자가 수동으로 api를 실행하는 수고를 많이 했다.

 

보통 MSA를 도입하겠다고하면 그 이점과 단편적인 단점만 보고 분리를 결정할 수 있는데, 중요한건 장애가 발생하는 경우와 이를 회복할 때 드는 비용도 파악하고 도입하는게 중요하다.

 

MSA 구조에 대해

데이터는 오너십을 가진 서비스에 배치한다.

 

도메인 별로 서비스를 분리했다면 해당 도메인에 관련된 데이터는 해당 서비스에 몰아 넣는게 일반적인 생각이다. 하지만 실제론 해당 서비스 보다 다른 서비스에서 변경이나 조회가 자주 일어나는 데이터가 있다. 이는 꼭 도메인 영역에 얽매일 필요 없이 자주 사용하는 서비스에서 데이터를 관리하는 것이 좋다.

 

트랜잭션 난이도가 너무 높다? 서비스를 합치거나 경계를 변경해도 괜찮다.

 

설계 시엔 완벽한 설계를 하도록 노력하지만, 완벽할수도 없고 비즈니스 요구사항에 따라 완벽했던 구조가 개발 생산성과 성능을 저하시키는 구조가 되기도한다. 마찬가지로 분산 환경에 대한 구조도 운영하면서 정합성 유지나 성능 측면에서 문제가 된다면 서비스를 합치거나 분리하는 것을 고려해보자.

 

lock은 어플리케이션 레벨에서 해야한다.

 

트랜잭션 보장이 되지 않기 때문에 Lock또한 개발자가 고민해야할 사항 중 하나다. 하지만 실무에선 크리티컬한 서비스는 디비의 락 기능을 쓰지 않는다고 한다. 교착 상태 등으로 더큰 장애가 발생할 수 있기 때문이다. 크리티컬한 도메인은 모놀리식에서도 디비의 락 기능을 이용하기 보단 락 테이블을 만들어 락 기능을 제어하기 때문에, Lock을 따로 관리해야하는 것은 MSA에서 단점으로 볼 수 없다고한다.

 

MSA에서의  오류

MSA에서 많은 오류는 네트워크 통신을 통해 처리해야한다. 이 오류를 어떻게 다루는게 좋을까?

 

API 실패시 단순 재시도는 대부분 안티패턴이다.

 

마이크로 서비스에선 api로 통신할 때가 많은데, 여기서 오류가 발생하는 경우 단순히 재시도 처리하는 것은 좋은 패턴이 아니다.

api 요청에 오류가 발생했다는건 그 서비스에 문제가 발생했을 경우가 높다. 문제가 발생한 서비스에 다시 요청해봤자 같은 오류가 발생할 것이며 오히려 부하만 더 주게 된다.

 

물론 네트워크 통신 장애로 인한 몇 번의 오류는 발생할 수 있다. 여기서 말하는건 그 이상인 듯하다. 단, 단순 네트워크 오류도 단순 재시도 보단 Back Off 전략을 사용하는 것이 좋을 것 같다.

 

참고

Retry 전략에 대해서(Exponential Backoff, Jitter) 

Spring Cloud Stream 재시도 구현하기

 

msa는 아니지만 client에서 graphql을 사용하는데, 여기서 조회가 실패하면 retry를 10번씩 하도록 만들어 특정 오류 발생 시 자체 ddos가 걸리는 웃지 못할 상황도 발생했었다. 그만 큼 retry는 주의가 필요하다.

 

이벤트를 통해서 안정적인 재시도를 할것. 단, 멱등성을 지켜야한다.

 

강연에선 단순 재시도보단 메시지큐를 통한 이벤트로 재시도를 할 것을 강조한다. 하지만 이 또한 완벽하진 않다. 응답은 time out 등으로 실패라고 파악했지만, 실제 내부적으로는 요청이 성공한 경우가 발생한다. 결과적으론 같은 요청이 두 번 발생한다.

 

이렇듯 api 요청이 두 번 이상 될 경우가 있으니 api에 멱등성을 보장해야한다. 예를 들어, 생성 api에서 이미 생성된 데이터가 있으면 이를 무시한다.

 

롤백보단 안전한 재시도

 

데이터베이스에선 트랜잭션 내에서 완전한 롤백을 보장하기 때문에 오류 발생시 롤백을 한다. 이를 MSA에서 그대로 적용하여 특정 기능을 수행하다 오류가 발생하면 관련된 서비스의 데이터를 모두 롤백하는 것을 생각할 수있다. 하지만 이런 방법은 개발자가 직접 트랜잭션과 롤백을 관리해야하기 때문에 쉽지 않다. 복잡한 서비스라면 더더욱 불가능하다.

 

그러므로 단일 디비처럼 기능의 실패 시  롤백을 하는 것 보단 재시도를 통해 완전한 처리를 보장하는 것이 더 유용하다. 물론 이를 위해선 api를 멱등성 있게 만드는 것이 중요하다.

 

MSA에서 통합 테스트는?

다른 서비스 끼리 통합테스트가 필요하다면 잘못된 구조일 가능성이 높다.
단독적으로 배포될 수 있는 단위로 서비스를 나눠야한다.

 

MSA는 필수적인 기술인가?

그렇지 않다. 모놀리식을 대체하기보단 필요에 의해서 사용되는 기술이다.
팀의 규모가 10명 내외면 모놀리식을 유지할 것을 권장한다.

 


MSA는 독립된 작업을 할 수 있게하여 개발 생산성을 높이고, 잘 만들어진 구조라면 성능과 장애 대응측면에서 많은 이점을 보인다.

하지만 미성숙한 MSA의 사용은 성능과 장애, 장애 처리 측면에서 이점을 상쇄할 만큼의 비용이 발생하므로 이를 이해하고 성숙하게 기술을 사용하는게 중요하다.

 

 

 

 

Spring Camp

애플리케이션 서버 개발자들과 함께 가치있는 기술에 관한 정보과 경험을 `공유`하고, 참가한 사람들과 함께 `인연`을 만들고, 시끌벅적하게 즐길 수 있는 개발자들을 위한 '축제'를 목표로 하는

springcamp.ksug.org

댓글