Linkerd는 서비스 메시 아키텍처의 핵심 구성 요소로서, 데이터 영역(data plane)에 위치한 프록시가 애플리케이션 간 통신을 효율적으로 처리할 수 있도록 설계되어 있습니다. 이 프록시는 다중 스레드(multithreaded) 방식으로 동작하며, 워크로드 특성에 따라 적절한 수의 작업 스레드를 동적으로 운영할 수 있습니다.
이론적으로 프록시가 사용 가능한 모든 CPU 코어를 활용할 수 있다면 최고의 처리량(throughput)과 최저 지연(latency)을 기대할 수 있습니다. 그러나 실제 환경에서는 이러한 이상적인 조건이 항상 성립하지 않습니다. 왜냐하면 Linkerd 프록시는 일반적으로 애플리케이션 컨테이너와 함께 사이드카(sidecar) 형태로 배포되기 때문입니다. 즉, 각 프록시 인스턴스는 해당 Pod의 입출력 트래픽만 담당하며, 전체 성능은 결국 애플리케이션 자체의 처리 능력에 제약을 받게 됩니다.
예를 들어, 애플리케이션이 초당 100건의 요청밖에 처리하지 못한다면, 프록시가 초당 수천 건을 처리할 수 있더라도 그 의미는 크지 않습니다. 더 나아가 과도한 CPU 자원을 프록시에 할당하면, 오히려 애플리케이션과의 리소스 경쟁으로 인해 전체 시스템 성능이 저하될 수 있습니다. 따라서 개별 프록시의 리소스 사용량을 적절히 조정하여 애플리케이션의 요구에 맞추는 것이 중요합니다. 주요 조정 방법 중 하나는 프록시의 작업 스레드 수를 제어하는 것입니다.
proxy-cpu-limit 애노테이션 사용하기
가장 간단하고 효과적인 방법은 config.linkerd.io/proxy-cpu-limit 애노테이션을 사용하는 것입니다. 이 애노테이션은 프록시 주입 과정에서 프록시 컨테이너에 전달되는 환경 변수를 설정하여, 사용할 CPU 코어 수를 지정합니다.
CLI를 통해 설치할 때는 linkerd install 명령어에 --proxy-cpu-limit 옵션을 추가하면 전역적으로 적용할 수 있습니다.
linkerd install --proxy-cpu-limit 2 | kubectl apply -f -
이 명령은 클러스터 내 모든 새 주입 대상 프록시에 대해 최대 2개의 CPU 코어를 사용하도록 설정합니다.
보다 세부적인 제어가 필요하다면, 특정 디플로이먼트나 네임스페이스 단위로 애노테이션을 적용할 수 있습니다. 예를 들어 다음 YAML은 my-deployment에 포함된 프록시가 1개의 CPU 코어만 사용하도록 지정합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
metadata:
annotations:
config.linkerd.io/proxy-cpu-limit: "1"
spec:
containers:
- name: app-container
image: my-app:latest
주의할 점은 이 애노테이션 값은 정수 형태로 지정해야 하며, 소수점 값은 반올림됩니다. 예를 들어 0.8은 1로 처리됩니다.
Kubernetes CPU 리소스 요청 및 제한 사용하기
또 다른 접근법은 쿠버네티스의 리소스 사양인 resources.limits.cpu와 resources.requests.cpu를 활용하는 것입니다. 하지만 이 방식은 kubelet 설정에 따라 의도치 않은 결과를 초래할 수 있으므로 주의가 필요합니다.
kubelet은 --cpu-manager-policy 설정에 따라 CPU 제한을 다르게 적용합니다.
- 기본 정책 (
none): CFS(C Completely Fair Scheduler) quota를 사용하여 CPU 사용 시간을 제한합니다. 이 경우 프록시가 많은 스레드를 생성해도 커널이 실행 시간을 제한하게 되며, 이는 빈번한 컨텍스트 스위칭을 유발하여 성능에 부정적 영향을 줄 수 있습니다. - 정적 정책 (
static):cgroup cpusets를 사용하여 특정 CPU 코어를 직접 할당합니다. 이 방식에서는 프로세스가 실제로 접근 가능한 코어 수가 줄어들기 때문에, 자연스럽게 프록시가 적은 스레드를 생성하게 되며proxy-cpu-limit과 유사한 효과를 얻을 수 있습니다.
다만, cpuset 기반 할당을 사용하려면 다음 조건을 모두 충족해야 합니다:
- kubelet이
--cpu-manager-policy=static으로 설정되어 있어야 함 - Pod의 QoS 클래스가 Guaranteed여야 함 (모든 컨테이너의 CPU 및 메모리 limit과 request가 일치)
- CPU limit과 request가 모두 1 이상의 정수여야 함
이러한 조건을 만족하지 못하는 환경에서는 proxy-cpu-limit 애노테이션을 사용하는 것이 더 안정적이고 예측 가능한 결과를 제공합니다.
Helm을 통한 설정
Helm 차트를 사용하는 경우, proxy.cores 값과 proxy.cpu.limit 값을 명확히 구분하여 설정해야 합니다. 특히 static CPU 관리자 정책을 사용하지 않는다면, proxy.cores를 명시적으로 지정하여 프록시의 스레드 수를 제어하는 것이 바람직합니다.
# values.yaml
proxy:
cores: 1
cpu:
limit: "1000m"
request: "100m"
이 설정은 프록시가 1개의 코어에서 실행되도록 하고, 동시에 쿠버네티스 리소스 제한을 통해 1000m CPU까지 사용할 수 있도록 보장합니다.