GDSC 톰캣 스터디 회고

belowyoon·2023년 12월 2일

GDSC

목록 보기
1/1

GDSC에서 2023 하반기 톰캣 스터디를 진행했다.
해당 스터디를 하며 느낀점 및 배운점을 써보려 한다.

미션 1

처음에 톰캣에 대해서 전혀 모르고 시작한 것 같다.

코드가 어떻게 돌아가는지, Request와 Response를 어떻게 받아서, 처리를 해서 보내야 하는지 등 html을 화면에 띄우는 것 조차 힘들었던 것 같다.

그래서 Http11Processor에 모든 기능을 구현한 것이 생각난다.

구현하면서도 아 이건 아닌 것 같은데… 했지만 어떻게 구현해야할지 감이 안와서 넘겼었다.

GitHub - belowyoon/jwp-dashboard-http-mission at step1

미션 2 / 미션 3

모든 기능을 Http11Processor에 구현한 모든 기능을 책임 분리 하기 위해 다음과 같은 개념들을 공부하며 코드를 어떻게 수정할지 생각했다.

WAS

WAS는 Web Application Server의 약자로 웹 서버 + 웹 컨테이너가 합쳐진 형태로, 웹 서버 단독으로 처리할 수 없는 데이터베이스의 조회나 다양한 로직 처리가 필요한 동적 컨텐츠를 제공한다.

  • 웹 컨테이너란?

    여기서 웹 컨테이너란 웹 서버가 보낸 JSP, PHP 등의 파일을 수행한 결과를 다시 웹 서버로 보내주는 역할이다. 컨테이너란 JSP, Servlet 등을 실행 시킬 수 있는 소프트웨어를 의미한다.

    • JSP 란?
      JSP는 동적 웹 페이지를 생성하기 위한 Java 기반의 웹 프로그래밍 언어로 JSP 파일은 일반적으로 HTML 코드 내에 Java 코드를 포함하고 있으며, JSP는 서버 측에서 실행되어 동적으로 HTML 코드를 생성하고 클라이언트에 전달한다.

    • PHP 란?
      PHP는 서버 측에서 실행되는 스크립트 언어로, 주로 동적인 웹 페이지를 생성하는 데 사용된다. PHP 코드는 HTML 문서 내에 삽입되어 서버에서 실행되고, 그 결과가 클라이언트에게 전송된다.

  • 동적 컨텐츠, Dynamic Pages

    인자의 내용에 맞게 동적인 contents를 반환한다. 즉, 웹 서버에 의해서 실행되는 프로그램을 통해서 만들어진 결과물이다. *Servlet은 WAS 위에서 돌아가는 자바 프로그램이다.

WAS는 JSP, Servlet 구동 환경을 제공해주기 때문에 웹 컨테이너 혹은 서블릿 컨테이너 라고도한다.

  • Servlet 이란?
    Servlet, 서블릿은 자바를 사용하는 웹 개발을 위한 기술로 동적인 웹 페이지를 생성하고 HTTP 요청에 대한 동작을 처리하는 자바 클래스이다. 서블릿은 주로 웹 어플리케이션 서버에서 동작하며, client의 요청에 따라 동적인 콘텐츠를 생성하여 응답한다.    

그리고 톰캣은 WAS의 대표적인 종류이다.

즉, 클라이언트의 요청(Request)을 WAS에 보내고, WAS가 처리한 결과를 클라이언트에게 전달 (응답, Response)해야한다.

여기서 클라이언트는 웹 브라우저를 의미한다.

Dispatcher-Servlet

Dispatch는 보내다란 의미를 가지고 있다. 가장 먼저 요청을 받고, 적절하게 처리할 함수, 즉 컨트롤러를 찾아서 정해주는 역할을 한다.

즉, Front Controller 이다. 프론트 컨트롤러란 서블릿 컨테이너 맨 앞에서 모든 요청을 받아 적합한 컨트롤러에 위임해 주는 컨트롤러를 의미한다.

  • 정적 자원의 처리 : 요청을 처리할 컨트롤러를 탐색하고 없으면 정적 자원 요청으로 처리한다.

다음과 같이 동작한다.

  1. 클라이언트의 요청을 디스패처 서블릿 (Front Controller) 이 받는다.
  2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾는다.
  3. 요청을 위임할 핸들러 어댑터를 찾아서 전달한다.
  4. 핸들러 어댑터가 컨트롤러로 요청을 위임한다.
  5. 비즈니스 로직을 처리한다.
  6. 컨트롤러가 반환값을 반환한다.
  7. 핸들러 어댑터가 반환값을 처리한다.
  8. 서버의 응답을 클라이언트로 반환한다.


    다음과 같은 과정을 반영하여 Http11Processor을 다음과 같이 간략화 하였다.
@Override
    public void process(final Socket connection) {
        try (final var inputStream = connection.getInputStream();
             final var outputStream = connection.getOutputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {

            HttpRequest httpRequest = new HttpRequest(reader);
            HttpResponse httpResponse = new HttpResponse();

            Controller controller =  CONTROLLER.match(httpRequest);
            controller.handleRequest(httpRequest, httpResponse);

            outputStream.write(httpResponse.generateResponse().getBytes());
            outputStream.flush();

        } catch (IOException | UncheckedServletException e) {
            log.error(e.getMessage(), e);
        }
    }

CONTROLLER이 프론트 컨트롤러이고

controller.handleRequest → 이 부분이 핸들러 어댑터 역할을 한다고 볼 수 있다.

HttpRequest와 HttpResponse가 요청과 응답을 파싱해서 저장하는 클래스이다.


FrontController
public class FrontController {

    private static final Logger log = LoggerFactory.getLogger(FrontController.class);
    private final Map<String, Controller> controllerMap;
    public FrontController() {
        controllerMap = new HashMap<>();
        controllerMap.put("/login", new LoginController());
        controllerMap.put("/register", new RegisterController());
    }

    public Controller match(HttpRequest httpRequest) {
        Controller controller = controllerMap.get(httpRequest.getRequestPath().getPath());
        if (controller != null)
            return controller;
        return new StaticController(); // 찾지 못하면 정적 자원 컨트롤러로
    }
}
public interface Controller {
    HttpResponse handleRequest(HttpRequest httpRequest) throws IOException;
}

여기서 LoginController, RegisterController, StaticController 등 각각 경로에 따른 컨트롤러를 만들어주고 비즈니스 로직 처리를 해주었다.

GitHub - belowyoon/jwp-dashboard-http-mission at step2


미션 3에서 쿠키와 세션에 대한 구현 사항이 있었다.

HTTP는 connectionless, stateless한 특성을 가지기 때문에 서버는 클라이언트가 누구인지 매번 확인을 해야한다.

connectionless : 클라이언트가 요청을 한 후 응답을 받으면 연결을 끊어버린다. 보통 header에 keep-alive라는 값을 줘서 커넥션을 재활용하는데 HTTP 1.1에서는 이것이 디폴트이다.

stateless: 통신이 끝나면 상태를 유지하지 않는 특징

쿠키와 세션은 위 두가지의 특징을 해결하기 위해 사용한다.

쿠키란?

클라이언트 (브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일로 사용자 인증이 유효한 시간을 명시할 수 있고, 유효 시간이 정해지면 브라우저가 종료되어도 인증이 유지된다는 특징이 있다. 그래서 쿠키는 클라이언트의 상태 정보를 로컬에 저장했다가 참조한다.

즉, HTTP 헤더에 쿠키를 포함시켜 응답을 보내는데 이때 브라우저가 종료되어도 쿠키 만료 기간이 있으면 클라이언트에서 보관을 하고 있다. 이때 같은 요청을 할 경우 HTTP 헤더에 쿠키를 함께 보내고, 서버에서 쿠키를 읽어 이전 상태 정보를 변경할 필요가 있을 때, 쿠키를 업데이트 하여 변경된 쿠키를 HTTP 헤더에 포함시켜 응답한다.


쿠키의 사용 예
  1. 방문 사이트에서 로그인 시, "아이디와 비밀번호를 저장하시겠습니까?"
  2. 쇼핑몰의 장바구니 기능

세션이란?

일정 시간 동안 같은 사용자(브라우저)로 부터 들어오는 일련의 요구를 하나의 상태로 보고, 그 상태를 유지시키는 기술이다.

세션의 동작 순서

  1. 클라이언트가 페이지에 요청한다.
  2. 서버는 접근한 클라이언트의 헤더에 쿠키를 확인하여, 클라이언트가 해당 세션 ID를 보냈는지 확인한다.
  3. 세션 ID가 존재하지 않는다면 서버는 세션 ID를 생성해 클라이언트에 넘겨준다.
  4. 클라이언트는 서버로부터 받은 세션 ID를 쿠키에 저장하고 서버 요청 시 이 쿠키의 세션 ID 값을 같이 서버에 전달한다.
  5. 서버는 전달받은 세션 ID로 세션에 있는 클라이언트 정보를 가지고 요청을 처리한 후 응답한다.

세션의 사용 예

  • 화면을 이동해도 로그인이 풀리지 않고 로그아웃 하기 전 까지 유지

세션과 쿠키의 차이점

  • 세션은 쿠키를 기반으로 하고 있지만, 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버 측에서 관리한다. 즉, 세션은 서버의 자원을 사용한다.
  • 보안 면에서는 세션이 우수하고, 요청 속도는 쿠키가 세션보다 더 빠르다. 쿠키는 클라이언트 로컬에 저장되기 때문에 변질되거나 스니핑 당할 우려가 있지만 세션은 쿠키를 이용해서 session id만 저장하고 그것으로 구분해서 서버에서 처리하기 때문에 비교적 보안성이 좋다.
  • 라이프 사이클도 쿠키는 만료 기간이 있지만 파일로 저장되기 때문에 브라우저를 종료해도 정보가 유지될 수 있다. 그리고 만료기간을 따로 지정해 쿠키를 삭제할 때까지 유지할 수도 있다. 하지만, 세션은 브라우저가 종료되면 만료기간에 상관없이 삭제된다.

세션의 동작 순서를 참고하여 세션을 구현하였다.

GitHub - belowyoon/jwp-dashboard-http-mission at step3

미션 4

ExecutorService

매번 새로운 쓰레드를 만드는 것은 비효율 적이다. 그래서 쓰레드를 미리 만들어두고 재사용하기 위한 Thread Pool이라는 것이 있다. 이것을 사용하게 해주는 것이 ExecutorService이다.

ExecutorService를 사용하면 다음과 같은 장점이 있다.

  • 스레드 풀은 스레드의 생성과 소멸을 최소화 한다. 그래서 스레드를 반복적으로 생성하는 비용을 줄인다.
  • 생성되는 스레드 수 maximum을 정할 수 있다.
  • 작업 완료 여부 확인도 가능하다.

Session Manager, ConcurrentHashMap

ConcurrentHashMap이란 Java에서 제공하는 Thread Safe한 HashMap 이다.

여러 스레드가 동시에 맵에 접근할 때 발생할 수 있는 경쟁 조건을 피하기 위해 ConcurrentHashMap은 여러개의 버킷(Bucket)으로 구성되어 있다. 각각의 버킷은 독립적으로 작동하며, 한 스레드가 한 버킷에 대한 작업을 수행하는 동안 다른 스레드는 다른 버킷에 대해 작업을 수행할 수 있다.

로그인 처리 1 - 쿠키, 세션 2

GitHub - belowyoon/jwp-dashboard-http-mission at step4

회고 / 느낀 점

전체적으로 톰캣, WAS가 어떻게 돌아가는지에 대한 이해도를 높일 수 있던 스터디였다.

첫 코드와 마지막 코드의 차이만 봐도 많은 발전이 있었다는 것이 확 느껴진다…

처음에 추상적으로만, 얕게 알고 있던 개념들을 공부하며 실제로 어떻게 작동하는지 알게되었다. 그리고 객체지향적인 코드 작성법에 대해서도 깊게 생각하는 시간이 되었다.

그리고 스터디를 통해 다른 스터디원의 코드를 보면서 얻어가는 것도 많았다. 다양한 접근 방법이나 코딩 스타일을 배우는 기회가 되었던 것 같다.

앞으로 더 배워가야할 점이 많다는 것, 내가 부족한 점들을 느끼기도 했다. 앞으로 이 배워야 할 것들을 차근차근 배워가면서 또 성장하고 싶다 😊

profile
공부 모음집

0개의 댓글