비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축 #5 (MSA 전환과 운영에 대한 tip)

박주진·2021년 9월 10일
0

아래 내용은 비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축 강의를 기반으로 하여 정리한 내용입니다. 자세한 내용 및 코드가 궁금하면 위에 강의를 참고해주세요.

사전작업

구성원 설득

  • monolithic -> MSA 전환은 많은 리소스가 필요한 작업이기 때문에 전환 사유가 명확해야 한다.
    • 서버간의 통신량 증가로 네트워크 리소스 증가
    • 분리되는 서비스가 증가됨으로 관리, 운영, 모니터링 비용 증가
    • 전환 과정에서 기획, 개발 비용 소요
  • 아래와 같은 전조 증상이 있으면 monolithic구조가 회사의 성장을 뒷받침하기 힘든 구조라 볼 수 있다.
    • 개인 감당하기에는 너무 큰 코드 베이스
    • 코드 파악 및 유지보수 어려움
    • 정기배포가 생기고 점점 새로운 기능 구현, 테스트, 배포 속도가 느려짐
    • 막연한 장애 발성 가능성에 때문에 신규 기능 개발과 배포에 대한 부담감 증가
  • 설득시 중요 포인트
    • 기존 업무와 전환 업무를 병행 가능.
    • 전환후에는 시장의 변화에 빠르게 대응가능. 왜냐하면 각 팀마다 자신의 목표와 속도에 맞게 빠르게 개발 및 배포가 가능하기 때문이다.
    • 많은 성공적인 전환 사례 어필.

도메인 의존관계 그리기

  • MSA는 비즈니스 도메인을 중심으로 모델링된 서비스이기 때문에 회사 전체의 비즈니스 도메인을 그려보고 파악해야 한다.
  • 도메인 간의 의존관계 정확하게 파악해야 한다.

먼저 전환할 도메인 찾기

  • 유저 경험,매출과 같은 비즈니스 임펙트가 가장 큰 도메인 먼저!
    • 임팩트가 커야 혜택도 커진다.
  • 신규 기능은 시작부터 MSA기반으로 우선 고려하자!
    • 비즈니스 상황상 굳이 monolithic에서 구현해야 되는 상황이 아니면 MSA기반으로 개발하는 것이 좋다.
  • 한정된 리소스에서 monolithic 과 msa 사이의 적절한 타협!
    • 빠르게 구현이 가능하고 시급하다면 monolithic에서 개발해야 한다. (항상 기술보다 비즈니스 목표가 우선!)

API 체계를 정하기

  • 응답체계는 시스템 전체가 일관된 형태를 가져가야 한다.
    - 일관된 응답체계가 있어야 서비스 전체 모니터링을 구축할 수 있다.
    • 응답 체계 일정되면 서버와 클라인트 간의 불필요한 커뮤니케이션 비용을 줄일 수 있다.
    • 응답 체계 일정하지 않으면 API 불일치가 발생할 가능성이 높아지는데 이는 컴파일 타임에 찾기 힘들다.

과정

단기적인 성과를 빠르게 창출해야 한다

  • MSA전환의 장점을 팀원, 경영진 등 구성원에게 빠르게 증명해야 향후 여러가지 지원을 받을 가능성이 높다.
  • 복잡하지 않지만 유저에게 필요한 신규 기능을 첫 성과를 위해 선택하는게 좋다. 왜냐하면 기존기능에 대한 전환은 유저와 시스템 기준에서 변하는게 없기때문이다.
  • 설계와 구현 측면에서 높은 수준으로 진행해야 한다. 왜냐하면 향후 동료들이 해당 프로젝트를 참고해서 전환을 진행하기 때문이다.

점진적으로 전환하자

  • monolithic에서 MSA로의 빅뱅 방식의 전환은 위험, 높은 부담감, 속도 등과 같은 측면에서 권장하지 않는다.
  • MSA전환전 기존 monolithic서비스에 대해 리팩토링을 진행하면 전환시 많은 도움이 된다.(불필요한 로직제거로 전환이 수월함)
  • 적용할 수 있는 2가지 패턴
    • 스트랭글러 패턴 (Strangler Pattern)
      • monolithic(구 서비스)에서 MSA(신규 서비스)로 전환시 신규 서비스에 유입되는 트래픽을 모니터링하면서 점진적으로 늘여가는 방식
    • shared database 패턴
      • monolithic(구 서비스)에서 MSA(신규 서비스)로 전환시 코드를 먼저 분리하고 데이터베이스는 일정기간 동안 공유하는 방식

데이터베이스 분리

  • 진정한 MSA를 완성하고 SPOF이슈를 방지하기 위해서는 도메인 마다 자체 데이터베이스를 가지고 있어야 한다.
  • 데이터베이스 분리 절차
    • 신규 데이터베이스로 데이터 일괄복제 및 배치를 통해 데이터 동기화 처리
    • 기존 데이터베이스와 신규 데이터베이스에 둘다 write(dual write)
      • 읽기는 기존 데이터베이스에서 처리하도록해 신규 데이터베이스의 데이터 정합성 이슈가 서비스에 영향을 주지 않아야한다.
    • 데이터 정합성의 문제가 없다면 서비스에서 신규 데이터베이스만 사용하도록 변경

현실적인 리팩토링

  • 테스트 코드를 기반으로 진행해야 한다.
  • 테스트 코드가 없는 경우 상세로그를 확보하고 이를 기반으로 테스트 코드를 작성한 후 진행한다.
  • 리팩토링의 필요성을 팀원들에게 납득시키여 한다.(신규 기능 구현 속도 향상, 버그 원인파악 수월 등과 같은 장점들 기반으로 어필)

신규기능은 MSA 기반으로 진행하자

  • monolithic에서 보다 구현 속도가 빠르다. (상황에 따라 다를 수 있을듯 하다.)
  • 데이터베이스 분리가 아직 이루어지지 않았다면 shared database 방식으로 진행해도 무방하다.

운영환경에서 테스트 하자

  • 운영환경과 완전히 동일한 테스트 환경을 구축하는 것은 불가능이기 때문에 운영환경에서 테스트 하는것이 가장 정확한 테스트이다.
  • 운영환경에서 테스트를 진행하기 전에 필요한 사항들
    • 병렬배포 (신규와 실행중인 버전을 같이 배포할 수 있는 환경)
    • 메트릭 기반 모니터링 (이슈 여부 판단)
    • 트래픽 라우팅 (신규와 실행중인 서비스에 대한 트래픽을 조절할 수 있는 환경)
    • 빠르게 롤백할 수 있는 환경
  • 내부 구성원에게만 신규 기능을 오픈하여 운영환경에서 테스트를 진행할 수 있다.

플랫폼 조직의 필요성

  • 개발팀은 도메인 개발에 집중할 수 있도록 MSA의 전반적인 환경(고도하된 배포, 모니터링, 로깅 ,보안 네트워크)에 대한 작업과 의사결정을 진행할 팀이 필요하다.

서버간 통신 매커니즘 정의

  • MSA는 서버간 통신이 빈번하기 때문에 통신 매커니즘 정의는 매우 중요하다.
  • 통신 메커니즘을 요청과 응답방식으로 분류하면 동기식 그리고 비동기식 이벤트 방식이 있다.
  • 메시지 포맷으로 구분한다면 텍스트 기반의 포맷(JSON,XML)과 바이너리(gRPC) 기반의 포맷이 있다.
  • 구체적인 종류들
    • HTTP API
      • 장점: 단순하고 익숙하다.
      • 단점: 동기식이기 떄문에 API 호출 과정에서 양쪽 서버가 모두 실행 중이여 한다.
    • gRPC
      • 장점: 바이너리 기반이기 때문에 매우 빠르다. 데이터 타입을 명확하게 정의할 수 있다.
      • 단점: 학습비용, 브라우저와 같이 클라이언트에서의 gRPC 지원이 아직 미흡하다.
    • 메시지 기반 비동기 메시징
      • 장점: 서버간의 결합도가 낮아진다.
      • 단점: 메시지 브로커 운영경험 필요, 브로커 다운시 전체 장애

고도화

CQRS 뷰 모델 구현

  • 하나의 중앙화된 뷰 데이터베이스를 구축해 다양한 도메인의 데이터를 하나의 API로 조회 가능하도록하는 서비스
  • 각각의 도메인 서비스는 데이터가 변경될 때마다 이벤트를 발생시키면 이를 조회 목적의 데이터베이스에 적용/갱신하는 구조이다.
  • 쿼리 전용 서비스 도입은 아래와 같은 장점이 있다.
    • 트래픽의 대부분을 차지하는 주요 조회 API를 분리할 수 있고 성능을 극대화할 수 있다.
    • 각각의 도메인 서비스는 조회 보다는 CUD와 같은 고유한 기능에 집중할 수 있다.
    • MSA전환으로 클라이언트에서 호출해야 하는 API가 많아지면서 발생하는 성능 및 가용성 이슈를 해결할 수 있다.

kafka 기반의 비동기 메시징 구현시 검토할 내용

  • rebalancing 이슈

    • rebalancing란 consumer group에 consumer가 추가 및 삭제 될때마다 전체 consumer가 메시지 처리 작업을 중단하고 parition을 재할당하는 것
    • 애플리케이션이 배포 될때마다 발생할 수 있어 수시로 배포되는 환경에서는 성능에 큰영향을 줄 수 있다.
    • 해결방안 - kafka2.3 버젼 이후부터는 Incremental Cooperative Rebalancing 라
      는 디자인이 적용되어 해결됨
  • 메시지 순서보장

    • 기본적으로 kafka는 같은 파티션의 메시지만 처리 순서가 보장되고 나머지는 순서가 보장이 안된다.
    • 해결 방안- 메시지 발행시 key값을 넘겨주면 해당 값을 기반으로 파티셔닝 되기때문에 같은 key를 가진 메세지에 한에서는 순서대로 처리된다.
  • 중복 메시지 처리

    • kafka에서 메시지를 consume한 후 처리한 작업에 대해 기록을 못하는 경우 중복 메시지 처리 이슈가 발생할 수 있다.
    • 해결방안
      • consuemr 로직을 멱등하게 구현하여 중복으로 처리되어도 문제가 발생하지 않게끔 구현 한다.
      • 처리된 메시지를 기록하는 테이블을 별도로 두고 consuemr의 처리 로직과 하나의 트랜잭션으로 묶는다. (동일한 메세지를 처리하는 메시지 기록 테이블에 insert 에러가 발생하여 방지 가능)

Graceful shutdown 설정하기

  • 해당 설정이 없으면 배포시 서버가 아직 실행중인 프로세스가 있는데 죽어버려 데이터 정합성 등과 같은 이슈가 발생할 수 있다.

API 호출시 TIMEOUT 설정

  • connection timeout(클라이언트가 서버와 연결을 맺는 과정에서의 timoeout), read timeout (연결이후 서버로 부터 데이터를 수신하는 과정의 timeout)을 무조건 설정해야 한다.
    - 누락되면 서버쪽 응답이 없으면 무한정으로 대기하다 thread가 빠르게 고갈되어 대형 장애가 발생할 수 있다.
  • 클라이언트 timeout 설정은 서버측 처리 시간보다 약간 길게 잡아야 한다.
    • 서버에서는 처리완료 되었으나 클라이언트는 실패로 처리하는 의도치 않은 상황이 발생할 수 있다.

2개의 댓글

comment-user-thumbnail
2021년 11월 23일

잘보고 갑니다. 해당강의가 들을만 한가요!?

1개의 답글