
DevOps의 성능 최적화 및 테스트 효율성 가이드
인사말 (Intro)
안녕하세요. 숨고 DevOps Engineer Lyon입니다.
현재 숨고의 DevOps Chapter는 SRE 업무를 포함하여 다양한 역할을 수행하며 한 팀으로서의 효율성을 극대화하고 있습니다. 효율화에 대해선 여러 카테고리가 있지만 최근에 집중했던 영역 중 하나는 성능 최적화입니다.
성능 최적화는 단순히 속도를 높이는 것에 국한되지 않고, 사용자 경험을 극대화하고 운영 효율성을 증대시키는 핵심 과정입니다. 또한, 성능 테스트는 이러한 최적화를 검증할 수 있는 필수적인 단계로, 시스템의 안정성과 신뢰성을 확보하는 데 필수적입니다.
이번 글에서는 성능 최적화의 정의와 목표, 필요한 이유, 성능 테스트의 프로세스와 계획, 그리고 숨고의 실제 사례를 통해 성능 테스트의 유용성에 대해 소개하고자 합니다. 더불어 성능 최적화와 테스트의 관계에 대한 설명과 이를 통해 얻은 인사이트를 공유하고자 합니다.
성능 최적화(Performance Optimization) 가이드라인
성능 최적화 정의 (Definition of Performance Optimization)
성능 최적화(Performance Optimization)는 시스템, 소프트웨어, 네트워크 및 애플리케이션 등 다양한 기술 환경에서 성능을 개선하는 과정입니다. 이 과정은 속도, 처리량, 자원 효율성 그리 안정성 등 여러 측면에서 이루어지며, 궁극적으로 사용자 경험과 운영 효율성을 극대화하는 것을 목표로 합니다.
성능 최적화의 주요 목표 (Key Objectives of Performance Optimization)
성능 최적화의 목표는 여러 가지가 있습니다. 먼저, 응답 시간 단축을 통해 사용자가 요청한 작업을 더욱 빠르게 처리할 수 있습니다. 그리고, 처리량 증가를 통해 단위 시간당 처리 가능한 작업의 수를 늘려 시스템의 효율성을 높일 수 있습니다.
자원 효율성 개선 또한 중요한 목표입니다. CPU, 메모리, 디스크 I/O, 네트워크 대역폭 등 자원의 활용도를 최적화하여 비용을 절감할 수 있습니다. 그 밖에도, 확장성 향상을 통해 사용량 증가 시에도 성능을 유지할 수 있도록 설계하고, 안정성 보장을 통해 과부하 상황에서도 시스템이 안정적으로 작동하도록 개선하는 것 역시 성능 최적화의 주요 목표입니다.
성능 최적화가 필요한 이유 (Reasons for the necessity of performance optimization)
성능 최적화는 여러 이유로 필수적입니다. 첫째, 빠른 응답속도를 통해 사용자 경험 제고에 큰 기여를 할 수 있습니다. 둘째, 비용 절감을 통해 자원을 효율적으로 사용하면 불필요한 하드웨어 증설이나 클라우드 사용량 증가를 방지할 수 있습니다.
셋째, 경쟁력 확보를 통해 성능이 뛰어난 애플리케이션이나 서비스는 시장에서 차별화 요소로 작용할 수 있습니다. 마지막으로, 확장 가능성을 통해 트래픽 증가에도 성능이 유지되는 시스템을 구축함으로서 비즈니스 성장을 효과적으로 지원할 수 있습니다.
성능 최적화의 주요 대상 (Primary Targets of Performance Optimization)
성능 최적화의 주요 대상 중 하나인 애플리케이션에서는 알고리즘과 데이터 구조를 최적화하고, 병렬 처리, 비동기 작업, 캐싱 등의 기법을 활용하여 성능을 향상시킵니다. 데이터베이스에서는 쿼리 성능을 개선하고, 인덱스를 효율적으로 사용하여 데이터 조회 속도를 높입니다.
네트워크 최적화는 CDN을 사용하여 콘텐츠를 사용자와 가까운 서버에서 제공하고, 데이터 압축 및 최적화된 전송 경로를 통해 대역폭을 절약합니다. 시스템에서는 CPU, 메모리, 디스크 I/O 자원의 효율적인 사용을 최적화하고, 가상화 및 컨테이너화 기술을 도입하여 자원 관리를 개선합니다. 마지막으로, 인프라에서는 클라우드 환경에서 오토 스케일링을 설정하여 유연하게 리소스를 사용할 수 있도록 합니다.
성능 최적화의 기본 프로세스 (Basic Process of Performance Optimization)
성능 최적화는 몇 가지 기본 단계로 이루어집니다. 첫째, 병목 현상 분석을 통해 성능 문제를 진단합니다. 이를 위해 Datadog, New Relic, Prometheus, Grafana와 같은 프로파일링 및 모니터링 도구를 활용합니다. 둘째, 응답 시간 20% 단축 등의 구체적인 목표를 설정합니다.
셋째, 개선 방안 적용 단계에서는 코드 최적화, 데이터베이스 쿼리 튜닝, 캐싱 도입 등의 방안을 실행합니다. 넷째, 테스트 및 검증을 통해 변경 사항의 효과를 확인합니다. 마지막으로, 반복 개선을 통해 지속적으로 성능 데이터를 모니터링하며 최적화 작업을 반복합니다.
성능 최적화와 성능 테스트의 관계 (Relationship Between Performance Optimization and Performance Testing)
성능 최적화는 성능 테스트 (소프트웨어의 성능을 측정하고 검증하는 과정)를 통해 발견된 문제를 해결하는 과정입니다. 성능 테스트를 통해 시스템의 성능 저하가 발생하는 지점과 원인을 파악하고, 이를 바탕으로 성능 최적화를 진행합니다. 최적화 작업을 완료한 후에는 다시 성능 테스트를 실행하여 개선 효과를 확인하고, 필요한 추가 최적화를 진행하는 반복적인 과정입니다.
성능 테스트는 성능 문제를 식별하고 한계를 측정하는 데 필요하며, 성능 최적화는 성능 테스트에서 발견된 문제를 해결하고 시스템 성능을 향상시키는 과정입니다. 성능 최적화 후 다시 성능 테스트를 실행하여 개선된 결과를 확인하고 추가 최적화가 필요한지를 판단합니다. 결론적으로, 성능 테스트와 성능 최적화는 시스템이 최대 성능을 발휘하도록 협력하는 중요한 역할을 합니다. 이러한 과정을 통해 보다 나은 사용자 경험과 운영 효율성을 달성할 수 있습니다.
다음 문단에서는 성능 최적화와 필수 불가결인 관계인 성능 테스트에 대해 자세히 알아보고자 합니다.
성능 테스트(Performance Testing)란?
성능 테스트 정의 (Definition of Performance Testing)
성능 테스트는 소프트웨어의 성능을 측정하고 검증하는 중요한 과정입니다. 이 과정에서는 특정 워크로드 환경에서 응답 시간, 안정성, 확장성, 가용성 그리고 리소스 사용량 등의 주요 지표를 평가합니다. 이를 통해 소프트웨어가 고객에게 높은 가치를 제공할 수 있는지를 판단할 수 있습니다.
- 응답 시간 : 사용자의 요청에 대해 소프트웨어가 반응하는 데 걸리는 시간입니다
- 안정성 : 다양한 부하 조건에서도 서비스 품질을 일정하게 유지할 수 있는 능력입니다
- 확장성 : 워크로드가 증가하거나 시스템 리소스의 한계에 도달했을 때, 시스템이 수직 또는 수평으로 확장하여 품질을 유지할 수 있는 능력입니다
- 가용성 : 부하 상황에서도 요구되는 서비스 품질(p99 응답 시간 XXms 이하)을 유지하며 지속적으로 고객에게 서비스를 제공할 수 있는 능력입니다
성능 테스트 프로세스 (Performance Testing Process)
성능 테스트는 다음과 같은 단계로 진행됩니다.
- 테스트 항목 정의 : 성능 테스트의 목적과 측정해야 할 주요 지표를 명확히 설정합니다
- 테스트 조건 정의 : 테스트를 수행할 환경, 부하 조건, 테스트 데이터 등을 설정합니다
- 테스트 시나리오 생성 : 실제 사용자 워크로드를 시뮬레이션할 수 있는 구체적인 테스트 시나리오를 만듭니다
- 점검 항목 확인 : 테스트 결과를 바탕으로 유효한 결론을 도출합니다
성능 테스트 유효 결론 도출하기 (Valid Conclusions from Performance Testing)
성능 테스트의 결과에서 도출할 수 있는 유효한 결론은 다음과 같습니다.
- 테스트 목표 달성 여부 : 설정한 목표(예: 응답 시간, 처리량)가 달성되었는지 확인합니다
- Peak Time 서비스 안정성 : 피크 타임에 애플리케이션 및 데이터베이스 등 제3자 서비스가 안정적으로 작동했는지 평가합니다
- 트래픽 증가에 따른 확장성 : 트래픽 증가에 대해 수직(Scale-Up) 및 수평(Scale-Out) 확장이 원활히 이루어졌는지를 평가합니다
- 최소 리소스 요건 : 일부 시스템이 다운되더라도 서비스 수행을 위한 최소 리소스가 무엇인지 분석합니다
- 오버 프로비저닝 여부 : 시스템 및 서비스가 과도하게 프로비저닝되어 불필요한 리소스를 사용하고 있는지 검토합니다
- 시스템 및 서비스 메트릭 분석 : CPU 사용률, 메모리 사용량, I/O 대기 시간 등의 메트릭 데이터를 통해 병목 현상을 파악합니다
- 최적의 설정값 제안 : 목표 달성을 위해 필요한 설정값과 구성을 제시합니다
성능 테스트 계획 (Performance Testing Plan - Grafana k6)
개발자 친화적이고 확장 가능한 오픈 소스 부하 테스트 도구인 Grafana k6를 활용하여 성능 테스트를 계획하면 다양한 시나리오와 워크로드를 기반으로 설계할 수 있습니다. 숨고의 DevOps Chapter에서는 주로 Stress Testing*에 초점을 맞추어 시스템의 한계를 평가하고 안정성을 검증합니다. 아래 표는 성능 테스트 계획을 위한 테스트 케이스별 예시입니다.
Test | Case | Type | Workload | Automation | Frequency |
---|---|---|---|---|---|
GETendpoint | Top Throughput | Spike | VUs 10,000, duration 10m | Scenario: constant-vus | Automation Testing |
GETendpoint | Most Time Consuming | Load | MaxVUs 5,000, duration 10m | Scenario: constant-arrival-rate | Developer Self Testing |
GETendpoint | Top Throughput | Stress | MaxVUs 30,000, iterations 15m | Scenario: ramping-vus | Focused Testing and Automation in DevOps |
GETendpoint | Top Slowest | Stress | MaxVUs 15,000, iterations 15m | Scenario: ramping-vus | Focused Testing and Automation in DevOps |
*Stress Testing은 시스템이 과부하 상태에서도 정상적으로 작동할 수 있는지를 확인하는 테스트입니다. 이 테스트의 주요 목표는 시스템의 안정성을 측정하고, 최대 성능 한계를 파악하는 것입니다. 또한, 장애 상황에서의 복구 가능성을 검토하여 시스템의 전반적인 신뢰성을 높이는 데 기여합니다.
성능 테스트는 단순한 점검을 넘어, 소프트웨어의 품질을 지속적으로 향상시키고 사용자에게 더 나은 경험을 제공하는 중요한 단계입니다. 이러한 과정을 통해 우리는 시스템의 전반적인 건강 상태를 평가하고, 최적의 성능을 유지하기 위해 필요한 조치를 취할 수 있습니다.
성능 테스트 도구 (Performance Testing Tools): Grafana k6 활용 가이드
Grafana k6 Operator 패턴
Kubernetes 환경에서 k6-operator를 통해 동작하며, 이는 숨고의 성능 테스트 인프라에서도 적극 활용되고 있습니다. k6-operator를 통해 테스트 인프라를 쉽게 구성하고 유지할 수 있습니다.


숨고의 성능 테스트 인프라 아키텍처
숨고의 성능 테스트는 Karpenter on EKS로 구성되어 있으며, Terraformer를 통해 운영 환경과 동일한 세팅을 수집하여 Alpha 정보로 변환하여 비용 효율적으로 운영됩니다. LGTM 스택을 적용함으로써, 프로메테우스 부하 없이 Grafana k6 결과 메트릭을 수집할 수 있는 구조입니다.

숨고의 성능 테스트 사례 (Performance Testing Case of Soomgo)
주요 테스트 사례와 결과 (Key Test Cases and Results)
숨고는 다양한 성능 테스트 시나리오를 통해 시스템의 병목 현상을 발견하고 최적화하고 있으며, 트래픽 증가에 따른 시스템의 반응, 확장성 테스트, 데이터베이스 쿼리 성능 등을 포함하여 다양한 사례를 보유하고 있습니다. 그중에서도, Stress Testing을 통해 얻은 개선 효과를 공유하고자 합니다.
성능 테스트해 보기 (Try Performance Testing)
숨고의 성능 테스트 인프라 아키텍처를 기반으로 설계된 환경에서 k6-operator를 사용하는 k6 manifest 예시입니다.
apiVersion: k6.io/v1alpha1 kind: TestRun metadata: name: k6-xxx-service spec: parallelism: 4 cleanup: post script: localFile: ./test.js runner: image: soomgo/k6 env: - name: K6_PROMETHEUS_RW_SERVER_URL value: "<http://mimir-nginx.monitoring.svc.cluster.local:80/api/v1/push>" - name: K6_PROMETHEUS_RW_TREND_STATS value: "count,sum,min,max,avg,med,p(90),p(95),p(99)" - name: K6_OUT value: "experimental-prometheus-rw" # Custom environment variables - name: URI value: "<https://alpha.com/>" - name: AUTH_ENABLED value: "true" - name: TOKEN value: "Bearer XXXX" resources: limits: cpu: 3600m memory: 7Gi requests: cpu: 3600m memory: 7Gi nodeSelector: eks.amazonaws.com/nodegroup: k6 kubernetes.io/arch: arm64 tolerations: - effect: NoSchedule key: system-type operator: Equal value: k6 arguments: --config ./ramping-vus/5000-15m.json --tag testid=k6-xxx-service-001
위의 설정대로 테스트를 실행하면 Loki를 통해 아래와 같은 로그를 확인할 수 있습니다.
2025-XX-XX 12:27:59.402 { 2025-XX-XX 12:27:59.402 "paused": null, 2025-XX-XX 12:27:59.402 "vus": null, 2025-XX-XX 12:27:59.402 "duration": null, 2025-XX-XX 12:27:59.402 "iterations": null, 2025-XX-XX 12:27:59.402 "stages": null, 2025-XX-XX 12:27:59.402 "scenarios": { 2025-XX-XX 12:27:59.402 "throughput": { 2025-XX-XX 12:27:59.402 "executor": "ramping-vus", 2025-XX-XX 12:27:59.402 "startTime": null, 2025-XX-XX 12:27:59.402 "gracefulStop": null, 2025-XX-XX 12:27:59.402 "env": { 2025-XX-XX 12:27:59.402 "SERVICE_TYPE": "xxx-service" 2025-XX-XX 12:27:59.402 }, 2025-XX-XX 12:27:59.402 "exec": "stress", 2025-XX-XX 12:27:59.402 "tags": { 2025-XX-XX 12:27:59.402 "test_type": "api" 2025-XX-XX 12:27:59.402 }, 2025-XX-XX 12:27:59.402 "startVUs": 100, 2025-XX-XX 12:27:59.402 "stages": [ 2025-XX-XX 12:27:59.402 { 2025-XX-XX 12:27:59.402 "duration": "15m0s", 2025-XX-XX 12:27:59.402 "target": 5000 2025-XX-XX 12:27:59.402 } 2025-XX-XX 12:27:59.402 ], 2025-XX-XX 12:27:59.402 "gracefulRampDown": null 2025-XX-XX 12:27:59.402 } 2025-XX-XX 12:27:59.402 }, 2025-XX-XX 12:27:59.402 "executionSegment": null, 2025-XX-XX 12:27:59.402 "executionSegmentSequence": null, 2025-XX-XX 12:27:59.402 "noSetup": null, 2025-XX-XX 12:27:59.402 "setupTimeout": null, 2025-XX-XX 12:27:59.402 "noTeardown": null, 2025-XX-XX 12:27:59.402 "teardownTimeout": null, 2025-XX-XX 12:27:59.402 "rps": null, 2025-XX-XX 12:27:59.402 "dns": { 2025-XX-XX 12:27:59.402 "ttl": null, 2025-XX-XX 12:27:59.402 "select": null, 2025-XX-XX 12:27:59.402 "policy": null 2025-XX-XX 12:27:59.402 }, 2025-XX-XX 12:27:59.402 "maxRedirects": null, 2025-XX-XX 12:27:59.402 "userAgent": null, 2025-XX-XX 12:27:59.402 "batch": null, 2025-XX-XX 12:27:59.402 "batchPerHost": null, 2025-XX-XX 12:27:59.402 "httpDebug": null, 2025-XX-XX 12:27:59.402 "insecureSkipTLSVerify": null, 2025-XX-XX 12:27:59.402 "tlsCipherSuites": null, 2025-XX-XX 12:27:59.402 "tlsVersion": null, 2025-XX-XX 12:27:59.402 "tlsAuth": null, 2025-XX-XX 12:27:59.402 "throw": null, 2025-XX-XX 12:27:59.402 "thresholds": null, 2025-XX-XX 12:27:59.402 "blacklistIPs": null, 2025-XX-XX 12:27:59.402 "blockHostnames": null, 2025-XX-XX 12:27:59.402 "hosts": null, 2025-XX-XX 12:27:59.402 "noConnectionReuse": null, 2025-XX-XX 12:27:59.402 "noVUConnectionReuse": null, 2025-XX-XX 12:27:59.402 "minIterationDuration": null, 2025-XX-XX 12:27:59.402 "ext": null, 2025-XX-XX 12:27:59.402 "summaryTrendStats": [ 2025-XX-XX 12:27:59.402 "avg", 2025-XX-XX 12:27:59.402 "min", 2025-XX-XX 12:27:59.402 "med", 2025-XX-XX 12:27:59.402 "max", 2025-XX-XX 12:27:59.402 "p(90)", 2025-XX-XX 12:27:59.402 "p(95)" 2025-XX-XX 12:27:59.402 ], 2025-XX-XX 12:27:59.402 "summaryTimeUnit": null, 2025-XX-XX 12:27:59.402 "systemTags": [ 2025-XX-XX 12:27:59.402 "check", 2025-XX-XX 12:27:59.402 "error", 2025-XX-XX 12:27:59.402 "error_code", 2025-XX-XX 12:27:59.402 "expected_response", 2025-XX-XX 12:27:59.402 "group", 2025-XX-XX 12:27:59.402 "method", 2025-XX-XX 12:27:59.402 "name", 2025-XX-XX 12:27:59.402 "proto", 2025-XX-XX 12:27:59.402 "scenario", 2025-XX-XX 12:27:59.402 "service", 2025-XX-XX 12:27:59.402 "status", 2025-XX-XX 12:27:59.402 "subproto", 2025-XX-XX 12:27:59.402 "tls_version", 2025-XX-XX 12:27:59.402 "url" 2025-XX-XX 12:27:59.402 ], 2025-XX-XX 12:27:59.402 "tags": { 2025-XX-XX 12:27:59.402 "testid": "k6-XXX-service-001" 2025-XX-XX 12:27:59.402 }, 2025-XX-XX 12:27:59.402 "metricSamplesBufferSize": null, 2025-XX-XX 12:27:59.402 "noCookiesReset": null, 2025-XX-XX 12:27:59.402 "discardResponseBodies": null, 2025-XX-XX 12:27:59.402 "totalDuration": "15m30s", 2025-XX-XX 12:27:59.402 "maxVUs": 5000 2025-XX-XX 12:28:52.037 % Total % Received % Xferd Average Speed Time Time Time Current 2025-XX-XX 12:28:52.037 Dload Upload Total Spent Left Speed 2025-XX-XX 12:28:52.114 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0100 240 100 153 100 87 1990 1131 --:--:-- --:--:-- --:--:-- 3157 2025-XX-XX 12:28:52.118 % Total % Received % Xferd Average Speed Time Time Time Current 2025-XX-XX 12:28:52.118 Dload Upload Total Spent Left Speed 2025-XX-XX 12:28:52.121 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0100 240 100 153 100 87 53930 30666 --:--:-- --:--:-- --:--:-- 117k 2025-XX-XX 12:28:52.125 % Total % Received % Xferd Average Speed Time Time Time Current 2025-XX-XX 12:28:52.125 Dload Upload Total Spent Left Speed 2025-XX-XX 12:28:52.214 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0100 240 100 153 100 87 1719 977 --:--:-- --:--:-- --:--:-- 2727 2025-XX-XX 12:28:52.218 % Total % Received % Xferd Average Speed Time Time Time Current 2025-XX-XX 12:28:52.218 Dload Upload Total Spent Left Speed 2025-XX-XX 12:28:52.221 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0100 240 100 153 100 87 45863 26079 --:--:-- --:--:-- --:--:-- 80000
테스트가 정상적으로 실행되면 Grafana 대시보드에서 실시간으로 테스트 결과를 확인해볼 수 있으며 테스트가 완료되면 결과를 요약하여 결과 측정 항목에 대한 통합된 통계 값이 표시됩니다.
2025-XX-XX 12:43:54.215 2025-XX-XX 12:43:54.215 ✓ http response status code is 200 2025-XX-XX 12:43:54.215 2025-XX-XX 12:43:54.215 checks.........................: 100.00% 479706 out of 479706 2025-XX-XX 12:43:54.215 data_received..................: 574 MB 636 kB/s 2025-XX-XX 12:43:54.215 data_sent......................: 79 MB 87 kB/s 2025-XX-XX 12:43:54.215 failed_requests................: 0.00% 0 out of 479706 2025-XX-XX 12:43:54.215 http_req_blocked...............: avg=9.43µs min=1.38µs med=2.71µs max=51.34ms p(90)=3.4µs p(95)=3.78µs 2025-XX-XX 12:43:54.215 http_req_connecting............: avg=5.85µs min=0s med=0s max=51.29ms p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.215 http_req_duration..............: avg=197.32ms min=51.18ms med=155.93ms max=1.49s p(90)=393.48ms p(95)=475.73ms 2025-XX-XX 12:43:54.215 { expected_response:true }...: avg=197.32ms min=51.18ms med=155.93ms max=1.49s p(90)=393.48ms p(95)=475.73ms 2025-XX-XX 12:43:54.215 http_req_failed................: 0.00% 0 out of 479706 2025-XX-XX 12:43:54.215 http_req_receiving.............: avg=29.6µs min=9.64µs med=28.43µs max=35.54ms p(90)=36.37µs p(95)=40.65µs 2025-XX-XX 12:43:54.215 http_req_sending...............: avg=7.78µs min=4.09µs med=7.08µs max=473.2µs p(90)=9.43µs p(95)=12.88µs 2025-XX-XX 12:43:54.215 http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.215 http_req_waiting...............: avg=197.28ms min=51.15ms med=155.9ms max=1.49s p(90)=393.44ms p(95)=475.69ms 2025-XX-XX 12:43:54.215 http_reqs......................: 479706 532.042607/s 2025-XX-XX 12:43:54.215 iteration_duration.............: avg=1.19s min=1.05s med=1.15s max=2.49s p(90)=1.39s p(95)=1.47s 2025-XX-XX 12:43:54.215 iterations.....................: 479706 532.042607/s 2025-XX-XX 12:43:54.215 vus............................: 441 min=0 max=1250 2025-XX-XX 12:43:54.215 vus_max........................: 1250 min=1250 max=1250 2025-XX-XX 12:43:54.215 2025-XX-XX 12:43:54.268 2025-XX-XX 12:43:54.268 ✓ http response status code is 200 2025-XX-XX 12:43:54.268 2025-XX-XX 12:43:54.268 checks.........................: 100.00% 479493 out of 479493 2025-XX-XX 12:43:54.268 data_received..................: 573 MB 636 kB/s 2025-XX-XX 12:43:54.268 data_sent......................: 79 MB 87 kB/s 2025-XX-XX 12:43:54.268 failed_requests................: 0.00% 0 out of 479493 2025-XX-XX 12:43:54.268 http_req_blocked...............: avg=11.53µs min=2.28µs med=4.62µs max=46.64ms p(90)=5.57µs p(95)=6.25µs 2025-XX-XX 12:43:54.268 http_req_connecting............: avg=6.07µs min=0s med=0s max=46.57ms p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.268 http_req_duration..............: avg=197.34ms min=50.89ms med=155.88ms max=1.47s p(90)=393.69ms p(95)=475.42ms 2025-XX-XX 12:43:54.268 { expected_response:true }...: avg=197.34ms min=50.89ms med=155.88ms max=1.47s p(90)=393.69ms p(95)=475.42ms 2025-XX-XX 12:43:54.268 http_req_failed................: 0.00% 0 out of 479493 2025-XX-XX 12:43:54.268 http_req_receiving.............: avg=46.05µs min=16.81µs med=44.16µs max=23.73ms p(90)=56.78µs p(95)=64.27µs 2025-XX-XX 12:43:54.268 http_req_sending...............: avg=13.87µs min=7.04µs med=11.95µs max=20.18ms p(90)=20.09µs p(95)=22.02µs 2025-XX-XX 12:43:54.268 http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.268 http_req_waiting...............: avg=197.28ms min=50.84ms med=155.82ms max=1.47s p(90)=393.63ms p(95)=475.37ms 2025-XX-XX 12:43:54.268 http_reqs......................: 479493 531.816961/s 2025-XX-XX 12:43:54.268 iteration_duration.............: avg=1.19s min=1.05s med=1.15s max=2.47s p(90)=1.39s p(95)=1.47s 2025-XX-XX 12:43:54.268 iterations.....................: 479493 531.816961/s 2025-XX-XX 12:43:54.268 vus............................: 627 min=0 max=1249 2025-XX-XX 12:43:54.268 vus_max........................: 1250 min=1250 max=1250 2025-XX-XX 12:43:54.268 2025-XX-XX 12:43:54.327 2025-XX-XX 12:43:54.327 ✓ http response status code is 200 2025-XX-XX 12:43:54.327 2025-XX-XX 12:43:54.327 checks.........................: 100.00% 479432 out of 479432 2025-XX-XX 12:43:54.327 data_received..................: 573 MB 636 kB/s 2025-XX-XX 12:43:54.327 data_sent......................: 79 MB 87 kB/s 2025-XX-XX 12:43:54.327 failed_requests................: 0.00% 0 out of 479432 2025-XX-XX 12:43:54.327 http_req_blocked...............: avg=11.87µs min=2.35µs med=4.61µs max=74.81ms p(90)=5.54µs p(95)=6.27µs 2025-XX-XX 12:43:54.327 http_req_connecting............: avg=6.13µs min=0s med=0s max=74.74ms p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.327 http_req_duration..............: avg=196.95ms min=51.66ms med=155.52ms max=1.49s p(90)=392.98ms p(95)=474.38ms 2025-XX-XX 12:43:54.327 { expected_response:true }...: avg=196.95ms min=51.66ms med=155.52ms max=1.49s p(90)=392.98ms p(95)=474.38ms 2025-XX-XX 12:43:54.327 http_req_failed................: 0.00% 0 out of 479432 2025-XX-XX 12:43:54.327 http_req_receiving.............: avg=46.23µs min=17.68µs med=44.35µs max=4.99ms p(90)=57.37µs p(95)=64.81µs 2025-XX-XX 12:43:54.327 http_req_sending...............: avg=13.67µs min=6.97µs med=11.82µs max=2.51ms p(90)=19.89µs p(95)=21.72µs 2025-XX-XX 12:43:54.327 http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.327 http_req_waiting...............: avg=196.89ms min=51.61ms med=155.46ms max=1.49s p(90)=392.91ms p(95)=474.32ms 2025-XX-XX 12:43:54.327 http_reqs......................: 479432 531.776881/s 2025-XX-XX 12:43:54.327 iteration_duration.............: avg=1.19s min=1.05s med=1.15s max=2.49s p(90)=1.39s p(95)=1.47s 2025-XX-XX 12:43:54.327 iterations.....................: 479432 531.776881/s 2025-XX-XX 12:43:54.327 vus............................: 1 min=0 max=1249 2025-XX-XX 12:43:54.327 vus_max........................: 1250 min=1250 max=1250 2025-XX-XX 12:43:54.327 2025-XX-XX 12:43:54.386 2025-XX-XX 12:43:54.386 ✓ http response status code is 200 2025-XX-XX 12:43:54.386 2025-XX-XX 12:43:54.386 checks.........................: 100.00% 479928 out of 479928 2025-XX-XX 12:43:54.386 data_received..................: 574 MB 636 kB/s 2025-XX-XX 12:43:54.386 data_sent......................: 79 MB 87 kB/s 2025-XX-XX 12:43:54.386 failed_requests................: 0.00% 0 out of 479928 2025-XX-XX 12:43:54.386 http_req_blocked...............: avg=13.71µs min=2.28µs med=4.73µs max=51.67ms p(90)=5.67µs p(95)=6.38µs 2025-XX-XX 12:43:54.386 http_req_connecting............: avg=6.23µs min=0s med=0s max=51.6ms p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.386 http_req_duration..............: avg=197.19ms min=51.57ms med=155.62ms max=1.43s p(90)=393.94ms p(95)=475.51ms 2025-XX-XX 12:43:54.386 { expected_response:true }...: avg=197.19ms min=51.57ms med=155.62ms max=1.43s p(90)=393.94ms p(95)=475.51ms 2025-XX-XX 12:43:54.386 http_req_failed................: 0.00% 0 out of 479928 2025-XX-XX 12:43:54.386 http_req_receiving.............: avg=47.23µs min=17.86µs med=45.27µs max=5.17ms p(90)=58.37µs p(95)=65.77µs 2025-XX-XX 12:43:54.386 http_req_sending...............: avg=13.97µs min=7.18µs med=11.99µs max=1.85ms p(90)=20.19µs p(95)=21.93µs 2025-XX-XX 12:43:54.386 http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s 2025-XX-XX 12:43:54.386 http_req_waiting...............: avg=197.13ms min=51.5ms med=155.56ms max=1.43s p(90)=393.88ms p(95)=475.46ms 2025-XX-XX 12:43:54.386 http_reqs......................: 479928 532.28729/s 2025-XX-XX 12:43:54.386 iteration_duration.............: avg=1.19s min=1.05s med=1.15s max=2.44s p(90)=1.39s p(95)=1.47s 2025-XX-XX 12:43:54.386 iterations.....................: 479928 532.28729/s 2025-XX-XX 12:43:54.386 vus............................: 4 min=0 max=1250 2025-XX-XX 12:43:54.386 vus_max........................: 1250 min=1250 max=1250
위 성능 테스트 결과를 Grafana 대시보드에서 확인한 메트릭 지표입니다.


성능 최적화 결과 RPS 2,000에 미치지 못하는 서비스가 리소스 및 워커 프로세스 조정만으로 RPS 3,700 수준에 도달하게 되었으며, 응답 시간 지표 또한 크게 개선된 것을 확인할 수 있습니다.
사례로 본 개선된 지표와 효과 (Improved Metrics and Effects)
- 응답 시간 감소 : 최적화 작업을 통해 고부하 상태에서의 응답 시간이 1,000% 이상 개선되었습니다. 이는 사용자 경험을 크게 향상하는 결과를 가져왔습니다
- 처리량 증가 : 시스템은 고부하 상태에서 최대 200% 더 많은 동시 요청을 처리할 수 있게 되었습니다. 이는 서비스의 가용성을 높이고, 사용자 만족도를 증대시키는 데 이바지했습니다
- 자원 효율성 개선 : 서버 리소스 소비가 10% 줄어들면서도, 고부하 상황에서 안정성을 유지할 수 있게 되었습니다. 일부 서비스에서는 고부하 안정성을 확보하기 위해 리소스를 추가로 사용하였지만, 전체적인 효율성은 크게 향상되었습니다
이러한 성과들은 숨고가 성능 테스트를 통해 얻은 귀중한 경험을 바탕으로, 지속적으로 시스템을 개선하고 사용자에게 더 나은 서비스를 제공하기 위한 노력의 일환입니다. 성능 테스트는 단순한 점검을 넘어, 시스템의 전반적인 건강 상태를 유지하고 최적의 성능을 발휘하도록 돕는 중요한 과정입니다.
결론 및 인사이트 (Conclusion and Insights)
성능 최적화의 조직적 가치 (Organizational Value of Performance Optimization)
성능 최적화는 단순히 시스템의 성능을 향상하는 것을 넘어, 오버프로비저닝된 리소스를 확인하고 효율적으로 관리하는 데 중요한 역할을 합니다. 이를 통해 숨고는 투자 대비 10배 이상의 성능 개선을 달성할 수 있었습니다.
이러한 과정은 숨고의 DevOps Chapter가 건강하고 신뢰할 수 있는 서비스를 제공하는 데 기여하며, Self Performance Testing 문화를 구축하여 지속적인 개선을 추구하는 기반이 됩니다.
성능 테스트를 통해 얻은 교훈과 제언 (Lessons Learned and Recommendations from Performance Testing)
성능 최적화를 성공적으로 수행하기 위해서는 모든 문제를 한 번에 해결하려고 하기보다, 우선순위가 높은 병목 현상부터 해결하는 것이 중요합니다. 이를 위해 Grafana k6와 같은 적합한 도구를 활용하여 성능 문제를 시각화하고 분석하고, 성능 테스트를 자동화하여 지속적인 개선을 유지하는 것이 중요합니다.
성능 최적화는 단순히 속도를 높이는 작업이 아니라, 시스템의 효율성과 안정성을 높이는 전반적인 과정입니다. 어떤 방법을 사용할지는 구체적인 환경과 요구 사항에 따라 달라질 수 있으며, 성능 병목이 발생하는 지점을 먼저 진단하고 해당 부분을 개선하는 데 초점을 맞추는 것이 중요합니다.
- 테스트 자동화의 중요성 : 성능 테스트는 주기적으로 자동화하여 효율적으로 진행해야 합니다
- 모니터링의 지속성 : 최적화 후에도 지속적인 모니터링을 통해 성능 유지보수가 필요합니다
- 적절한 테스트 시나리오 설정 : 다양한 시나리오를 통해 실제 목표한 상황에 맞는 성능 테스트를 수행해야 합니다
이러한 접근 방식을 통해 숨고는 시스템의 성능을 지속적으로 개선하고, 사용자에게 최상의 경험을 제공할 수 있도록 노력하고 있습니다. 성능 최적화는 단순한 과제가 아닌, 조직의 전반적인 성공을 위한 필수 요소임을 잊지 말아야 합니다.
지금까지 긴 글을 읽어주셔서 감사합니다.
- #devops
- #grafana
- #grafana k6
- #improve reliability
- #kubernetes
- #performance optimization
- #performance testing
- #sre
