한 기술 면접에서 면접관님이 여쭤보셨다.
"이 서비스의 백엔드는 API를 하루에 얼마나 처리해봤나요?" (다소 의역)
그대로 굳었다. 그냥 API 를 만들고 서비스를 개발하는 것만 신경쓰다보니 백엔드 개발자로서 응당 신경써야 할 이런 부분을 놓치고 있었다. 면접에서는 "그 부분에 대해 체크할 생각을 못해봤습니다. 잘 모르겠습니다." 라고 말할 수 밖에 없었다.
면접장에서 나오자마자 "이걸 당장 만들어봐야겠다" 라는 생각이 들었다.
현재 서비스 중인 프로젝트에 이 API 를 통계내는 시스템을 만들어보기로 했다.
인프라 구조
백엔드로 요청오는 API 를 로깅하고 가공하기 위해선 인프라 구조에 대한 이해가 필요하다.
현재 프로젝트는 아래와 같은 구조로 돌아가고 있다.

백엔드 서버는 프론트엔드 서버와 하나의 EC2에서 구동되고 있고 NginX 리버스 프록시를 통해 프론트엔드의 요청이 백엔드 서버로 들어온다.
API 로그를 어떻게 저장하고 모니터링할 것인가
백엔드 서버로 들어오는 요청은 결국 NginX를 거치므로 NginX의 access log 를 활용하기로 했다.
24시간동안의 access log를 shell script로 통계내고 스케쥴러를 이용해 매일 0시(UTC 기준)에 텔레그램 메시지로 통계 정보를 보내도록 설계했다.
NginX Access Log 저장하기
NginX 로 들어오는 백엔드 요청을 저장하기 위해 아래와 같이 conf 파일을 수정했다.
# /etc/nginx/conf.d/project.conf
server {
listen 80;
server_name ramenroad.com;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:5010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /api/ {
# 이 부분 액세스 로그를 저장하는 설정
access_log /var/log/nginx/backend/access.log;
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_request_buffering off;
}
}
Access Log 분리
나는 매일매일 24시간 동안의 API 통계를 알고싶기 때문에 효율을 위해 날짜별로 액세스 로그를 분리해줘야 한다. 안그러면 access.log 에 모든 로그가 쌓이게 될 것이고 그렇게 시간이 오래 지나면 통계내는데 시간이 오래 걸릴 것이다..
로그 파일은 /etc/logrotate.d/ 에서 관리 설정을 할 수 있다. 나는 아래와 같이 설정했다.
# /etc/logrotate.d/nginx-backend
/var/log/nginx/backend/access.log {
daily
# 날짜 형식으로 파일명 변
dateext
dateformat -%Y%m%d
# 며칠 치 로그를 보관할지 설정
rotate 7
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
# Nginx가 새 로그 파일을 열도록 신호를 보냄
[ -f /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
endscript
}
코드에 대해 간단히 설명하자면 /var/log/nginx/backend/access.log 파일에 저장되는 로그를 하루 단위로 분리한다.
또, 하루가 지나면 압축을 하도록 했고 로그는 7일까지 저장하도록 설정했다.
그리고 이 logrotate.d는 매일 0시에 돌아가도록 되어있다. (cron 기본 설정 / 리눅스 배포판마다 다를 수 있음)
API 통계 + 텔레그램 메시지 발송 쉘 스크립트 작성
이렇게 저장한 access log 를 통계내고, 또 텔레그램으로 메시지를 발송하는 쉘 스크립트 코드가 필요하다.
나는 아래와 같이 작성했다.
#!/bin/bash
BOT_TOKEN="비밀"
CHAT_ID="비밀"
LOG_DIR="/var/log/nginx/backend"
# 어제 날짜를 YYYYMMDD 형식으로 가져오기 (logrotate 형식과 일치)
TODAY=$(date +%Y%m%d)
TARGET_LOG_FILE="${LOG_DIR}/access.log-${TODAY}"
if [ ! -f "$TARGET_LOG_FILE" ]; then
echo "로그 파일을 찾을 수 없습니다: $TARGET_LOG_FILE"
exit 1
fi
# 1. 총 API 호출 수 계산
TOTAL_CALLS=$(wc -l < "$TARGET_LOG_FILE")
# 2. API 경로별 호출 수 계산 (상위 15개)
# awk의 gsub 함수를 사용해 경로의 UUID와 숫자 파라미터를 각각 {uuid}, {id}로 치환합니다.
API_BREAKDOWN=$(awk -F'"' '{path=$2; gsub(/ HTTP.*/, "", path); gsub(/\?.*/, "", path); gsub(/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}/, "{uuid}", path); gsub(/\/[0-9]{3,}/, "/{id}", path); print path}' "$TARGET_LOG_FILE" | sort | uniq -c | sort -nr | head -n 30)
# 3. 텔레그램 메시지 생성
MESSAGE_DATE=$(date --date="yesterday" +"%Y년 %m월 %d일오전 9시부터 24시간동안")
MESSAGE="🔔 **${MESSAGE_DATE} API 호출 통계** 🔔
**총 API 호출**: ${TOTAL_CALLS} 회
--- **호출 빈도 TOP 30** ---
\`\`\`
${API_BREAKDOWN}
\`\`\`"
# 4. 텔레그램으로 메시지 발송 (curl 사용)
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}" \
--data-urlencode "text=${MESSAGE}" \
-d "parse_mode=Markdown"
echo "텔레그램 메시지 발송 완료."
전반적인 코드의 흐름은 이렇다.
1. 저장한 24시간동안의 액세스 로그 정보를 가져온다.
2. API 가 호출된 횟수를 계산하고
3. 각각의 API 가 호출된 횟수를 기록한다. (쿼리/path가 다르고 경로는 동일한 경우 동일한 API로 판단)
4. 가장 많이 호출된 API 30개를 뽑는다.
5. 텔레그램 메시지로 결과를 전송한다.
스케쥴러에 등록
이렇게 쉘 스크립트까지 작성을 완료했다면 매일매일 자동으로 실행되도록 스케쥴러(cron) 에 등록해주어야한다.
crontab -e 명령어를 통해 스케쥴러에 등록할 수 있으며 나는 아래와 같이 등록했다.
5 0 * * * /home/ec2-user/send_nginx_stats.sh > /home/ec2-user/cron_job.log 2>&1
access.log 가 0시에 날짜 별로 정리되기때문에 0시 5분에 해당 스크립트가 돌아가도록 설정했다.
* 쉘 스크립트에 대한 소유주는 디렉토리 소유주(나의 경우엔 ec2-user) 로 해야하고 실행 권한을 부여해줘야 한다.
결과
이렇게 모든 작업이 끝나면 텔레그램으로 0시 5분( UTC 시간 기준 / 한국시간으로는 오전 9시 5분 )에 메시지가 도착한다.

어제는 총 830번 API 가 호출되었다.
이렇게 서비스가 처리하는 API 가 얼마나 되는지를 알아볼 수 있는 간단한 시스템을 만들었다. 앞으로는 이런 정말 백엔드스러운.. 눈에 보이지않지만 안정적인 시스템을 위해선 필요한 작업들을 많이 해보려고 한다.
'DevOps' 카테고리의 다른 글
| fly.io 서버 배포 및 API 테스트 방법 (3) | 2024.11.13 |
|---|