티스토리 뷰
✏️ 배경
지난 글(모니터링 구축기)에서 Grafana Alloy → Grafana Cloud Mimir로 메트릭을 보내는 파이프라인까지는 만들어뒀는데, 실제로 이게 지금도 잘 동작하고 있는지, 그리고 이걸로 뭘 봐야 하는지는 다시 점검해본 적이 없었다. 이번엔 이 파이프라인을 처음부터 다시 훑으면서 발견한 문제들과, 그 과정에서 처음으로 커스텀 비즈니스 메트릭(로그인 성공/실패)을 붙여본 기록해 보려고 한다.
✏️ 1. 현재 상태 점검
코드베이스만 봐서는 "Prometheus 엔드포인트는 열려 있는데, 그걸 누가 가져가는지"가 안 보였다. EC2에 직접 들어가서 확인해보니 eatssu-prod 컨테이너만 떠 있고, systemctl status alloy는 3주 넘게 재시작 없이 살아있었다. 아키텍처 자체는 멀쩡했다. 문제는 그 다음이었다.
✏️ 2. 트러블슈팅: 401 → 429
journalctl -u alloy 로그에 두 개의 서로 다른 사건이 섞여 있었다.
① 최초 배포 시점 - 401 Unauthorized: 초기 인증 정보가 잘못 들어가 있었고, 같은 날 재시작하며 자연히 해결됨.
② 2주 뒤 - 429 Too Many Requests (진짜 문제)
네트워크(curl로 405 확인 = 정상 도달), 인증 형식, 메모리(스왑 사용 중이라 의심했었음) 순으로 배제해나간 끝에, 순수 요청 속도 초과라는 걸 확정했다.
err="server returned HTTP status 429 Too Many Requests: the request has been rejected because the tenant exceeded the request rate limit, set to 75 requests/s ... (err-mimir-tenant-max-request-rate)"
✏️ 3. 원인 - dev/prod가 같은 Grafana Cloud 토큰을 공유
dev EC2의 config.alloy를 열어보니 basic_auth username이 prod와 완전히 동일했다. 즉 두 인스턴스가 하나의 테넌트(75 req/s 한도)를 나눠 쓰고 있었던 것. 배포 이력과 대조해보니 그 시점엔 배포가 없어서 "동시 배포로 인한 버스트"는 아니었고, 이후 13일간 재발이 없어 일시적 재시도 폭주 정도로 추정. 급한 불은 아니지만 dev 장애가 prod 모니터링까지 막을 수 있는 구조라는 게 남은 문제.
✏️ 4. dev는 없애도 될까?
한 번은 "dev 모니터링을 없애면 되지 않나" 생각했는데, dev는 TestFlight 배포용 - 실제 외부 베타 테스터가 쓰는 환경이었다. 프로덕션 배포 전 문제를 잡아내는 게 dev의 존재 이유라 계속 모니터링해야 한다는 결론.
남은 선택지는 완전 분리(토큰/스택 분리, 운영 부담 2배) vs 공유 유지 + 재발 방지(queue_config 조정, 비용 없음). 규모상 후자가 현실적이라는 결론까지 냈고, 실제 반영은 다음 작업으로 남겨뒀다.
✏️ 5. "그런데 우리가 이걸로 뭘 보고 싶은 거지?"
Actuator + Micrometer가 기본으로 주는 건 JVM 힙, GC, HikariCP, HTTP 처리량 같은 인프라 지표뿐이었다. "서버가 안 죽었는지"는 보이는데 "서비스가 잘 되는지"는 안 보였다.
Slack 알림은 사건이 터진 순간을 알려주는 반응형 신호고, Grafana/Prometheus는 추세를 보고 사전에 알아채는 용도라는 역할 구분을 정리하고 나서, 커스텀 비즈니스 메트릭을 하나 추가해보기로 했다.
✏️ 6. 첫 커스텀 메트릭: 로그인 성공/실패
Micrometer Counter를 쓰는 코드가 프로젝트에 하나도 없어서, 첫 시도는 범위를 최대한 좁혔다.
- 메트릭: login.attempts (Prometheus: login_attempts_total)
- 태그: provider(kakao/apple), result(success/fail) - 딱 2개. 카디널리티 늘리면 429 리스크도 같이 커지니 신규가입 여부나 에러코드는 제외.
- 위치: OAuthService.kakaoLoginV2 / appleLoginV2
public Tokens kakaoLoginV2(KakaoLoginRequestV2 request) {
try {
User user = findOrCreateUser(request.email(), KAKAO, request.providerId(), request.deviceType());
user.updateDeviceType(request.deviceType());
Tokens tokens = generateOauthJwtTokens(user.getEmail(), user.getProvider(), user.getProviderId());
countLoginAttempt("kakao", "success");
return tokens;
} catch (Exception e) {
countLoginAttempt("kakao", "fail");
throw e;
}
}
catch (Exception e)로 넓게 잡은 이유는, 내부에서 Spring Security authenticate()가 실패하면 BaseException이 아니라 AuthenticationException이 던져지기 때문 - 이것도 실패로 잡아야 정확한 실패율이 나온다.
V1은 계측하지 않았다. /actuator/prometheus에서 http_server_requests_seconds_count로 확인해보니 한 달간 V1 요청이 0건 - 이미 삭제 예정인 죽은 코드에 투자할 이유가 없었다.
✏️ 7. 다음 할 일
- queue_config로 Alloy 재시도 폭주 방지
- HealthCheckController가 앱 포트에서 항상 UP 반환하는 문제 정리
- 배포 후 대시보드에서 login_attempts_total 실제 반영 확인
'Back-End > 잇슈' 카테고리의 다른 글
| [ EAT-SSU / 잇슈 ] - Flyway 마이그레이션 실패로 인한 배포 장애 막기 (0) | 2026.08.19 |
|---|---|
| [EAT-SSU / 잇슈] - RDS 다운 원인을 찾아 떠난 트러블슈팅 기록 #1 (0) | 2026.08.13 |
| [EAT-SSU / 잇슈] - Swagger 문서 분리와 DTO 패키지 재정리 (0) | 2026.07.24 |
| [EAT-SSU / 잇슈] - CI/CD 개선 작업 정리 #1 (0) | 2026.07.05 |
| [EAT-SSU / 잇슈] - Grafana Cloud + Alloy로 모니터링 구축 (0) | 2026.06.30 |
- Total
- Today
- Yesterday
- 이분 매칭
- Do it!
- 자바스크립트
- 스택
- BFS
- java
- c++ string
- 반복문
- 알고리즘
- 카운팅 정렬
- html
- 유클리드 호제법
- 자료구조
- HTML5
- 세그먼트 트리
- DP
- 알고리즘 공부
- 투 포인터
- DFS
- js
- 에라토스테네스의 체
- 스프링 부트 crud 게시판 구현
- 유니온 파인드
- Spring Boot
- 백준
- 우선순위 큐
- 백준 풀이
- 자바
- CSS
- C++
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
