서버 장애 상황
EC2 프리티어이며 사용자 3~4명 어플의 간단한 crud API를 스프링부트로 열어논 상태였습니다. 근데 하루에 2~3번 CPU가 100%를 차지하며 1시간 가량 유지되다가 서버가 터졌고 (상태검사 실패) 서버에 대해 잘 몰랐던 저는 nohup.out 파일만을 보고 에러를 해결하기 시작하였습니다.
아래는 제가 썻던 해결 메모장입니다.
(1)
2023-11-02T15:08:26.118Z WARN 1290 --- [io-8080-exec-10] o.s.web.servlet.PageNotFound : No mapping for GET /cluster/list.query
10/30 -> 이런 요청이 옴 내 프로젝트에 저런 주소는 없음…
11/01 ->> 시큐리티 적용 후 일어나지 않음
(2)
Thread starvation or clock leap detected (housekeeper delta=48s763ms136µs340ns).
10/30 -> 위 문장이 수십 개 뜸
11/01 ->> 히카리풀을 20으로 늘림 경과 보는 중
(3)
[nio-8080-exec-9] o.s.web.servlet.PageNotFound
: No mapping for GET /hudson
10/30 -> 프로젝트엔 저런 주소가 없음
11/01 ->> 시큐리티 적용 후 일어나지 않음
(4)
2023-11-02T17:14:57.707Z WARN 1290 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 08001
2023-11-02T17:14:57.906Z ERROR 1290 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : HikariPool-1 - Connection is not available, request timed out after 119201ms.
10/30-> 데이터베이스 연결 실패가 뜸
10/31 ->> 예상원인 pool이 부족해서 연결 가능한 쓰레드가 없어서 커넥트가 안됨
11/01 ->>> 풀 늘리고 경과 보는 중
문제상황(1) - 프로젝트에 없는 주소로 요청이 들어옴
제가 설정한 api에 대해서만 요청을 하도록 스프링 시큐리티를 도입했고 아래 포스팅에 자세히 적어 놓았습니다!
(업로드 예정)
⭐️⭐️ 문제상황(2) - Thread starvation or clock leap detected Dead Lock, hikari ⭐️⭐️
1. 프로젝트의 한 thread 내의 별도 트랜잭션에서 추가적인 SQL문 실행이 필요해지면서 쓰레드가 커넥션을 더 필요로 하게 됨,
2. JPA 개념 중 영속성 컨텍스트 전략을 생각했을 때, 만약 서비스 메소드에서 2개의 다른 JPA레파지토리(extend)가 있고 각각 엔티티 매니저를 가지고 있을 때 엔티티 매니저는 DB연결이 필요한 시점에 각 각의 커넥션을 얻어야 한다. 이때 하나의 쓰레드에서 2개의 레파지토리(엔티티매니저)가 하나의 트랜잭션 범위에 있고 이 두개의 레파지토리(엔티티매니저)는 같은 영속성을 공유한다!
3. 이때 엔티티 매니저가 2개니까 한 트랜잭션에 2개의 커넥션이 필요하다!
그러나 쓰레드가 커넥션을 필요로 하는데 커넥션 풀에 자원이 부족하면 데드락이 발생한다. 쓰레드는 하나의 트랜잭션을 끝내지 못하고 쓰레드 Starvation 상황으로 이어진다. 이 상황에서 추가적인 다른 요청이 오면
4. 새로운 요청에 대한 작업을 할 쓰레드가 없어 NIO 커넥터가 계속 쓰레드를 생성하지만 2,3번 과정으로 남은 커넥션이 없어서 (나머지 쓰레드들은 커넥션이 부족해서 데드락) 반복해서 NIO 커넥터가 쓰레드를 생성하고 무한 반복이 되다가 총 쓰레드 량이 부족해지고 cpu를 과하게 쓰다가 99.9 까지 간 것이다.. 그래서
Thread starvation or clock leap detected Dead Lock, hikari 에러가 계속해서 생긴 것이고 EC2 서버는 상태검사를 통과하지 못 하고 죽은 것!
이후 히카리풀의 설정을 바꾸었다.
pool size = Tn x (Cm - 1) + 1 -> 최적의 Maximum Pool Size 구하는 공식 이용
이후 추가적인 작업을 해준 뒤에는 Thread starvation or clock leap detected Dead Lock, hikari
에러는 줄어들었고 cpu를 계속해서 점유하지 않았다.
hikari:
maximum-pool-size: 20
#클라리언트가 커넥션을 기다리는 최대시간(ms)
connection-timeout: 10000
#커넥션이 유휴상태로 풀에 유지되는 최대시간(ms)
idle-timeout: 10000
#커넥션이 풀에 의해 폐기되기 전에 유휴상태로 풀에 유지되는 최소시간(ms)
max-lifetime: 580000
data-source-properties:
#캐쉬 사용 여부
cachePrepStmts: true
#드라이버가 연결당 cache할 statement 수
prepStmtCacheSize: 200
#캐쉬할 SQL의 최대 길이
prepStmtCacheSqlLimit: 2048
#최신 버전 지원 받는 설정
useServerPrepStmts: true
문제상황(3) 그러나 계속해서 다른 프로세서가 80% 가량 CPU를 머금고 있어서 확인을 시작하였다.
문제의 프로세스 2개 snapd & amazon-ssm-agen
snapd란?
linux는 Open Source 로 구성된 OS 이기 때문에 그 기반으로 확장되어 개발사에 따라 Ubuntu, Fedora, Debian, Cent 등 다양하게 파편화 되었다.
그 상황에서 패키지 관리 툴은 apt, yum 등으로 해당 OS에 맞는 버전의 패키지만 관리할 수 있도록 함께 파편화 되었다.
따라서 linux 관리자는 다양한 패키지 관리 툴을 익혀야 하는 불편한 상황이 연출되었다.
이에 따라 Ubuntu 에서는 일원화된 패키지 관리 툴을 발표하는데 그것이 Snapd 이다.
출처 : https://yhjin.tistory.com/49
- 난 snap 관련 명령어를 쓰지 않는다. 그래서 지우기로 마음 먹었다 또한 디렉터리를 보다 알게 된 것인데 amazon-ssm-agen는 Snap안에 있는 파일로 같이 날렸다.
아래 게시물을 보고 지울 수 있었다. 꼭 마지막 apt-mark hold snapd 명령어로 다시 설치되지 않게 방지하자!
sudo systemctl status snapd.service
sudo systemctl stop snapd.service
sudo systemctl disable snapd.servic
sudo apt-mark hold snapd -> 다시 설치되지 않게 방지
https://hoing.io/archives/8933
https://dragontory.tistory.com/445
이후
Thread starvation or clock leap detected Dead Lock, hikari 에러는 잘 보이지 않고 서버가 꺼지지도 않았다 ..흑 ㅠ....