본문 바로가기
SK Planet ASAC

웹 구성 간 흐름

 

 

웹 검색 엔진은 어떻게 작동할까

만약 세계 모든 웹 서버의 웹 페이지 정보들에 접근이나 조회하고 싶다면, 모든 웹 서버의 도메인 네임(IP 주소)를 통해 직접 일일히 웹 페이지 정보들에 접근해야 할까? 

만약 그래야 한다면, 아마 웹 페이지는 사용자 경험이 최악이라고 할 수 있을 것이다. 무엇인가가 대신 세계의 모든 웹 서버의 웹 페이지들을 미리 다 찾아놓고, 분류 및 정리한 뒤에 내 검색어에 따라 적합한 웹 페이지들만 골라 전달해주면 어떨까?

 

우리는 그 무엇인가를 Google로 정의해보자. Google의 경우 세계 모든 웹 페이지 정보를 수집하는 봇을 통해 웹 크롤링을 실시한다. 예를 들어 나만의 블로그를 개발할 때 sitemap.xml을 통해 "홈페이지 내부에 웹 페이지는 이렇게 연결되어 있다"고 Google에게 알려줄 수 있다. 그렇게 하지 않으면 검색하기 매우 불편하기 때문에 Google에서 내 웹 사이트를 싫어하게 된다. 때문에 우리의 사이트가 검색 엔진에서 상단에 노출될 수 있는 기회가 낮아진다. 

 

검색 엔진

앞서 우리는 Goolgle의 웹 크롤러 봇을 통해 세계 모든 웹 페이지들을 미리 찾아놓고 분류 및 정리했다. 그렇다면, 이제 사용자의 검색어에 알맞은 정보를 찾아주는 일만 남았다. 그 일을 하는 것이 검색 엔진이다. 

검색 엔진에서 가장 중요한 것은 사용자가 원하는 정보를 적절하게 노출시키는 것이다. 이를 검색 시 상위 노출 전략이라 하는데, SEO라고 한다.

 

 

SEO(Search Engine Optimization)

우리가 웹 페이지에 "JAVA의 특징"에 대해서 검색했다고 가정하자. 아마도 우리는 프로그래밍 언어인 JAVA의 정보를 원했을텐데, 인도네시아의 커피 종류 중 하나인 JAVA 커피를 노출해준다. 실제로 JAVA가 해당 커피의 이름을 따서 지은 것은 맞지만, 보통 많은 사람들은 커피의 특징 보단 프로그래밍 언어의 특징을 원했을 것이다.  

내부 엔진과 외부 엔진

SEO도 내부와 외부 엔진으로 분리할 수 있는데, 내부 엔진이란 한 회사의 직원들만 사용하게 되는 경우를 예로 들 수 있으며 내부 직원들이 사용하기 때문에 엄청난 최적화가 필요없다. 하지만 실제 서비스를 고객에게 제공할 때(외부 사용자)는 특정 상품이 상위 노출이 되게 만들거나 기타 등등 여러가지 최적화가 필요할 수 있다. 즉, 외부 사용자에게는 빠른 검색 속도와 적합한 콘텐츠 노출이 중요한 것이다. 

 

따라서 검색 시 상위 노출에 대한 조건은 아래와 같다.

 

1. 좋은 내용(Good Contents)

2. Semantic HTML (HTML의 태그들을 활용해 각 태그가 어떤 역할을 하는지 명확하게 나타낸다. div 남발 금지)

3. 키워드 및 메타 태그

4. 성능 (Performance Metrics)

5. 웹 접근성 

 

물론 Google 외에 네이버, 다음 등 다른 검색 엔진에도 존재하고, 각 검색 엔진에서 상위 노출을 위해 컨텐츠를 평가하는 방법은 다를 것이다. 

 

성능 (Performance Metrics)

그렇다면, 웹 페이지의 성능은 구체적으로 무엇을 이야기 하는 걸까. 

웹 페이지의 성능 만족도는 연관된 정보의 질과 양 + 페이지 이동 및 이벤트 반응 속도로 정의할 수 있다. 

 

1. Load Time: 페이지의 모든 요소가 다 뜰 때까지 걸리는 시간

2. FCP(First Contentful Paint): 웹 페이지 내 가장 첫 정보가 보여지는 순간까지 시간

3. LCP(Largest Contentful Paint): 웹 페이지 내 가장 큰 정보가 보여지는 순간까지의 시간

4. TBT(Total Blockign Time): 동기 실행 시 멈춘 시간들 (즉, 사용자가 어떤 입력과 같은 동작을 할 때 얼마나 지연이 걸리는가)

5. TTI(Time to Interactive): JS 자바스크립트가 모두 동작 가능한 상태로 준비 완료되기까지의 시간

6. FID(First Input Delay): 이벤트 버튼 등을 누르고 그 이벤트 반영이 시작하기까지의 지연 시간

 

 

컴파일과 런타임 과정

 

컴파일 과정 

Java코드 (.java)를 ByteCode(.class)로 자바 컴파일러(Javac)를 통해 변환한다. 

 

런타임 과정

ByteCodes(.class)를 기계어(Binary Code)로 자바 엔진(JVM)을 통해 변환한다. 이때 JVM이 머신에 맞추어 기계어로 인터프리팅 후 실행한다. 

 

 

JRE(Java Runtime Environment) 

Other Libraries(API)와 JVM(Java Virtual Machine)의 합을 이야기 한다. JDK에 일부로 포함되어 있다. 자바 프로그램을 실행하는 데 필요한 모든 요소들을 제공한다. 

JRE는 자바 애플리케이션을 실행하기 위해 설치되어 있어야 한다. 

 

JDK(Java Development Kit) 

그렇다면, 자바 개발자에게 필요한 것은 무엇일까. JDK는 JRE와 Java 개발에 필요한 컴파일러와 디버거 등의 추가 도구들이 포함되어 있다. JDK를 설치하면 애플리케이션을 컴파일 및 디버깅하고, 실행 파일로 패키징 할 수 있다.

 

JAR

Spring boot 프로젝트 같은 JAVA 파일을 배포하려면 패키징을 해야한다. 이 때 JAR와 WAR를 사용한다. 

JAR는 Java Archive다. .jar 확장자 파일에는 Class와 같은 Java 리소스와 속성 파일이나 라이브러리 설정 파일들이 압축되어 있다. Maven이나 Gradle을 통해 내려받는 라이브러리들은 Class 파일이 묶인 .jar 파일로 구성되어 있으며 Class 파일들이 묶인 .jar 파일을 가져와서 그 안에 있는 서비스를 이용한다. 

JRE 실행 환경이 있어야 실행할 수 있다. 기본적으로 메타데이터 META-INF, MANIFEST.MP 등이 포함된다. 

 

WAR(Web Application Archive)

JSP나 Servlet 등 WAS 컨테이너 위에서 동작하게끔 빌드된 형태. 서블릿, JSP, HTML, CSS, JavaSript, 이미지, 그리고 웹 애플리케이션의 설정 파일들을 포함한다. tomcat과 같은 웹 애플리케이션 서버에 배포된다. 

WEB-INF의 web.xml 파일에 서블릿 매핑, 필터, 리스너 등 웹 애플리케이션의 설정을 정의한다. 

단독으로 실행할 수 없고 서버 컨테이너에 의해 실행된다. 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>BE_WS_02</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
</web-app>

 

 

요약하자면 JAR 파일은 JAVA 라이브러리나 애플리케이션을 패키징하는데 사용하고, WAR 파일은 JAVA 웹 애플케이션을 패키징하고 배포하는 데 사용한다. 기본적으로 spring boot는 내장된 웹 서버를 통해 독립 실행형 JAR 파일로 배포되도록 되어있다. 그러나 설정에 따라 WAS로 배포할 수도 있다. 

 

웹 서버(WS)와 웹 어플리케이션 서버(WAS) 

앞서 배운 웹 서버는 외부에 제공하고자하는 논문, 연구 결과 등을 웹 페이지의 형태로 한데 모아 요청에 따라 반환한다. 즉, 미리 만들어진 웹 페이지를 단순히 요청에 따라 반환하기 때문에 정적 웹 페이지라고 한다.

 

동적 리소스를 반환하자

어떤 쇼핑몰 웹 사이트에 마이 페이지가 존재한다고 가정하자. 쇼핑몰의 이용자는 100명이고, 각자의 주문을 확인하기 위해서 마이페이지로 이동한다. 정적 웹 페이지라면 아마 100명의 이용자 웹 페이지가 필요하게 될 것이고, 100개의 정적 웹 페이지를 만들어야 한다. 그렇게 된다면 웹 서버의 용량도 많이 필요해질 것이다. 

반복되는 템플릿(View)과 유저 정보(data)를 분리한다면 어떨까. 즉 마이 페이지 View에 데이터만 변경하는 것이다. 이를 동적 웹 리소스 반환이라 하는데, 이를 통해 웹 어플리케이션 서버(WAS)가 등장했다.

 

일반적인 웹 서버
요청을 받아 페이지를 반환한다.

어플리케이션
요청을 받아 연산(데이터 CRUD, 변수 설정, 함수 수행 등) 후에 반환한다.

 

동적 웹 페이지를 만드는 주체는 어플리케이션이다. 동적 웹 페이지를 통해 수많은 페이지들을 웹 서버가 들고 있을 필요 없이 매번 만들어서 반환할 수 있게 되었고, 요청이 들어온 순간의 데이터로 만들기 때문에 데이터 및 웹 페이지의 신선도가 높아질 수 있었다. 

 

초기의 웹 어플리케이션 서버  - "CGI로 연결할건데?"

웹 서버가 요청을 받으면 어플리케이션에게 동적 웹 페이지 생성 작업을 위임한다. 이때, 동적 웹 페이지 생성 작업을 요청하고 어플리케이션을 실행하기 위한 연결 고리로 CGI를 사용했다.

 

CGI(Common Gateway Interface)

웹 서버와 어플리케이션을 연결하기 위한 기술이다. 당시의 어플리케이션은 Java와 Python이 아닌 Shell, Bash와 같은 스크립트 언어였다. 유명한 서버 스크립트 언어로는 PHP, Perl, Ruby와 같은 것들이 있는데, 이때 CGI는 서버 측에서 프로그램을 실행해 사용자의 요청에 따라 웹 페이즈를 동적으로 생성할 수 있도록 도왔다.

후에는 PHP의 언어적인 불편함과 한계점 개선을 위해 JAVA와 같은 프로그래밍 언어들이 등장했는데, 그러면서 WAS 방식에도 변화가 생겼다.

 

 

초기의 CGI 

1개의 요청에 1개의 비상주 프로세스로 이뤄졌다. 매번 요청에 따라 프로세스가 실행되고 웹 페이지를 만들어 반환 후에 프로세스가 죽는(없어)다. 이를 Stateless(비상태성)이라 하는데, 하나의 작업에 생성-실행-죽음이기 때문에 요청 간에 정보 교환이란 없다. 

 

그래서 나온 FCGI ( Fast Common Gateway Interface )

1개의 요청에 1개의 상주 프로세스로 이뤄진다. 요청에 따라 이미 열려있던 프로세스가 웹 페이지를 만들고 반환 후에도 프로세스가 죽지 않는다. 프로세스가 계속 상주하니 초기 CGI보다 요청마다 프로세스의 준비 기간이 줄어든다. 

이를 Stateful(상태성)이라 하는데, 아무리 많은 요청이 와도 기존 프로세스가 실행하기에 요청 간에 정보 공유가 가능하다. 

 

 

현대 웹 어플리케이션 서버 - "스레드 단위로 할거고 웹 서버에 어플리케이션 내장할건데?"

설명에 앞서 프로세스와 스레드의 차이를 간략하게 요약해보자. 프로세스는 실행 단위가 크고 한개의 프로그램에 한개의 프로세스만 존재한다. 스레드는 실행 단위가 작고 한개의 프로그램 내 수많은 스레드가 존재 가능하다.

즉, 프로세스는 [무겁고] 스레드는 [가벼우면서 여러 작업]을 할 수 있는 것이다. 실행(작업)의 단위가 작아졌기 때문에 다중 작업의 부담이 없는 것.

과거에는 웹 서버와 어플리케이션을 분리했고 그 사이를 CGI가 연결해줬다. 하지만, 현대의 WAS는 WAS 내부에 Application을 넣었다. 때문에 1개의 요청에 1개의 스레드를 생성한다. 이를 Spring에서 "Servlet"으로 설명한다.

 

1개의 요청에 1개의 스레드라구요?

이는 위에서 언급했던 상주 프로세스의 Stateful 장점(프로세스가 안 죽으니까 정보 공유가 가능하다)과 Stateless의 장점(프로세스가 죽는다)을 스레드를 통해 얻어낸 것이다. 

스레드를 어떤식으로 사용하나..

하나의 요청이 들어오면 그때서야 1개의 스레드를 생성하는 것은 아니다. 매번 생성하기보다 미리 스레드를 만들어 놓고 필요에 따라 할당하는 방식을 사용한다.
이를 스레드 풀(Thread Pool)이라 하는데, 몇개의 스레드를 만들어놓고 대기 시킬지 개수를 지정해 놓는 것이다. 
       executor.setCorePoolSize(2); //기본 스레드 수
       executor.setMaxPoolSize(5); //최대 스레드 수​

 

즉, 스레드는 할당 -> 수행 -> 반환의 여정을 거치고 반환은 스레드 풀로 다시 되돌아간다.
이 스레드를 자바에서는 Servlet이라고 부른다. 

 

 

현대의 WAS는 위와 같은 그림의 구조로 설계 되었다. WAS가 Application을 내장하고, 그 내부의 각각의 단위는 프로세스가 아닌 스레드(Servlet). Spring boot로 예를 들면, Tomcat과 같은 WAS를 내장하고 있어 이를 사용할 수 있고, 사용자가 제작한 로직들은 어플리케이션이 되어 실행되는 것.

 

 

WAS의 MVC 패턴

앞서 WAS의 경우 요청 -> 연산(CRUD 등) -> 반환으로 언급했다. 이를 우리는 MVC 패턴으로 만들 수 있다. 

이때 연산은 데이터베이스에서 데이터를 조회하는 것(Model), 그것을 기반으로 웹 페이지(View)를 만들어 Controller가 이를 반환한다. 

 

Controller

요청을 받고, 그에 따른 연산(로직)을 명령하며 그 결과를 반환한다. 어플리케이션과 웹 서버의 관계에서 웹 서버가 Controller와 비슷하다. 

 

Model

데이터에 대한 조회와 조작을 수행한다.

 

View

Model을 기반으로 만들어진 웹 페이지와 유저의 동작을 받아 Controller에게 전달하는 역할을 한다. 이때 유저가 보는 것은 Controller가 반환해준 웹 페이지, 유저가 하는 것은 자바스크립트 Interaction으로 Conroller를 호출하는 것이다. 

 

 

 

웹 페이지 렌더링의 3가지 방식

SSG(Static Sitie Generation) 

대표적으로 Nginx, S3가 있으며 미리 만들어진 정적 웹 페이지를 요청에 따라 반환한다. 

 

SSR(Server Side Rendering)

Spring, Thymeleaf, Next.js가 그 예다. 요청에 따른 동적 웹 페이지를 만들어서 반환한다. 반복적인 템플릿과 데이터로 이루어진 동적 웹 페이지를 만들어내는 것이 템플릿 엔진의 역할이다. 아래는 Thymeleaf의 예시다.

<!-- greetings.html -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Sample Page</title>
</head>
<body>
    <h1>Welcome to our website, <span th:text="${name}">Name</span>!</h1>
    <p>Today is: <span th:text="${today}">Today's Date</span></p>
</body>
</html>

 

여기서 ${name}과 같은 요소들이 동적으로 변경 가능한 부분이다. 템플릿 엔진이 웹 어플리케이션 서버(WAS)에 있다면 서버 사이드 템플릿 엔진이다. 웹 어플리케이션 서버(WAS)가 동적 웹 페이지를 생성 후에 반환하는 것이라 생각하면 될듯.

 

이는 장단점이 존재한다. 웹 페이지를 요처할 때마다 웹 서버가 만들어줘야 하기 때문에 유저가 보기까지 시간이 꽤 걸린다. 또한, 웹 서버의 CPU, 메모리 자원이 사용되기 때문에 클라우드를 사용하면 비용이 부담될 수도 있다. 하지만 웹 크롤러 입장에서 해당 웹 페이지가 가진 모든 것을 볼 수 있어 SEO가 가능하다.

 

 

CSR(Client Side Rendering) 

React.js가 대표적인 예다. 템플릿 엔진이 웹 어플리케이션 서버가 아닌 웹 브라우저 내에 있다. 즉, 클라이언트 사이드 템플릿 엔진이다. 웹 브라우저가 동적 웹페이지를 생성 후에 반환한다. 

처음 템플릿 엔진 파일을 가져오는 게 매우 크기 때문에 렌더링 시간이 오래걸린다는 단점이 있다. 또한, 해당 홈페이지에서 어떤 웹 페이지가 있는지 알기 어려워 SEO가 불가능하다. 

 

하지만 일단 한 번 가져오고 나면 그 이후로부터는 웹 페이지 전환이 굉장히 빠르다.