[Microservices] - 4

마이크로 서비스 15원칙

Intro


클라우드 네이티브

퍼블릭/프라이빗/클라우드 환경에서 컨테이너/서비스 메시 등 기존 설정 그대로 느슨하게 이루어진 구조로 어디든 공통적인 환경을 갖도록 하는 것이 클라우드 네이티브의 목적입니다.

Microservice

클라우드 네이티브의 애플리케이션이며 느슨하게 결합되어 병렬 개발, 독립적 배포 및 확장이 가능한 유연성 제공 느슨하게 결합되어 일부 개선이 가능하다는 것이 클라우드 네이티브의 애플리케이션 중 하나라고 볼 수 있습니다.

비즈니스 로직 분리 후 컨테이너 분리 후 도커와 같은 환경으로 배포되며 컨테이너는 가볍고 필요한 패키징만을 포함하기 때문에 여러 인프라에 걸쳐 이식성이 뛰어납니다.

수평 확장으로 트래픽 발생시 모든 트래픽 분리가 가능하며 더 많은 서비스 인스턴스를 추가하는 것도 쉽습니다. (K8s등의 도구로)

개발팀 운영팀과 사이에 중재하는 데브옵스 직책 또한 클라우드 네이티브가 기준으로 작동합니다. 개발 간소화를 위한 통합/지속 제공/자동 배포 파이프라인 및 배포 프로세스 등.

클라우드 네이티브 앱과 기존 앱

서버 문제 발생시 기본 애플리케이션은 예측이 어렵지만 마이크로서비스의 경우 비즈니스 로직이 느슨히 결합되어 문제 추적이 쉽다.

클라우드 네이티브는 OS에 종속되지 않으며 컨테이너 기반에 독립적인 방식으로 환경이 구축되고 용량이 기존 앱 보다 적다. 또한 데브옵스 원칙과 자동화로 지속 제공이 가능하다.

개발 표준 지침

2012년 Heroku Cloud Platform 엔지니어링 팀의 12가지 요소의 방법론이 표준으로 전승되고 있다. 클라우드 네이티브 어플리케이션 개발을 위한 지침은 다음과 같다. 다음 요소들이 충족되어야 클라우드 네이티브앱이라 할 수 있다.

  1. Codebase: 버전 제어에서 추적되는 하나의 코드베이스, 많은 배포
  2. Dependencies: 명시적으로 종속성을 선언하고 격리
  3. Config: 환경에 구성을 저장
  4. Backing services: 백업 서비스를 첨부된 리소스로 처리
  5. Build, release, run: 빌드와 실행 단계를 엄격하게 분리
  6. Processes: 앱을 하나 이상의 상태 비저장 프로세스로 실행
  7. Port binding: 포트 바인딩을 통한 서비스 내보내기
  8. Concurrency: 프로세스 모델을 통한 확장
  9. Disposability: 빠른 시작 및 우아한 종료로 견고성을 극대화
  10. Dev/prod parity: 개발, 스테이징, 프로덕션을 최대한 유사하게 유지
  11. Logs: 로그를 이벤트 스트림으로 처리
  12. Admin processes: 관리/관리 작업을 일회성 프로세스로 실행

이에 추가로 Kevin Hoffman이 3가지 원칙을 더 추가해 15가지 원칙으로 계승되었다.

하나의 코드베이스와 어플리케이션

두개 이상의 애플리케이션이 서로 공통된 코드가 존재하는지 탐색하고 공통 코드를 별도의 독립형 서비스로 배포해야한다. 도커 컨테이너 혹은 패키지 등 각 환경 배포 때마다 개별로 관리하지 않는다.

개발/테스트/운영 환경을 최대한 유사하게 유지해야 한다.

API를 먼저 생각하라

API 우선 접근 방으로 테스트 가능한 통합 작성 및 배포를 수행한다. API 도움으로 서비스를 이용하고 내부 수정사항을 반영한다.

종속성 관리

종속 항목을 명시적으로 선언해야 한다. Maven, Gradle, pom.xml, build.gradle, pakage.json 등.

디자인/빌드/릴리즈/실행

  • 디자인 단계에서는 필요 기술 및 종속성 도구를 결정한다. 개발 및 단위 테스트 등을 설계한다.
  • 빌드 단계에서는 필요 종속성을 사용하여 코드 베이스를 컴파일하고 패키징 한다. 이때 코드베이스는 누군가 수정해서는 안 될 정도로 공통화가 잘 되어 있어야 한다. 수동 작업은 권장하지 않는다.
  • 릴리즈 단계에서는 코드 베이스 패키지를 배포 구성과 결합해야 한다. 데이터베이스 키, 폴더 구조, 서버 config, 마이크로서비스 config, 애플리케이션별 버전 등
  • 실행 단계에서는 지정 환경에서 실행되어야 한다.(컨테이너 등)

자격 증명 및 코드 config

코드에 포함되서는 안되며 기밀 사항인 데이터베이스 키등 모든 구성을 별도로 유지 관리 해야 한다. spring 환경에서는 Spring Cloud Config Server 등으로 관리할 수 있다.

로그 저장

마이크로서비스 100개 서버가 있다고하면 100개별로 로그를 따로 저장하지 않습니다. 하나하나 들여다보는것도 일이니까요. 이 경우 마이크로서비스들의 로그들을 모두 모아 시간 이벤트를 기준으로 한나의 로그로 볼 수 있도록 Log Aggregator tool을 이용하는것이 좋습니다.

Disposability

마이크로서비스 내부에서 수백 개 서비스가 있어 여러 인스턴스가 실행됩니다. 수동으로 상태를 모니터링하고 점검은 쉽지 않습니다. 이 경우 k8s와 같은 도구로 자동으로 새 인스턴스로 교체하거나 트래픽 부하가 높은 경우 레플리카를 생성하여 관리합니다. 시스템 탄력성을 보장하죠.

Backing services

마이크로서비스는 데이터베이스, SMTP서버, FTP서버, 메시지 브로커 등 같은 다른 많은 외부 리소스에 의존합니다. 이런 지원 리소스의 경우 코드 내부를 변경할 필요없이 연결을 유지해야합니다.

또한 다른 데이터베이스 혹은 다른 서비스로 쉽게 전환 가능하도록 지원해야합니다.

Environment parity

환경 동등성으로 운영시 어떠한 환경이 달라지더라도 가능한 한 동등하게 작동하도록 유지해야 합니다. CI/CD 파이프라인 자동화 및 코드 개발 프로덕션 배포 시간 등 타임갭이 동일해야 합니다.

개발자는 개발을 하고 플랫폼 운영자는 운영을 해야합니다. DevOps문화를 받아들여 인력 격차를 줄이고 협력이 가능하도록 해야합니다. 환경이 동일해보이도록 하는 것이 중요합니다.

서비스 관리 도구 또한 동등해야합니다. 개발, 데모, 프도덕션 모두 동등한 지원 서비스를 이용해야합니다. 어떤 곳은 H2 DB가 아니라 PG를 쓰고 하는건 안되죠.

Adminstrative processes

마이그레이션 데이터 정리 데이터 업데이트 등 데이터베이스는 관리할 요소가 많습니다. 이런 유지 관리 작업은 격리된 프로세스로 처리되고 있어야 합니다. 따로 패키징 되어 있어야하죠. 개발 단계에서는 이를 수행하지 않고 운영에서만 적용할 수도 있지만 이 방법은 피해야합니다.

프로세스를 잘 설계하고 동일하게 적용하는 훈련이 필요합니다. 기존 서비스는 유지하면서 마이그레이션은 새롭게 패키징된 애플리케이션이 실행되는 각 환경에 배포되어야하죠. 독립 적인 마이크로서비스로 필요할 때 한번만 사용하고 작업이 완료되면 폐기하는 방법이 좋습니다. 사용자 입장에서 최대한 영향을 줄여야 합니다.

Port 바인딩

모든 CNA는 독립적이고 해당 서비스를 포트 바인딩을 통해 노출해야합니다. 애플리케이션은 실행시 외부 서버를 의존하면 안됩니다. Java App의 경우 Tomcat서비스를 통해 노출하죠 CNA에서는 Tomcat과 같은 외부서비스에 의존하지 않도록 하는 것이 중요합니다.

모두 패키징된 자체 독립형 서버로 시작하는 애플리케이션이어야 합니다. 애플리케이션을 노출 포트를 지정하고 CNA는 포트 바인딩을 통해 외부의 요청을 받도록 해야 합니다. 외부 Tomcat 서버나 외부 서버에 의존하는 CNA는 절대로 구성해선 안됩니다.

Stateless processes

CNA는 높은 확장성을 가지고 개발된 마이크로서비스입니다. 주요 원칙 중 하나는 무상태 프로세스로 설계하는것입니다. 여러 인스턴스가 실행되는 단일 마이크로서비스가 있고 계정 마이크로서비스와 같은 사용성이 높은 서비스의 경우 쉽게 확장할 수 있어야 합니다.

일부 데이터를 저장하거나 인메모리로 데이터를 저장하고 있는 경우 비즈니스 로직에 영향이 발생할 수 있으므로 이 경우 Redis 캐시 등을 이용해 저장해야 합니다. 내부에서 인메모리 데이터를 가지고 있어선 안됩니다.

Concurrency(동시성)

Stateless도 중요하지만 여러 사용자를 수용할 수 있는 동시성 또한 중요합니다. 동시 처리를 지원해야 하죠. 많은 요청을 동시에 병렬로 처리할 수 있어야 합니다. Java는 JVM으로 이런 동시성을 지원하는 기능이 내장되어 있습니다. 스레드 풀에서 스레드 하나 하나가 병렬로 요청을 처리하죠.

또한 더 많은 트래픽을 감당하기 위해 하드웨어를 업그레이드 하는 경우 수직적 확장 보단 수평적 확장을 우선해야 합니다.

Telemetry(원격 모니터링 및 측정)

마이크로서비스를 사용하면 여러 컨테이너가 실행됩니다. 이 경우 모니터링을 어떻게 수행할 수 있을까요? 한 곳에서 확인 가능하도록 모니터링하는 툴을 사용해야 합니다. 효과적인 관리를 위해서는 어떤 종류의 데이터가 필요한지, 로그, 지표, 추적, 상태 및 이벤트와 같은 원격 측정 데이터를 모니터링 해야합니다. 툴을 활용한 원격 측정이 지원되어야 합니다.

인증 및 권한 부여

보안은 SW 시스템에서 아주 중요합니다. 제로 트러스트 접근 방식을 준수해야합니다. 인증 및 권한 부여 외에 개발자의 책임도 있습니다. SSL 인증 및, 검증된 프로토콜 통신, 방화벽 보호가 있을 수 있죠.