Yunseok's Dev Blog

배운 것을 적는 블로그입니다.

마이크로 서비스란 무엇인가?

마이크로 서비스 인 액션 1장을 읽고 정리해보았습니다.

마이크로 서비스란 무엇인가?

마이크로 서비스란 자율적인 서비스의 집합이다. 이는 가치를 지속적으로 제공할 수 있는 더 나은 방법이다. 우리가 소프트웨어를 개발할 때 높은 응집도느슨한 결합도 를 강조한다. 이런 특성을 가진 시스템은 유지 및 관리가 쉽고 변화에 대처가 쉽기 때문이다. 마이크로 서비스에서도 이러한 특성을 반영하려고 한다. 하나의 마이크로 서비스는 높은 응집력을 가진다. 각 서비스는 서로의 내부 동작을 모를 수록 다른 서비스의 변경을 강요하지 않고도 변경이 쉬워진다.

모놀리식 vs 마이크로 서비스

  • 모놀리식은 일반적으로 수평적 복제를 통해 확장한다. 하지만 마이크로 서비스는 다양한 요건에 따라 분해해 수직적으로도 확장할 수 있다.

핵심 원칙

  • 자율성(Autonomy)
    • 각 서비스는 다른 서비스와 독립적으로 변경되고 운영된다. 느스한 결합과 독립적으로 배포가능하다.
    • 또한 자율성을 문화에 관한 것인데 조직의 구성이 시스템 설계에 영향을 주고 서비스의 소유권이 명확하면 팀이 자치적인 의사결정을 내릴 수 있따. 서비스의 개발과 운영모두를 담당하느 소유방식을 촉진하기에 이상적이다.
  • 회복성(Resilience)
    • 마이크로 서비스를 독립저긍로 배포하면 장애는 시스템의 일부에만 영향을 미친다.
    • 하지만 이는 장애지점이 늘어나는 원인이 된다.
  • 투명성(Transparency)
    • 시스템 하나가 아니라 여러 서비스에 의존하고 상호작용한다. 따라서 시스템이 어느지점에서나 투명하고 관찰 가능해야 문제를 관찰하고 진단할 수 있다.
  • 자동화(Automation)
    • 자동화를 도입하고 서비스 간 일관된 인프라스트럭처를 만들면 부가적인 복잡성을 관리하기 위한 비용을 획기적으로 줄일 수 있다. 정확한 배포와 운영을 보장하려면 자동화를 적용해야 한다.
  • 동기화(Alignment)
    • 개발팀의 노력을 올바른 방향으로 동기화하는 것이 매우 중요하다.

장점: 왜 마이크로 서비스여야 하는가?

  • 기술의 혼재성(Heterogeneity)
    • 비즈니스 문제를 해결할 수 있는 다양한 기술을 선택할 수 있다. 기존의 시스템이 만약 PHP언어를 사용해서 만들어져 있고 새로운 기능을 추가할 때 기존의 언어를 이용해서 만들지 않아도 된다.
  • 마찰과 위험을 줄여준다.
    • 작은 독립적인 변경을 지속적으로 전달할 수 있다.
    • 변경이 쉽고 유연한 시스템을 구축할 수 있고 위험 감소와 함께 지속 가능한 비즈니스 영향을 제공할 수 있다.
    • 의존성을 격리시키고 최소화한다.
  • 독립적으로 개발, 배포, 확장할 수 있다.
  • 교체될 수 있다.

단점: 무엇이 마이크로 서비스를 어렵게 만드는가?

소프트웨어의 복잡성을 제거해주는 마법 같은 기술은 존재하지 않는다. 서비스들이 자율적이 되려면 전체적으로는 느슨하게 연결되고 개별적으로는 기능 요소들이 높은 응집도를 가지도록 설계를 해야하는데 이는 점직적으로 개발해나가야 한다. 서비스 범위가 시간이 지남에 따라 변할 수 있고 새로운 기능을 뗴어내거나 제거할지를 선택해야 한다. 이런 선택이 어려운 일이고 개발 시작단계에서는 더욱더 어려운 일이다.

설계상의 어려움

  • 서비스의 범위를 정하는 것은 도메인 지식을 요구한다.
    • 각 마이크로 서비스가 담당할 역량을 도출하는 것은 비즈니스 도메인 지식이 필요하다. 도메인에 대해 충분히 이해하지 못한상태로 진행한다면 나쁜 디자인이 나올 수 있다.
  • 서비스 간 계약 유지하기
    • 독립적인 서비스과 상호작용하기 위해서는 마이크로 서비스는 계약을 노출한다. 이 것은 서비스가 수신하고 응답하기를 바라는 메세지를 정의 하는 것으로 객체 지향 서비스의 인터페이스와 유사하다.
    • 좋은 계약은 다음과 같은 특성들이 있다.
      • 완전성: 상호작용의 완전한 범위를 정의한다.
      • 충분성: 필요 이상의 정보를 제거해 적절한 범위에서 메시지를 구성한다.
      • 예측성: 무든 구현의 실제 행동을 정확하게 반영한다.
    • 시간이 지나면서 계약은 기존의 API를 사용하는 협력자와의 하위 호환성을 유지하면서 진화해야 하는데 이러한 안정성과 변화사이의 처리가 쉽지 않다.
  • 마이크로 서비스 애플리케이션은 여러 팀이 설계한다.
    • 팀이 다른 독립적인 타임라인과 우선순위를 고려해 개발을 조정해야 한다면 응집력 있는 시스템을 설계하기 어려울 수 있다.
    • 개발을 조율하려면 여러 팀 간의 우선순위와 일하는 방식을 합의하고 조정할 필요가 있다.
  • 마이크로 서비스 애플리케이션은 분산 시스템이다.
    • 애플리케이션 간의 상태에 대한 대기시간, 신뢰성, 일관성을 고려해야 한다. 일단 애플리케이션이 분산되면 하위의 상태 데이터가 곳곳에 분산되어 일관성 문제에 직면한다. 이는 애플리케이션 수준의 설계에 영향을 준다. 일관적이지 않은 상태에서 서비스가 동작하는 방법과 트랜잭션이 실패할 때 롤백하는 방법을 고려해야 한다.

운영상의 어려움

개발할 때는 마찰이 줄지만, 운영 중인 애플리케이션을 배포하고 검증하고 모니터링하는 방법이 더 복잡해진다. 관측 가능성과 장애 지점이 증가한다.

  • 관측 가능성은 달성하기 어렵다.
    • 시스템 전체를 이해하려면 현미경과 광각렌즈 모두를 이용해야 한다.
  • 서비스가 많아지면 장애 지점도 증가한다.
    • 개별 구성요소에 장애가 발생해도 어떻게 하면 시스템이 계속해서 동작할지에 대해 생각해 봐야 한다. 개별 서비스가 에러 검사, 장애 조치, 복구 등에 좀더 견고해질 필요가 있다.

마이크로 서비스 개발 라이프 사이클

설계

  • 모놀리식으로 시작할 것인지, 마이크로 서비스로 시작할지
    • 마이크로 서비스에서는 개발 초기에 시스템의 경계를 이해하기 어렵고, 잘못 설계한 경우 비용이 증가하기 떄문에 모놀리식으로 시작할 수 있다.
    • 마이크로 서비스로 시작할 경우 개발 초기의 속도는 느리지만, 향후 개발에서 마찰과 위험을 줄여준다.
  • 서비스 범위 정하기
    • 서비스가 조직에 제공하는 비즈니스 역량에 근거해 서비스를 모델링 해야한다.
  • 커뮤니케이션
    • 서비스 간의 커뮤니케이션 동기와 비동기가 있다.
    • 동기식 시스템은 추론하기 쉽다
    • 비동기 시스템은 결합도가 낮아서 변경의 위험을 줄여주고 잠재적으로 회복성이 더욱 뛰어나다.
    • 동기와 비동기식 메시징 사이에 균형을 맞춰서 여러 마이크로 서비스 사이에 효과적으로 작업을 조율해야 한다.
  • 회복성
    • 에러가 발생했을 때 백오프를 하거나 품질이 낮은 서비스로부터 요청을 제한하거나 정상 서비스를 동적으로 탐색하는 등의 방어적 설계를 해야 한다.

배포

수많은 자율적인 서비스로 구성된 시스템에서는 개발한 사람이 운영도 해야한다. 새로운 서비스를 배포하는 것이 더이상 특별한 이벤트가 아닌 단계에 도달하게 된다.

  • 배포 산출물 표준화
    • 기술적인 혼재성은 서비스 자율성이 주는 혜택이다. 그러나 배포는 쉽지 않다. 일관성이 없으면 운 환경으로 서비스를 이관하는 방식을 표준화 할 수 없어서 배포를 관리하고 새로운 기술을 도입하는 비용은 증가한다.
    • 컨테이너는 패키징과 애플리케이션의 실행 환경 인터페이스를 표준화 한다. 그리고 운영 환경과 코드 모두에 대해 불변성을 제공한다.
  • 지속 전달 파이프라인 구현하기
    • 지속 전달이란 개발자가 소프트웨어를 언제든 운영 환경으로 신뢰할 수 있게 출시하는 관행을 말한다.
    • 빌드, 단위테스트, 패키지, 통합 테스트, 인수테스트를 거치는 파이프라인을 구축해야 한다. 각 단계는 개발팀에게 코드의 정확성에 대해 피드백을 준다.
    • 반복적으로 서비스를 개발할 때 안전하게 일정한 속도로 개발하도록 도와준다. 제품의 관점에서 신속하게 가설을 검증하고 반복하기 때문에 최적화된 방식으로 일할 수 있게 된다.

관찰

운영환경에서는 시스템에 무슨 일이 일어나고 있는지 알아야 한다. 마이크로 서비스 애플리케이션을 완전히 모니터링 하는 것은 상당히 어려운데 단일 트랜잭션이 여러 서비스에 걸쳐 있기 때문이다. 그러나 시스템의 동작 방식을 이해하고 가까이 관찰하면 시스템을 효과적으로 변경할 수 있게 된다.

  • 잠재적으로 깨지기 쉬운 구현을 식별하고 리팩터하기
    • 시스템은 버그나 실행 환경 에러, 네트워크 장애, 하드웨어 문제 등으로 실패하게 되어있다. 알려지지 않은 버그와 에러를 제거하는 비용이 발생했을 때 신속하고 효과적으로 대응하는 비용보다 높아진다.
    • 모니터링과 알림 시스템은 문제를 진단하고 무엇이 문제를 일으켰는지 결정할 수 있게 도와준다.
    • 이런 장애의 영향을 최소화하고 시스템에 전파되는 것을 방지하기 위해 장애를 국소화하는 방향으로 서비스 간 의존성을 설계할 수 있어야 한다. 서비스 하나가 중단되더라도 전체 애플리케이션이 중단되지 않도록 해야 한다. 장애는 언제든 발생할 수 있다는 것을 인식하고 애플리케이션에서 장애가 발생할 수 있는 지점에 대해 적절한 대을을 준비하는 것이 중요하다.
  • 수백 개의 서비스에 걸친 동작 이해하기
    • 로그와 메트릭을 수집하고 분석과 경보를 위해 한곳에 저장하면 시스템의 행동을 모니터링하고 조사할 때 정보를 한곳에서 얻을 수 있는 시스템을 구축할 수 있다.

운영에 대해 인지하고 책임지는 엔지니어링 문화

작고 독립적인 서비스에 애플리케이션을 개발하는 것은 조직이 엔지니어링에 접근하는 방식을 크게 변경시킨다. 그래서 팀의 문화와 우선순위를 가이드하는 것은 마이크로서비스 애플리케이션의 성공적인 전달 여부를 결정하는 요소다.

Sources

  • 마이크로 서비스 인 액션 - 모건 부르스, 파울로 페레이라