백엔드

웹 서비스 동작구조와 소켓 통신

CyberI 2021. 2. 2. 14:07

안녕하세요.

이번 글은 웹 서비스 동작 구조와 소켓 통신을 알아보겠습니다.

 

목표

 

●     Client - Server 구조

●     Static Page & Dynamic Page 구분

●     Server 구성 및 Web/Was 차이 이해

●     Session & Timeout

●     3-Way handshake 이해

●     Apache 의 Timeout

●     WAS(Tomcat)의 Timeout

●     Web - WAS - DB 연동

●     WAS-DB 사이의 Timeout

●     OS level Timeout

 


Client – Server 구조 1

Client가 Server에 요청을 하면 Server는 결과물을 Client에 응답하는데 이러한  구조를 Client - Server 구조라고 합니다.

단순화시키면 위와 같은 모습을 가집니다. 이때 요청과 응답은 클라이언트와 서버가 각각 소켓을 만들어서 주고받는데 이 소켓에 관해서는 좀 더 아래쪽에서 알아보겠습니다.

Static Page & Dynamic Page

클라이언트가 서버에 페이지를 요청할 때 요청하는 인터넷 페이지에는 2가지 종류가 있습니다. Static Page와와 Dynamic Page인데인데 이름에서 알 수 있듯이 변하지 않는 페이지와 변하는 페이지입니다.

 

1.    Static Pages

             : 항상 동일한 페이지를 반환하며 image, html, css 등으로 구성된 정적인 페이지입니다.

1.    Dynamic Pages

             : 인자의 내용에 맞게 동적인 contents를 반환합니다.따라서 접속할 때마다 페이지의 내용이 바뀝니다.

 

Web & WAS

서버도 Web Server와 WAS(Web Application Server)로 나누어지는데

Web Server는  Static Page를, WAS는 Dynamic Page를 처리한다고 보면 됩니다.

 

1.    Web Server

      : Static Page를 처리(정적인 컨텐츠 제공), 동적인 컨텐츠가 필요할 경우 해당 요청을 WAS에 전달, WAS가 처리한 결과를 클라이언트에게 전달

 

1.    WAS

      : Web Server + Web Container 로 구성. DB 조회나 다양한 로직 처리 등 동적인 컨텐츠를 제공

 

WAS는 Web Server + Web Container 로 이루어져 있으며 이때 Web Container가 동적인 페이지를 처리합니다. WAS에도 Web Server가 있기 때문에 Web Server 없이 WAS만 존재하는 것도 가능합니다.

 

Web Server 와 WAS의 분리

WAS 에는 Web Server 가 포함되어 있기 때문에 WAS 로만 서버를 구성해도 됩니다. 그러나 일반적으로 Web Server 와 WAS 를 분리하는 경우가 많은데 여기에는 여러 이유가 있습니다.

 

1.    서버 부하의 방지

      : WAS가 정적, 동적 페이지 모두를 처리할 수 있다고 하지만 그만큼 WAS에 부담이 많아지게 됩니다. 그래서 기능을 분리해서 각 서버의 부하를 줄이기 위해서 Web Server와 WAS를 분리합니다.

 

1.    보안을 위하여

      : WAS에는 실제 Web Application 이 올라가기 때문에 외부와 직접 연결되면 중요한 파일이나 소스들이 노출될 수 있습니다. 그래서 이를 막기 위해서 Web Server를 WAS 앞단에 배치합니다.

 

1.    Web Server에 여러개의 WAS를 연결하기 위해

       : 규모가 큰 서비스에서는 수많은 요청을 한군데가 아닌 여러 군데에서 처리하기 위해 동일한 Web Application을 여러 개 띄웁니다. 이 때 Web Server를 두고 여러 WAS들을 Web Server에 연결해서 Web Server로 들어오는 수많은 요청을 각 WAS에 적절하게 분배해줍니다.

 

1.    여러 Web Applications을 서비스하기 위해

       : Java 서버, PHP 서버와 같이 서로 다른 서버를 하나의 Web Server에 연결해서 서비스할 수 있습니다.

 

Client – Server 구조2

 

Web Server와 WAS를 별도로 구성한다고 했을 때 위에서 단순화 시켰던 Server - Client 구조를 다시 그리면 위의 그림과 같은 구조라고 할 수 있습니다.

 

일반적으로 Web Server 는 Apache 를 많이 사용하며 WAS 는 Tomcat 을 많이 사용합니다. Tomcat 은 Apache Tomcat 이라고도 부르는데 Web Server의 역할도 할 수 있기 때문에 Apache Tomcat 이라고 부르는 것을 알 수 있습니다.

이중화 된 Web Server 와 WAS 는 위와 같이 구성되어 있으며 각각의 웹과 WAS 들이 이중화 되어 있습니다.

 

 Timeout

위에서 봤던 Server - Client 구조를 다시 보겠습니다.

 

Client 에서 Server로 요청을 보내면 Web Server로 요청이 갑니다. 그리고 해당 요청에 동적인 데이터가 필요하다면 그 요청을 다시 WAS로 보냅니다. 그리고 WAS에서도 DB에 접속을 해서 해당 데이터를 가지고 올 수 있습니다.

이렇게 클라이언트의 요청에 대해 한번의 요청이 아니라 여러 단계의 요청이 있을 수 있습니다.

 

그런데 통신 과정 중에 문제가 발생하면 요청과 응답이 제대로 이루어지지 않을 수 있습니다. 문제가 발생한 상황에서 응답을 계속해서 기다리기만 하면 무한정 대기해야 하는 상황이 생깁니다. 그래서 특정 시간이 지나도록 응답이 제대로 이루어 지지 않으면 클라이언트와 서버의 접속을 끊어야 하는데 이 때 그 요청을 기다리는 한계 시간을 Timeout 이라고 합니다.

 

그리고 요청과 응답에 여러 단계가 있기 때문에 Timeout 도 여러 종류가 있습니다.

 

 3-Way Handshake

 Client - Server 구조1 에서 서버와 클라이언트가 통신을 할 때 소켓을 이용한다고 했습니다. 웹 서비스의 경우 TCP 소켓으로 연결을 하는데 TCP 소켓은 서버와 클라이언트의 연결을 확인하고 연결이 확인이 되었을 때 에서야 데이터를 전송합니다.

 

즉 Client - Server 가 통신을 할 때 바로 페이지를 요청 하고 그 요청에 대한 응답을 받는게 아니라

1번과 2번의 단계를 통해서 Client - Server 의 통신이 가능한지 연결을 확인하고 연결이 확인 된 뒤에야 실제 데이터에 대한 요청인 3번과, 4번의 응답이 이루어집니다.

 

이 때 1,2번의 Client 와 Server의 연결을 확인하는 것을 3-Way HandShake 라고 합니다.

 

위 그림에서는 1번과 2번으로 요청과 응답의 2단계인 것으로 표현되어 있지만 실제로는 3단계 과정을 통해서 연결을 확인합니다.

 

즉 위 사진과 같이 3단계 과정을 거쳐 Client 와 Server 의 연결을 확인합니다.

 

●     Syn : 연결을 요청하는 패킷

●     Ack : 요청에 응답하는 패킷

 

1.    Client 가 서버에게 Syn 패킷을 보냅니다.

2.    Server 는 받은 Syn 패킷에 +1을 하여 Ack 패킷으로 보냅니다. 그리고 서버도 Client에게 별도의 Syn 패킷을 보냅니다.

3.    Client 가 Server에게서 Ack와 Syn 패킷을 정상적으로 받았다면 상태를 Established로 변경하고 Server에게 받은 Syn 패킷에 +1을 하여 다시 Server 에게 Ack 패킷으로 전송합니다. 그리고 Server는 이 Ack를 받으면 Established로 상태를 변경합니다.

 

 이 3단계의 과정을 통해서 연결이 확인 되면 그때부터 데이터가 전송됩니다. 그리고 이 과정이 끝이 나야 서버에 로그가 저장이 됩니다. 만약 3-Way handshake 가 제대로 이루어지지 않으면 서버의 로그에 기록이 남지 않은 채로 연결이 끊어집니다.

 

위의 2번 단계 후 Server는 Client가 ack를 다시 보낼 때 까지 대기를 하게 되는데 이 대기 시간을 Connection timeout 이라고 합니다.

  

SYN Flooding

3-Way handshake 의 취약점을 이용해서 서버를 공격하는 방법이 있는데 이를 SYN Flooding 이라고 합니다.  (SYN Flooding 도 DOS의 한 종류)

 

●     SYN Floding : 3-Way handshake 2단계에서 Server가 Client에게 ack + syn 을 보내고 다시 Client 에게 ack를 받을 때 까지 Server는 대기를 해야 하는데 1단계 요청만 무수히 많이 보내서 Server의 대기 중인 상태를 많이 만드는 것

 

이러한 공격을 막기 위해서는 여러가지 방법을 사용할 수 있지만 바로 위에서 봤던 Connection Timeout의 시간을 조절하는 방법을 알아보겠습니다.

 

Apache Connection Timeout

 Apache Web Server의 환경 설정에서 Connection Timeout 값을 설정할 수 있습니다.

Connection Timeout 이지만 Apache 의 환경설정에서는 그냥 Timeout 이라는 이름으로 되어 있습니다.

 

 

(설치경로)/httpd/conf/httpd.conf

 

해당 위치의 파일 열어서 수정하면 됩니다.

 

Timeout300

Apache의 Timeout 값의 기본값은 300(초)로 설정되어 있습니다.

Client와 Server의 상황에 맞게 이 값을 적절하게 조절해 줍니다. 해당 값이 너무 길다면 DDOS 공격에 취약해질 수 있으며 반대로 값이 너무 작으면 인터넷 속도가 느린 Client는 아예 접속을 할 수 없게 됩니다.

 

 Apache Keepalive Timeout

3-Way handshake를 통해서 Client과 Server의 연결이 확인되고 나면 데이터의 요청과 전송이 이루어집니다. 그리고 그 전송이 끝나고 나면 Client와 Server의 연결은 끊어지고 다음 요청 때 다시 3-Way handshake를 해서 연결을 확인하고 데이터를 주고 받습니다.

 

그러나 매 요청 마다 연결을 확인하는 것은 비효율적이기 때문에 연속된 요청과 응답에 대해서 소켓을 재사용 할 수 있습니다. 이것을 Keepalive 라고 부릅니다.

 

 

KeepAlive On/Off ( 기본값 : ON)

KeepAlive Timeout 5(초)

MaxKeepAliveRequests 100

 

위의 Apache Timeout과 동일한 파일에서 설정을 할 수 있습니다.

 

KeepAlive : On/Off 하여 설정 가능

KeepAlive Timeout : KeepAlive 가 On인 상태에 유효한 값이며 해당 시간(초) 동안 요청이 없으면 연결을 끊습니다.

MaxKeepAliveRequests : KeepAlive 가 On인 상태에서 유효한 값, 최대 몇 번의 요청까지 연결을 계속 사용할지 결정. 0은 무제한

 

WAS의 Session Timeout (Tomcat)

 Apache와 같이 Tomcat도 Timeout 이 있습니다.

 

Tomcat 은 WebServer의 역할도 같이 할 수 있기 때문에 앞선 Apache의 Timeout과 KeepAliveTimeout 이 있습니다. 그러나 Apache와 연동하여 사용하면 Tomcat의 Apache는 사용하지 않습니다.

 

 

Apache 에서는 Connection Timeout 을 그냥 Timeout 이라고 하였으나 Tomcat 에서는 Connection Timeout 으로 표기 합니다.

 

그리고 Web Server처럼 WAS에 요청과 응답 시간을 설정하는 Session Timeout 이 있습니다.

 

Tomcat을 기준으로 Session Timeout 설정에는 3가지 방법이 있으며 우선순위가 있습니다.(1>2>3)

 

1.    프로그램에 직접 코딩

 

<%

             session.setMaxInactiveInterval(int)

%>

 

1.    WEB/INF/web.xml 파일

 

<web-app>

             <session-config>

                           <session-timeout>15</session-timeout> //분

             <session-config>

</web-app>

 

1.    /conf/web.xml 파일

 

<session-config>

                           <session-timeout>30</session-timeout> //분

<session-config>

 

Web - WAS - DB 연동

 

 

Apache와 Tomcat을 연동하여 사용하고 Tomcat과  DB를 연동해서 사용하려면 중간에 모듈이 필요합니다.

 

1번의 Apache - Tomcat 연동의 경우

1.    mod_jk

2.    mod_proxy

3.    modproxyajp

 

의 3가지 방법을 사용할 수 있으며

2번의 Tomcat과 Oracle DB 연동의 경우 JDBC 중 OJDBC 라는 모듈을 사용합니다.

 

모듈을 통해서 연동을 하기 때문에 모듈과 다음 대상과의 통신에 대한 Timeout도 있으나 모듈에 따라 설정이 다릅니다.

 

WAS & DBMS 통신과 Timeout

 

WAS와 DB의 통신 사이에는 3가지 Timeout이 있습니다.

이 타임아웃들은 계층구조를 가지고 있으며 상위 타임아웃은 하위 타임아웃에 의존성을 가지고 있습니다.

즉 JDBC Driver Socket Timeout이 정상으로 동작하지 않으면 Statement Timeout과 Transaction Timeout도 정상으로 동작하지 않습니다.

 

그리고 JDBC Driver SocketTimeout은 OS의 SocketTimeout 설정에 영향을 받습는다. JDBC Driver SocketTimeout을 설정하지 않아도 네트워크 장애 발생 이후 30분이 지나서 자동으로 복구되는 것은 OS의 SocketTimeout 설정 때문입니다.

 

1.    Transaction Timeout

             : 프레임워크나 어플리케이션 레벨에서 유효한 타임아웃, StatementTimeout x N(Statement 수행 수) + a(가비지 컬렉션 및 기타) 라고 합니다. 전체 Statement 수행 시간을 제한할 때 사용합니다.

( Statement 를 아주 많이 수행할 때의 시간제한이라고 생각하면 됩니다.)

 

1.    Statement Timeout

             : Statement 하나가 얼마나 오래 수행되어도 괜찮은지에 대한 한계 시간 입니다. Statement는 DB에 쿼리를 보내는 객체입니다. java.sql.Statement.setQueryTimeout(int timeout) 메서드로 설정할 수 있습니다.

 

1.    JDBC Driver Socket Timeout

             JDBC Driver는 소켓을 사용하여 DB와 연결하는데 어플리케이션과 DB 사이의 Connection Timeout 처리는 DB에서 하지 않습니다. 따라서 소켓에 Timeout을 설정해야 하는데 Socket Timeout 은 JDBC Driver에서 설정할 수 있습니다.

 

Socket Timeout 은 2가지 방법이 있으며 드라이버별로 설정 방법이 다릅니다.

             3-1. Socket Connect Timeout

                           : Socket.connect(SocketAddress endpoint, int timeout) 로 설정

             3-2. Socket Read/Write Timeout

             :            Socket.setSoTimeout(int timeout) 로 설정

 

OS level socket timeout

위의 SocketTimeout이나 ConnectTimeout을 설정하지 않으면 어플리케이션이 네트워크 장애를 감지할 수 없습니다. 그러나 OS level 에서도 SocketTimeout 시간을 설정할 수 있기 때문에 이 값을 통해서 네트워크 연결 끊김을 확인할 수 있습니다.

 

Linux Socket Timeout

Server 에는 주로 Linux 를 사용하기때문에 Linux의 Socket Timeout 설정에 대해 알아보겠습니다.

Linux Socket Timeout에는 3가지 파라미터가 있습니다.

 

1.    tcpkeepalivetime : 전송된 마지막 패킷과 첫번째 Keepalive 의 간격. keepalive를 유지하는 시간을 의미하며 기본 7200초(2시간)으로 설정되어 있습니다.

 

/proc/sys/net/ipv4/tcp_keepalive_time 7200

  

1.    tcpkeepaliveprobes : tcpkeepalivetime 에 의해 보낸 keepalive 세그먼트를 보낼 횟수. 기본 설정 되어 있는 9회가 지나 가면 연결이 종료 됩니다.

 

/proc/sys/net/ipv4/tcp_keepalive_probes 9

  

1.    tcpkeepaliveintvl : keepalive 세그먼트를 보내고 다시 확인 하기 위한 시간. 처음 keepalive 를 보내고 미응답시 다음 keepalive를 보낼 시간. 기본 75초로 설정되어 있습니다.

 

/procs/sys/net/ipv4/tcp_keepalive_intvl 75

  

서버에 기본 설정된 위의 내용을 종합해보면 Client - Server 구조에서 2시간 동안 데이터를 주고 받은 경우가 없으면 서버는 keepalive 세그먼트를 보내고, 이 때 Client 가 미응답시 75초 이후 keepalive 세그먼트를 보내고, 총 9회 동안 미응답시 연결을 종료하게 됩니다.

  

정리

 

지금까지의 전체 흐름을 그려보면 위와 같습니다.

 

#과제

 

감사합니다.