1. 사건
어느날 제우스를 통하여 운영서버 CPU 사용률이 폭발적으로 올라가고, 무한로딩에 걸리는 현상이 나타났다. 이로인해 많은 사용자들에게 정상적인 서비스를 제공하지 못하는 상황이었고 이에 대해 즉각적인 대응을 하였다.



2. 원인
원인은 즉슨 한 테이블에 대하여 데이터를 조회후 POI 방식으로 엑셀파일을다운로드 하게되는  기능이었다. 이 테이블에는 150만건의 데이터가 누적되어 있었고, 테이블 풀 스캔 방지 및 인덱스 추가, 데이터 조회시 1개월 미만으로 조건을 걸어 성능 저하 방지를 예방 하였다. 인덱으로 인해 DB조회는 걱정 없었지만 문제는 js단에서만 데이터 조회기간 1개월을 걸어주는게 화근이었다. js에서만 기간 체크했지 Java단에서는 기 기간 체크하는 로직을 넣지 못하였고 이로인해 불특정 누군가 엑셀다운로드 하는하는 URL직접 입력, 이로 인해 150만건의 데이터를 풀 스캔 및 전부 엑셀화되어 서버에 부담이되고 CPU 사용률이 폭발적으로 증가하였다.



3. 대응
서버을 다운시키고 바로 재가동으로 엑셀화 로직 및 DB 조회를 강제로 막았으며, 1차 대응으로 엑셀 다운로드 버튼을 숨겼으나 다시 서버가 다운 및 무한로딩 현상이 일어났음을 보아 엑셀 다운로드 URL 직접 주소창에 쳐서 접근하는 걸로 파악되었다.



2차 대응으로 엑셀다운로드하는 맵핑주소를 변경 하였으며 이로인해 또 다시 서버가 터지는 일이 없었다.

4. 대처
직접 URL로 접근시 기간 파라미터가 없으면 강제로 오늘날짜 기준 1개월 기간을 잡을 수 있게 처리하였으며 각종 필수 값에 대한 처리도 파라미터에 담겨있지 않다면 오늘 기준 기본 셋팅값이 들어갈 수 있게 처리를 하였다.



5. 후기
여태 또 다시 해당 기능에 대해 이슈가 일어나지 않는걸 보아 새로 처리한 로직들이 제대로 가동되고 있다는 사실을 알 수 있었다. 또한 150만건 같은 큰 데이터들을 어떻게 다루어야 이를 조회시 무엇을  무엇을 생각해야하는지에 대해 한번더 고민 해보고 생각해보는 이슈였던 거 같다.



6. 여담
여담이지만 바로 하위 메뉴에 똑같은 기능에 다른 테이블을 바라보고 있는 다른 URL도 파라미터 없이 다운로드가된 기록이 남아있다. 이걸보고 로봇이 데이터 수집하고 간거 아닐까 생각한다. 

2021년도에 입사를 해서 온보딩 시간과 첫 프로젝트를 거쳐 느꼇던 경험들을 다시 생각해 보려는 시간을 가지겠다.

 

2022년도 목표

- 회사 적응 잘하기

- 1인분 충분히 해내기

- git, 블로그활동 꾸준히 하기

- 정처기 기사 따기

 

결과적으로 말하면 꾸준한 성실성이 필요한 git, 블로그 활동은 제대로 실패고 정처기 시험 준비는 계속 같은 우물만 팠던거 같다. 그외 회사적응 잘하기와 1인분해내기는 어찌어찌 클리어 하고 있던 2022년이었던거 같다.

할 줄아는 일이 늘어나니 책임지는 일도 늘어났고 그에 부응하기 위해 실무 공부를 많이 했던 2022년도 이었던거 같다

 

 

내가 하는 일은 내가 책임을 진다.

 

1. 첫 프로젝트

2022년도 첫 프로젝트를 시행하면서 (하필 첫프로젝트가 회사 지부사상 제일 큰 규모의 프로젝트..) 진짜 제대로 내가 1인분을 할 수 있는지에 대한 역량 평가와 많은 실무 기술을 접했는데 제일 고전 했던건 올바른 요구사항 분석과 제대로된 클린 코딩이었던거 같다.

 

올바른 요구사항 분석은 아직 신입이라는 변명을 가능 했지만 클린코딩은 내 실력과 직결하기에 만족할만한 코드를 짜려고 노력해왔고 그만큼 시간을 많이 부었던거 같다. 

기억에 남았던 힘들었던 기능들은 기존에 레거시 코드를 토대로 메인페이지에 달력모양에 일정을 띄우는 기능이었는데 여러가지 홈페이지들이 얽히면서 많은 조건문들이 주렁주렁 달렸고 최대한 깔끔하려고 노력을 많이 했던거 같다.

 

그중 제일 힘들었던건 기존 레거시  CMS는 Oracle DB를 사용했는데 새로운 버전의 CMS는 CubirdDB를 사용하면서 달라진 문법 사용법들( 크게 달라지진 않지만 옵티마이저의 rownum, order By 처리순서 차이) 등등 자잘 자잘하게 나를 괴롭혔던것과 OracleDB에있던 기존 데이터들을 CubridDB로 마이그레이션 할때 제일 압박감과 어려움이 있었다고 생각한다.

 

2. 후회

사실 이제 6개월차 까지 유지보수 및 자잘자잘한 기능 개발만 하다 첫 프로젝트를 맞이하면서 실력에 대한 부끄러움과, 더많이 공부를 못했던 나에 대한 후회가 많이 있었다. 바쁘다는 핑계와 피곤하다는 핑계로 프로젝트 전 시간이 충분히 많았음에도 불구 하고 게을르고 나에 대한 반성을 연말에 많이 했던 것 같다.

 

3. 새로운 목표

2023년에는 좀더 발전한 나를 위해 그리고 내가 사랑하는 일을 위해 여러가지 목표를 잡아 보았다.

 - 정처기 따기

-  sqld 따기

 - 프로그래머스 알고리즘,  sql 꾸준히 풀기

 - 토이프로젝트 시작해보기

 - 운동하기(잦은 야근으로 인한 몸관리)

 

크게 4가지로 선정해 놓았고 정처기 시험 준비는 이미 시작하고 있었다. 기사 자격증이 없으니 많이 아쉬운 부분이 많았던거 같다. 서비스 직렬로 바꾸면 불필요 하려나?

 

더나은 내일을 위해 2022년 회고록을 마치도록 하겠다. 부끄럽고 후회가 있었던 2022년이었지만 성장하고 아프고 지금의 나로 있게해준 소중한 2022년이었던것 같다.

 

2023에도 잘해보자.

2023년에도 잘부탁 드립니다.
원인 :  UserDetailsService를 Implements 한 UserDetailServiceImpl 매소드중 로그인 실행시 
실행 되는 loadUserByUsername 매소드의 반환 
return new User(user.getUnm(), user.getPw(), authorities); 안에 파라미터가 하나라도 null 일시 생기는 오류

해결방안

1. 파라미터들(user.getUnm(), user.getPw(), authorities)의 널체크

2. UserEntity user = mapper.selUser(username); 같이 매퍼에 연결 되어 있을 경우 sql 다시 체크 

 

먼제 AWS에 인스턴스를 만들고 난 후를 가정한다

AWS에서 ec2인스턴스를 아직 못 만들었다면 이 글을 읽고 따라하길 바란다 

 

AWS 인스턴스 개념잡기

https://youtu.be/Pv2yDJ2NKQA

출처 : 생활코딩

 

실제로 배포할때 따라했던 AWS셋팅 

 

https://youtu.be/eLa6Ud5RYR8?t=1346 

 

이후 3강에 puTTY를 이용한 ubuntu 접속까지.

https://youtu.be/S5ETW2zCbuA

 

이 강의 5개를 (6강은 docker) 2번 정독 했다.

출처:데어 프로그래밍

 

데어 프로그래밍

getinthere@naver.com

www.youtube.com

 

 

자 AWS EC2 셋팅과 인스턴스를 설정했고 puTTY를 이용해서 ubuntu에 접속했다면, 이제 본격적으로 ubuntu에서 war파일을 배포할 준비가 끝났다는 것이다.

프로젝트 mvc : SPRING4
언어: JAVA
Cloud: AWS/ EC2/ UBUNTu
WAS : Tomcat9
DB: MARIADB

 

 

 

고생길 가즈아ㅏㅏㅏㅏㅏㅏㅏㅏㅏ

 

 

 

 

첫 화면

이 떻다면 ubuntu를 입력해주고 시작하자.

 

본인은 5일동안 하루에 3시간 자며 개고생했으며 war 배포방법을 여러가지로 접했는데 모든 방법과 경험을 취합해서 하나의 메인 스트림으로 쭉 알려드리려고자 한다.

 

 

 

ubuntu에 war파일을 이용하여 배포하기 위해 해야 할것은

 

  1. jre 설치 
  2. jdk 설치
  3. JAVA_HOME 환경변수 설정
  4. tomcat9 설치 (apt-get install tomcat9
    • tar.gz 다운 방식은 해봤는데 초큼.... 파일 접근 권한 설정이 신경쓰여서...
  5. mysql설치
  6. war 배포(git clone, tomcat9-manager)

 

순서대로 잘따라오길 바란다!

 

1. jre 설치 

 

$ sudo apt-get update

리파지토리 업데이트

 

$sudo apt-get upgrade

리파지토리 업데이트

 

$sudo dpkg-reconfigure tzdata

날짜 시간변경 asia 엔터 ->seoul 엔터

 

 

$sudo apt-get install openjdk-8-jre-headless

jre 설치

 

 

2. jdk 설치

사실 리눅스에는 open jdk가 별도 내장되어 있어서 설치가 필요없긴하다 그래도 모르니

java -version 검색후 안뜨면 ㄱ

$sudo apt-get install openjdk-8-jdk

 

잘 설치 되어있는지 확인:

$java -version

$javac -version

둘 다 입력했을때 버전이 잘뜨면 됩니다. (jdk=java, jre = javac)

 

 

 

 

3. JAVA_HOME 환경변수 설정

 

JAVA_HOME 즉 자바 경로을 알려주기 위해 설정을 해야하는데 

$sudo nano /etc/profile

에 하는게 좋다 nano는 메모장 마치 txt 파일 작성을 편하게 해줌

제일 밑 하단에 

#JAVA
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64


#path
export PATH=$PATH:$JAVA_HOME/bin

를 추가해준다 (나중에 톰캣 설치하면 catalina_home이랑 path도 설장 할 것이다.)

 

$ source /etc/profile 입력 하여 즉시 적용 필수

 

JAVA_HOME의 경로는  환경마다 다를 수 있는데 수 많이 해본결과 apt-get intall로 설치하거나 리눅스 내장 경로는 저것일 것이다 혹시 모르니 경로 검색은

$sudo find / -name java-8-openjdk-amd64

하면 경로가 뜸 그걸 /bin/java 파일 전 경로까지 입력

 

 

4. tomcat9 설치

wget 으로 tar.gz 파일 받아서 war하려 했지만 추후 404에러 크리로 정식 루트를 타서 설치하려고함

$sudo apt-get install tomcat9
$sudo apt-get install tomcat9-admin (톰캣 매니저 사용위함)

y/n 뜨면 y눌러서 계속 설치 

 

다 설치 되었으면 CATALINA_HOME 환경변수 설정

$sudo nano /etc/profile

JAVA_HOME 밑에
#Tomcat9 Home
export CATALINA_HOME=/usr/share/tomcat9

#path에 추가 
export PATH=$PATH:$CATALINA_HOME/bin

 

/etc/profile 최하단 전문

#JAVA
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64


#Tomcat8 Home
export CATALINA_HOME=/usr/share/tomcat9


#path
export PATH=$PATH:$JAVA_HOME/bin
export PATH=$PATH:$CATALINA_HOME/bin

 

5. mariaDB 설치

 

 

$sudo apt-get install mariadb

 

마리아 db 실행 코드

$sudo mysql -r root -p 엔터 두번

root계정을 들어가는건데 처음엔 root로 들어가서 유저 설정 후 설정 유저로 들어가는걸 추천

설치 직후엔 root 계정 비번 설정을 안했기 때문에 password 요구해도 엔터 치면 넘어가짐

 

- 유저 설정(나중에 heidiSQL로 외부접속 하려면 필수 애초에 root로 접근 비추)

use myslq;

create user '유저명'@'%' identified by'비번';

%는 외부에서 접근 허용 하겠다는 말(내부만 가능하게 하려면 % -> localhost)

 

이제 권한을 주자 

GRANT ALL privileges ON DB명.* TO 유저명@'%';

 

본인 프로젝트에 맞는 sql를 사용하여

create database OO;를 해주자

 

6. war 프로젝트 파일 배포

 

방법은 3가지

git clone을 이용하여 파일 받아서 배포 

filezilla 사용

tomcat9-manager 사용하여  deploy

본인은 마지막 방법 사용 할 것이다.

 

이제 톰캣을 구동 할 것인데 톰캣 구동시 항상

$sudo tail -f /var/log/tomcat9/catalina.날짜.log

를 실행해둔 putty 창을 하나 띄워놓고 하길바란다 실시간 로그 띄워서 어디서 에러 터트리는지 알아야함.

permision denied 뜨면  cd /var, cd log, cd tomcat9 으로 한칸씩 접속하다 보면

아마 tomca9 접근할때 permision denied 가 뜰 것이다. 그럴때 

$sudo chmod 755 tomcat9 하면 접근가능

거기서 $sudo tail -f catalina.날짜.log 를 치면 댐

 

 

 

톰캣 start stop restart


$sudo service tomcat9 start
$sudo service tomcat9 stop
$sudo service tomcat9 restart

$sudo service tomcat9 start 시작해서

IP:8080 으로 접속 기본 index.html이 출력 될것이다. (이건 webapps 안 root폴더안에 있는 놈)

거기서 밑에 manager 링크를 클릭하면

 

IP:8080/manager/html 으로 가는데 404에러를 터트릴것

이걸 해결하기위해 tomcat9 폴더안 tomcat-users.xml를 수정해야한다

 

$cd /var/lib/tomcat9/conf 으로 접근
permision 또뜨면 한칸씩 올라가면서 
$sudo chmod 755 파일명 으로 뚫어주자

conf 폴더안 tomcat-users.xml 수정

$sudo nano tomcat-users.xml

<tomcat-users>
	<role rolename="manager-gui"/>
	<role rolename="manager-script"/>
	<role rolename="manager-jmx"/>
	<role rolename="manager-status"/>
	<role rolename="admin-gui"/>
	<role rolename="admin-script"/>
	<user username="admin" password="admin" 
	<roles="manager-gui,manager-script,
	manager-jmx,manager-status,admin-gui,admin-script"/>   ==> 추가
</tomcat-users>

설정후 톰캣 재시작 $sudo service tomcat9 restart

 

톰캣 가동후

IP:8080/manager 로들어가면 아이디 비밀번호 치라고 하는데 본인이 설정한 아이디 비번 치면댐

초기 설정 안했다면 admin/admin 으로 위에 설정하였다.

 

이런 화면이 뜬다면 밑에 war로 추출한 프로젝트를 선택하여 Delploy 시키면된다

선택한 war프로젝트가 자동으로 webapps 안에 위치하게 해줌

 

위에 리스트에 추가되면서 Running이 true로 바뀐다면 오른쪽 탭에 start를 눌러준다.

 

끘!!!!!

 

ps. 톰캣 가동후 계속 실시간 로그를 봐야한다 에러터지면 하나하나 검색하여 수정해줘야 함 start 눌러서 IP:8080/프로젝트 접글 할 때까지 로그에서 눈 떼지말라

PS. css 나 js가 먹히지 않고 로딩이 되었다면 호출되는 css,js 경로가 : /프로젝트명/경로/이름.css,js 에서 /프로젝트명 이빠져서 그런것일 수 도있다. 이럴땐 url 접근 경로를 바꾸기 위해 tomcat9/conf/server.xml안 <host><Context path="/" docBase="프로젝트명" reloadable="false"/></host>로 수정하자. 수정 톰캣 재실행 하면 IP:8080으로 접근 가능하면 바로 프로젝트가 뜰것

PS. 프로젝트404에러가 터지면 프로젝트 webapps안에 프로젝트 파일의 tomcat접근 권한이 있는지 확인해보자

cd /var/lib/tomcat9/webapps 로가서 ls -al를 치면 본인 프로젝트 파일 소유가 tomcat9 tomcat9이 되어 잇어야 한다.

'프로젝트' 카테고리의 다른 글

To do list 만들기(1)  (1) 2021.05.07

bin 폴더에 가서 

bin $ sudo ./catalina.sh start  구동시 
tomcat started 문구는 떻지만 화면은 안뜰때.

 

1. 로그 파일 확인 (로그 경로 위치파악)

$sudo find / -name catalina.out

 

2. 로그파일 상위에 들어가기 ( 경로는 상황에 다를 수 있음)

$cd /home/ubuntu/apache-tomcat-9.0.52/logs

 

3.로그파일 읽기

$sudo tail -f /home/ubuntu/apache-tomcat-9.0.52/logs/catalina.out

 

4. 발생원인  Caused by: java.lang.IllegalArgumentException: The main resource set specified [] is not valid

conf 안 server.xml 안에 맨밑 <host> <Context path="" docBase="" /></host>

에서 docBase안에 파일을 찾지못해서 발생 docBase경로를 바꾸어준거나 이름 오타 확인

java.lang.NumberFormatException: For input string: "writer"
	java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	java.lang.Integer.parseInt(Integer.java:580)
	java.lang.Integer.parseInt(Integer.java:615)
	javax.el.ListELResolver.coerce(ListELResolver.java:150)
	javax.el.ListELResolver.getValue(ListELResolver.java:67)
	org.apache.jasper.el.JasperELResolver.getValue(JasperELResolver.java:125)
	org.apache.el.parser.AstValue.getValue(AstValue.java:169)
	org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:190)
	org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:699)
	org.apache.jsp.WEB_002dINF.views.user.info_jsp._jspService(info_jsp.java:129)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:71)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:467)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:378)

 필자의 오류는 리스트안에 객체중 특정 값을 뽑아낼때 오류가 발생

 

데이터구조: 

Mapper

mapper를 통해 DB에서 데이터를 추출 BoardDomain 타입으로 리턴

infoService.java

리스트 형식으로 묶어서 반환 한뒤

infoController

controller에서 객체를 만들고 model를 사용해 infoUser의 명명으로  jsp에 뿌리고 있었다.

즉 List<BoardDomain>으로 mapper에서 바로 만들어 dto에 담아서 jsp로 날리고 있었음

그중 list안 BoardDomian중 writer를 뽑아낼때  

<div>${requestScope.infoUser.boardList.writer} 님의 프로필</div>

를 사용했었는데 이때 오류가 터진것 

 

원인: List로 날리고 있었기 때문에 for을 돌릴땐 list안 객체수만큼 반복이 되지만 단독으로 뿌릴땐 index번호가 필요 

 

해결: 

<div>${requestScope.infoUser.boardList[0].writer} 님의 프로필</div>

 

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.koreait.alsamo.user.info.InfoMapper.countAllReply
	org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)
	org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53)
	org.apache.ibatis.binding.MapperProxy.lambda$cachedInvoker$0(MapperProxy.java:115)
	java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688)
	org.apache.ibatis.binding.MapperProxy.cachedInvoker(MapperProxy.java:102)
	org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:85)
	com.sun.proxy.$Proxy45.countAllReply(Unknown Source)
	com.koreait.alsamo.user.info.InfoService.selAllReplyCount(InfoService.java:36)
	com.koreait.alsamo.user.info.InfoUserController.infoUser(InfoUserController.java:22)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

1. mapper 인터페이스 안에 생성된 매소드와 mapper.xml 안에 sql문이 1대1일 매핑이 되어있는지 확인

2. 매핑이 1대1 되어있는게 맞다면 sql문의 id명 오타가 있나 없나 확인

3. 오타도 없다면 mapper.xml과 mapper인터페이스 사이 경로가 제대로 되어있나 확인

Mapper.xml안에 설정 sql문이 없어서 생기는 문제

@Mapper
public interface UserMapper {
    int insUser(UserEntity param);

    UserEntity selUser(UserEntity param);

    int insGoogleUser(UserEntity param);

    UserEntity checkSocialUserExsist(UserEntity param);

    UserEntity chckAuthkey(UserEntity param);

    int upAuth_no(UserEntity param);

    int updUser(UserEntity param);

    UserEntity selId(UserEntity param);

    int updMark(UserEntity param);

    String selNowMark(int authNo);
}

mapper 클래스에 있는 모든 매소드가 mapper.xml 파일안에 sql로 제대로 있는지 확인 있다면 쿼리문 id 오타 확인

+ Recent posts