2023.05.16 - [🌏 인프라/모니터링] - Prometheus + Grafana로 Redis 모니터링 구축하기

과제를 진행하면서 새롭게 알게된 기술들을 정리해보고자 합니다!

 

✔️ 목차
1. 메트릭
2. 프로메테우스
3. 그라파나

 

먼저, 메트릭(metrics)이란 뭘까?

성능 지표..? 정도로 알고 있는데 정확히 자세히 아는 것이 중요하기 때문에 정리해보겠습니다.

 

Metric

메트릭하면 다음과 같이 화려한 대시보드를 떠올리실 수 있을 것 같습니다.

https://danawalab.github.io/common/2021/09/02/redis-monitoring-tools.html

 

어떤 애플리케이션을 쓰는지, 어떤 서비스인지에 따라 해석이 달라질 수 있지만

보편적으로 메트릭은 수집되는 시계열 데이터를 말합니다.

 

웹서버에서는 요청 시간이 될 수 있고, 데이터베이스에서는 활성 연결 수나 활성 쿼리 수 등이 될 수 있습니다.

 

  • 로그와 달리 메트릭은 주기적으로 발생합니다.
    • 로그는 어떤 이벤트가 발생했을 때 로그 파일에 기록되지만, 메트릭은 주기적으로 발생하는 이벤트의 데이터를 수집
  • 시스템 리소스 모니터링에 정기적으로 수집되는 데이터 : CPU 사용량, 시간당 데이터 처리량, 분당 네트워크 속도 등
  • 프로메테우스의 메트릭은 "메트릭명{필드1=값, 필드2=값} 샘플링데이터"와 같이 수집

 

 

Prometheus

✅ 공식 문서

https://prometheus.io/docs/

웹이나 DB를 운영할 때 사용자의 이용이 생깁니다. 트래픽이 발생하고, 정도에 따라 지연시간이 생길 수 있습니다. 당연히 자원 사용이 동반되므로 서버 메모리나 CPU 사용률이 부족하지는 않은지 지켜보면서 관리해주어야 합니다. 이럴 때 사용할 수 있는 것이 프로메테우스입니다.

 

각종 지표를 수집하여 저장하고 검색할 수 있는 모니터링 시스템으로서 특징은 다음과 같습니다.

  • 이벤트 모니터링 및 경고에 사용되는 무료 소프트웨어
  • 독립형 오픈소스 프로젝트로 어떤 회사와도 독립적으로 유지 관리됨
  • Go로 작성되었고, 아파치2 라이선스를 따름
  • 그라파나를 통한 시각화 지원
  • 많은 시스템을 모니터링 할 수 있는 다양한 플러그인
  • 프로메테우스가 주기적으로 exporter(모니터링 대상 시스템)로부터 pulling 방식으로 메트릭을 읽어서 수집함

 

 

Grafana

✅ 공식 문서

https://grafana.com/docs/

그라파나는 프로메테우스 등 여러 데이터들을 시각화해주는 모니터링 툴입니다.

 

  • 알람 기능을 무료로 사용할 수 있음
  • 시계열 데이터를 시각화하기 위한 대시보드 제공
  • 여러 데이터 소스들을 시각화할 수 있음
  • 키바나와 호환성이 높음

 

공식 사이트에서 라이브 데모도 제공하고 있으니 사용하기 전에 확인해봐도 좋을 것 같다!

https://play.grafana.org/

 

 

 

 

참고 사이트

우리 팀에서 하고 있는 DB 모니터링 방법 중 하나는 프로메테우스와 그라파나를 이용하는 것이다. DBMS variables 비교 사이트에서 다뤘던 Redis, MySQL, PostgreSQL 중 하나씩 맡아서 직접 모니터링을 구축해보는 시간을 갖게 되었고, Redis를 담당하게 되었다.

 

NHN 면접에서 어떤 메트릭을 어떻게 모니터링 할 수 있을 지에 대한 질문을 받아보기도 했었고, 늘 해보고 싶던 부분이어서 이번 기회에 확실히 알고 넘어가야겠다! 아자 💪

 

과제 요구사항은 다음과 같다. 일단 다 처음이기 때문에 주신 내용을 이해하는게 먼저..! 하나씩 스터디하면서 차근차근 설치해봐야겠다 :)

 

과제 1

  • 서버 1: DB 서버
    • DB 설치
    • 프로메테우스 exporter 설치 (node exporter, db exporter)
  • 서버 2: 모니터링용 서버
    • 프로메테우스 설치
    • 그라파나 설치
  • 서버 1에는 2개 이상의 db 인스턴스 띄우기
    • 같은 버전으로? 아니면 다른 버전?
    • Docker compose?
  • node exporter는 서버당 한개, db exporter는 db 인스턴스별로 띄우기
  • 그라파나 로그인해서 접속하면 대시보드에서 인스턴스 상태 확인할 수 있도록 구축

 


과제 2

  • alert manager 설치
  • 프로메테우스 alert rules 수집
    • 알람을 받아야 하는 rule 생성, 알람을 받아야 하는 이유 생각해보기
  • web hook
    • 두레이 웹훅 이용하여 특정 rule 도달했을 때 알람 받도록 설정

 

 

 

nohup

리눅스에서 프로세스를 실행한 터미널의 세션 연결이 끊어지더라도 지속적으로 동작 할 수 있게 해주는 명령어

 

nohup 명령을 백그라운드(&)로 실행

&를 사용하면 프로세스가 백그라운드로 실행이 됨

 

백그라운드로 실행 중인지 확인하기

ps -ef | grep python

 

nohup&의 차이

  • nohup
    • 프로그램을 데몬 형태로 실행시키는 것이므로 세션 연결이 끊기더라도 프로세스가 계속 동작됨
    • 실행 시키면 대기 상태가 발생하고, 세션 연결이 끊기면 프로세스는 바로 종료됨
  • 백그라운드(&)
    • 실행 시키면 대기 상태가 없지만, 세션 연결이 끊기면 프로세스도 함께 종료됨
  • 따라서, nohup 명령을 백그라운드(&)로 같이 실행시키게 되면, 대기 상태도 없고 세션 연결이 끊기더라도 프로세스의 종료 없이 백그라운드로 실행되게 된다.

문제 상황

nohup node ./node_modules/@vue/cli-service/bin/vue-cli-service serve --port [PORT] &
nohup python manage.py runserver [IP]:[PORT] --settings=main.config.settings.debug

위의 명령으로 사이트를 서버에 백그라운드로 실행하고 있다고 생각했는데..
때때로 웹이 내려가는 이슈가 발생했다.

 

원인

잘못된 명령어로 인해서 사실 백그라운드로 실행이 안 되고 있는게 아닐까? 라는 생각이 들어서

왜 그러는지 실행할 때 명령을 다시 살펴봤더니

띄울 때 장고 실행에 & 를 붙이지 않고 실행해서 터미널 세션을 닫으면 프로세스도 같이 종료되었던 것이었다..

nohup python manage.py runserver [IP]:[PORT] --settings=main.config.settings.debug

 

해결방법

1. 띄울 때 & 를 잊지 말자!

nohup python manage.py runserver [IP]:[PORT] --settings=main.config.settings.debug &

 

2. 프로세스 모니터 크론잡 등록

서버가 아예 재부팅 되거나 그럴 수도 있으니까
크론잡으로 5분마다 프로세스가 내려가 있는지 체크하고 내려가 있으면 자동으로 올려주도록 스크립트를 등록한다.

#!/usr/bin/env bash

# 로그 파일 위치
LOG_DIRECTORY="/home1/irteamsu/cronjob/logs"
LOG_FILE="$LOG_DIRECTORY/logfile_$(date "+%Y%m%d_%H").log"

# 확인할 프로세스
PYTHON_PROCESS="/home1/irteamsu/.pyenv/versions/py39/bin/python manage.py runserver [IP]:[PORT] --settings=main.config.settings.debug"
NODE_PROCESS="node ./node_modules/@vue/cli-service/bin/vue-cli-service serve --port [PORT]"

# 실행할 디렉토리
PROCESS_DIRECTORY="/home1/irteamsu/variable-comparison"

# 로그에 남길 현재시각
log_current_time() {
    current_time=$(date "+%Y-%m-%d %H:%M:%S")
    echo "[$current_time] $1" >> "$LOG_FILE"
}

# 현재 시간을 시간 단위로 구하기
current_hour=$(date "+%H")

# 이전 시간대의 로그 파일 유지, 나머지 로그 파일 삭제
for ((hour=0; hour<current_hour; hour++)); do
    if [ "$hour" -lt 10 ]; then
        rm "$LOG_DIRECTORY/logfile_$(date "+%Y%m%d_0$hour").log" 2>/dev/null
    else
        rm "$LOG_DIRECTORY/logfile_$(date "+%Y%m%d_$hour").log" 2>/dev/null
    fi
done

# python 프로세스 실행 중인지 확인
if pgrep -f "$PYTHON_PROCESS" >/dev/null; then
    log_current_time "Python process is already running."
else
    log_current_time "Python process is not running. Starting the process..."
    source ~/.bash_profile
    cd "$PROCESS_DIRECTORY"
    pyenv activate py39
    nohup /home1/irteamsu/.pyenv/versions/py39/bin/python manage.py runserver [IP]:[PORT] --settings=main.config.settings.debug > /dev/null 2>&1 &
    if pgrep -f "$PYTHON_PROCESS" >/dev/null; then
        log_current_time "Python process started."
    else
    log_current_time "Failed to start Python process."
    fi
fi

# node 프로세스 실행 중인지 확인
if pgrep -f "$NODE_PROCESS" >/dev/null; then
    log_current_time "Node.js process is already running."
else
    log_current_time "Node.js process is not running. Starting the process..."
    cd "$PROCESS_DIRECTORY"
    nohup node ./node_modules/@vue/cli-service/bin/vue-cli-service serve --port [PORT] > /dev/null 2>&1 &
    if pgrep -f "$NODE_PROCESS" >/dev/null; then
        log_current_time "Node.js process started."
    else
        log_current_time "Failed to start Node.js process."
    fi
fi
*/5 * * * * ~/cronjob/background_process_monitor.sh

 

결과

  • 로그 파일 생성 후 1시간 동안만 보관
    • 크게 유의미한 로그가 아니기 때문에 오래 보관할 필요가 없다.

  • 프로세스가 종료된 경우 자동으로 웹이 다시 올라오게 된다!

1. 문제 상황

잘 접속되던 서버였는데 갑자기 에러가 뜨면서 접속이 안 되었다.

 

위의 상황이 발생하는 이유를 예를 들어보자면,

 

A host가 있고, B server가 있다.

A는 항상 B server에 ssh 접속을 하고 있었는데, B server에 ssh나 os를 새로 설치하는 작업을 했다.

그랬는데 A가 똑같이 B에 접속을 시도하고,

B의 IP는 똑같다면 위와 같은 메시지가 뜬다.

 

SSH 최초 접속 시에 A와 B가 서로 인증을 하는데

B는 새로 설치되었는데 A는 예전 B에 IP로 인증이 되어있는 상태에서 B로 로그인을 하면

B는 인증정보가 없기 때문에 위와 같은 메시지가 뜨는 것이다.

 

 

2. 해결 방법

vi /Users/nhn/.ssh/known_hosts

# 보통은
# /root/.ssh/known_hosts
# /home/username/.ssh/known_hosts

접속해서 해당 IP 접속을 지우고 다시 접속을 한다.

 

접속해보니 장비(시스템)명이 바뀐거 같았다!

 

 

 

 

 

 

참고 사이트

+ Recent posts