반응형
개요
- Spring + ELK Stack으로 로그 모니터링 시스템을 구축하려 했지만, ElasticSearch가 서버에 너무 무거워서 정상적으로 동작하지 않았습니다. 이에 대한 대안으로 ELK 대신 Loki와 Grafana로 로그 시각화 툴을 구축하고, 추가적으로 Prometheus를 도입해 메트릭또한 수집해 보고자 합니다.
- 먼저 Grafana, Loki, Promtail을 필요로 하는데, 각 서비스의 역할은 다음과 같습니다.
- Grafana: 로그 시각화
- Loki: 로그 데이터 저장 및 인덱싱
- Prometheus : Spring, MySQL, Nginx등의 매트릭 수집
- Grafana와 Loki는 별도의 모니터링 서버에 구축하고, Promtail은 Application 서버에 구축하려 합니다.
Grafana + Loki 구축하기
먼저 Grafana와 Loki 서버를 모니터링 서버에 구축해봅니다.
- docker-compose.yml
version: '3'
services:
loki:
image: grafana/loki:2.8.0
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
- ./loki-storage:/loki
grafana:
image: grafana/grafana:9.5.1
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=???
volumes:
- ./grafana-storage:/var/lib/grafana
- loki-config.yaml
auth_enabled: true
server:
http_listen_port: 3100
http_server_read_timeout: 30s
http_server_write_timeout: 30s
grpc_server_max_recv_msg_size: 10485760
grpc_server_max_send_msg_size: 10485760
auth:
type: basic
basic:
username: ??
password: ??
ingester:
wal:
enabled: true
dir: /loki/wal
lifecycler:
address: 127.0.0.1
ring:
kvstore:
store: inmemory
replication_factor: 1
final_sleep: 0s
chunk_idle_period: 5m
chunk_retain_period: 30s
schema_config:
configs:
- from: 2020-05-15
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
storage_config:
boltdb_shipper:
active_index_directory: /loki/boltdb-shipper-active
cache_location: /loki/boltdb-shipper-cache
cache_ttl: 24h
shared_store: filesystem
filesystem:
directory: /loki/chunks
compactor:
working_directory: /loki/boltdb-shipper-compactor
shared_store: filesystem
limits_config:
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h
chunk_store_config:
max_look_back_period: 0s
table_manager:
retention_deletes_enabled: false
retention_period: 0s
- 설정 파일 파라미터는 아래에서 확인할 수 있습니다. 필요한 부분만 수정하였습니다.
- 각 설정에 대한 설명은 다음과 같습니다.
- server: 서버 포트, 패킷 크기, 타임아웃 정의
- auth: Loki에 업로드하기 위한 인증 정보
- Ingester: 로그 데이터 수신 및 저장 역할
- wal: Ingester가 수신한 로그를 로그 형태로 기록 후 전송
- lifecycler: Ingester의 생명 주기 관리
- schema_config: BoltDB-Shipper 저장소와 파일 시스템 객체 저장소에 로그 저장
- Compactor: 저장된 로그 데이터를 최적화 및 압축
Promtail 구축하기
다음으로 application server에 Promtail 컨테이너를 등록하여 Spring에서 설정한 로그 파일을 가져갈 수 있도록 합니다.
- docker-compose.yml(Spring 서버)
version: '3'
services:
min-ticketing:
# ...
volumes:
- ./logs:/app/logs
# ...
promtail:
image: grafana/promtail:2.8.0
container_name: promtail
volumes:
- ./logs:/logs
- ./promtail-conf.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
depends_on:
- min-ticketing
어플리케이션 로그가 저장되는 logs 폴더와 promtail이 감시할 logs 폴더에 볼륨을 설정하여 promtail이 로그 파일을 가져가서 Loki로 전송할 수 있도록 하였습니다.
- promtail-conf.yml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: ??
basic_auth:
username: "??"
password: "???"
scrape_configs:
- job_name: spring_application
static_configs:
- targets:
- min_ticketing
labels:
job: ticketing_logs
__path__: /logs/ticketing_*.log
pipeline_stages:
- json:
expressions:
timestamp: '"@timestamp"'
level: level
logger: logger_name
thread: thread_name
message: message
- timestamp:
source: timestamp
format: RFC3339Nano
- labels:
level:
logger:
thread:
- Promtail 설정으로, LogstashEncoder 기반으로 저장된 어플리케이션 로그를 Promtail에서 파싱하여 전송하도록 설정하였습니다.
Prometheus 설정하기
- 그 다음으로 Prometheus를 추가해 줄 것인데, 먼저 이전에 Grafana, Loki 컨테이너를 실행하는 docker-compose 파일에 Prometheus를 추가해 줍시다.
version: '3'
services:
# .....
prometheus:
container_name: prometheus
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus-config.yml:/etc/prometheus/prometheus.yml
- prometheus-config.yml은 다음과 같습니다.
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'spring-actuator'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['spring actuator ip:9090']
- job_name: 'mysql'
scrape_interval: 5s
static_configs:
- targets: ["mysql exporter ip:9104"]
labels:
group: 'mysql'
service: 'mysql'
- job_name: 'mysql-node'
scrape_interval: 5s
static_configs:
- targets: ["mysql node exporter ip:9100"] # Node Exporter의 IP와 포트
labels:
group: 'mysql'
service: 'node'
- job_name: 'nginx'
static_configs:
- targets: ['nginx exporter ip:9113']
- 저는 Spring 외에도 MySQL Exporter, Node Exporter, Nginx Exporter를 추가로 사용하였는데요, 이 글에서는 모두 다루기엔 분량상 너무 길어질 거 같으니 도움을 얻을 수 있는 링크만 남기도록 하겠습니다.
- 그 후 Spring Actuator + Prometheus Registry 라이브러리를 추가하여 메트릭을 제공하도록 해야합니다.
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
- 그 후 Spring application.yml 파일에 아래와 같이 설정해줍니다.
management:
endpoints:
web:
exposure:
include: health, prometheus
metrics:
tags:
application: ${spring.application.name}
server:
port: 9090
- 저는 웹 Port와 Actuator Port를 구분하여 외부 사용자가 Actuator에 접근할 수 없도록 제한하였습니다.
Grafana 등록
이제 Grafana에 DataSource를 등록해 주면 됩니다.
그 후 대시보드를 등록하면 되는데, 제가 사용한 대시보드 들은 아래와 같습니다.










반응형
'Spring > Ticketing 프로젝트' 카테고리의 다른 글
공연 예매 시 Proxy를 사용해 DB 부하 줄이기 (2) | 2024.11.16 |
---|---|
공연 정보 조회 API 쿼리 분석하고 개선하기 (0) | 2024.11.15 |
비동기 환경에서 Request를 유지하려면 어떻게 해야할까? (0) | 2024.11.15 |
Database Unique Constraint를 활용한 중복 예약 방지 로직 구현하기 (0) | 2024.11.15 |
N + 1 쿼리 개선하고 확장성 있는 코드 만들기 (0) | 2024.11.15 |