HTTP/1.1 은 변해가는 웹서비스 환경에서 발생하는 상당한 규모의 문제들을 처리하는데 훌륭한 방법을 제시해주었고, 


그 결과 성능적으로나 서비스적으로나 변해가는 웹생태계에 걸맞는 진화를 보여주었다.


하지만 그럼에도 불구하고 웹의 사용자는 계속해서 웹서비스에게 많은 리소스를 요구하고, 많은 리소스로 클라이언트를 충족해줘야만 살아남을 수 있게 바뀌어 가고 있다.


실제로 웹 초창기에 비해 평균 다운로드하는 리소스의 용량은 60배 이상 늘었으며, 이 추세는 계속될 것으로 보인다.


이에 HTTP/2 는 HTTP/1.1 에서 다소 불안정하던 부분을 해소하고 웹어플리케이션을 더 빠르고 효율적으로 만들어주는데 초점을 두었다.


HTTP/2 의 근본을 이해하기 위해서는 Google 이 2000년대에 진행했던 프로젝트인 SPDY 를 이해해야 한다.


SPDY(스피디) 란 Google이 개발한 비표준 네트워크 프로토콜로 패킷 압축, Multiplexing 을 기반으로 인터넷에서의 Latency 를 줄이기 위해 고안된 프로토콜로, 초창기 크롬 브라우저에 탑재되어 높은 로딩 속도를 자랑하게 했던 구글의 자체 프로토콜이다.


HTTP/2 는 바로 이 SPDY 에 기반을 둔 HTTP 프로토콜 Layer 하위의 TCP 통신 레이어에 새로운 Binary 계층을 도입하여 HTTP 의 기반이 되는 TCP 연결의 호율성을 추구하였다.


HTTP/2 의 특징들은 다음과 같다.


(1) Binary Framework


 HTTP/2 는 TCP 계층과의 사이에 새로운 Binary Framework 를 통해 네트워크 스택을 구성한다.

기존에 텍스트 기반으로 Header 와 Data 가 연결되고 있던 1.1 이하 버전과 다르게 HTTP/2 는 전송에 필요한 메시지들을 Binary 단위로 구성하며 필요 정보를 더 작은 프레임으로 쪼개서 관리한다. 


여기서 데이터를 Binary Encoding 방식으로 관리하는데, 인코딩된 데이터를 다루기 위해서는 반드시 Decoding 과정이 필요하게 된다.


즉, 이말은 HTTP/1.1 버전의 클라이언트는 HTTP/2 버전의 서버와 통신이 불가능하다는 뜻이다.

그래도 걱정할 필요는 없다. 해당 메커니즘은 이미 도입이 되었고 충분히 지원하는 상황이기 때문에 이슈가 생기지 않는다면 추가로 신경쓸 필요는 없다.



(2) Packet Capsulation


 HTTP/2 의 패킷들은 더 작은 단위로 Capsulation 된다. 여기서 Frame 과 Message, Stream 이라는 개념이 도입된다.


 - Frame : HTTP/2 의 통신 최소단위로 모든 패킷에는 하나의 Frame Header 가 포함된다.

 - Message : Frame 의 시퀀스 데이터를 말한다.

 - Stream : 연결의 흐름을 의미한다. 


HTTP/2 의 모든 연결은 TCP 기반의 Stream 이며 양방향으로 Frame Header 를 지닌 Message 들을 통신한다.

데이터는 위에서 언급한 바 대로 Binary 인코딩된 데이터들이며 Multiplexing 과 성능 최적화 알고리즘들이 적용된다.



(3) Multiplexing 개선


<출처 : https://medium.com/@factoryhr/http-2-the-difference-between-http-1-1-benefits-and-how-to-use-it-38094fa0e95b>


 

 HTTP/1.1 에도 멀티플렉싱을 지원하기 위한 노력은 있었지만, HTTP/1.1 은 이 부분에서 다소 한계점을 갖고 있었다. 

(참고 : http://jins-dev.tistory.com/entry/HTTP11-%EC%9D%98-HTTP-Pipelining-%EA%B3%BC-Persistent-Connection-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC)


요청과 응답의 동시처리는 이루어지나 결국 응답처리를 지연시키는 블로킹 방식이었기 때문에, 한 개의 Connection 이 하나의 Request / Response 를 처리하는 한계를 극복하기는 어려웠으며 그로 인해 결국 HOL(Head Of Line) 문제 발생과 연결에 있어서 비효율성을 갖는다는 아쉬운 부분이 있었다.


HTTP/2 는 이부분에서 개선된 멀티플렉싱을 지원하며, Connection 하나에서 다수의 입출력이 가능하게끔 지원한다.


이것이 가능한 이유는 HTTP/2는 패킷을 Frame 단위로 세분화하여 순서에 상관없이 받는쪽에서 조립하도록 설계하였기 때문이다. 


그렇기 때문에 HTTP/2 에서는 각 요청과 응답을 병렬로 전달할 수 있으며 하나의 Connection 에서도 여러 응답 / 요청을 처리할 수 있게 되었고 HTTP/1.1 에서 사용하던 임시방편을 사용할 필요가 없어졌다.



(4) Header Compression


 HTTP/2 의 Header 필드는 Huffman code 로 인코딩되며 이에 따라 텍스트적인 압축이 수반된다. 여기서 패킷을 더 최적화해 만들어진 HPACK 알고리즘은 Header 의 크기를 80% 이상 압축해서 전송한다고 알려져있다.



(5) Server Push


 HTTP/2 에서 서버는 단일 클라이언트의 요청에 대해 추가적인 응답을 내려줄 수 있다.

HTTP에서 Push 문제는 쉽지않은 이슈이지만, HTTP/2 에서는 이를 PUSH_PROMISE 라는 Frame 을 이용해 제공한다.

이렇게 제공되는 Push 리소스는 캐싱되거나 재사용 또한 가능해서 유용하게 사용이 가능할 것으로 보인다.



그 외에도 보안적인 측면이나 세세한 부분에서 HTTP/2 는 개선을 위한 노력들이 많이 보이며 확실히 효율적인 프로토콜로 자리매김한 것으로 보인다.


일각에서는 여전히 쿠키 보안에 취약하며 성능에 있어서의 향상 수준이 호환성을 저해할 만큼 대단한 것인가에 대한 의문도 있는 모양이지만, 개인적으로는 상당히 훌륭하고 배울 부분이 많은 프로토콜로 생각된다.



 무중단 배포란 알고있는대로, 서버를 실제로 서비스할 때 서비스적 장애와 배포에 있어서 부담감을 최소화할 수 있게끔 서비스가 중단되지 않고도 코드를 Deploy할 수 있는 기술이다


예전에는 배포 자체가 하나의 거대한 일이었고, 이를 위한 팀과 개발팀이 날을 잡고 새벽에 배포하는 일이 잦았지만, 최근에는 무중단 배포 기능을 탑재한 Deploy 자동화 툴을 이용해서 개발자들이 스스로 배포까지 담당하는 DevOps 의 역할을 하게되면서, DevOps 의 필수 기술 중 하나가 되었다.


 무중단 배포 방식에는 주로 사용되는 것들에 AWS에서 Blue-Green 무중단 배포(Blue는 기존버전, Green은 새로운버전. Router를 통해 Blue로 이동하는 트래픽을 Green으로 변경시켜준다. 원리는 동일하다.), Docker를 이용한 웹서비스 무중단 배포가 있다


IDC에서 직접 L4 스위치를 이용해서 하는 방안도 간단하지만, 이는 비용적으로 효율적이지 않아 많이 없어지는 추세이다


또한 NginX 등을 이용해서 저렴하게 무중단 배포를 하는 방식도 있다


이 방법을 사용하면 클라우드 인프라가 갖춰져있지 않아도 되고 별도의 인스턴스를 갖고 있지 않아도 가능하다

(Spring jar 2개를 여러 포트에 나눠서 배포하고 그 앞에 NginX 로 밸런싱해주면 된다.)


 무중단 배포의 원리




간단한 원리는 위와 같다. 핵심은 Reverse Proxy 가 서로 다른 인스턴스의 각기 다른 포트와 서브 도메인으로 연결하고, 지속적으로 Health Check 하면서 배포시 서브도메인을 메인 도메인으로 Switching 해주고, 배포가 끝나면 다시 메인도메인으로 Reload 해주는 것이다


이 구조에서 주의해야할 점은, 배포가 서비스에 영향을 주지 않도록 해야한다는 것이다. 예를들어 DB의 구조를 바꾸는 JPA와 같은 기술들이 사용되어 있을 경우 검토가 필요하다.


 도커 컨테이너를 이용하면 이는 매우 간단해진다

하나의 이미지에서 여러 컨테이너를 생성해서 호스트의 docker 명령어를 이용해서 손쉽게 서버 이중화 및 Switch, Reload 가 이루어진다

빌드 서버에서 이미지를 만들고 해당 이미지를 distribution 을 통해 다른 서버에서 이를 가져오는 식으로 구성된다.


 도커의 Service Discovery 라는 개념을 이용하면 nGinX 를 통해 배포할 때의 단점인 설정 파일의 수정과 재시작이 수반되어야 한다는점과 Proxy 대상 IP Port 가 고정이어야 한다는 점, Health Check 오버헤드를 피할 수 있다


Service Discovery는 서버들의 정보를 포함한 정보들을 저장해서 가져오고, 값의 변화가 일어날 때 이벤트 형식으로 설정을 수정하고 재시작하는 개념이다.




위의 구조에서는 Key/value 스토어를 이용해서 서버 정보를 저장하였으며 Configuration Manager 가 이를 watch하면서 이벤트 방식으로 설정 파일을 만들고 기존 파일에 덮어 쓰는 작업을 하고 있다


docker에서 대표적인 Service discovery tool docker-gen 이 있다


자세한 내용 참조

(https://subicura.com/2016/06/07/zero-downtime-docker-deployment.html)


실습가능한 참조 링크

http://jojoldu.tistory.com/267




nginx 의 설정은 nginx 를 구성하는 핵심으로 nginx 는 설정파일만 갖고 동작을 결정한다고 해도 과언이 아니다.


보통 nginx 의 환경설정을 구성하는 파일은 /usr/local/nginx/conf 폴더 하위에 위치하며 nginx.conf 파일을 수정함으로써 환경설정을 정의할 수 있다.


환경설정은 document 를 보는 것보다 예제로 파악하는게 좋아보이므로 예제를 중심으로 기술한다.



http {
### Load balancing ###
upstream {
### Target Proxy Host ###
server server01;
server server02;
}
### Main server configuration ###
server {
listen 80;
server_name nginx.sample.com;
client_header_timeout 10;
client_body_timeout 10;
charset UTF-8;
root /home/my-doc;
######### log #######
access_log logs/access.log main;
error_log logs/error.log;
#####################
############## internal location ############################
location /monitor {
allow 127.0.0.1;
deny all;

proxy_pass http://monitor.proxy:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
############## main location ############################
location / {
proxy_pass http://localhost:8080;
}
}
}


nginx 설정은 계층적 구조를 이루며 하위 블록에서의 선언은 상위 블록에서의 선언을 덮어쓴다.


http 블록은 nginx 설정의 루트 블록이라고 할 수 있다. 기본적으로 여러개 정의할 수는 있으나 관리상의 이유로 보통 하나의 블록 안에서 해결한다.


server 블록은 Host 의 개념으로 웹서버의 메인 설정이라 할 수 있다.


upstream 블록은 로드밸런싱을 하는데 사용되며 nginx 를 로드밸런서로 사용할 경우 기술된 서버로 해당 요청을 중계해준다.


옵션값으로 default(선언하지 않을 경우 라운드로빈), least_conn (연결이 가장 적은 서버로 중계), ip_hash(ip값을 이용한 해시주소로 요청 분배) 등 분산 알고리즘의 설정이 가능하다.


log 항목은 nginx 의 중요 기능 중 하나로 nginx 를 거치는 모든 로그 및 에러 로그를 기록하는 데 사용된다.


location 블록은 서버 내에서 요청을 다르게 라우팅하고 싶을 경우 사용한다. nginx 로 프록시 서버를 구성할 때 해당 경로로 proxy pass 를 지정함으로써 라우팅을 처리할 수 있다.


nginx 의 설정 반영은 서버를 재시작해야 적용되므로 설정 후에는 OS 에 맞게 서비스를 재시작 해주도록 하자.




 로드밸런싱(Load Balancing) 이란 Software 용어로 부하 분산의 의미를 갖고 있다. 말그대로 동작에 있어서 부하가 심해져 병목현상이 생기는 것을 방지하기 위해 사용한다.

이는 컴퓨팅 리소스, 네트워크 리소스 등 모든 부분에서의 성능향상을 기대할 수 있게 한다.


일반적으로 L4 Load Balancer 와 L7 Load Balancer 가 존재한다.




(1) L4 Load Balancing


 L4는 네트워크 Layer 4번째 계층을 의미한다. 4번째 계층에서 수행되어야할 작업의 중요한 역할 중 하나는 IP, 포트, 세션을 기반으로한 LoadBalancing 작업이 있다.

이런 이유로 L4 Load Balancer 를 Connection Load Balancer 혹은 Session Load Balancer 라 부르기도 한다.


4계층에 포트정보가 들어감으로써 디테일한 로드밸런싱이 가능하기 때문에 일반적으로 Load Balancer 를 말할 때 L4 스위치 자체를 말하기도 한다.

이렇게 L4 스위치만 이용하더라도 부하분산 및 포트에 대한 필터링이 가능하다. 

로드밸런서가 있으면 서버 몇대에 이상이 생기더라도 다른 서버가 대신 작업을 수행하는 Failover가 가능하며,

또한 이 부분에서 TCP/UDP 패킷 분석이 가능하기 때문에 Firewall 처리도 수행한다.



보통 로드밸런서의 설정 시 서버들에 대한 주기적인 health Check를 통해 장애 여부를 판단할 수 있으며 분산알고리즘(metric)에는 흔히 알려진 라운드로빈, Least Connection, Response Time, Min miss, bandwidth based, 해싱 알고리즘이 있다.


- 라운드로빈 : 세션을 순차적으로 맺어주는 방식이다. 일반적으로 5:5의 분산이 가능하나 경로별로 같은 처리량이 보장이 안된다.


- Least Connection : 가장 적은 Open Session을 가진 서버로 연결을 붙여준다. 가장 많이 사용되는 방식이다.


- Response Time : 각 Real Server 들이 다루는 Resource의 양과 Connection 시간, 데이터 양이 다른 경우 사용하기 적합하다. 로드밸런서가 서버와 직접 통신을 하면서 응답시간이 빠른쪽으로 많은 세션을 할당해준다.


- Hash : 특정 클라이언트는 특정 서버로만 할당시키는 방식. 경로가 보장되며 접속자수가 많을수록 분산 및 효율이 뛰어나다. 다만 접속자수가 적을수록 공평하게 분산이 안될수도 있다.


- Minimum Missis : 해시 기법과 유사하지만 특정 서버 다운시 해시값의 재할당이 이루어진다. Source IP 기반으로 해싱을 하기 때문에 프록시를 사용하는 경우 Hashing이나 Min miss를 사용하면 안된다.


- Bandwidth based Loadbalancing : 서버들과의 대역폭을 고려하여 분산한다.



(2) L7 Load Balancing


 L4 Load Balancer 가 일반적으로 TCP / UDP 에 대해서만 동작하는 것과 다르게, L7 Load Balancer 는 OSI 7 층의 HTTP 에 대해서도 작동한다.

Layer 7 의 로드밸런서는 주로 HTTP 라우팅에 대한 처리를 담당한다. 


Layer 7 Load Balancing 의 주요 특징들은 다음과 같다.


- Persistence with Cookies : 주로 쿠키를 활용한 Connection Persistence 를 유지하며, 쿠키 정보를 분석한다. WAS 로 이루어지는 연결에 대해 해당 연결을 동일한 서버로 연결되게끔 해준다.


- Context Switching : 클라이언트가 요청한 리소스에 대해 Context 를 전환할 수 있다. 가령 Static 이미지 리소스 등에 대해 Load Balancer 가 확장명에 따른 분류로 Image Server 로 연결해줄 수 있다.


- Content Rewriting : 전달받은 Request 를 변환해서 재전송이 가능하다.


그 외에도 프록시 처리(X-forwarded-for) 및 보안 로직 처리 등도 이루어진다.

로드밸런싱 알고리즘은 L4 와 유사하며 역시 가장 간단하게 라운드로빈 알고리즘이 주로 사용된다.


일반적으로 L7 로드밸런서는 L4 로드밸런서보다 비싸지만 상위 프로토콜에서 그 이상의 유연성을 보여준다.




 

 

HTTP/1.0 은 가장 기초적인 형태의 웹 프로토콜을 제시하였고, 이는 일전 포스팅에도 정리되어 있듯이 TCP 프로토콜 위에 HTTP Spec 을 이용한 HTTP 프로토콜을 충실히 따른다.


이 방식은 웹이라는 새로운 환경에서 TCP에 비해 나은 성질의 프로토콜이었으나, 웹의 규모가 거대해지면서 몇가지 이슈들이 발생하였다.

 

특히 Network Latency 이슈가 주된 문제였는데, HTTP/1.1 은 이 문제를 해결하기 위해 특징적인 2가지 개념을 도입한다.

 

(1) HTTP Pipelining (HTTP 파이프라이닝)

 

 

 

HTTP Pipelining 이란 HTTP1.1 로 스펙이 업그레이드 되면서 클라이언트와 서버간 요청과 응답의 효율성을 개선하기 위해 만들어진 개념이다.

 

HTTP Request 들은 연속적으로 발생하며, 순차적으로 동작한다.


HTTP/1.0 에서 HTTP Request 는 소켓에 write 한뒤, 서버의 Response 를 받아 다음 Request 를 보내는 방식으로 웹이 동작한다. 

여러 요청에 대해 여러 응답을 받고, 각 처리가 대기되는 것은 Network Latency 에 있어서 큰 비용을 요구한다.

게다게 HTTP/1.0 에서 HTTP 요청들은 연결의 맺고 끊음을 반복하기 때문에 서버 리소스 적으로도 비용을 요구한다.


HTTP/1.1 에서는 다수의 HTTP Request 들이 각각의 서버 소켓에 Write 된 후, Browser 는 각 Request 들에 대한 Response 들을 순차적으로 기다리는 문제를 해결하기 위해 여러 요청들에 대한 응답 처리를 뒤로 미루는 방법을 사용한다.

 

즉, HTTP/1.1 에서 클라이언트는 각 요청에 대한 응답을 기다리지 않고, 여러개의 HTTP Request 를 하나의 TCP/IP Packet 으로 연속적으로 Packing 해서 요청을 보낸다.


파이프라이닝이 적용되면, 하나의 Connection 으로 다수의 Request 와 Response 를 처리할 수 있게끔 Network Latency 를 줄일 수 있다.


하지만 위의 기법 설명에서 언급하듯이, 결국 완전한 멀티플렉싱이 아닌 응답처리를 미루는 방식이므로 각 응답의 처리는 순차적으로 처리되며, 결국 후순위의 응답은 지연될 수 밖에 없다.


<이미지 출처 : https://www.popit.kr/%EB%82%98%EB%A7%8C-%EB%AA%A8%EB%A5%B4%EA%B3%A0-%EC%9E%88%EB%8D%98-http2/>



이는 HTTP의 Head Of Line Blocking 이라 부르며 Pipelining 의 큰 문제점이다.


따라서 HTTP/1.1 의 웹서버는 서버측에 Multiplexing 을 통한 요청의 처리를 요구하며, 각 Connection 당 요청과 응답의 순서가 보장되는 통신을 한다.

 

HTTP 파이프라이닝은 HTTP/2 가 등장하면서 멀티플렉싱 알고리즘으로 대체되었고, 모던 브라우저들에서도 기본적으로는 활성화하지 않고 있다.

 

 

(2) Persistent Connection

 

 

HTTP 1.0 초기의 HTTP 연결은 요청시 TCP 의 3-way handshake 방식으로 연결이 이루어졌었다.

즉, 웹클라이언트와 서버간의 연결 성립 이후 SYN, SYN-ACK, ACK 핸드셰이킹이 발생하고 이를 바탕으로 통신을 구성한 뒤 연결을 끊는 순서가 필요했다..

웹의 초창기에는 컨텐츠의 수가 많지 않았기 때문에 이런 TCP 연결은 부담되지 않았지만, 웹을 통한 멀티미디어 컨텐츠의 발달로 인해, TCP Connection 의 재사용이 요구되게 되었다.

 

웹에서의 커넥션 재사용을 Keep-alive 또는 Connection reuse 라 하며, HTTP/1.0 에서는 클라이언트가 서버에게 요청하는 Request Header에 다음과 같은 값을 통해 연결을 유지하였다.

 

Connection: keep-alive


HTTP/1.1 에서는 이 헤더를 사용하지 않더라도 모든 요청/응답이 Connection을 재사용하도록 설계되어 있으며, 필요없는 경우에만 TCP 연결을 종료하는 방식으로 변경되었다.

 

Connection: close

 

해제 시에 위와 같은 명시적 Connection 헤더를 이용하며, 그렇지 않은 경우 무조건 연결은 재사용되게 되어 있다.

 

이러한 이슈는 HTTP/2 로 웹이 한단계 더 발전하면서 해결되었다.

자세한 건 다음 링크를 참조

(https://jins-dev.tistory.com/entry/HTTP2-%ED%8A%B9%EC%A7%95%EB%93%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC)

 


현재 웹 표준으로는 HTTP/2 가 개발중이며 이미 공개가 되어있다. HTTP/2 에서는 구글이 프로토타입으로 제시한 SPDY 등의 프로토콜을 기반으로 한 웹 기술의 발전이 예상되는 만큼 위의 기술들 또한 보다 더 나은 방향으로 진화될 것이라 생각한다.


 많은 어플리케이션들에서 사용되는 캐시 로직과 마찬가지로 Web browser 역시 캐시를 사용한다.


웹브라우저에서의 캐시 사용은 단순히 웹페이지의 빠른 로딩을 가능하게 할 뿐 아니라, 이미 저장된 리소스의 경우

서버측에 불필요한 재요청을 하지 않는 방법을 통해 네트워크 비용의 절감도 가져올 수 있다.


이는 아주 중요한 부분으로 리소스를 캐시했다가 재활용함은 트래픽 절감과 클라이언트 측에서의 반응성 향상 및 서버의 부하 감소라는 이점까지도 가져올 수 있다.


그렇다면 웹브라우저는 어떤 항목을 어떻게 캐시하는 것일까?


HTTP Spec 에 의하면, 모든 HTTP Request / Response 는 이러한 캐싱 동작과 관련한 설정을 Header 에 담을 수 있다.

주로 사용되는 HTTP Response Header 로는 Cache-Control 과 ETag 가 있다.


(1) Cache-Control


Cache-Control 헤더는 어떻게, 얼마나 오래 응답을 브라우저가 캐싱하면 좋을지를 브라우저에게 알려준다.


Cache-Control 헤더는 브라우저 또는 다른 캐시가 얼마나 오래 어떤 방식으로 캐싱을 할지를 정의한다. 


Web browser 가 서버에 리소스를 첫 요청할 때, 브라우저는 반환되는 리소스를 캐시에 저장한다. 

Cache-Control 헤더는 몇가지 서로다른 Pair 를 Parameter 를 가질 수 있다.


 - no-cache / no-store : no-cache 파라미터는 브라우저가 캐시를 사용하지 않고 무조건 서버에서 리소스를 받아오게끔 한다.

 하지만 여전히 ETags 헤더를 체크하기 때문에, ETags 헤더의 조건에 맞는다면 서버에 직접 요청하지 않고 캐시에서 리소스를 가져온다.

 no-store 파라미터는 ETags 에 상관없이 Cache 를 사용하지 않고 모든 리소스를 다운받도록 하는 옵션이다.


 - public / private : public 은 리소스가 공개적으로 캐싱될 수 있음을 말하고 private 은 유저마다 리소스에 대한 캐싱을 하도록 한다.

 private 옵션은 특히 캐시에 개인정보가 담길 경우 중요하다.


 - max-age : max-age 는 캐시의 유효시간을 의미한다. 초단위로 입력된다.


(2) ETag


ETag 헤더는 캐시된 리소스가 마지막으로 캐시된 이후에 변했는지를 체크해주는 헤더이다.

전체 리소스를 재다운로드하는 대신, 수정된 부분을 체크하고, Same Resource 는 재다운로드하지 않는다.

ETag 는 서버에서 리소스에 대해 할당하는 Random String 으로 할당이 되며, 이값을 비교함으로써 revision 을 체크한다.

이 유효성 검사 토큰을 사용하면 리소스가 변경되지 않은 경우 이므로 추가 데이터 전송 요청을 전송하지 않는다.


ETag 값은 다시 서버에 전송해야하며, 서버는 리소스의 토큰값과 비교해서 변경되지 않은 경우 304 Not Modified 응답을 반환한다.



이를 바탕으로 브라우저 캐싱 동작을 정리해보자.




웹브라우저는 서버의 응답값을 바탕으로 재사용가능한 Response 인지 확인하고, Validation 과 Cache 의 성질, Expiration Time 에 따라 캐시 정책을 결정한다.

이에 대해 구글은 위와 같은 명확한 형태의 Decision Tree 를 제공한다.


이외에도 웹에서 사용되는 캐시 로직을 좀 더 이해하기 위해선 서버사이드의 Cache 로직 역시 이해할 필요가 있다.


캐시 정책에 있어서 왕도는 없으며, 트래픽 패턴, 데이터 유형 및 서비스 종류에 따라 알맞게 설계하는 것이 중요하다.

그 중에서도 최적의 캐시 Lifetime 의 사용, Resource Validation, 캐시 계층 구조의 결정은 반드시 고려되어야 한다.




좀 더 자세한 자료는 다음을 참고한다.

[https://thesocietea.org/2016/05/how-browser-caching-works/]

[https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ko]



웹은 HTTP 의 특징 상 TCP와는 다르게 Stateless 프로토콜을 사용하기 때문에 HTTP 를 사용하면서 연결 관리를 위해 여러가지 도구를 사용한다.


그 중 하나가 Cookie 이며, 쿠키는 다양한 방법으로 웹서버의 동작에 도움을 준다.


먼저 쿠키에 대한 흔한 오해로, 웹사이트가 하드디스크에 저장하는 개인에 대한 정보이며 웹사이트에 접근시 사이트는 쿠키의 정보를 이용하며 새로운 정보를 저장할 수 있다는건 잘못된 정보이다.


Cookie 는 프로그램이 아니며, 개인에 대한 정보를 저장하지 못한다. 


Cookie 는 웹서버가 유저의 하드디스크에 저장하는 텍스트 조각이며 Binary 형태의 데이터가 될 수 없다.

일반적으로 쿠키는 Name-Value 쌍으로 이루어진 웹사이트 접근에 대한 정보이다.


웹서버마다 쿠키를 활용하는 방식은 다양하며, 단순히 접속에 대한 정보나 ID 만을 저장하는 데 그치지 않고, 세션 혹은 접속 시간 등 다양한 정보를 기록하기도 한다.


쿠키는 그 자체만으로 어떤 역할도 할 수 없으며, 단지 웹서버로 전송될 수 있는 정보를 가질 뿐이다.


쿠키는 HTTP 프로토콜 상의 제약에 따라 4kb 까지 저장할 수 있으며 하나의 도메인은 브라우저마다 다룰 수 있는 쿠키 갯수의 상한을 갖는다.

즉, 쿠키는 도메인별로 브라우저가 Storage 에 관리하는 형태의 정보로, 브라우저가 쿠키의 보안을 관리한다.


이렇듯 브라우저가 도메인별로 쿠키를 관리하기 때문에 서로 다른 브라우저는 서로 다른 쿠키를 갖는다. 즉, 브라우저별로 쿠키는 공유되지 않는 내부 저장 데이터이다.


쿠키는 서버와 유저의 Local storage 간의 약속이므로, 같은 Name 으로 Value 를 기록(Write) 하고 읽어오는 것(Read)이 중요하다. 

대부분 쿠키는 웹브라우저의 내부 저장소에서 Javascript 를 통해 서버에서 핸들링 할 수 있도록 처리된다.


"여기서 클라이언트가 서버에게 쿠키를 보낸다는 점이 중요한데, 대부분의 경우 특별한 제약 등을 정의하지 않으면 Cookie 는 서버로 향하는 모든 요청과 함께 전송된다."


주로 쿠키를 사용하는 목적은 다음과 같다.


- Authentication : 세션 관리.


- User Tracking : 유저 방문 추적


- Personalization : 테마, 언어 등 커스텀화된 설정에 대한 목적



웹사이트를 통해 개발한다면 브라우저의 개발자도구를 이용해 쿠키에 대한 정보를 언제든 접근 가능하다.




대부분 쿠키나 세션의 경우 브라우저에서는 Cookie API 를, 서버 측에서는 Web framework 들이 처리할 수 있는 로직을 내장하고 있으나, 

관련 작업을 할 경우 위와 같이 체크하면서 작업하면 유용하다.


Mozilla 공식 홈페이지는 쿠키의 생성 및 사용 로직이 단순하기 때문에 정해진 용도 이상의 사용, 특히 개인정보의 저장 등을 위해 사용하는 것이 위험하다고 경고하고 있다.




DNS란 웹사이트의 주소 이름을 IP Address 로 매핑시켜 기억할 수 있는 도메인으로 사이트에 접근할 수 있게 해주는 인터넷의 핵심 요소이다. 다음은 verisign 에서 제공하는 How DNS works 의 설명 내용이다.


(1) 쿼리 전송 : 브라우저가 유저로부터 입력받은 도메인 이름을 이용해 쿼리를 날린다. 쿼리는 ISP 나 무선 통신업체가 운영하는 DNS Resolver 서버에 도달하여 도메인네임을 IP로 바꾸기 위해 어떤 DNS 서버에 요청해야 하는지를 질의하게 된다.


(2) 루트 서버 : DNS Resolver 가 상호작용하는 첫번째 DNS 서버를 루트 서버라 하며, 루트 서버는 .com 과 같은 최상위 도메인에 대한 DNS 정보를 알고 있다. 이 루트서버는 쿼리를 요청한 지점에서 멀지 않은 도메인으로 전송시켜 준다.


(3) TLD 서버 : TLD 서버는 최상위 도메인 내에 차상위 도메인에 대한 주소 정보를 저장하는 서버로 쿼리가 TLD 서버에 도착하면 TLD 서버가 도메인 네임에 대한 IP주소를 답변한다.


(4) DNS : 서버를 거친 쿼리문이 도메인 네임에 대한 IP 주소를 DNS Resolver 로 전송한다.


(5) Web site : DNS Resolver 는 문의한 도메인 네임에 해당하는 IP주소를 브라우저에 알려주고 브라우저는 IP 주소로 접근하여 컨텐츠를 가져온다.



DNS 정보를 조회하는 Flow 는 다음과 같다.


1. 클라이언트(웹 브라우저)가 DNS 를 조회하는 쿼리를 발생시킨다.


2. 발생한 요청은 Local DNS 서버로 이동한다. 이 때의 요청은 다음과 같은 DNS Resolver 들을 거치게 된다.

 - 클라이언트에 저장된 로컬 네임 서버 DNS 캐시

 - Internet Service Provider(ISP) 가 제공하는 네임 서버 DNS 캐시

캐시에서 값이 있으면 해당 IP 정보를 응답값으로 전달한다.

여기서 ISP 가 제공하는 네임서버 DNS 캐시가 의무적으로 존재하지는 않는다. ISP 에 따라 존재하는 경우도 있고 없는 경우도 있다. 없다면 요청은 Local PC 의 설정만 조회해보고 바로 3번 이후로 넘어간다.


3. DNS 주소에 대한 쿼리가 Root 서버로 향한다. Root 서버는 .com 과 같은 최상위 도메인에 대한 DNS 정보를 포함한다.

도메인 정보에 따라서 일반 최상위 도메인(.com, .net, .org ...) 이나 국가 최상위 도메인(.kr, .jp ...) 으로 분류되어 각각에 알맞는 TLD 서버의 정보를 전달받는다.


4. TLD 서버 정보를 이용해 TLD 서버에서 해당 도메인 주소(tistory.com)에 대한 관리 주체 서버로 연결해준다. 


5. 도메인 주소를 관리하는 DNS 서버에서 해당 도메인 주소에 대한 IP 를 반환해준다.


6. 반환된 IP 가 응답으로 전달되면서 Local DNS 에 캐싱된다.


7. Local DNS 를 통해 클라이언트(웹 브라우저) 는 IP 정보를 얻게되고 해당 서버로 접근하게 된다.



DNS 를 관리하는 구조는 트리형태로 되어있으며 클라이언트가 트리 형태의 DNS 구조에서 쿼리를 통해 결과값을 받아가는 과정이 재귀적(Recursive)이라 하여, Resolver 를 Resulsive Resolver, Query 를 Recursive Query 등으로 부르기도 한다.




Software 를 다루는데 있어서 Proxy 는 흔히 접할 수 있는 단어이다.

많은 IT에 대해 잘 알지 못하는 사람들도 "우회" 를 목적으로 운영되는 프록시 서버에 대해 알고 있으며, Software 공학에 있어서 Proxy 는 상식처럼 알아두어야할 개념 중 하나이다. 

크게 많이 사용되는 Proxy 용어의 의미는 Proxy 서버, Proxy Design Pattern 등 다양하지만, 본 포스팅에서는 프록시 서버에 대해 다룬다.


Proxy 란 대리 혹은 중계 Agent 로써의 의미를 지니며 프록시 서버란 대리자 역할을 하는 서버를 말한다.


즉, 웹브라우저에서 Request를 보냈을 때 내 IP가 아닌 Proxy 서버의 IP로 웹서버에 접근하여 요청과 응답을 처리한 후 Proxy 서버에서 나에게 응답을 해주게 된다.


이렇게 프록시 서버를 사용하는 목적은 3가지 정도가 있다.


목적에 따른 분류


(1) 익명성과 우회접근


 : 서비스형태로 제공하는 Proxy 가 주로 이 범주에 속하며, IP를 숨기는 것이 주 목적이다. 요청을 대신 수행해주는 프록시 서버를 통해 우회하여 서버에 접근이 가능하다. 

IP 를 숨긴 채 모든 사용자가 접근가능하도록 허용하는 Open Proxy 형태가 있다.



(2) 서버의 부하를 줄여주기 위한 Filter 이자 Cache


 : Proxy 를 도구로써 사용하는 가장 대표적인 예시이다. 프록시 서버가 서비스 서버에 작업하는 위치와 네트워크 구성에 따라서 Forward Proxy / Reverse Proxy 로 구분된다.


 - Forward Proxy : 일반적인 프록시 서버를 말하며, 요청하는 Client 와 Service Server 사이에 위치하여 중간에서 요청을 중계한다. 가령 서버에 요청이 들어왔을 때, 요청은 Proxy를 거쳐 서버에 전달되며 이 과정에서 별도 작업을 처리해서 Service Server로 전달하거나, Cache 로써의 역할을 한다.


 - Reverse Proxy : 마찬가지로 Client 의 요청이 실제 Service Server의 도메인으로 이루어지는 것이 아닌 프록시 서버로 이동한다. 

Forward Proxy 와는 다르게, Service Server 들이 대게 내부망으로 구성되며 프록시에서만 연결을 허용하게 만들어 서비스를 위한 보안 채널을 구축하는 역할을 한다. 

이런 경우 Client 가 Service Server 에 직접 접근이 불가능하므로 Reverse Proxy 에서 요청을 좀 더 적극적으로 중계하는 Load Balancing 의 역할을 수행하기도 한다.


 : 이렇게 서버 측에 위치한 Cache 를 위한 Proxy 외에도 클라이언트 네트워크 쪽에서 프록시와 캐싱을 함께 수행하는 서버가 따로 존재한다. (Squid와 같은 서버가 예이다.) 

 : 이 때 캐싱 시에는 HTTP 헤더에 Cache-control : no-cache 옵션이 주로 작용하며 주로 포털 사이트에서 해당 헤더를 사용하는 경우를 볼 수 있다.

(Cache-control 옵션에 대해 얘기하자면, no-cache로 지정할 경우 캐싱을 사용하지 않고 실 서버까지 도달한다. 

그렇기 때문에 사용하려면 max-age=3600, must-revalidate 와 같이 지정해야 한다.)



(3) 서버 접근 작업 자체를 담당하는 서버


 : 다소 특수한 케이스로 주로 모니터링 및 데이터 분석을 위해 요청 자체를 기록하고 다루는 형태의 서버 엔진이 있다. 보안, ACL(Access Control List), Log / Audit 등을 위해 사용된다.



웹서비스를 구현하는 데 있어서 보통 사용되는 프록시 서버의 형태는 (1)번과 (2)번으로 Reverse Cache 의 형태가 가장 보편적이라고 할 수 있다.




Application Delivery Network CDN과 같이 사용자와 Origin Server 간의 지리적인 거리로 인해 느린 응답 속도를 해결하는 기술이지만 CDN 처럼 컨텐츠를 캐싱하는 방식이 아닌 망 지연이 생기는 구간의 트래픽 속도를 늘리는 기술이다


ADN은 컨텐츠 캐싱이 불가능한 개인별 컨텐츠(추천 서비스 등)에 적용하여 응답 속도를 향상시키는데 사용된다.


핵심 기술로는 다음과 같이 네트워크 지연을 위한 가속(Acceleration) 을 위한 기술들을 사용한다.


- Route(path) optimization : 사용자와 Origin Server 간의 라우팅 경로 최적화


- Packet Redundancy(FEC : Forward Error Correction) : 동일 패킷을 서로 다른 경로로 중복전달하여 패킷 손실 시 재전송 없이 복구할 수 있도록 함


- Data Compression : 데이터 압축을 통한 전송량 최소화


- Data De-duplication : 동일 byte system에 대해서는 중복 전송을 하지 않음.


- Application Optimization : 응용레이어(HTTP) 프로토콜 최적화(Prefetching, Pipelining)


- TCP Optimization : TCP 프로토콜 최적화(Fast Start, Large Window size )



+ Recent posts