프로그래밍/디자인패턴

사이드카 패턴(Sidecar Pattern) 완벽 정리

Jinwookoh 2025. 12. 7. 20:57

"우리 회사는 Java, Node.js, Go를 다 씁니다. 그런데 로그 포맷을 변경하려니 3가지 언어의 로깅 라이브러리를 모두 수정하고 배포해야 하네요?"

마이크로서비스 환경에서는 모든 서비스가 인증, 로깅, 모니터링, 트레이싱 같은 공통 기능(횡단 관심사)을 가져야 합니다. 이걸 해결하기 위해 **"내 코드 안에 라이브러리를 넣는 방식"**과 **"내 컨테이너 옆에 도우미 프로세스를 띄우는 방식"**이 치열하게 경쟁합니다.


1. 방식 1: 라이브러리/SDK 방식 (Fat Client) - "코드 내장형"

전통적인 방식입니다. 공통 기능을 .jar나 npm package 형태의 라이브러리로 만들어서 각 마이크로서비스 프로젝트에 의존성으로 추가합니다. 넷플릭스 OSS(Eureka, Ribbon, Hystrix)가 이 방식을 사용했습니다.

특징

  • 언어 종속적: Java용 SDK, Go용 SDK, Python용 SDK를 각각 개발하고 관리해야 합니다.
  • 높은 성능: 프로세스 내부에서 함수 호출로 실행되므로 네트워크 오버헤드가 없습니다.

코드 예시 (Spring Cloud)

Java
 
// build.gradle (라이브러리를 직접 의존)
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
    implementation 'org.springframework.cloud:spring-cloud-starter-sleuth' // 로깅/트레이싱
}

// 애플리케이션 코드
@SpringBootApplication
@EnableHystrix // 코드 레벨에서 기능 활성화
public class MyApplication {
    // 비즈니스 로직과 인프라 로직이 한 프로젝트 안에 섞임
}

장단점

  • 장점:
    • 성능: 네트워크를 타지 않고 메모리 내부에서 동작하므로 가장 빠릅니다.
    • 디버깅: IDE에서 브레이크 포인트를 찍고 한 번에 추적하기 쉽습니다.
  • 단점:
    • 폴리글랏(Polyglot) 지원 불가: 새로운 언어를 도입할 때마다 인프라 라이브러리를 새로 짜야 합니다.
    • 의존성 지옥: 라이브러리 버전을 올리려면 수백 개의 마이크로서비스를 전부 재배포해야 합니다.

2. 방식 2: 사이드카 컨테이너 방식 (Sidecar Container) - "인프라 위임형"

쿠버네티스(K8s)와 서비스 메시(Istio, Envoy)가 주도하는 현대적인 방식입니다. 오토바이 옆에 보조석(Sidecar)을 달고 달리듯, 애플리케이션 컨테이너 옆에 보조 컨테이너를 하나 더 띄워서 통신과 관리를 전담시킵니다.

특징

  • 언어 독립적: 애플리케이션이 Java든 Go든 상관없습니다. 사이드카는 네트워크 패킷만 가로채서 처리하니까요.
  • 투명성: 애플리케이션은 사이드카의 존재를 모릅니다. 그냥 localhost로 통신할 뿐입니다.

설정 예시 (Kubernetes Pod)

YAML
 
apiVersion: v1
kind: Pod
metadata:
  name: my-service-pod
spec:
  containers:
    # 1. 메인 애플리케이션 (비즈니스 로직만 집중)
    - name: main-app
      image: my-java-app:v1
      ports:
        - containerPort: 8080

    # 2. 사이드카 (Envoy Proxy - 로깅, 인증, 서킷브레이커 담당)
    - name: sidecar-proxy
      image: envoyproxy/envoy:v1.18
      args: ["-c", "/etc/envoy.yaml"]
      # 메인 앱으로 들어오고 나가는 모든 트래픽을 가로채서 처리함

장단점

  • 장점:
    • 관리의 분리: 인프라팀이 사이드카 설정만 바꾸면, 개발팀의 코드 수정 없이 보안 정책이나 로그 포맷을 일괄 변경할 수 있습니다.
    • 다양한 언어 수용: 어떤 언어로 개발하든 똑같은 사이드카(Envoy 등)를 붙이면 표준화된 관리가 가능합니다.
  • 단점:
    • 네트워크 오버헤드: 서비스 간 통신 시 App A -> Sidecar A -> Sidecar B -> App B 경로를 타야 하므로 미세한 지연(Latency)이 발생합니다.
    • 리소스 사용량: 모든 파드마다 사이드카 컨테이너가 하나씩 더 뜨기 때문에 메모리와 CPU를 더 많이 먹습니다.

3. 실무 비교: 언제 무엇을 쓰는가?

구분 Library / SDK (Fat Client) Sidecar Container (Service Mesh)
위치 애플리케이션 프로세스 내부 같은 파드(Pod) 내 별도 컨테이너
언어 지원 언어별로 각각 개발 필요 모든 언어 통합 지원
업데이트 앱 코드 수정 및 재배포 필수 사이드카 이미지만 교체 가능
성능 최상 (In-process) 약간 저하 (Network Hop 발생)
복잡도 의존성 관리가 복잡함 **인프라 설정(K8s)**이 복잡함
추천 상황 단일 언어(Java only), 극한의 성능 요구 다양한 언어(Polyglot), 대규모 MSA, Istio 도입

결론

팀이 **"우리는 죽어도 Java와 Spring만 쓴다"**라고 한다면 라이브러리(SDK) 방식이 성능 면에서 유리하고 관리도 익숙할 것입니다.

하지만 **"Node.js도 쓰고 Python도 쓰고 Go도 쓴다"**거나 **"인프라 로직과 비즈니스 로직을 완벽하게 분리하고 싶다"**면, **사이드카 패턴(Service Mesh)**을 도입하는 것이 운영의 지옥에서 탈출하는 유일한 방법입니다.