서비스 메시
서비스 간 통신에서 반복되는 일을 애플리케이션 밖의 프록시로 옮기는 구조
왜 필요한가
서비스가 20개면 각 서비스가 같은 일을 20번 구현합니다.
| 반복되는 일 | 내용 |
|---|
| 상호 인증 | 서비스끼리 서로를 확인하고 암호화한다 |
| 재시도와 타임아웃 | 실패에 대응한다 |
| 차단기 | 죽은 상대를 계속 부르지 않는다 |
| 부하 분산 | 여러 인스턴스에 나눈다 |
| 추적 정보 전파 | 요청 식별자를 다음 서비스로 넘긴다 |
| 지표 수집 | 요청 수, 지연, 오류율 |
언어가 여러 개면 더 나쁩니다. Java 용 라이브러리와 Go 용 라이브러리를 각각 만들고 각각 갱신해야 합니다.
구조
각 서비스 옆에 프록시를 붙이고, 모든 통신이 그 프록시를 지나가게 합니다.
| 구성 | 역할 |
|---|
| 사이드카 프록시 | 서비스마다 하나. 실제 트래픽을 처리한다 |
| 제어 평면 | 프록시들에 정책과 설정을 배포한다 |
애플리케이션은 자기 옆의 프록시에게만 보내고, 그 프록시가 상대 프록시로 보냅니다. 애플리케이션 코드는 바뀌지 않습니다.
얻는 것
| 항목 | 내용 |
|---|
| 언어 무관 | 프록시가 처리하므로 어떤 언어로 쓰였든 같다 |
| 코드 변경 없이 정책 적용 | 재시도 횟수를 설정으로 바꾼다 |
| 일관된 지표 | 모든 서비스의 통신 지표가 같은 형식으로 |
| 세밀한 트래픽 제어 | 5%만 새 버전으로 보내는 카나리 |
| 상호 인증 자동화 | 인증서 발급과 회전을 제어 평면이 맡는다 |
대가
| 항목 | 내용 |
|---|
| 지연 추가 | 요청마다 프록시를 두 번 지난다 |
| 자원 사용 | 서비스마다 프록시 프로세스가 하나 더 |
| 운영 복잡도 | 새 계층이 장애 지점이 된다 |
| 학습 비용 | 설정 모델이 복잡하다 |
| 디버깅 | 문제가 애플리케이션인지 프록시인지 구분해야 한다 |
언제 도입하나
| 상황 | 판단 |
|---|
| 서비스가 5개 이하 | 필요 없다. 라이브러리로 충분하다 |
| 언어가 하나 | 라이브러리가 더 값싸다 |
| 서비스가 수십 개, 언어가 여럿 | 값이 나온다 |
| 규제로 구간 암호화가 필수 | 자동화 이점이 크다 |
| 세밀한 카나리가 필요 | 트래픽 제어가 유용하다 |
첫 줄이 중요합니다. 서비스 메시는 반복 비용이 클 때 값이 나옵니다. 서비스가 몇 개뿐이면 도입 비용이 절약분보다 큽니다.
Q.서비스 메시는 무엇을 해결하나요?
서비스 간 통신에서 모든 서비스가 반복 구현하던 것을 밖으로 빼냅니다.
| 반복되던 일 | 메시가 대신하는 방식 |
|---|
| 상호 인증과 암호화 | 프록시가 인증서를 관리하고 구간을 암호화한다 |
| 재시도와 타임아웃 | 설정으로 정의하고 프록시가 적용한다 |
| 차단기 | 같다 |
| 부하 분산 | 프록시가 인스턴스 목록을 알고 나눈다 |
| 추적 정보 전파 | 프록시가 헤더를 이어준다 |
| 지표 수집 | 모든 서비스가 같은 형식으로 |
가장 큰 값은 언어와 무관해진다는 점입니다. Java 와 Go 와 Python 서비스가 섞여 있으면 라이브러리를 세 개 만들고 각각 갱신해야 하는데, 프록시는 하나로 끝납니다.
두 번째 값은 코드 변경 없이 정책을 바꾸는 것입니다. 재시도 횟수나 타임아웃을 조정하려고 20개 서비스를 재배포하지 않아도 됩니다.
흔한 실수: 서비스 메시를 서비스 디스커버리와 같은 것으로 보는 것. 디스커버리는 그 기능의 일부이고, 메시의 범위는 인증, 트래픽 제어, 관측까지 포함합니다.
Q.서비스 메시의 비용은 무엇인가요?
| 비용 | 내용 |
|---|
| 지연 추가 | 요청마다 프록시를 두 번 지난다. 밀리초 단위지만 누적된다 |
| 자원 | 서비스마다 프록시 프로세스가 하나씩 늘어난다 |
| 운영 복잡도 | 제어 평면과 프록시가 새 장애 지점이 된다 |
| 학습 | 설정 모델이 복잡해 팀 전체가 익혀야 한다 |
| 디버깅 | 문제가 애플리케이션인지 프록시인지 구분이 필요하다 |
| 업그레이드 | 프록시 버전 올리기가 전체 서비스에 영향을 준다 |
세 번째가 실제 사고로 이어집니다. 제어 평면 설정을 잘못 배포하면 모든 서비스의 통신이 동시에 영향을 받습니다. 라이브러리 방식이면 서비스별로 배포되므로 영향 범위가 좁습니다.
첫 번째도 지연이 중요한 서비스에서는 무시할 수 없습니다. 요청당 1밀리초가 붙고 호출이 5단계면 5밀리초입니다.
| 판단 기준 | 내용 |
|---|
| 서비스 수 | 5개 이하면 라이브러리가 값싸다 |
| 언어 다양성 | 하나면 라이브러리가 낫다 |
| 팀 규모 | 운영할 사람이 있는지 |
흔한 실수: 기능 목록만 보고 도입하는 것. 얻는 기능은 명확하지만, 그 기능이 지금 실제로 필요한지와 운영할 여력이 있는지가 판단의 중심입니다.
Q.사이드카 프록시는 어떻게 동작하나요?
애플리케이션과 같은 실행 단위에 프록시를 함께 두고, 들고 나가는 모든 트래픽을 그 프록시로 우회시킵니다.
| 단계 | 내용 |
|---|
| 1 | 배포 시 프록시 컨테이너가 함께 주입된다 |
| 2 | 네트워크 규칙으로 트래픽을 프록시로 돌린다 |
| 3 | 애플리케이션은 평소처럼 상대 주소로 요청한다 |
| 4 | 프록시가 받아 정책을 적용하고 상대 프록시로 보낸다 |
| 5 | 상대 프록시가 받아 자기 애플리케이션에 전달한다 |
3번이 이 방식의 값입니다. 애플리케이션 코드는 프록시의 존재를 모릅니다. 라이브러리를 넣거나 주소를 바꾸지 않아도 됩니다.
| 주의할 것 | 내용 |
|---|
| 시작 순서 | 프록시가 준비되기 전에 애플리케이션이 요청하면 실패한다 |
| 종료 순서 | 프록시가 먼저 죽으면 남은 요청이 실패한다 |
| 자원 할당 | 프록시 몫의 CPU 와 메모리를 따로 잡아야 한다 |
| 우회 대상 | DB 접속처럼 프록시를 거치지 않게 할 것을 정한다 |
첫 두 줄이 실제로 자주 겪는 문제입니다. 컨테이너 시작과 종료 순서를 제어하지 않으면 배포마다 소수의 요청이 실패합니다.
흔한 실수: 프록시가 모든 통신을 처리한다고 가정하는 것. 설정에 따라 특정 포트나 대상은 우회하며, 그 부분에는 정책과 지표가 적용되지 않습니다.
Q.서비스 메시 없이 같은 문제를 어떻게 다루나요?
| 방법 | 내용 | 한계 |
|---|
| 공용 라이브러리 | 재시도, 차단기, 추적을 라이브러리로 | 언어마다 만들어야 한다. 갱신 시 전체 재배포 |
| API 게이트웨이 | 외부에서 들어오는 트래픽에 정책 적용 | 서비스 간 통신은 다루지 않는다 |
| 프레임워크 기본 기능 | 스프링이나 gRPC 의 내장 기능 | 언어와 프레임워크에 묶인다 |
| 인프라 계층 | 로드밸런서와 방화벽으로 일부 처리 | 세밀한 제어가 어렵다 |
서비스가 적을 때는 첫 번째가 합리적입니다. 언어가 하나이고 서비스가 다섯 개면, 라이브러리 하나로 대부분을 해결하고 운영할 것도 늘지 않습니다.
규모가 커질 때 첫 번째의 한계가 드러납니다.
| 규모 | 문제 |
|---|
| 언어 3개 | 라이브러리 3개를 각각 만들고 맞춰 갱신한다 |
| 서비스 30개 | 라이브러리 버전을 올리려면 30번 배포한다 |
| 정책 변경 | 코드 변경과 배포가 필요하다 |
그 시점에 서비스 메시가 값이 나옵니다. 순서를 뒤집어 말하면, 라이브러리로 감당이 안 될 때가 도입 시점입니다.
흔한 실수: 마이크로서비스를 시작하면서 함께 도입하는 것. 서비스가 세 개일 때 도입하면 운영 부담만 늘고, 정작 필요한 기능은 프레임워크로 충분합니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
분산 시스템 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.