hobokai 님의 블로그

[Linux] Apache Bench (ab) - 웹서버 성능 테스트의 모든 것 본문

Linux

[Linux] Apache Bench (ab) - 웹서버 성능 테스트의 모든 것

hobokai 2025. 8. 12. 16:25

웹서버 성능 검증의 필수 도구, Apache Bench (ab) 실무 활용법

간단하지만 강력한 성능 테스트 도구 ab의 설치부터 고급 활용까지 모든 것을 다룹니다.


🚀 Apache Bench (ab)란?

정의와 특징

Apache Bench (ab)는 Apache HTTP 서버의 성능을 측정하기 위해 개발된 명령줄 기반 부하 테스트 도구입니다.

# ab 기본 구조
ab [options] [http[s]://]hostname[:port]/path

주요 특징

  •  가볍고 빠름: 단일 바이너리로 즉시 실행 가능
  •  간단한 사용법: 복잡한 설정 없이 바로 테스트 시작
  •  실시간 결과: 테스트 진행 상황과 결과를 즉시 확인
  •  다양한 옵션: 동시 연결, 요청 수, 인증 등 다양한 시나리오 지원
  •  크로스 플랫폼: Linux, macOS, Windows 지원

📦 설치 방법

Linux 배포판별 설치

Ubuntu/Debian

# Apache utils 패키지 설치
sudo apt update
sudo apt install apache2-utils

# 설치 확인
ab -V

CentOS/RHEL/Rocky Linux

# httpd-tools 패키지 설치
sudo yum install httpd-tools
# 또는 dnf (최신 버전)
sudo dnf install httpd-tools

# 설치 확인
ab -V

Arch Linux

# apache 패키지 설치
sudo pacman -S apache

# 설치 확인
ab -V

macOS 설치

# Homebrew를 통한 설치
brew install httpd

# 설치 확인
ab -V

Windows 설치

  1. Apache Lounge에서 Windows용 Apache 바이너리 다운로드
  2. 압축 해제 후 bin 디렉토리에서 ab.exe 실행
  3. 또는 WSL(Windows Subsystem for Linux) 사용

🔧 기본 사용법

1. 가장 간단한 테스트

# 웹사이트에 10개 요청 보내기
ab -n 10 https://example.com/

# 결과 예시
Server Software:        nginx/1.18.0
Server Hostname:        example.com
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256
Document Path:          /
Document Length:        1256 bytes

Concurrency Level:      1
Time taken for tests:   2.531 seconds
Complete requests:      10
Failed requests:        0
Total transferred:      15230 bytes
HTML transferred:       12560 bytes
Requests per second:    3.95 [#/sec] (mean)
Time per request:       253.100 [ms] (mean)
Time per request:       253.100 [ms] (mean, across all concurrent requests)
Transfer rate:          5.88 [Kbytes/sec] received

2. 동시 연결 테스트

# 100개 요청을 동시에 10개씩 처리
ab -n 100 -c 10 http://localhost:8080/api/health

# -n: 총 요청 수 (requests)
# -c: 동시 연결 수 (concurrency)

3. 시간 기반 테스트

# 30초 동안 계속 요청 보내기
ab -t 30 -c 5 http://localhost:3000/

# -t: 테스트 시간 (초)
# -c: 동시 연결 수

⚙️ 주요 옵션 상세 가이드

요청 제어 옵션

# 기본 요청 설정
ab -n 1000 -c 50 http://example.com/        # 1000개 요청, 동시 50개
ab -t 60 -c 10 http://example.com/          # 60초간 테스트, 동시 10개
ab -k -n 500 -c 25 http://example.com/      # Keep-Alive 사용

# 요청 간격 제어
ab -n 100 -c 1 -i http://example.com/       # HEAD 요청만 수행
ab -n 100 -c 5 -r http://example.com/       # 소켓 에러 시 종료하지 않음

HTTP 헤더 및 메서드

# POST 요청 테스트
ab -n 100 -c 10 -p data.json -T 'application/json' http://api.example.com/users

# 커스텀 헤더 추가
ab -n 50 -c 5 -H "Authorization: Bearer token123" http://api.example.com/protected

# 여러 헤더 추가
ab -n 100 -c 10 \
   -H "Content-Type: application/json" \
   -H "X-API-Key: abc123" \
   -H "User-Agent: LoadTest/1.0" \
   http://api.example.com/data

인증 관련

# Basic Authentication
ab -n 100 -c 10 -A username:password http://secure.example.com/

# Proxy Authentication
ab -n 100 -c 10 -P proxy-user:proxy-pass http://example.com/

SSL/TLS 옵션

# SSL 인증서 검증 무시 (개발/테스트 환경)
ab -n 100 -c 10 -Z cipher https://self-signed.example.com/

# 특정 SSL cipher 사용
ab -n 100 -c 10 -f TLS1.2 https://secure.example.com/

📊 결과 해석과 분석

핵심 지표 이해

1. 기본 서버 정보

Server Software:        nginx/1.18.0     # 웹서버 종류와 버전
Server Hostname:        api.example.com  # 대상 서버
Server Port:            443              # 포트 번호
Document Path:          /api/users       # 요청 경로
Document Length:        2048 bytes       # 응답 크기

2. 성능 지표

Concurrency Level:      10               # 동시 연결 수
Time taken for tests:   5.234 seconds    # 전체 테스트 시간
Complete requests:      1000             # 성공한 요청 수
Failed requests:        0                # 실패한 요청 수

3. 핵심 성능 메트릭

# 초당 처리 요청 수 (TPS)
Requests per second:    191.07 [#/sec] (mean)

# 평균 응답 시간
Time per request:       52.340 [ms] (mean)

# 동시 요청 간 평균 응답 시간  
Time per request:       5.234 [ms] (mean, across all concurrent requests)

# 데이터 전송률
Transfer rate:          389.23 [Kbytes/sec] received

응답 시간 분포 분석

# 백분위수 옵션으로 상세 분석
ab -n 1000 -c 50 -g output.tsv http://example.com/

# output.tsv 파일로 응답 시간 데이터 저장
# 엑셀이나 gnuplot으로 그래프 생성 가능

🔥 실무 활용 시나리오

1. API 성능 테스트

REST API 부하 테스트

#!/bin/bash
# api_load_test.sh

API_BASE="http://localhost:8080/api"
CONCURRENT_USERS=50
REQUESTS_PER_TEST=1000

echo "=== API 성능 테스트 시작 ==="

# GET 요청 테스트
echo "1. GET /users 테스트"
ab -n $REQUESTS_PER_TEST -c $CONCURRENT_USERS \
   -H "Accept: application/json" \
   "$API_BASE/users" > results_get_users.txt

# POST 요청 테스트
echo "2. POST /users 테스트"
cat > user_data.json << EOF
{
  "name": "Test User",
  "email": "test@example.com",
  "age": 25
}
EOF

ab -n 100 -c 10 \
   -p user_data.json \
   -T "application/json" \
   -H "Authorization: Bearer test-token" \
   "$API_BASE/users" > results_post_users.txt

# 인증이 필요한 API 테스트
echo "3. 보호된 리소스 테스트"
ab -n 500 -c 25 \
   -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
   "$API_BASE/protected/data" > results_protected.txt

echo "=== 테스트 완료 ==="

2. 웹사이트 성능 검증

프론트엔드 리소스 테스트

#!/bin/bash
# website_performance.sh

WEBSITE="https://mywebsite.com"
CONCURRENT=20
REQUESTS=500

echo "=== 웹사이트 성능 테스트 ==="

# 메인 페이지
echo "1. 메인 페이지 테스트"
ab -n $REQUESTS -c $CONCURRENT -k "$WEBSITE/" > main_page.txt

# CSS 파일
echo "2. CSS 리소스 테스트"  
ab -n $REQUESTS -c $CONCURRENT -k "$WEBSITE/assets/css/main.css" > css_test.txt

# JavaScript 파일
echo "3. JavaScript 리소스 테스트"
ab -n $REQUESTS -c $CONCURRENT -k "$WEBSITE/assets/js/app.js" > js_test.txt

# 이미지 파일
echo "4. 이미지 리소스 테스트"
ab -n $REQUESTS -c $CONCURRENT -k "$WEBSITE/assets/images/hero.jpg" > image_test.txt

# 결과 요약
echo "=== 결과 요약 ==="
echo "메인 페이지 RPS: $(grep "Requests per second" main_page.txt | awk '{print $4}')"
echo "CSS 파일 RPS: $(grep "Requests per second" css_test.txt | awk '{print $4}')"
echo "JS 파일 RPS: $(grep "Requests per second" js_test.txt | awk '{print $4}')"
echo "이미지 파일 RPS: $(grep "Requests per second" image_test.txt | awk '{print $4}')"

3. 마이크로서비스 개별 테스트

서비스별 성능 검증

#!/bin/bash
# microservices_test.sh

declare -A SERVICES=(
    ["user-service"]="http://localhost:8001/health"
    ["order-service"]="http://localhost:8002/health"
    ["payment-service"]="http://localhost:8003/health"
    ["notification-service"]="http://localhost:8004/health"
)

CONCURRENT=30
REQUESTS=1000
DURATION=60

echo "=== 마이크로서비스 성능 테스트 ==="

for service in "${!SERVICES[@]}"; do
    echo "Testing $service..."
    
    # Health check 테스트
    ab -n $REQUESTS -c $CONCURRENT "${SERVICES[$service]}" > "${service}_health.txt"
    
    # 지속성 테스트 (60초간)
    ab -t $DURATION -c $CONCURRENT "${SERVICES[$service]}" > "${service}_duration.txt"
    
    # 결과 추출
    RPS=$(grep "Requests per second" "${service}_health.txt" | awk '{print $4}')
    AVG_TIME=$(grep "Time per request" "${service}_health.txt" | head -1 | awk '{print $4}')
    
    echo "$service - RPS: $RPS, Avg Time: ${AVG_TIME}ms"
done

📈 고급 활용 기법

1. 스크립트를 통한 자동화

성능 모니터링 스크립트

#!/bin/bash
# performance_monitor.sh

TARGET_URL="http://api.example.com/health"
THRESHOLD_RPS=100
THRESHOLD_RESPONSE_TIME=500  # milliseconds
LOG_FILE="performance_monitor.log"

monitor_performance() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # ab 실행
    local result=$(ab -n 100 -c 10 -q "$TARGET_URL" 2>/dev/null)
    
    # 결과 파싱
    local rps=$(echo "$result" | grep "Requests per second" | awk '{print $4}' | cut -d'.' -f1)
    local avg_time=$(echo "$result" | grep "Time per request" | head -1 | awk '{print $4}' | cut -d'.' -f1)
    
    # 로그 기록
    echo "$timestamp - RPS: $rps, Avg Time: ${avg_time}ms" >> "$LOG_FILE"
    
    # 임계값 체크
    if [ "$rps" -lt "$THRESHOLD_RPS" ]; then
        echo "⚠️  WARNING: Low RPS detected ($rps < $THRESHOLD_RPS)"
        # 알림 발송 (예: Slack, 이메일 등)
        send_alert "Low performance detected: RPS $rps"
    fi
    
    if [ "$avg_time" -gt "$THRESHOLD_RESPONSE_TIME" ]; then
        echo "⚠️  WARNING: High response time detected (${avg_time}ms > ${THRESHOLD_RESPONSE_TIME}ms)"
        send_alert "High response time detected: ${avg_time}ms"
    fi
}

send_alert() {
    # Slack webhook 예시
    curl -X POST -H 'Content-type: application/json' \
        --data "{\"text\":\"$1\"}" \
        "$SLACK_WEBHOOK_URL"
}

# 5분마다 모니터링 실행
while true; do
    monitor_performance
    sleep 300
done

2. 다양한 시나리오 테스트

점진적 부하 증가 테스트

#!/bin/bash
# gradual_load_test.sh

URL="http://localhost:8080/api/users"
MAX_CONCURRENT=100
STEP=10
REQUESTS_PER_STEP=500

echo "=== 점진적 부하 증가 테스트 ==="
echo "URL: $URL"
echo "Max Concurrent: $MAX_CONCURRENT"
echo "Step: $STEP"
echo ""

for ((concurrent=1; concurrent<=MAX_CONCURRENT; concurrent+=STEP)); do
    echo "Testing with $concurrent concurrent users..."
    
    result=$(ab -n $REQUESTS_PER_STEP -c $concurrent -q "$URL" 2>/dev/null)
    rps=$(echo "$result" | grep "Requests per second" | awk '{print $4}')
    avg_time=$(echo "$result" | grep "Time per request" | head -1 | awk '{print $4}')
    failed=$(echo "$result" | grep "Failed requests" | awk '{print $3}')
    
    echo "Concurrent: $concurrent, RPS: $rps, Avg Time: ${avg_time}ms, Failed: $failed"
    
    # CSV 형태로 저장
    echo "$concurrent,$rps,$avg_time,$failed" >> gradual_load_results.csv
    
    # 실패율이 높으면 중단
    if [ "$failed" -gt 10 ]; then
        echo "❌ Too many failures. Stopping test."
        break
    fi
    
    # 잠시 대기 (서버 복구 시간)
    sleep 2
done

echo ""
echo "✅ 테스트 완료. 결과는 gradual_load_results.csv 파일을 확인하세요."

3. 결과 분석 및 시각화

성능 데이터 분석 스크립트

#!/bin/bash
# analyze_results.sh

analyze_ab_results() {
    local result_file=$1
    local test_name=$2
    
    echo "=== $test_name 분석 결과 ==="
    
    # 기본 통계
    local rps=$(grep "Requests per second" "$result_file" | awk '{print $4}')
    local avg_time=$(grep "Time per request" "$result_file" | head -1 | awk '{print $4}')
    local total_time=$(grep "Time taken for tests" "$result_file" | awk '{print $5}')
    local failed=$(grep "Failed requests" "$result_file" | awk '{print $3}')
    local success_rate=$(grep "Complete requests" "$result_file" | awk '{print $3}')
    
    echo "🚀 RPS (초당 요청 수): $rps"
    echo "⏱️  평균 응답 시간: ${avg_time}ms"
    echo "⏰ 전체 테스트 시간: ${total_time}초"
    echo "✅ 성공한 요청: $success_rate"
    echo "❌ 실패한 요청: $failed"
    
    # 성능 등급 판정
    local rps_num=$(echo $rps | cut -d'.' -f1)
    local avg_time_num=$(echo $avg_time | cut -d'.' -f1)
    
    if [ "$rps_num" -gt 500 ] && [ "$avg_time_num" -lt 100 ]; then
        echo "🏆 성능 등급: 우수 (Excellent)"
    elif [ "$rps_num" -gt 200 ] && [ "$avg_time_num" -lt 300 ]; then
        echo "👍 성능 등급: 양호 (Good)"
    elif [ "$rps_num" -gt 50 ] && [ "$avg_time_num" -lt 1000 ]; then
        echo "👌 성능 등급: 보통 (Fair)"
    else
        echo "👎 성능 등급: 개선 필요 (Poor)"
    fi
    
    echo ""
}

# 여러 결과 파일 분석
for file in *.txt; do
    if [[ -f "$file" ]]; then
        analyze_ab_results "$file" "$(basename "$file" .txt)"
    fi
done

⚠️ 주의사항과 한계

1. ab 도구의 한계

# ❌ 복잡한 시나리오 불가
# - 로그인 → 페이지 탐색 → 구매 같은 플로우 테스트 어려움
# - JavaScript 실행 불가 (SPA 테스트 제한)
# - 쿠키/세션 관리 제한적

# ✅ ab는 단순한 HTTP 요청 테스트에 최적화
ab -n 1000 -c 50 http://api.example.com/simple-endpoint

2. 윤리적 고려사항

# ⚠️ 주의: 본인 소유가 아닌 서버 테스트 금지
# - DDoS 공격으로 간주될 수 있음
# - 법적 문제 발생 가능

# ✅ 안전한 테스트 환경
ab -n 100 -c 10 http://localhost:8080/      # 로컬 개발 서버
ab -n 100 -c 10 http://test.mycompany.com/  # 회사 테스트 서버

3. 시스템 리소스 고려

# 클라이언트 시스템 한계 확인
ulimit -n  # 파일 디스크립터 한계 확인

# 필요시 한계 증가
ulimit -n 65536

# 네트워크 대역폭 고려
# - 높은 동시 연결 시 네트워크 포화 가능
# - 테스트 결과가 네트워크가 아닌 애플리케이션 성능을 반영하는지 확인

🆚 대안 도구 비교

ab vs 다른 성능 테스트 도구

도구장점단점적합한 용도

ab (Apache Bench) 간단, 빠른 설치, 직관적 복잡한 시나리오 불가 빠른 HTTP 성능 체크
wrk 높은 성능, Lua 스크립팅 러닝 커브 존재 고성능 부하 테스트
JMeter GUI, 복잡한 시나리오 무겁고 복잡함 종합적인 성능 테스트
Artillery 현대적, 설정 기반 Node.js 의존성 CI/CD 통합
k6 JavaScript, 클라우드 상용 기능 제한 개발자 친화적

도구 선택 가이드

# 간단한 API 테스트 → ab
ab -n 1000 -c 50 http://api.example.com/health

# 고성능이 필요한 경우 → wrk  
wrk -t12 -c400 -d30s http://example.com/

# 복잡한 시나리오 → JMeter
# GUI 환경에서 테스트 계획 작성

# CI/CD 파이프라인 → Artillery 또는 k6
# YAML/JavaScript 설정 파일로 자동화

🎯 실전 팁과 베스트 프랙티스

1. 효과적인 테스트 설계

# 단계적 테스트 접근법
echo "1단계: 기본 동작 확인"
ab -n 10 -c 1 http://api.example.com/health

echo "2단계: 소규모 부하 테스트"  
ab -n 100 -c 10 http://api.example.com/health

echo "3단계: 중규모 부하 테스트"
ab -n 1000 -c 50 http://api.example.com/health

echo "4단계: 대규모 부하 테스트"
ab -n 5000 -c 100 http://api.example.com/health

2. 결과 저장 및 관리

# 체계적인 결과 저장
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
TEST_NAME="api_performance"
RESULT_DIR="test_results/$TIMESTAMP"

mkdir -p "$RESULT_DIR"

# 테스트 실행 및 결과 저장
ab -n 1000 -c 50 http://api.example.com/users \
   > "$RESULT_DIR/${TEST_NAME}_users.txt" 2>&1

ab -n 1000 -c 50 http://api.example.com/orders \
   > "$RESULT_DIR/${TEST_NAME}_orders.txt" 2>&1

# 요약 보고서 생성
echo "테스트 일시: $(date)" > "$RESULT_DIR/summary.txt"
echo "테스트 대상: api.example.com" >> "$RESULT_DIR/summary.txt"
grep "Requests per second" "$RESULT_DIR"/*.txt >> "$RESULT_DIR/summary.txt"

3. 성능 기준 설정

#!/bin/bash
# performance_standards.sh

# 성능 기준 정의
MIN_RPS=100           # 최소 초당 요청 수
MAX_RESPONSE_TIME=500 # 최대 응답 시간 (ms)
MAX_FAILURE_RATE=1    # 최대 실패율 (%)

check_performance_standard() {
    local result_file=$1
    
    local rps=$(grep "Requests per second" "$result_file" | awk '{print $4}' | cut -d'.' -f1)
    local avg_time=$(grep "Time per request" "$result_file" | head -1 | awk '{print $4}' | cut -d'.' -f1)
    local total_requests=$(grep "Complete requests" "$result_file" | awk '{print $3}')
    local failed_requests=$(grep "Failed requests" "$result_file" | awk '{print $3}')
    local failure_rate=$(echo "scale=2; $failed_requests * 100 / $total_requests" | bc)
    
    echo "=== 성능 기준 검사 ==="
    echo "측정값 - RPS: $rps, 응답시간: ${avg_time}ms, 실패율: ${failure_rate}%"
    echo "기준값 - RPS: >=$MIN_RPS, 응답시간: <=${MAX_RESPONSE_TIME}ms, 실패율: <=${MAX_FAILURE_RATE}%"
    
    local passed=true
    
    if [ "$rps" -lt "$MIN_RPS" ]; then
        echo "❌ RPS 기준 미달 ($rps < $MIN_RPS)"
        passed=false
    fi
    
    if [ "$avg_time" -gt "$MAX_RESPONSE_TIME" ]; then
        echo "❌ 응답시간 기준 미달 (${avg_time}ms > ${MAX_RESPONSE_TIME}ms)"
        passed=false
    fi
    
    if (( $(echo "$failure_rate > $MAX_FAILURE_RATE" | bc -l) )); then
        echo "❌ 실패율 기준 미달 (${failure_rate}% > ${MAX_FAILURE_RATE}%)"
        passed=false
    fi
    
    if [ "$passed" = true ]; then
        echo "✅ 모든 성능 기준 통과!"
        return 0
    else
        echo "❌ 성능 기준 미달"
        return 1
    fi
}

🔧 트러블슈팅

일반적인 문제와 해결책

1. "apr_socket_recv: Connection reset by peer" 오류

# 원인: 서버가 연결을 강제로 끊음
# 해결책: 동시 연결 수 줄이기
ab -n 1000 -c 10 http://example.com/  # -c 값을 낮춤

# Keep-Alive 사용
ab -k -n 1000 -c 50 http://example.com/

2. "socket: Too many open files" 오류

# 파일 디스크립터 한계 확인
ulimit -n

# 한계 증가 (임시)
ulimit -n 65536

# 영구적 설정 (/etc/security/limits.conf)
echo "* soft nofile 65536" | sudo tee -a /etc/security/limits.conf
echo "* hard nofile 65536" | sudo tee -a /etc/security/limits.conf

3. SSL 인증서 오류

# 자체 서명 인증서 무시
ab -n 100 -c 10 -Z ALL https://self-signed.example.com/

# 특정 SSL 프로토콜 지정
ab -n 100 -c 10 -f TLS1.2 https://secure.example.com/

4. 느린 테스트 성능

# DNS 조회 제거 (IP 직접 사용)
ab -n 1000 -c 50 http://192.168.1.100:8080/

# Keep-Alive 활성화
ab -k -n 1000 -c 50 http://example.com/

# 로컬 테스트로 네트워크 지연 제거
ab -n 1000 -c 50 http://localhost:8080/

📋 체크리스트

테스트 실행 전 확인사항

  •  권한 확인: 테스트 대상 서버에 대한 부하 테스트 권한
  •  네트워크 확인: 충분한 대역폭과 안정적인 연결
  •  시스템 리소스: 클라이언트 머신의 파일 디스크립터 한계
  •  베이스라인: 정상 상태의 성능 지표 사전 측정
  •  모니터링: 서버 측 리소스 모니터링 도구 준비

테스트 실행 중 모니터링

  •  서버 CPU 사용률: htop, top 명령어로 확인
  •  메모리 사용량: free -h 명령어로 확인
  •  네트워크 사용량: iftop, netstat 명령어로 확인
  •  디스크 I/O: iotop 명령어로 확인
  •  에러 로그: 서버 로그 파일 실시간 모니터링

테스트 완료 후 분석

  •  결과 저장: 모든 테스트 결과 파일 저장
  •  트렌드 분석: 이전 테스트 결과와 비교
  •  병목 지점: 성능 저하 구간 식별
  •  개선 계획: 성능 최적화 액션 아이템 도출
  •  문서화: 테스트 조건, 결과, 분석 내용 문서화

💡 결론

Apache Bench (ab)는 간단하면서도 강력한 웹서버 성능 테스트 도구입니다.

핵심 장점

  •  즉시 사용 가능: 복잡한 설정 없이 바로 테스트 시작
  •  가볍고 빠름: 시스템 리소스를 적게 사용하면서 빠른 결과 제공
  •  스크립팅 친화적: 자동화 스크립트에 쉽게 통합
  •  실무 검증: 오랜 기간 검증된 안정적인 도구

적합한 사용 사례

  • 🎯 API 엔드포인트 성능 검증
  • 🎯 웹서버 설정 변경 후 성능 비교
  • 🎯 CI/CD 파이프라인 성능 게이트
  • 🎯 빠른 성능 체크 및 문제 진단

다음 단계

ab로 기본적인 성능 테스트에 익숙해진 후에는:

  1. wrk로 고성능 테스트 경험
  2. JMeter로 복잡한 시나리오 테스트
  3. k6 또는 Artillery로 현대적인 성능 테스트 도구 활용

성능 테스트는 지속적인 과정입니다. ab를 활용해 정기적으로 성능을 모니터링하고, 문제를 조기에 발견하여 안정적인 서비스를 제공하세요!


📚 참고 자료: