클라우드 네이티브 설계
- 클라우드에서 최적화된 애플리케이션을 설계, 배포, 운영하는 방식
- 마이크로서비스, 컨테이너 오토스케일링, 분산 시스템을 중심으로 하며, 애플리케이션을 독립적으로 배포하고 관리
vs. monolithic
- 모놀리식은 모든 기능이 하나의 코드베이스로 구성.
- 모든 기능이 함께 배포되고 관리됨
초기에는 간단하지만 시간이 지나고 기능이 늘면 확장성과 유지보수 측면에서 어려움이 생김
- 클라우드 네이티브는 각 기능을 독립적인 마이크로서비스로 구성
- 확장성과 유지보수를 용이하게 한다.
- The Twelve-Factor App은 확장 가능하고 유지 보수성이 높은 애플리케이션을 개발하기 위한 표준이자 원칙이 된다.
- 12요소는 각기 독립적인 모듈로, 애플리케이션이 다양한 클라우드 환경과 하이브리드 환경에서 일관되게 동작하게 하고, 관리할 수 있도록 돕는 설계 원칙이다.
12 Factor App
- codebase
- 하나의 코드베이스를 가져야하며, 이 코드베이스는 버전 관리 시스템에 의해서 추적되어야 한다.
- 하나의 코드베이스를 기반으로 다양한 환경(dev, stage, prod)을 지원할 수 있다.
- 모든 환경은 동일한 코드베이스에서 파생된다.( 다른 버전의 코드를 사용하지 않는다. )
- 동일한 코드베이스로부터 빌드된 여러 배포가 존재할 수 있다.
- dependencies(Explicitly Declare Dependencies)
- 애플리케이션이 의존하는 모든 라이브러리, 패키지를 명시적으로 선언해야 한다.
- 이를 통해 일관된 빌드를 보장하고, 종속성 관련 문제를 최소화한다.
- 모든 의존성은 완벽히 관리되고 동일한 패키지를 사용하도록 보장된다.
- config(Store Config in the Environment)
- 설정정보는 코드 베이스가 아닌 환경 변수나 외부 설정 파일로 분리해야 한다.
- 이는 다양한 환경에서 일관되게 동작할 수 있도록 한다.
- 설정 정보가 코드에 포함되지 않아서 보안 문제도 해결할 수 있다.
- backing services(Treat Backing Services as Attached Resources)
- DB, MessageQueue, Cache 같은 외부 서비스는 백엔드 리소스로 취급된다. (연결된 자원)
- 애플리케이션은 이들 서비스와 독립적으로 실행되어야 한다.
- 백엔드 서비스의 위치나 구성 변경 시에도 애플리케이션의 코드에 수정이 필요하지 않도록 해야 한다.
- 이 접근법은 애플리케이션이 어느 환경에서도 일관되게 동작할 수 있도록 보장한다.
- build release run(Strictly Separate Build and Run Stages)
- 애플리케이션은 build, release, run 단계를 명확히 구분해야 한다.
- 빌드 단계에서는 코드를 컴파일하고, 릴리즈 단계에서는 빌드된 아티팩트와 설정 정보를 결합하며, 실행 단계에서는 해당 릴리즈 버전을 실행한다.
- CI/CD를 통해서 빌드하고, 결과물을 환경 설정과 결합하여 릴리즈 버전을 생성한다.
- 그리고 배포하여 실행한다.
- 코드와 설정 정보 분리 이유는 동일한 코드베이스가 다양한 환경에서 설정만 변경하여 사용할 수 있도록 하기 위함이다.
- processes
- 애플리케이션은 상태를 가지고 있지 않아야 한다.
- 만약 상태를 가져야 한다면 db같은 backing service에 저장되어야 한다.
- port binding(Export Services via Port Binding)
- 애플리케이션이 특정 포트를 통해 외부와 통신할 수 있도록 하는 것이다.
- 외부와의 통신을 위해서 포트 바인딩을 통해서 서비스를 제공해야 한다.
- 이를 통해서 애플리케이션은 웹 서비스와 같은 외부 프로세스에 의존하지 않고 자체적으로 HTTP 트래픽을 처리할 수 있다.
- 웹서버를 이용할 수도 있고, 로드밸런서도 쓸 수 있다.
- 애플리케이션이 포트에 직결해서 서비스 할 수 있다면 더 유연하다.
- 애플리케이션이 외부에 의존 없이 포트 바인딩으로 자체적으로 서비스 제공하면 애플리케이션의 독립성과 확작성을 높인다.
- concurrency(Scale Out via the Process Model)
- 애플리케이션은 프로세스 기반으로 동시성을 처리해야 한다.
- 여러 프로세스나 인스턴스를 통해서 확장성을 제공한다.
- 이는 수평 확장을 통해서 더 많은 트래픽을 처리할 수 있게 한다.
- 동시성: 여러 작업이 동시에 처리될 수 있도록 프로세스를 병렬로 실행하는 것
- 애플리케이션은 프로세스 모델을 통해서 동시성을 제공한다.
- 프로세스 간 상태 공유 없이 독립적으로 동작할 수 있어야 한다.
- disposability
- 프로세스는 언제든 처분될 수 있으며, 이는 언제든지 실행되거나 종료될 수 있음을 의미한다.
- 프로세스의 시작 시간은 최소화되어야 한다.
- 짧은 시작시간은 릴리즈, 스케일 업에 유연성을 부여한다.
- 종료는 우아하게 되어야 한다.
- 또한 고장 발생시 갑작스런 종료에 견고해야 한다.
- dev/prod parity
- 최대한 dev/stage/prod 간 차이가 크지 않아야 한다.
- 시간적 차이: 개발 단계에서 배포 전까지 기간이 반드시 존재한다.
- 인원적 차이: 개발은 개발자가, 배포는 엔지니어가 한다.
- 도구적 차이: 각 단계에서 사용하는 도구가 다르다. - 즉 이 차이들을 줄이려면 주기적으로 지속적으로 배포해야 한다. - 또한 인원 차이를 문서화등 명시적으로 작성하는 것으로 극복해야 한다. - 마지막으로 개발, 배포 간 차이를 줄여야 한다.
- logs(Treat Logs as Event Stream)
- 애플리케이션에서 발생하는 모든 로그는 이벤트 스트림으로 처리되야 한다.
- 별도의 로그 처리 시스템에서 중앙화 하여 관리할 수 있다.
- 로그는 단순 출력이 아니라, 애플리케이션의 상태를 모니터링하고 문제를 디버깅하는 중요한 데이터 소스다.
- EventStream: 애플리케이션에서 발생하는 이벤트를 시간 순서대로 처리하는 방식이다. 이를 통해서 실시간 데이터 분석, 모니터링이 가능하다.
- admin processes(Run Admin/Management Tasks as One-off Process)
- DB 마이그레이션이나 백업 같은 관리자 작업은 애플리케이션의 코드와 별도로 독립적인 프로세스로 관리되어야 한다.
- 이러한 작업은 운영 중인 애플리케이션과 분리되며, 애플리케이션에 영향을 미치지 않도록 처리한다.
- 관리 작업은 독립적 프로세스로 실행되어야 한다.
- 이 작업은 애플리케이션에 영향을 미치지 않아야 한다.
1. CAP
- CAP 이론은 Consistency, Availability, Partition Tolerance 중 두 가지를 선택해야 한다는 이론이다.
- 이 세가지 요소는 서로 상충되기에, 한 시스템에서 세 가지를 동시에 완벽하기 어렵다.
- 아키텍쳐 설계 단계에서 뭘 더 중점을 둘지를 정해야 한다.
- Consistency
- 일관성은 분산 시스템에서 모든 노드가 동일한 데이터 상태를 유지하는 것을 의미한다.
- 한 노드에서 데이터를 업데이트하면, 그 업데이트는 다른 모든 노드에 즉시 반영되어야 한다.
- 장/단점
- 장점: 데이터 신뢰성, 정확성이 높아진다.
- 단점: 모든 데이터를 즉시 동기화해야 해서, 네트워크 지연이나 장애 발생 시 가용성이 떨어진다.
- Availability
- 가용성을 장애가 발생하거나 네트워크가 분리되더라도 모든 요청에 대해서 응답할 수 있는 능력을 의미한다.
- 이는 분산 시스템의 중요한 목표 중 하나다.
- 사용자 요청을 무조건적으로 처리해주는 것을 보장한다.
- 장/단점
- 장점: 사용자 경험이 지속적으로 유지, 시스템 가동 중단을 최소화할 수 있다.
- 단점: 노드 간에 일관성이 일시적으로 깨질 수 있다.
- Partition Tolerance
- 파티션 허용성은 네트워크 분할이 발생했을 때도 시스템이 정상적으로 동작할 수 있는 능력을 의미한다.
- 분산 시스템에서 네트워크 연결이 끊기거나, 일부 노드가 다른 노드와 연결되지 못하는 상황을 의미한다.
- 이런 경우에도 시스템은 가능한 한 정상적으로 작동해야 한다.
- 장/단점
- 장점: 네트워크 분리 시에도 서비스가 계속 제공될 수 있다.
- 단점: 일관성과 가용성 중 하나를 포기해야 한다.

- 일관성 우선: 데이터 정확성이 중요한 경우 선택. 가용성과 파티션 허용성을 어느정도 희생
- 가용성 우선: 대규모 트래픽을 처리해야 하는 경우 선택.
- 파티션 우선: 글로벌 서비스를 제공하는 클라우드 환경에서 선택
2. 데이터 복구, 장애 복구
- 분산 시스템에서 데이터를 여러 노드로 복제하여 시스템의 고가용성을 보장하는 것이 중요하다.
- 데이터 복제는 한 노드에서 데이터를 변경했을 때, 그 변경 사항이 다른 노드에서도 복사되는 것을 의미한다.
- 이를 통해서 장애가 발생해도 데이터를 잃지 않고 시스템을 빠르게 복구할 수 있다.
- 데이터 복제의 중요성
- 고가용성 보장: 하나의 노드에 장애가 발생하더라도 다른 노드에 동일 데이터가 있어서 서비스 중단이 없다.
- 데이터 손실 방지: 실시간으로 데이터를 여러 노드에 복제함으로써, 시스템 장애나 데이터센터의 물리적 손상에서도 데이터 복구가 가능
- 복제 방법
- 동기 복제: 데이터 변경할 떄, 모든 노드가 데이터 변경 사항을 즉시 반영한다. 이는 데이터 일관성을 보장하지만, 지연 시간이 길어질 수 있다.
- 비동기 복제: 데이터 변경 후, 일정 시간이 지난 후에 데이터를 복제한다. 짧은 시간 일관성이 떨어질 수 있지만, 시스템 성능과 가용성이 높아진다.
- 장애 복구 전략
- 자동 복구(Self-healing): 클라우드 네이티브 시스템은 장애가 발생하면 자동으로 복구될 수 있도록 설계되어야 한다.
- 백업, 복원: 중요 데이터는 정기적으로 백업하고, 장애 발생 시 이를 통해서 복원해야 한다. 데이터 손실을 최소화 하기 위해서 여러 데이터 센터에서 복제된 백업을 보유하는 것이 좋다.
3. 네트워크 레이턴시
- 분산 시스템에서 성능을 저하시키는 요소 중 하나
- 노드 간 이동하는데 걸리는 시간을 의미한다.
- latency가 길어지면 응답 시간이 길어져 사용자 경험에 악영향을 미친다.
- 따라서 통신을 최적화해야 한다.
- 레이턴시 발생 원인
- 지리적 거리: 사용자 - 서버 간 물리적 거리가 멀면 느려질 수 있다.
- 네트워크 혼잡: 네트워크가 많은 트래픽을 처리해야 하면 느려질 수 있다.
- 잘못된 라우팅: 네트워크 내에서 잘못된 경로로 전송하면 추가적 레이턴시가 발생할 수 있다.
- 최적화
- CDN 사용: 지리적으로 가까운 서버에서 받을 수 있도록 한다.
- DNS 최적화: 라우팅을 최적화 하여 사용자가 가까운 서버에 연결되도록 한다.
- 오토스케일링 및 로드 밸런싱: 트래픽이 많으면 자동으로 서버를 추가하고, 트래픽을 분배해서 네트워크 혼잡을 방지한다.
- 서비스 간 통신 최적화:
- 서비스 메시: 서비스 메시를 사용해서 마이크로서비스 간 통신을 효율적으로 관리할 수 있다. 서비스 메시를 통해서 통신 경로를 최적화하고, 성능을 모니터링할 수 있다.
- RPC: 원격 노드 간의 통신을 최적화하는 방법이다. 서비스 간 빠른 데이터 전송을 가능하게 한다. gRPC는 RPC를 개선하여, 데이터 전송 속도를 높였다.
4. ServiceMesh/ API gateway
4.1. 서비스 메시
- 분산 시스템에서 마이크로 서비스 간의 통신을 최적화하는 구조다.
- 여러 개의 마이크로 서비스가 통신할 때, 서비스 메시가 각 서비스 간의 트래픽을 라우팅하고, 보안 및 모니터링을 담당한다.
- 주요 기능
- 트래픽 관리: 서비스 간의 통신 경로를 최적화 하고, 필요한 경우 트래픽을 제한하거나 우선순위를 설정
- 보안: 서비스 메시를 통해서 마이크로서비스 간의 통신을 암호화하고, 인증 및 권한 부여 기능을 통해 보안을 강화
- 모니터링 및 로깅: 서비스 메시가 모든 서비스 간의 트래픽을 감시하고, 성능을 모니터링한다. 또한, 로깅 기능을 통해 문제가 발생한 서비스의 통신 기록을 분석할 수 있다.
4.2. API gateway
- 외부 클라이언트가 여러 마이크로서비스에 접근할 수 있도록 라우팅을 제공하는 진입점 역할을 한다.
- 클라우드 네이티브에서는 중요한 역할을 하며, 서비스 메시와 사용되기도 한다.
- 주요 기능
- 트래픽 라우팅: API 게이트웨이는 클라이언트 요청을 적절한 마이크로서비스로 라우팅하여 각 서비스가 개별적으로 처리할 수 있도록 한다.
- 보안: 보안, 인가, 데이터 검증 등의 기능을 제공하여, 외부 클라이언트 - 내부 마이크로서비스 간의 보안을 강화한다.
- 로드밸런싱: 여러 마이크로서비스 간 트래픽을 분산하여, 특정 서비스에 과부화가 걸리지 않도록 조정한다.
API 설계와 버저닝
- 마이크로 서비스 간 통신을 관리하고 데이터를 주고받는 중요한 요소
- 서비스 간 연결성을 보장
- 클라우드 네이티브에서는 여러 마이크로서비스가 독립적으로 배포되고 관리되기에 각 서비스가 다른 서비스와 통신할 수 있도록 API 설계, 버저닝이 중요
- 잘 설계된 API는 확장성, 유지보수성 그리고 서비스 간 안정적 통신을 보장
a. API 설계 원칙
1. RESTful
- REST(REpresentational State Transfer)
- 인터넷 사이 상호 운용성을 제공하는 방법
1.1. 어떻게 정보를 공유할 것인가?
- 장점:
- 표준화되니 방식으로 설계되어, 다양한 클라이언트에서 사용 가능함
- 무상태성으로 인해 서버 확장성이 높다.
- 직관적인 설계를 통해 자원에 대한 접근을 쉽게 이해할 수 있다.
- 단점
- 대규모 요청에서 불필요한 데이터 전송이 발생할 수 있다
- 요청한 데이터 외에도 많은 자원 정보를 보내기 때문에 대역폭이 낭비될
GraphQL
- facebook이 개발한 쿼리 언어, 클라이언트가 단일 엔드포인트롤 통해서 필요한 데이터만 요청할 수 있다.
- 불필요한 정보 송수신을 줄일 수 있다.
- 장점
- 클라이언트가 필요한 데이터만 요청할 수 있어 효율적이다.
- 하나의 엔드포인트에서 다양한 자원에 접근이 가능하다.
- API 변경 시에도 클라이언트와의 호환성을 유지할 수 있다.
- 단점
- 복잡한 쿼리 로직이 많다면 서버 부하가 생길 수 있다.
- GraphQL 스키마를 정의하고 유지관리하는데 추가적인 작업이 필요하다.
gRPC
- 구글에서 개발한 RemoteProcedureCall 프레임워크
- 고성능 통신을 위해서 프로토콜 버퍼를 사용해서 데이터를 직렬화 하고 비동기 통신을 지원한다.
- 마이크로서비스 간의 저지연, 고성능 통신을 위해서 사용된다.
- HTTP/2 프로토콜 기반으로 작동한다.
- 장점
- 프로토콜 버퍼를 사용한 데이터 직렬화로 매우 빠른 데이터 전송이 가능
- HTTP/2 기반으로 다중 요청 및 스트리밍을 지원해서 네트워크 효율이 뛰어남
- 언어에 구애받지 않음
- 단점
- RESTful에 비해 상대적으로 복잡
- 브라우저에서 직접적으로 사용하기 어려움(프록시 서버가 필요)
b. 버전 관리 전략
- 여러 버전으로 존재해야 할 수도 있다.
- 기능이 추가되면서 기존 명세는 유지해야할 수도 있다.
- 이 경우 버전 관리가 중요하다.
- URI, Header, Parameter 세 가지 종류가 있다.
- URI: /v1/users
- 장점:
- 클라이언트가 명확하게 버전을 선택할 수 있다.
- URL에 버전을 포함해서 쉽게 관리할 수 있다.
- 단점
- 여러 버전 API를 유지 관리해야해서 복잡할 수 있다.
- Header: API-Version: v1
- 장점:
- URI를 변경하지 않고도 버전관리를 할 수 있다.
- 클라이언트가 헤더를 통해서 유연하게 API를 선택할 수 있다.
- 단점
- 클라이언트에 요청 헤더를 추가해야한다.
- URI에 버전 명시가 없어서 가시성이 떨어진다.
- Parameter: ~?version=v1 // ~;version=1
- 장점:
- 클라이언트가 요청 파라미터로 버전을 쉽게 설정할 수 있다.
- 버전이 API 경로와는 별개로 관리되기 때문에 URI 설계에 영향을 주지 않는다.
- 단점:
- URL이 복잡해질 수 있다. 파라미터를 일일이 관리해야 한다.
- 쿼리 또는 경로 파라미터가 없는 케이스를 처리해야 한다.