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이다. 일단 메모리 설정부터 하자.
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 돌렸으면 바로 잡을 수 있던건데, 실제로 메모리 누수에 대한 트러블 슈팅은 처음이어서 우왕좌왕 해맸던 것 같다. 처음에 이 메모리 관련 이슈로 문제가 발생했을 때 어디서부터 봐야하나 감을 잡을 수 없었는데 이번 경험을 통해서 앞으로 메모리 관련이슈가 발생했을때 음..이거랑 저거 한번체크해봐야겠구만! 하는 약간의 시야는 생긴 것 같다 ㅋㅋ
위 명령어를 먹여주자! 저게 뭐냐면 라우팅정보를 가지고 있는 테이블이 있는데 앞으로 80으로 들어오는 포트번호는 8080으로 해석해주세요~ 라고 입력해 놓는거다. 그럼 우리가 그냥 인터넷 주소치듯이 (보통 인터넷 포트가 80포트니까 80포트는 생략함) 치면 사실 80포트로 요청이 갈껀데 저 테이블 정보를보고 아! 80포트는 8080으로 해석하라네!? ㅇㅋㅇㅋ 하고 8080으로 변환을 시켜주는거다. 그럼 우리 톰캣주소로 포워딩이 되는거다.
말은 거창했는데 명령어를 먹이면 뭐.. 큰 반응은 없다..
3. 결과 확인
변경 전 :http://자기AWS아이피:8080/reqUrl.do?reqParam=3
변경 후 :http://자기AWS아이피/reqUrl.do?reqParam=3
자 변경 후 주소로 접속이 가능한걸 확인 할 수 있다. 아마도 우리 소스대로라면 구글을 띄울것이다.
처음에 했던 테스트했던 URL인데 다른점이라면 중간에 프로젝트명이 바꼈다. 변경후 경로를 요청해보면 아마 원하는 창이 뜰꺼다. 변경전 주소를 떠도 될꺼고! 서버에서 중간에 CP_service-1.0.0 이라는 프로젝트명 경로가오면 / 경로로 포워딩시켜주는 원리인 것 같다.
이제 프로젝트명이 안보이니 그래도 좀 구실은 갖춘것 같다.
만약 저거 톰캣 껏다켜도 안되는사람은 rebbot 명령어로 EC2 인스턴스를 재부팅시키고 다시 Putty로 붙어서 해당 경로까지가서 다시 톰캣을 재실행봐라. 무슨 이유인지 모르겠는데. 톰캣 종료할때 프로세스가 안죽는 현상이 있는 것 같다..
요기 링크를 보고 이해하면 될 것 같다.일단 시작하기 전에 우리가 어디까지 왔는지 한번 보자. 내가 항상 어떤 작업을 하던지 느끼는거지만, 전체 숲을 보고 이해를 해야 비로소 그 숲에서 본인이 뭘 하는지 알 수 있다. 군 생활을 하던 회사 생활을 하던, 숲을 모른체로 시키는 것만 하다보면 내가 뭔가를 하고 있어도 그 큰 숲에서 뭘하는지 모르면, 내가하는 것도 이해할 수 없기 때문에 우리가 지금 어떤 부분에서 뭘 하려는지 먼저 알아보자.
짜잔. 금방 파워포인트로 만들었다. 우리가 저번 시간까지 스프링 예제 프로젝트를 하나 만들어 놨고, 이제 그걸 돌리기 위해서 아파치 톰캣이란 놈 위에 올릴 것이다. 그러기 위해 먼저 톰캣을 설치하고, 그다음에 스프링 프로젝트랑 연결할 계획이다.
저 박스안에 있는 버튼을 클릭해서 다운받아주자. 용량은 10메가 정도라 금방 받는다. 다운받은 파일을 실행해주자.
1. 넥스트를 눌러주자.
2. 열심히 하곘냐는 약속에 동의해주자.
3. 여기도 걍 넘어가준다.
요기는 좀 설명할 내용이 있다. 1번 박스를 보자.
- Server Shutdown Port : 셧다운 명령어로 끌 수 있게할 건지인데 -1 포트는 사용안함이다. 무난하게 8005로 맞춰주자.
- HTTP/1.1 Connector Port : 제일 중요하다. HTTP 통신 포트를 뭘로 할꺼냐는데 우리가 저번에 AWS 톰캣 포트 방화벽을 8080으로 열어놨으니 8080으로 설정해주자. 혹시 오라클 등 다른 프로그램과 충돌날 것이 무서운 사람은 8090으로 설정해도 무방하다.
- Windows Service Name : 이 톰캣 서비스 이름이 머냐는데 그냥 둬도 무방하다.
- Create Shortcut for all users : 무슨 의민지 모른다. 걍 두자. 아는사람 있으면 알려줘라
- Tomcat Administrator Login(optional)
- User Name/Password : 해당 톰캣에 접속할 ID와 비번
- Roles : 권한 같은데 그냥 두자.
위 내용들을 다 기입해주고, Next버튼을 눌러주자. 위 내용중 사용자 계정내용만 각자쓰고 나머지는 같게하면 될 것 같다.
1. 자바 JDK가 설치된 위치를 확인하고 NEXT를 눌러준다. 보통 자동으로 잡아주는거 같은데 혹시 경로를 못잡거나 해당 경로에 자바 JDK가 없으면 나중에 오류뜨니 한번 저 경로에 가보길 추천한다.
2. 톰캣을 어디다 설치할껀지 경로를 지정한다. 원하는 드라이브에 바로 Tomcat 8.5 이름으로 생성하는 것을 추천한다.
3. 마지막 화면에서 둘다 체크를 해제하고 완료를 누른다. 혹시 Run Apache Tomcat 버튼을 눌렀다면 화면 우측 하단 트레이 아이콘 모인데에 가서 아파치 실행되고 있는걸 오른쪽 마우스 누른뒤 Stop Service를 눌러주자.
아파치 톰캣 연동
자 다시 저번시간에 우리가 만들었던 프로젝트로 돌아와서 상단에 Window-Preferences 버튼을 눌러주자. 혹시 프로젝트 생성을 못했다면 저번 글을 읽고 따라하면 된다. 아 그리고 저번 포스팅에는 아파치 8.0으로 한다 했었는데 8.x버전중에 8.5가 최신이길래 이번편부턴 다 8.5로 진행하는 것으로 할 예정이다. 저번 Servlet Spec은 영향이 없는데 아파치 톰캣 8.5도 Dynamic Web Module Version 3.1을 사용하기 때문에 상관이 없다.
좌측 1번에서 Server를 눌러주고 하위 메뉴인 Runtime Envirionment 클릭 후 3번에 있는 Add버튼을 클릭한다. 이후 4번 박스에 있는 아파치 톰캣 8.5를 선택해주고 넥스트를 눌러준다.
여기도 개쉽다. 1번 Name은 톰캣 이름인데 간지나는걸로 하나 정해준다. 사실 기본값인 Apache Tomcat 8.5가 제일 간지나니 걍 둬도 된다.
이후 2번 박스에있는 Browse.. 버튼을 눌러서 아까 톰캣 설치한 폴더로 경로를 잡아준다. 이후 3번 박스를 보면 잡힌 경로를 볼 수 있다. 이후 4번 Finish 버튼을 눌러 마무리 해주자.
오우~shit~ 정상적으로 등록이 돼따.6번 박스에 있는 Apply and Close 버튼을 눌러 마무리 해주자.
메인화면에서 Server 탭을 누르고 다음 밑에 긴 텍스트를 눌러주자. 그럼 아마 우측 사진의 화면을 보면 저렇게 되어있을꺼다. 3번 박스에있는 아파치 톰캣 8.5가 선택되어있고, 4번 박스에는 저렇게 기본 설정이 되어 있을 것이다.
제일 중요한건 저기 Server runtime environment에 아까 만든 Apache Tomcat v8.5 라는 실행환경이 잡히나 봐야한다. 저게 뜨면 아까 만든 실행환경이 잡히는거다. 그러므로 서버 이름 고칠꺼면 고치고 꾸밈은 사치라고 판단되는 사람은 그냥 파로 5번 박스에 있는 Next 버튼을 누르면 된다.
자 화면에서 우리가 만들었던 프로젝트가 뜰텐데 그걸 누르고 2번 박스인 Add버튼을 누른다 그럼 3번 박스위치로 프로젝트가 이동한다. 사용 가능한 프로젝트중 어떤 프로젝트를 톰캣에 올릴껀지 정하는 화면이다. 다됐으면 4번 Finish버튼을 눌러주자.
오우 씨엣..! 톰캣 서버가 만들어졌다..!
보면 Package Explore 창을 보면 Servers 라는 폴더가 추가된 것을 알 수 있다. 잘 되었다는 뜻이다. ㅎㅎ
톰캣 세부 설정
자 그냥 돌리면 접속 주소가 http://localhost:8090/CP_service 로 접속해야 프로젝트가 돌아간다. 이렇게하면 두 가지 문제점이 있다. 먼저 우린 톰캣 포트를 8080으로 할껀데..? 8090으로 설정되니 이거 바꿔야하고, 두번째 주소 맨뒤에 프로젝트의 이름이 노출되어 있다. 이후 어떤 요청을 하더라도 저 프로젝트 명이 따라다니니 저걸 숨겨줄 예정이다.
자 일단 하단의 1번 박스인 서버탭에 가서 2번 추가한 톰캣 서버를 "더블 클릭" 한다.
그럼 톰캣 설정화면이 나오는데 1번 박스에 지금 8090으로 되어있을 텐데 8080으로 변경하고 "Ctrl+S"를 눌러 저장한번 해주고 2번 박스에 있는 모듈 탭으로 이동한다.
모듈탭으로 이동 후 1번 박스에 있는 추가한 프로젝트를 눌러주고 2번 박스에 있는 Edit 버튼을 누른다. 3번 박스를 보면 우리 프로젝트의 이름이 디폴트로 들어가 있을텐데 다 지워주고 4번 박스인 OK를 눌러주자
그리고 마지막으로 "Ctrl+S"를 눌러 꼭 저장해주자!!!
그 다음 우리 1번 박스의 우리 서버를 눌러주고 2번 박스에 있는 재생버튼을 눌러주자.
머 이런 방화벽 경고가 뜰텐데 다 허용해주자.
이후 간지나는 Log 들이 찍히면서 구동된다.
톰캣 상태도 Strated로 변한 것을 볼 수 있다.
프로젝트 서비스 접속
http://localhost:8080/
자 위 주소를 인터넷 주소창에 쓰고 엔터를 눌러보자!
대표사진 삭제
사진 설명을 입력하세요.
참고로 localhost란 바로 자기 자신 컴퓨터의 주소를 말한다. 저렇게 localhost라고 써놓고 컴퓨터가 작업을 수행할때는 localhost -> 127.0.0.1 로 변환한다. 여기서 127.0.0.1 이란 컴퓨터 세계에서 자기 자신이라고 약속한 IP주소이다.
그리고 뒤에 나오는 :8080은 포트번호인데 8080이 톰캣포트니까 처음부터 보자면 http:// 즉HyperText Transfer Protocol 통신방식으로 내컴퓨터의 톰캣포트를 요청한다~ 정도 되겠다.
여기서 또 http의 의미가 궁금할 수도 있는겠지만, 비전공자분들 수준에선 우리가 어떤 정보를 남에게 전달할때, 말로도 할 수 있고, 편지로도 줄 수 있고, 택배로도 줄 수있고, 전화로도 줄 수 있는 것 처럼. 정보를 전달하는 방법의 한 가지라고 생각하면된다.
살짝만 더 들어가면, www(world wide web) 세상에서 웹페이지나 그림같은 것을 전달하는 통신 규약이라고 생각하면 된다!
저번 시간까지 PUTTY를 이용해서 원격 서버에 접속하는 법에 대해서 배웠다. 이제 본격적으로 웹 서비스를 만들어 볼껀데 그전에 우리 비전공자분들도 이해를 하고 출발해야 나중에 포기를 안하니, 웹 서비스가 무엇인지 알아보자.
자 일단 학부생 수준부터 이야기 해보면 과거에 프로젝트 하면서 APM서버라는 말을 많이 들어봤을 것이다. 혹은 AMP서버라고도 부르기도 하던데 바로 Apache + PHP + MYSQL 조합으로 연동하여 웹 서비스를 수행하는 것이다. 대략적인 큰 그림은 이것과 비슷하다.
웹 서비스 = ①Server + ②Spring (Project) + ③Database (DBMS)
자 가장 중요하다고 생각하는 3개 요소를 내 뇌피셜로 한번 써봤다. 자 어떤거부터 알아봐야 할까? Server가 먼지부터 알아보자! 그전에 내가 포스팅 하는 목적은 비전공자들도 이해할 수 있도록 눈높이에 맞는 비유나 표현을 사용할 예정이니 전문 개발자들 분께선 뭐 글이 이따위야! 하시지 마시고 이해해주셨으면 한다.
1. Server = Apach Tomcat Server
비전공자도 이해하려면 이걸 어떻게 설명해야할까 고민이 많다. 서버라...음.. 그냥 눈에 보이진 않지만.. 뭔가를 처리해주는.. 로봇같은...역할? 이정도 수준으로 일반인들은 느끼고 잇을 것이다.
먼저 서버는 WEB 서버가 있고 WAS 서버가 있다. 앗. 비전공자들 이해할 수 있을정도로 쉽게 알려준다 해놓고 시작부터 어려운 것부터 꺼내냐고 할 수 있겠지만.. 나도 고민하다가 이 말부터 꺼내야 뒷 내용 전개가 가능 할 것같다.
2. WEB서버 (Web Server)
자 히스토리부터 살펴보자. 예전엔 WEB 서버라는 것이 주로 쓰였다. 한글 발음 그대로 웹 서버! 들어는 봤을 것이다. 이친구는 정적인 자료의 처리를 해준다. css (화면 레이아웃 설정파일정도), html (웹페이지 화면), 이미지(화면에 띄어지는) 등등 내용이 변하지 않는 파일들의 요청을 들어준다.
예를들어 우리가 extsdd.tistory.com이라는 웹 주소를 요청하면 서버는 그 요청에 해당하는 화면을 html 파일로 뿌려준다. html과 동시에 위에나온 화면 레이아웃을 설정해주는 css파일 그리고 화면에 띄어줄 이미지들 이것들은 내용이 변하지 않고 정적인 파일이기 때문에 이 WEB서버란 친구가 착실하게 뿌려주는 것이다.
사용자 입장에선 이 서버로부터 받아낸 html, css, 이미지 등을 조합해 내 화면에 구성해서 띄어주는거다. 이 방법은 정적이기 때문에 그 사이트의 모든 화면들은 모두 html 파일로 서버에 저장해놓고 그걸 그대로 뿌려주는 것이다. 예를들면 로그인 화면, 첫 번째 글을 눌렀을 때 화면, 두 번째 글을 눌렀을 때 화면 등. 그 사이트에서 존재하는 모든 화면이란 화면은 모두 서버에 html 패거리(css, 이미지 등)를 다 저장해 놨던것이다.
이렇게 모든 화면에 대해서 서버가 다 가지고 있다보니 화면을 조금 수정하려고하면 HTML을 전부 수정하거나, 모든 HTML 리소스들을 다 가지고 있다보니 서버 자원들도 커지고, 한 화면마다 다 하나하나 요청을 처리하다보니 부하도 있고 문제가 많았다. 그래서 등장한게 바로 Dynamic Web이다. 동적 웹!!
3. WAS서버 (Web Application Server)
기존 Web server의 한계는 위에 적어놨고, WAS는 한층더 발전된 개념이다. 바로 Dynamic 해졌다..! 한국말로는 동적으로 변했다..! 이게뭐냐면 Servlet Container라는 개념이 추가됐다. 이게 머냐면은 사용자가 웹 페이지 요청을 보내면 이 Servlet Container 라는 친구가 요청을보고 아! 이요청은 이화면에 이런 정보들이 필요한 페이지구나!! 하고 이친구가 뚝딱뚝딱 정보를 만들어서 실시간으로 html파일을 만들어버린당..! 그리고 그걸 바로 사용자에게 줘버린다..ㄷㄷㄷㄷㄷㄷㄷㄷㄷㄷ
즉. 예전처럼 웹 사이트의 모든 html파일을 가지고 있지않아도, html을 어떻게 만들지 정도만 정의해 놓으면 이 WAS라는 친구가 그 요청에 필요한 html을 만들어버리는 것이다.! 구몬을 얼마나 해야 이런 아이디어가 나오지..! 이렇게 되면 모든 리소스를 미리 안가지고 있어도 되는 장점이 생기며 그만큼 부하도 적어지게 되는 것이다.
잘 생각해보면 이게 가능한 이유는 간단하다. 어떤 글을 요청하던 화면이 크게 바뀌진 않는다. 글을 누르면 제목이 있고 본문이 있고 댓글들이 있고.. 그렇다. 큰 틀은 같은데 안에 정보들만 바꿔주면 되는것이다. 그렇게 이 동적 웹서비스를 가능케 하는게 바로 우리 WAS성님 되시겠다.
4. WEB서버 + WAS서버
자 그럼. WAS서버가 좋다고해서 WAS만 쓸까? 아니다. 여전히 이미지파일이나 소수의 HTML과 같은 정적인 리소스들도 아직도 처리해야하기 때문에 WEB서버도 필요하다. 그래서 아주 간단하다. 같이 쓴다. WEB서버와 WAS서버 둘다 같이 사용하는 것이다. 정적인건 WEB이 그대로 처리하고, 동적인건 WAS가 처리하고. 위와 같은 그림이 될 것이다. 우측에 DB는 아직 머리아프니 나중에 알아보도록 하자.
프로세스를 보면 이런거다. 사용자한테 페이지 요청이 서버에 들어오면 처음에 WEB이 받는다. 만약 간단한거 머 이미지나 css파일 처럼 정적인거면 WEB이 바로 반응을 해준다. 헤헤..이거 필요한거지!? 이런식으로... 그런데 살짝 어려운게 왔다. 동적인 페이지 요청이 왔다하면 WEB이 어찌할줄을 몰라하면서 하.....이거 뭐징...ㅠㅠ 하면서 WAS한테 보내서 걔한테 처리하라고 해야겠다 하고! WAS에게 던진다. 근데 WAS는 똑똑하니까 그 동적 요청을 DB에서 정보들을 끌어와서 그 요청에 맞게 HTML을 작성한다. 그리고 그걸 다시 WEB한테 보내고 WEB은 아하!!!!!!!역시 WAS야! 하면서 WAS에게 받은걸 사용자한테 뿌듯해하면서 준다.
5. Apache Tomcat Server
와우 이제 마지막 개념정리다. 방금까진 살짝 x밥 같았지만 이제야 좀 그럴싸한 내용이 나왔다. 아.파.치. 톰.캣!! 아주~~널리 쓰고 있는 서버구성의 이름이다. 아직 개념이 안잡히면 헷갈릴 수도 있다. 아니 아파치 서버도 있고 톰캣 서버도 있고 아파치 톰캣 서버도 있고! 대체뭐야! 같은건가? 라고도 생각 할 수 있는데 살짝 다르다.
가. Apache Server = WEB Server
아파치 서버라고 하면 위에 계속 설명했던 WEB 역할을 하는 서버의 이름이다.
나. Tomcat Server = WAS Server
톰캣 서버는 WAS서버의 역할을 하는 서버의 이름이다.
다. Apache Tomcat Server = WEB Server + WAS server
아파치 톰캣 서버는 WEB서버와 WAS서버 두개다 동작하는 서버구성이다. 위와 같다고 생각하면 되겠다. 이렇게 구성해놓고 어떤 요청이왔을때 정적인 리소스를 요청하면 Apache가 처리하고 동적인 요청이 오면 Tomcat에게 넘겨 처리하도록 하는 것이다!
6. WAS의 처리 프로세스
와우 이제 좀..어려워 졌다.. 하지만 WAS를 좀 구체적으로 그린것 밖에 없고 나머지는 다 똑같다. WAS에 대해 더 알아보자면 컨테이너란 녀석이 WAS가 돌아가는 동안은 24시간동안 당직을 서고 있는다. 이 컨테이너라는 친구가 WEB에서 못해먹겠다고 동적 요청을 받으면 그 요청에대한 정보로 httpServletRequest 객체(정보 뭉텅이라고 생각하면 됨)와 httpServletResponse라는 빈 객체를 만들고 그걸 새 쓰레드(작업 단위라고 생각하면 됨)로 생성한다.
이렇게 해당 작업에 대한 쓰레드에 요청과, 응답 객체를 생성해두고 또 다른 한편으론 Web.xml이라는 파일에 접근해 이 요청을 어떤놈이 처리하는지를 알아가지고 온다. 그 요청을 처리하는 친구가 Servlet 즉 서블릿 이란 친군데 담당 Selvlet을 찾아내면 그 서블릿에대 대고 doGet() 함수와 doPost()함수를 실행시킨다. 즉, httpServletRequest에서 전달받은 데이터들로 새로운 동적 페이지를 만드는 거다. 중간에 필요한 정보들은 DB에서 받아오기도 한다. 이렇게 만들어진 결과 페이지는 아까 만들어 두었던 httpServletResponse 객체에 담아놓고 작업이 완료되면 다시 WEB한테 보내는데 WEB은 HTTP(80포트)만 다루는 친구라 알아먹을 수 있게 HttpResponse 형태로 가공해서 WEB한테 던져주게 된다.
던져 주면서 동시에 방금 만들었던 httpServletRequest, httpServletResponse 객체들 그리고 해당 쓰레드, 즉 작업했던 것 모든것을 소멸시키고 아까 HttpResponse 를 받았던 WEB은 그와중에 그걸 사용자에게 전달하게 되면 요청이 완료가 되는 것이다.