• Date 헤더는 웹서버가 클라이언트의 요청에 응답한 시간을 표시
  • Date 헤더 값을 컨텐츠 자체의 생성/수정된 시간으로 알고 있지만, 해당 내용은 잘못된 정보임
  • 컨텐츠 자체의 생성/수정된 시간은 Last-Modified 라는 헤더에서 표시


HTTP 1.1에서는 아래 형식으로 시간 정보를 표시 → RFC 1123에 정의

  • HTTP 프로토콜에서 Date 헤더의 기본 형식
    Date: Thu, 17 Aug 2017 05:52:23 GMT


HTTP 1.1 이전 버전에서 사용되었던 시간 포맷도 HTTP 1.1에서 처리 가능

1. RFC 850에 정의한 Date 형식

Date: Thursday, 17-Aug-17 05:52:23 GMT

2. C-Language 라이브러리 표준인 Date 형식

Date: Thu Aug 17 05:52:23 2017



Date 정보가 포함하지 않는 경우

  • HTTP에서는 Date 정보를 웹서버에서 응답할 때 반드시 포함해야하지만, 특별한 경우에는 Date 정보를 포함하지 않아도 됨
  • Date 정보가 포함되지 않는 경우
    1. 상태 코드가 "100 Continue" 와 "101 Switching Protocols" 인 경우에 Date 정보 X
    2. 서버 에러(예, 500 Internal Server Error) 경우와 웹서버가 유효한 date 정보를 생성하지 못함

문법

 ### 문법
Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT


 ### 사용 예제
Date: Wed, 21 Oct 2015 07:28:00 GMT

지시자

1. <day-name>

  • "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 또는 "Sun" 중 하나가 표시
  • 대소문자 구분

2. <day>

  • 날짜
  • 두 글자로 표시
  • 예시 : "04" 또는 "23"

3. <month>

  • "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 중 하나가 표시
  • 대소문자 구분

4. <year>

  • 연도
  • 네 글자로 표시
  • 예시 : "1990" 또는 "2016"

5. <hour>

  • 시간
  • 두 글자로 표시
  • 예시 : "09" 또는 "23"

6. <minute>

  • 두 글자로 표시
  • 예시 : "04" 또는 "59"

7. <second>

  • 두 글자로 표시
  • 예시 : "04" 또는 "59"

8. GMT

  • 그리니치 표준시
  • HTTP 날짜는 현지 시각이 아닌, 언제나 GMT로 표현

'HTTP > HTTP 헤더' 카테고리의 다른 글

HTTP 프로토콜 Expect 헤더  (0) 2022.06.25
HTTP 프로토콜 ETag 헤더  (0) 2022.06.25
HTTP 프로토콜 Content-Type 헤더  (0) 2022.06.25
HTTP 프로토콜 Content-Encoding 헤더  (0) 2022.06.25
HTTP 프로토콜 Connection 헤더  (0) 2022.06.25
  • HTTP 메시지(요청과 응답 모두)에 담겨 보내는 데이터의 형식을 알려주는 헤더
  • Content-Type 헤더는 리소스의 media type을 나타내기 위해 사용
  • HTTP 표준 스펙을 따르는 브라우저와 웹서버는 Content-Type 헤더를 기준으로 HTTP 메시지에 담긴 데이터를 분석과 파싱
  • 중요한점은 HTTP 요청의 경우 GET방식인 경우에는 무조건 URL 끝에 쿼리스트링으로 value=text 형식으로 보내지기 때문에 Content-Type은 필요 X → GET방식으로 데이터를 전송 시 웹서버 입장에서는 value=text 형식 데이터라고 판단
  • Content-Type은 POST나 PUT처럼 메시지 BODY에 데이터를 보낼때 필요
  • 브라우저를 기준으로 설명하자면 AJAX를 통해 json 형식의 데이터를 전송하는 경우 Content-Type 값을 application/json 으로 지정하여 전송
  • 브라우저들은 어떤 경우에는 MIME 스니핑을 해서 Content-Type 헤더의 값을 꼭 따르지는 않음 → 해당 현상을 막기 위해, X-Content-Type-Options (en-US) 헤더를 nosniff으로 설정 가능


문법

Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something



중요한 Content-Type

1. application/octet-stream

  • MIME의 개별 타입 중 application에 속하는 타입으로, 8비트 단위의 binary data 의미
  • 특별히 표현할 수 있는 프로그램이 존재하지 않는 데이터의 경우 기본값으로 octet-stream을 사용 → 브라우저가 보통 자동으로 실행하지 않거나 실행할지 묻기도 하는 타입
  • Content-Disposition 헤더를 attachment로 줌으로써 해당 데이터를 수신받은 브라우저가 파일을 저장 또는 다른이름으로 저장 여부를 설정 가능

※ Content-Disposition 헤더

  • Disposition이란 기질, 성향, 배치, 배열 이란 뜻
  • HTTP Response Header에 들어가는 Content-Disposition은 HTTP Response Body에 오는 컨텐츠의 기질/성향을 알려주는 속성
  • default 값은 inline으로 web에 전달되는 data라고 생각하면 됨
  • 특수한 경우는 Content-Disposition에 attachment를 주는 경우로, 이때 filename과 함께 주게 되면 Body에 오는 값을 다운로드 받으라는 의미
    Content-Disposition: attachment; filename="hello.jpg"


2. text/plain

  • 텍스트 파일에 대한 기본값
  • 실제로 알려지지 않은 텍스트 파일일지라도 브라우저들은 디스플레이할 수 있다고 가정함
  • text/plain이 모든 종류의 텍스트 데이터를 의미하지는 않음
  • CSS 파일을 선언한 alignment로부터 text/plain 파일을 다운로드할 경우, text/plain으로 표현된다면 브라우저는 유효한 CSS 파일로 감지 X → CSS의 MIME 타입인 text/css이 사용해야함


3. text/css

  • 웹 페이지 내에서 보통 인터프리트되어야 하는 모든 CSS 파일들은 text/css 파일이 되어야 함.
  • .css 접미사를 가진 파일들을 CSS 파일이라고 인식하지 못해 text/plain 혹은 application/octet-stream MIME 타입으로 전송 → 해당 사항은 대부분의 브라우저들이 CSS 파일이라고 인식하지 못 하며 실행 X
  • 올바른 타입으로 CSS 파일을 서브하는데 특별한 주의가 필요


4. text/html

  • Content-Type 헤더의 값을 직접 설정하지 않으면, HTML 문서의 MIME 타입인 text/html로 자동 설정


Content-Type의 종류

1, Multipart Related MIME 타입

  • Content-Type: Multipart/related → 기본 형태
  • Content-Type: Application/X-FixedRecord


2. XML Media의 타입

  • Content-Type: text/xml
  • Content-Type: Application/xml
  • Content-Type: Application/xml-external-parsed-entity
  • Content-Type: Application/xml-dtd
  • Content-Type: Application/mathtml+xml
  • Content-Type: Application/xslt+xml


3. Application의 타입

  • Content-Type: Application/EDI-X12 → Defined in RFC 1767
  • Content-Type: Application/EDIFACT → Defined in RFC 1767
  • Content-Type: Application/javascript → Defined in RFC 4329
  • Content-Type: Application/octet-stream → 디폴트 미디어 타입은 운영체제 종종 실행파일, 다운로드를 의미
  • Content-Type: Application/ogg → Defined in RFC 3534
  • Content-Type: Application/x-shockwave-flash → Adobe Flash files
  • Content-Type: Application/json → JavaScript Object Notation JSON; Defined in RFC 4627
  • Content-Type: Application/x-www-form-urlencode → HTML Form 형태
  • Content-Type: application/xml
  • Content-Type: application/pdf

※ 참고

  • x-www-form-urlencode와 multipart/form-data은 둘다 폼 형태
  • x-www-form-urlencode은 대용량 바이너리 테이터를 전송하기에 비능률적
  • 대부분 첨부파일은 multipart/form-data를 사용


4. 오디오 타입

  • Content-Type: audio/mpeg → MP3 or other MPEG audio
  • Content-Type: audio/x-ms-wma → Windows Media Audio;
  • Content-Type: audio/vnd.rn-realaudio → RealAudio; 등등


5. Multipart 타입

  • Content-Type: multipart/mixed → MIME E-mail
  • Content-Type: multipart/alternative → MIME E-mail
  • Content-Type: multipart/related → MIME E-mail → Defined in RFC 2387 and used by MHTML(HTML mail)
  • Content-Type: multipart/formed-data → 파일 첨부


6. TEXT 타입

  • Content-Type: text/css
  • Content-Type: text/html
  • Content-Type: text/javascript
  • Content-Type: text/plain
  • Content-Type: text/xml


7. file 타입

  • Content-Type: application/msword → doc
  • Content-Type: application/pdf → pdf
  • Content-Type: application/vnd.ms-excel → xls
  • Content-Type: application/x-javascript → js
  • Content-Type: application/zip → zip
  • Content-Type: image/jpeg → jpeg, jpg, jpe
  • Content-Type: text/css → css
  • Content-Type: text/html → html, htm
  • Content-Type: text/plain → txt
  • Content-Type: text/xml → xml
  • Content-Type: text/xsl → xsl


8. image 타입

  • Content-Type: image/gif → gif 이미지
  • Content-Type: image/png → PNG 이미지
  • Content-Type: image/jpeg → JPEG 이미지
  • Content-Type: image/bmp
  • Content-Type: image/webp
  • Content-Type: image/svg+xml → SVG 이미지 (벡터 이미지)


9. video 타입

  • Content-Type: video/webm
  • Content-Type: video/ogg

'HTTP > HTTP 헤더' 카테고리의 다른 글

HTTP 프로토콜 ETag 헤더  (0) 2022.06.25
HTTP 프로토콜 Date 헤더  (0) 2022.06.25
HTTP 프로토콜 Content-Encoding 헤더  (0) 2022.06.25
HTTP 프로토콜 Connection 헤더  (0) 2022.06.25
HTTP 프로토콜 Accept-Ranges 헤더  (0) 2022.06.25
  • 웹서버가 응답으로 전달하는 메시지의 인코딩 방식을 명시하는 헤더
  • 주로 Content-Type 헤더와 같이 사용 → Content-Type 헤더는 전달하는 컨텐츠의 포맷
  • Content-Encoding 헤더는 전달하는 메시지의 압축방식과 관련함
  • Content-Encoding 헤더는 HTTP 메시지 전송방식의 Transfer-Encoding 헤더와 비슷하면서도 차이가 있음
    1. Content-Encoding 헤더는 전달하는 컨텐츠 본래 형식으로 전송
    2. Transfer-Encoding 헤더는 HTTP 서버에 의해 적용되는 컨텐츠 전송
  • Content-Encoding 헤더는 미디어 타입을 압축하기 위해 사용
  • Content-Encoding 헤더가 존재하면, Content-Encoding 헤더의 값은 개체 본문에 컨텐츠 인코딩이 적용될지를 나타냄
  • Content-Type 헤더에 의해 참조되는 미디어 타입을 얻도록 디코드하는 방법을 클라이언트가 알게 해줌
  • 가능한 더 많은 데이터를 압축하기 위해 Content-Encoding 헤더 사용이 권고되지만, jpeg 이미지와 같은 유형의 리소스들은 이미 압축되어 때때로 추가적인 압축이 별 소용이 없고 페이로드를 더 길게 만들수도 있음


HTTP 에서는 Content-Encoding 의 값으로 총 4가지를 사용할 수 있음을 정의

  1. compress : 유닉스 시스템에서 사용하는 압축방식
  2. deflate : zlib 압축 포맷 -> RFC 1950에 정의
  3. gzip : gzip 프로그램을 이용하여 압축한 형태 -> RFC 1952에 정의
  4. identity : 특정한 압축 포맷이 사용되지 않았음을 의미


HTTP에서 Content-Encoding 사용 주의

  • 서버는 어떤 압축 방법도 사용하도록 강요받지 않음
  • 압축은 서버 설정과 사용되는 서버 모듈에 상당히 의존적


클라이언트가 요청한 aaa.pdf 파일에 대한 웹 서버의 응답 결과 확인

  • 웹서버의 응답헤더에서 Content-Encoding, Content-Type 결과 확인
    1. Content-Type : application/pdf → 문서가 PDF 형태의 문서
    2. Content-Encoding : gzip → 전달하는 메시지 인코딩 방식은 'gzip' 을 이용해서 전달

문법

Accept-Encoding: gzip
Accept-Encoding: compress
Accept-Encoding: deflate
Accept-Encoding: br
Accept-Encoding: identity



디렉티브

  1. gzip
    • 32비트 CRC와 함께 Lempel-Ziv coding (LZ77)를 사용하는 압축 포맷
    • Unix gzip 프로그램의 포맷
    • HTTP/1.1 표준 컨텐츠 인코딩을 지원하는 서버는 호환성 목적으로, x-gzip 별칭의 인지가 권고
  1. compress
    • Lempel-Ziv-Welch (LZW) 알고리즘을 사용하는 압축 포맷
    • Unix 배포판으로부터 사라진 압축 프로그램으로, 오늘낭의 브라우저에서 사용 X
  1. deflate
    • deflate 압축 알고리즘과 함께 zlib 구조를 사용하는 압축 포맷
  1. br
    • Brotli 알고리즘을 사용하는 압축 포맷
  1. identity
    • 압축하지 않거나 수정하지 않은 경우를 표시
    • identity 값은 존재하지 않은 경우에도 항상 수용 가능


gzip을 이용해 압축 예시

  • 클라이언트 측에서, HTTP 요청 내에 함께 전송될 압축 목록을 알릴 수 있음 → 클라이언트에서 Accept-Encoding 헤더를 사용하여 컨텐츠 인코딩 협상을 위해 사용
  • 클라이언트에서 Accept-Encoding을 사용하여 웹 서버에게 압축 목록을 전달
    Accept-Encoding: gzip, deflate
  • 웹 서버는 사용한 Content-Encoding 응답 헤더에 표시하여 응답
    Content-Encoding: gzip
  • HTTP 전송이 완료된 후에 TCP 연결을 차단할 지 열어둘지를 결정
  • HTTP/2를 사용하지 않는다면 보통 HTTP/1.1을 사용 → Connection: Keep-Alive 헤더는 HTTP/1.1에서는 default이기에 문제 없음
  • HTTP/2에서는 Connection: Keep-Alive 사용 X
  • Connection 일반 헤더는 현재의 전송이 완료된 후 네트워크 접속을 유지할지 말지를 제어
  • 전송된 값이 keep-alive면, 연결은 지속되고 끊기지 않으며, 동일한 서버에 대한 후속 요청을 수행 가능
  • 커넥션을 맺고 끝는데서 발생하는 지연을 없애기 위해서 한번 연결한 TCP 커넥션을 재활용하는 방법을 지속 커넥션(Persistent Connection)이라함
  • 서버 측에서 명시적으로 접속을 끊고 싶을 경우 Connection 헤더에 Close라고 지정
  • Connection와 Keep-Alive 같은 연결-지정(Connection-specific) 헤더 필드들은 HTTP/2에서 사용 금지됨
    • 크롬과 파이어폭스는 HTTP/2 응답에서 Connection과 Keep-Alive을 무시
    • 사파리는 HTTP/2 규격 요건에 따라 해당 필드가 포함된 응답은 처리 X


Connection: Keep-Alive가 없는 경우(HTTP/1.0버전)

  • HTTP/1.1 이전에는 클라이언트와 서버 사이에 트랜잭션 한번이 일어나면 HTTP Connection 이 끊어짐
  • TCP 커넥션을 맺는데 발생하는 지연과 느린 시작 지연이 트랜잭션마다 발생하기 때문에, 한 웹페이지에서 여러 이미지와 HTML을 요청해야 하는 경우 성능이 매우 안 좋아짐
  • 지속 커넥션(Persistent connetion)을 HTTP/1.0에서 활용하기 위해는 특정한 헤더들을 추가해줘야함
  • 지속 커넥션을 사용하기 위해서 활용하는 헤더는 Connection헤더와 Keep-Alive헤더
  • HTTP 요청을 보낼때 Connection: Keep-Alive와 같이 Connection 헤더에 Keep-Alive를 보낼 수 있음
  • 클라이언트 측에서 커넥션을 유지하기를 바라는 요청하지만, 서버가 Connection: Keep-Alive를 지켜준다는 보장은 없음


Connection 헤더의 두가지 기능

1. Connection 헤더는 중간에 위치한 프록시 서버에게 실제 서버로 전달하지 말아야 할 헤더를 알려주는 역할 → 기능은 있지만 활용 X

  • 아래 그림처럼 프록시 서버를 통해 실제 웹서버로 전달되지 말아야 할 헤더 정보(Upgrade 헤더 정보)를 Connection에 명시하면, 프록시 서버는 명시된 헤더는 실제 웹서버로 전달 X
  • 실제로 활용되는 사례를 찾기 어려움

2. HTTP는 Connection 헤더를 통해 연결 유지 기능(Persist Connection)을 관리

  • Connection 헤더를 통해 연결을 즉시 끊을 수도 있고, 또는 연결 유지를 지속적으로 가능함
  • 연결 유지(Persist Connection)는 HTTP 1.1 의 기본 동작 → default 설정
  • 하나의 TCP 연결을 통해 동일한 웹서버에 여러개의 HTTP 트랜잭션을 수행 가능 → 연결 유지 기능(Persist Connection)를 통해 가능
  • 연결 유지 기능을 사용하지 않고자 하는 경우 → Connection 헤더에 close 값을 명시

    • 웹서버는 해당 요청을 받게 되면 요청한 컨텐츠에 대해 응답하고 바로 세션을 끊게 됨
    • Connection: close는 요청 또는 응답 모두 사용 가능
      Connection: close
  • 연결 유지 기능을 사용하고자 하는 경우에는 Connection 헤더에 내용을 추가

    • Connection: Keep-Alive를 통해 연결 유지 기능을 사용
    • Keep-Alive 헤더는 옵션으로 연결 유지를 얼마나 할것인지 초단위로 정의가 가능
      GET / HTTP /1.1
      Connection: Keep-Alive
      Keep-Alive: timeout=10

  • 웹서버가 연결 유지를 지원하는 경우 아래와 같은 응답헤더 내용을 확인 가능

    • 응답 헤더에서도 Connection: Keep-Alive를 통해 연결 유지 기능을 사용할 수 있음을 확인 가능
    • Keep-Alive 헤더는 옵션으로 연결 유지를 얼마나 할것인지 초단위로 정의가 가능
      HTTP /1.1 200 OK
      Connection: Keep-Alive
      Keep-Alive: timeout=10, max=120
      Content-Type: text/html


다음(www.daum.net) 메인 페이지를 접속한 헤더 정보

  • 클라이언트는 연결유지를 사용하기 위해 Connection: Keep-Alive 헤더를 전송
  • 클라이언트에 Keep-Alive 요청을 하였지만, 서버에서는 연결유지를 사용하지 않고 응답과 함께 세션을 끊어버림
  • HTTP 요청에 대해 HTTPS 접속으로 리다이렉트 하기 위한 것 → HTTP 요청에 대해서는 끊어버리고, 새로 HTTPS 접속 요청
  • http://www.daum.net으로 요청

보배드림(https://www.bobaedream.co.kr/) 메인 페이지를 접속한 헤더 정보

  • 클라이언트와 서버에서 모두 연결 유지를 사용
    • Connection: kepp-alive 설정
    • Keep-Alive: timeout=15, max=9999 → 연결 유지를 기본 15초이며, 연결 최대 횟수를 9999회로 정의
  • 서버에서 연결 유지를 얼만큼 할것인지에 대해 추가적인 정보를 Keep-alive 헤더를 통해 클라이언트에게 전달

Connection의 Keep Alive

  • 연결된 socket에 IN/OUT의 access가 마지막으로 종료된 시점부터 정의된 시간까지 access가 없더라도 대기하는 구조
  • 정의된 시간내에 access가 이루어진다면 계속 연결된 상태를 유지
  • time out 내에 requset 재요청시 이미 열려있는 port로 연결


문법

Connection: keep-alive
Connection: close

디렉티브

  1. close
    • 클라이언트 혹은 서버가 연결을 닫으려고 하는 것
    • HTTP/1.0 요청에서 기본 값
  1. 쉼표로 구분된 HTTP 헤더 목록 [보통 keep-alive 만 해당]
    • 클라이언트가 연결을 열린 상태로 유지하려는 것
    • 영속적인 연결을 가지는 것은 HTTP/1.1 요청의 경우 기본
    • 헤더 목록은 첫번째 반투명 프록시 혹은 중간 캐시에 의해 제거될 헤더의 이름
    • 헤더들은 목적지 노드가 아닌 (요청) 발행자와 첫번째 개체 사이의 연결을 정의
  • Accept-Ranges 응답 HTTP 헤더는 부분 요청의 지원을 알리기 위해 서버에 의해 사용
  • Accept-Ranges 필드의 값은 범위를 정의하기 위해 사용될 수 있는 단위를 표시
  • Accept-Ranges 헤더가 존재하면, 브라우저는 처음부터 다시 다운로드를 시작하지 않고, 중단된 다운로드를 연속으로 가능 → Range 헤더
  • 클라이언트가 Range 헤더를 이용해서 요청하는 경우 서버 역시 Range 요청을 처리할 준비 필요 → 서버가 클라이언트에게 Range 헤더에 대한 처리 지원 여부를 알려주는데 Accept-Range 헤더가 사용


HTTP 1.1에서는 Accept-Range의 두가지 형태의 값

  1. Accept-Range: bytes
    • Range 요청을 처리 가능
  1. Accept-Ragne: none
    • Range 요청을 지원 X

※ 침고

  • 클라이언트의 Range 요청에 대해 서버는 Accept-Range 헤더를 반드시 포함하고 있어야하는 것 아님 → 서버가 Accept-Range 헤더를 포함하지 않아도 Range 헤더 사용 가능
  • 클라이언트의 Range 요청을 서버가 지원하지 않는다면, Range 요청에도 불구하고 전체 컨텐츠를 전달


Range 헤더를 포함하여 요청한 예

  • 서버에서 Range 요청을 지원하기 때문에 206 Partial Contents 메시지와 함께 데이터를 전달
  • 60~65 바이트를 전달해 줄것을 요청
  • 웹서버가 클라이언트의 Range 헤더 요청에 대한 응답을 정상적으로 전송
  • 응답헤더의 Accept-Range: bytes 와 Content-Length: 6을 통해 데이터 확인 가능 → Content-Length는 6 bytes
  • Content-Range은 전송하는 "bytes 용량/최종 용량"을 표시

서버에서 Range 요청을 지원하지 않는 예

  • 클라이언트에서 Range 요청을 했음에도 불구하고 서버는 컨텐츠의 전체 용량을 전달
  • 응답헤더의 Accept-Ranges: none 헤더와 Content-Length: 298997을 통해 전체 사이즈가 모두 전달되었음을 확인

문법

Accept-Ranges: bytes
 # 또는
Accept-Ranges: none

디렉티브(directive)

  1. none
    • 지원되는 범위의 단위가 없음을 표시
    • none은 헤더가 존재하지 않는 경우와 동일하므로 거의 사용 X
    • IE9 같은 브라우저의 경우 다운로드 매니저의 일시중지 버튼을 비활설화(disable) 혹은 제거(remove)할 때 사용
  1. bytes
    • 범위는 바이트로 표현 가능
  • 웹의 여러 요소들은 그냥 주고 받기에는 너무 큼 → 여러 압축 알고리즘을 통해 압축을 한 후 주고 받음
  • 어떤 것들은 이미 압축이 되어 다시 압축할 필요가 없는 경우도 있고, 클라이언트나 서버에서 어떤 알고리즘은 지원하고 어떤 것은 지원하지 않는지 확인이 필요함
  • 클라이언트가 서버에게 Accept-Encoding 헤더를 보냄으로써 사용 가능한 압축 알고리즘을 알 수 있음
  • 즉, Accept-Encoding 헤더는 클라이언트(브라우저)가 지원하는 압축방식을 열거함으로써, 클라이언트는 웹서버에게 요청할 때 "나는 이런이런 형태의 압축을 풀어 볼수 있으니, 원하면 명시된 압축방식을 이용해서 보내도 괜찮아요.."라는 메시지를 주는것


Accept-Encoding 헤더 사용 예시

  • 클라이언트가 Accept-Encoding 헤더에 gzip, br, 그리고 가중치를 함께 적음으로서 서버에게 사용할 알고리즘을 전달함
  • gzip, compress, br을 함께 적으면, 셋 모두 클라이언트에서 처리할 수 있으니 서버에게 셋 알고리즘 중 아무 형태든 보내달라고 함
    Accept-Encoding: gzip  
    Accept-Encoding: gzip, compress, br  
    Accept-Encoding: br;q=1.0, gzip;q=0.8, \*;q=0.1
  • 네이버의 PC 홈 화면에서 날라가는 request를 캡쳐 → Accept-Encoding 헤더가 gzip, deflate, br 으로 구성

의미

  • gzip의 경우 그 유명한 gzip 알고리즘 의미
  • br의 경우 구글에서 만든 Brotli 압축 알고리즘을 의미 → 크롬의 경우 버전 50 이후(2016년 배포), 파이어폭스는 44 이후(16년), 사파리는 11 이후 (17년 배포) 버전을 이용한다면 이용 가능
  • br의 경우 css, js, html 파일에 대해 gzip보다 대략 15~20% 크기 측면에서 효율적
  • 2개 이상의 압축방식을 지원하는 경우 쉼표(,) 로 구분하여 표시
  • "압축방식; 퀄리티 정보" 형식 → 퀄리티 부분은 1일 경우 마찬가지로 생략 가능
  • 가중치를 주어서 계산 가능
    1. deflate → deflate 압축 알고리즘과 함께 zlib 구조를 사용하는 압축 포맷으로, q값이 생략됨으로 선호도는 1임
    2. gzip;q=1.0 → gzip 압축 알고리즘을 사용하는 압축 포맷으로, q=1.0으로 선호도는 1임
    3. *;q=0.5 → 표현된 선호 대상이 없다는 것을 의미로 아무 압축 알고리즘을 사용하여 전송해달라는 것, q=0.5로 q=1.0이 없는 경우 전송 요청
      Accept-Encoding: deflate, gzip;q=1.0, \*;q=0.5

※ q는 quality의 약자로 품질의 의미

  • 가중치를 줘서 선호하는 압축 알고리즘을 서버에게 알려줌
  • q 의 값은 0 ~ 1 사이의 값이 부여
  • 1이 최고로 선호하는 품질
  • q는 값이 1일때 생략 가능
  • 웹서버는 클라이언트가 선호하는 형태의 요청을 받게 되면, 압축 알고리즘을 클라이언트가 선호하는 방법으로 제공하여 데이터 전송


문법

Accept-Encoding: gzip  
Accept-Encoding: compress  
Accept-Encoding: deflate  
Accept-Encoding: br  
Accept-Encoding: identity  
Accept-Encoding: \*

 # Multiple algorithms, weighted with the quality value (en-US) syntax:  
Accept-Encoding: deflate, gzip;q=1.0, \*;q=0.5



디렉티브

  1. gzip
    • 32비트 CRC와 함께 Lempel-Ziv coding (LZ77)를 사용하는 압축 포맷
  1. compress
    • Lempel-Ziv-Welch (LZW) 알고리즘을 사용하는 압축 포맷
  1. deflate
    • deflate 압축 알고리즘과 함께 zlib 구조를 사용하는 압축 포맷
  1. br
    • Brotli 알고리즘을 사용하는 압축 포맷
  1. identity
    • 압축하지 않거나 수정하지 않은 경우를 표시
    • identity 값은 존재하지 않은 경우에도 항상 수용 가능
  1. *(asterisk)
    • 헤더 내에 아직 나열되지 않은 컨텐츠 인코딩이라도 일치
    • 헤더가 존재하지 않을 경우, 기본값 → 모든 알고리즘이 지원된다는 것을 의미 X
    • 표현된 선호 대상이 없다는 것을 의미
  1. ;q= (q값 가중치)
    • weight라고 부르는 상대적인 퀄리티 값을 사용
    • 표현한 선호도에 따라 배치된 값

포트 변경

  • ssh 접속할 수 있는 포트를 지정해야 ansible 코어 서버에서 접근 가능

  • 기본은 22번 포트

    $ vi /etc/ansible/ansible.cfg
    remote_port    = 22000
    #remote_port    = 22



출력되는 내용의 양식 결정

  • 기본은 skippy

  • debug로 표시하면 조금 더 가독성이 좋아짐

  • json으로 표시하면 json 파일 형태로 표시되어서 향후 웹서버에서 이용하기 편리함

    $ vi /etc/ansible/ansible.cfg
    stdout_callback = skippy
    #stdout_callback = debug
    #stdout_callback = json
  • json 파일을 적용하려면 stdout_callback = json으로 지정하고 난 뒤에 아래 부분도 변경해줘야함

    $ vi /etc/ansible/ansible.cfg
    #callback_whitelist = timer, mail
    callback_whitelist = json, timer



접속하는 서버의 /root/,ssh/known_hosts 파일에 접근 자동 저장

  • 처음 접속하는 서버는 known_hosts에 저장할 것인지 질의 → 질의에 대한 응답으로 yes를 해야만 ssh 접속이 가능

  • 수 많은 서버를 관리하는 입장에서 지속적으로 known_hosts에 저장하는 것은 번거로운 일이다.

  • 처음 서버에 접속하는 것에 대한 질의를 없애고 바로 known_hosts에 저장할 수 있도록 설정

    $ vi /etc/ansible/ansible.cfg
    ## 주석처리된 것을 삭제하면 됨
    ## host key checking setting above. 
    record_host_keys=False
    
    ## 주석처리된 것을 삭제하면 됨 
    ## uncomment this to disable SSH key host checking 
    host_key_checking = False



root로 직접 서버에 접속할 수 없는 경우 su 권한을 얻어서 서버에 적용

  1. become: 권한 상승 여부 (기본: True)

  2. become_method: 권한 상승 방법 (기본: sudo) →전체 적용되기에 보안상 위험해서 yml파일에 필요시 대입

  3. become_user: 권한 상승할 사용자 (기본: root)

  4. become_ask_pass: 권한 상승 방법의 패스워드 요청/입력 여부 (기본: false) -> yes로 변경해야 root 비밀번호도 입력 가능

    $ vi /etc/ansible/ansible.cfg
    ## 주석처리된 것을 삭제하면서 아래 내용과 같이 수정
    [privilege_escalation]
    become=True
    #become_method=su
    become_user=root
    become_ask_pass=True



ansible pipeline 설정

  • 파이프라인은 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조

  • 기존 (총 3번의 통신 필요)

    1. ssh 통신 : ~/.ansible/tmp 의 임시 저장 공간 생성
    2. sftp, scp, piped 통신 : 실행될 파일을 전달 (ansible-playbook )
    3. ssh 통신 : 실행
  • 파이프라이닝 옵션 적용 후

  • ssh 로 파일을 보냄과 동시에 실행

  • 적용 방법 → # pipelining = False의 주석을 제거하고 True로 변경

    $ vi /etc/ansible/ansible.cfg 
    # 주석처리된 것을 삭제하면서 아래 내용과 같이 수정
    # Enabling pipelining reduces the number of SSH operations required to
    # execute a module on the remote server. This can result in a significant
    # performance improvement when enabled, however when using "sudo:" you must
    # first disable 'requiretty' in /etc/sudoers
    #
    # By default, this option is disabled to preserve compatibility with
    # sudoers configurations that have requiretty (the default on many distros).
    #
    pipelining = True



ansible forks 설정

  • 한번에 실행하는 값

  • 운영체제에서는 System Call(fork)을 통해서 하나의 프로세스에서 자식 프로세스로 분기를 의미

  • pipelining을 통해 실행할때 forks = 5가 기본값으로 설정 (통로가 5개 만들어짐)

  • forks를 늘리면 자식 프로세스가 많아져서, 부하가 많이 발생할 수 있기에, 적절한 개수 설정이 필요

  • 부하 관련 참고 URL : https://medium.com/devops-srilanka/difference-between-forks-and-serial-in-ansible-48677ebe3f36

  • 적용 방법 → # pipelining = False의 주석을 제거하고 True로 변경

    $ vi /etc/ansible/ansible.cfg 
    # 주석처리된 것을 삭제하면서 아래 내용과 같이 수정
    forks          = 10
  • Consistent Hashing에 가장 큰 특징 중 하나는 HashRing에 k 개의 노드가 있는 상황에서, 노드가 사라지거나 추가될 때 1/k 정도의 key에 대한 것만 유실이 되고 나머지 key는 변동 없이 유지되는 것 임
  • 같은 값으로 노드들이 만들어지면 순서도 항상 동일

 

Consistent Hashing의 핵심은 hash 함수

  • Consistent Hashsing 의 가장 큰 핵심은 hash 함수
  • hash 함수의 특징은 f = hash(key) 의 결과가 항상 같은 key에 대해서는 같은 hash 결과 값이 나옴 -> host1, host2, host3 와 같은 주소를 해시하면 hash 함수를 바꾸지 않는 이상은 항상 같은 hash 값이 나옴
  • hash 값으로 정렬을 하게 되면 항상 같은 순서가 나옴

 

hash 값으로 Hash Ring을 생성하는 경우

  • 이해를 쉽게 하기 위해서, hash의 결과가 0 부터 1 까지 float 형태로 나온다고 가정
  • hash("host1") = 0.25, hash("host2") = 0.5, hash("host3") = 0.75 가 나온다고 가정
  • 특정 key에 대한 hash 결과는 hash 값이 크면서 가장 가까운 host에 저장이 된다고 가정
    1. hash("key1") = 0.3 이면 key1이라는 key가 위치할 서버는 0.5 값을 가지는 host2가 되게 됨
    2. 0.75 보다 크면 Ring 이므로 다시 첫번째 host1에 저장이 됨
  • hash 함수와 서버의 목록만 알면, 특정 key를 어디에 저장할 것인지 결정 가능

 

Consistent Hashing에서 서버가 추가되거나 삭제될 때 1/k 개의 key만 삭제

  • hash("host4") = 0.6 인 서버가 하나 추가되었다고 가정
  • 서버가 들어오면 순서는 host1, host2, host4, host3 이 됨
  • host4 와 host3 사이의 값, 즉 hash 함수의 결과가 0.6 ~ 0.75 인 key들만 저장해야 할 서버가 바뀌지, 다른 key들은 원래의 위치에 그대로 저장됨
  • 아래 그림으로 Consistent Hashing

 

1. A, B, C 세 대의 서버가 hash Ring을 구성

2. 첫번째 1이라는 key가 들어오면 hash("1") 해서 나온 결과값을 보니 B가 규칙에 맞아서 B에 저장

3. 두번째 2가 들어올 경우 hash("2") 해서 나온 결과값을 보니 C가 규칙에 맞아서 C에 저장

4. key 3,4는 hash("3"), hash("4")의 값이 A 서버에 속하므로 A 에 들어가고, key 5는 C에 가까워서 C에 들어가게 됨

5. A, B, C의 공간이 서로 균일하지가 않음 -> 가상 서버(vnode) 생성

  • B가 죽는다고 가정하면 B의 부하는 전부 C로 넘어가게 됨 -> 불공평한 일이 발생 가능
  • 불공평한 일이 발생할 가능성을 제거하기 위해 가상의 친구들을 더 만들어냄
    1. 가상 서버들을 한 서버당 2개씩 더 만듦 -> hash('A'), hash('A+1'), hash('A+2') 로 Hash Ring 에 추가
    2. B는 hash('B'), hash('B+1'), hash('B+2') 등으로 추가
    3. 총 3개의 서버를 9개로 보이게 함
  • 아래와 같이 A+1은 실제로는 A지만, hash ring에서 가상적으로 다른 서버로 보이게 함
  • hash ring 자체도 더 촘촘해지고, 어떤 서버가 한대 장애가 나더라도, 그 부하가, 적절하게 나머지 두 서버로 나눠지게 됨
  • 실제 서비스에서는 서버당 수십개의 가상 노드를 만들어서 처리 -> 예시로2~3개로 설명하였지만, 실제는 많음

6. 핵심 결론 -> 서버 이름으로 hash 값을 만들어서 정렬한 것을 하나의 Ring 처럼 생각해서 key를 hash 값에 따라 저장

 

python2의 Consistent Hashing 코드 -> rebuild가 핵심

### consistent_hash.py 파일
import sys
import hashlib
import struct

VALUE_IDX = 2
HASH_IDX = 3
LAST = -1
FIRST = 0

class ConsistentHash:
    def __init__(self, kvlist, replica, hash_func = None):
        self.hash_func = hash_func
        if not self.hash_func:
            self.hash_func = self.ketama_hash
        self.kvlist = kvlist
        self.replica = replica
        self.continuum = self.rebuild(kvlist)

    def ketama_hash(self, key):
        return struct.unpack('<I', hashlib.md5(key).digest()[0:4])

    def rebuild(self, kvlist):
        continuum = [(k, i, v, self._hash("%s:%s"%(k,i))) \
                     for k,v in kvlist \
                     for i in range(self.replica)]
        continuum.sort(lambda x,y: cmp(x[HASH_IDX], y[HASH_IDX]))
        return continuum

    def _hash(self, key):
        return self.hash_func(key)

    def find_near_value(self, continnum, h):
        size = len(continnum)
        begin = left = 0
        end = right = size
        while left < right:
            middle = left + (right - left) / 2
            if continnum[middle][HASH_IDX] < h:
                left = middle + 1
            else:
                right = middle
        if right == end:
            right = begin
        return right, continnum[right][VALUE_IDX]

    def get(self, key):
        h = self._hash(key)
        if h > self.continuum[LAST][HASH_IDX]:
            return self.continuum[FIRST][VALUE_IDX]
        return self.find_near_value(self.continuum, h)

if __name__ == "__main__":
    replica = 2
    kvlist = [("host1", "value1"), ("host2", "value2"), ("host3", "value3"), ("host4", "value4")]
    ch = ConsistentHash(kvlist, replica)
    print ch.continuum
    v = ch.get(sys.argv[1])
    print v[0], ch.continuum[v[0]]
    
    
##### 실행
$ python2 consistent_hash.py hosts1
[('host3', 0, 'value3', (1063727328,)), ('host4', 1, 'value4', (1685475194,)), ('host2', 1, 'value2', (2063768010,)), ('host4', 0, 'value4', (2327965545,)), ('host1', 1, 'value1', (2749222897,)), ('host2', 0, 'value2', (2807531582,)), ('host1', 0, 'value1', (3226067400,)), ('host3', 1, 'value3', (3295705430,))]
(1, ('host4', 1, 'value4', (1685475194,)))

$ python2 consistent_hash.py hosts2
[('host3', 0, 'value3', (1063727328,)), ('host4', 1, 'value4', (1685475194,)), ('host2', 1, 'value2', (2063768010,)), ('host4', 0, 'value4', (2327965545,)), ('host1', 1, 'value1', (2749222897,)), ('host2', 0, 'value2', (2807531582,)), ('host1', 0, 'value1', (3226067400,)), ('host3', 1, 'value3', (3295705430,))]
(6, ('host1', 0, 'value1', (3226067400,)))

 

Hash Ring을 구성하는 서버의 이름이 바뀌는 경우 -> hash ring이 다르게 구성됨

  • Consistent hashing을 많이 쓰는 libmemcached 의 경우 보통 서버 주소가 들어가게됨
  • "1.1.1.1:11211", "1.1.1.2:11211", "1.1.1.3:11211" 서버 이름을 가진 상황에서 1.1.1.2 서버가 문제가 발생
  • 기존 장비를 교체하기 위해 새 장비를 받는데, 해당 장비의 IP는 1.1.1.4 가짐 -> Hash Ring이 꼬여 버릴 수 있음
  • Hash Ring이 꼬이는 문제를 해결하기 위해서는 직접적인 이름 대신에 alias한 다른 이름으로 Consistent Hashing을 구성 필요
  • 즉 redis001, redis002, redis003, redis004 이름으로 Hash Ring을 구성하고, 서버가 바뀌더라도 기존 이름을 사용사용하면 Consistent hashing의 문제 없음

 

Hash 재분배 vs Consistent Hashing 재분배

1.Hash 재분재

2.Consistent Hashing 재분배

 

Consistent hashing 응용

1.Web Cache

  • 웹 캐시는 웹 서비스 품질을 높이려고 할 때, 가장 먼저 고려하는 요소 -> CSS, 자바스크립트, 이미지, HTML과 같은 정적인 페이지를 고성능의 서버에 캐시하고 있다가 웹 서버 대신 응답해 주는 일
  • 캐시하기 힘든 동적인 페이지, 혹은 캐시 실패한 요청만 웹 서버로 전달
  • Consistent hash를 이용하면, 분산 웹 캐시 시스템을 만들 수 있음
  • Consistent hash로 구성하면, (관리 없이)자유롭게 캐시를 늘리거나 줄일 수 있음 -> 대량의 멀티미디어 파일을 서비스에 특히 유용하게 사용 가능
  • Web Cache 순서
    1. 유저의 요청은 먼저 Proxy server로 향함
    2. Proxy 서버는 유저가 요청한 자원(URL)이 해시테이블에 있는지 확인
    3. 해시테이블에 있다면, Cache Server에 요청
    4. 해시테이블에 없거나, 캐시에서 가져오는게 실패했다면 Web Server에 요청

2. 샤딩(Sharding)

  • 데이터베이스 샤드(Shard)는 검색이나 데이터베이스에서 사용하는 horizontal partition 기법
  • 데이터베이스의 내용이 여러 서버 인스턴스로 저장하는 방식으로 로드를 분산함
  • Key-Value 기반의 NoSQL 데이터베이스에서 consistent hash를 이용해서 샤딩을 구현하는 경우가 많음

※ 참고

'IT 학습 용어' 카테고리의 다른 글

CI/CD 설명  (0) 2022.07.07
file storage, block storage, object storage이란  (0) 2022.07.03
페이로드(payload)  (0) 2022.06.27
M3U8 파일  (0) 2022.06.27
LRU (Least Recently Used)  (0) 2022.06.27

+ Recent posts