티스토리 뷰

반응형

HTTP Message, Entity

HTTP Message는 서버와 클라이언트가 HTTP 통신 내에서 서로 주고받는 데이터를 의미한다.

  • 보통 클라이언트에서 서버로 '요청'하는 메시지를 HTTP Request Message라고 하고, 반대로 서버가 클라이언트에게 응답하는 메시지를 HTTP Response Message라고 한다.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages/httpmsgstructure2.png

 

Entity는 HTTP Message의 일부라고 생각하면 된다.

  • 여러 외부 자료에서 HTTP Message가 컨테이너면 Entity는 화물이라고 비유하고 있다.

 

Entity는 Request/Response Payload를 이루는 Raw data이다.

  • Response header 중 Content prefix가 붙은 것들은 Entity를 표현하는 용도이다.

 


ETag

ETag는 Entity-Tag의 약자이다.

HTTP Caching하면 많이 등장하는 녀석인데, 특정 버전의 리소스(Entity)를 식별하는 식별자(identifier)이다.

 

보통 2가지 용도로 사용된다.

  1. 리소스 캐싱
    • 리소스에 변화가 없으면, 클라이언트 측에 캐싱 된 데이터를 사용하라고 알려준다.
  2. 충돌 방지
    • 리소스 변화 요청을 수행하기 이전에 클라이언트가 갖고 있는 데이터가 현재 데이터와 다르면 변화 요청을 수행하지 않는다.

 

리소스 캐싱 (If-None-Match)

Cache와 identifier라는 키워드에서 눈치챌 수 있듯, 식별자를 통해 변화가 없으면 cache 된 것을 사용하는 프로세스이다.

 

좀 더 프로세스를 자세히 보면,

  • Client의 HTTP Request에 따라 Server에서 HTTP Response를 내려준다. 이 때 Response에 ETag header에 식별자 값을 담아 내려준다.
  • Client는 응답을 받아 처리하면서 ETag 식별자와 Entity 값을 저장(캐싱)해둔다.
  • 이후 요청했던 URL로 HTTP Request를 보낼 때, 저장해두었던 ETag 값을 If-None-Match 헤더 필드에 담아 전송한다.
  • Server에서는 If-None-Match 헤더가 존재하는지 확인하고, 존재한다면 해당 헤더의 값과 현재 버전의 리소스의 ETag를 비교한다.
    • 만약 두 값이 일치한다면 아직 캐시된 버전이 유효하다는 것이므로 304(Not Modified)를 반환하여 Client에게 알려준다. Client는 캐싱되었던 Entity를 재활용한다.
    • 만약 두 값이 일치하지 않는다면 리소스가 변경되었다는 것이므로 새로운 응답을 내려준다. (ETag 값도 새로 계산해 내려준다)

 

https://blog.kakaocdn.net/dn/bl6GTX/btrOwkX53AE/0KfhJKsrrDV7OjA6DR2JK0/img.png

 

유의할 점은 “캐싱”이라는 것에 맞게 Cache-Control header 값에 영향을 받는다.

  • no-store 값이면 캐싱을 금지하는 정책이므로, 위 과정을 수행하지 않는다. (무조건 응답을 내려준다)

+) 헤더에 따른 행동/액션은 ‘모든 구현체는 이렇게 동작하고 있음’이 아니다. RFC 스펙/명세서일 뿐이다. 많이 사용하는/알려진 구현체에서는 일반적으로 알맞게 동작한다(ex. Web browser, ...). 하지만 스펙을 고려하지 않고 구현 된 구현체도 존재할 수 있으므로 유의해야한다 (이미 잘 알려진 라이브러리가 있음에도 직접 구현해 production에서 활용하는 것을 주의하고, 막 가져다가 사용하지 말자 제발).

 

아무튼 이렇듯 캐시된 버전을 사용함으로써 Entity를 Message에 포함시키지 않아 대역폭을 줄일 수 있고, 응답 속도 또한 줄일 수 있는 장점이 있다.

 

충돌 피하기 (If-Match)

ETag는 특정 리소스 변경 요청에 대하여 충돌을 피하는 용도로도 사용된다.

  • 보통 이를 Lost update problem 이라고 한다. 여러 사용자간에 하나의 리소스를 업데이트하고자 할 때, 따로 관리해주지 않았다면 제일 마지막 요청에 대해서만 반영하게 될 것이다. 0.0001초 전에 온 요청이 있을지라도 마지막에 들어온 수정사항만 반영되버린다.
  • 기존 데이터의 형태를 보고 수정사항을 반영해야하는 경우 Critical 할 수 있다. 이러한 문제에 있어서 Etag를 통해 충돌을 방지할 수 있다.

 

예를 들어, 특정 리소스를 변경하기 이전에 먼저 Client가 리소스를 요청했다고 하자.

이 때 Client에게 리소스를 해싱하여 ETag 헤더의 값에 넣어준다.

그 후 Client에서 리소스를 변경하고 이에 대한 수정을 요청할 때, If-Match 헤더에 앞서 받았던 ETag 값을 넣어서 Server에게 요청한다.

  • Server에서는 If-Match 헤더의 값과 현재 리소스를 바탕으로 ETag 값을 계산해 비교한다.
  • 만약 같으면, 아직 리소스가 변경되지 않았다는 뜻으로 변경 요청에 따른 변경 양식을 반영해 수정한다.
  • 만약 같지 않으면, 리소스를 수정하려던 사이에 리소스가 변경되었다는 뜻이므로 변경이 불가능하다는 표현으로 412 Precondition Failed 응답을 반환한다.

 

+) MDN 문서에서는 이를 mid-air collision으로 소개하고 있다. 비행 중 항공기가 충돌하는 것을 비유한 말인데, 네트워크 상에서 동시다발적인 리소스 변화 요청이 발생해 충돌하는 것을 의미한다.

+) 이 부분에 대한 더 자세한 내용은 아래 주소들을 참고

 

ETag 비교

ETag와 어떤 값을 비교하는가?

앞에서 살펴보았듯 If-None-Match 헤더 또는 If-Match 헤더 값으로 들어온 값과 현재 버전의 리소스의 ETag 값을 비교한다.

현재 버전의 리소스의 Etag는 실제로 서버 단에서 캐싱된 리소스/ETag 값일 수 있고, 요청 때마다 리소스를 구해 ETag 값을 계산해낼 수도 있다. (보통은 후자인 것 같다)

 

ETag 값은 어떻게 생성하는가?

보통 ETag를 만들 때, MD5 알고리즘이 사용된다.

  • 원본이 같은 값이었는지 확인하는 용도로 활용되며 128비트의 고정 길이 출력값을 반환한다.

 

ETag 생성에 있어서 2가지 방법(Strong ETag, Weak ETag)으로 나뉜다. (Strong Validator / Weak Validator)

 

1. Strong ETag

Strong ETag는 리소스의 바이트 단위까지 동일하다는 것을 목표로 한다. 즉, 엄격하게 리소스의 변화를 감지해낼 수 있다.

 

즉, 리소스 전체에 대하여 (보통) MD5 알고리즘을 사용하여 ETag 값을 생성한다.

  • ex) "a1b1c1"

 

2. Weak ETag

Weak ETag는 Strong ETag와 다르게 리소스 버전이 동일하다는 것에 중점을 둔다.

 

난 이 말이 참 이해가 안갔는데, 리소스 버전이 동일하다?는 것을 어떻게 알지 싶었다.

근데 좀 생각해보니 그 말대로 구현하는 측에서 다르게 설정해서 활용할 수 있다고 이해했다.

  • MDN에서 예제는 바닥글의 날짜만 다르거나 광고가 다른 페이지는 약한 유효성 검사를 사용하면 다른 페이지와 동일한 것으로 간주됩니다. 라고 나온다. 즉, 구현하는 측에서 리소스의 차이 구분을 어떤 것으로 둘 것인가에 따라 달라질 수 있다는 것이다.
    • x와 y 값을 가지는 리소스가 있다하자. 해당 리소스 버전을 평가할 때 x 값만 보면 된다고 한다면 ETag를 생성 시에 x 값만을 이용하여 생성한다. 그리고 ETag를 비교할 때 x 값만을 이용해 생성한 ETag를 비교하면 된다.
    • ex) 같은 블로그 글인데 날짜만 변경되어 있는 경우 → 글이 핵심이고 날짜는 핵심이지 않은 경우.

 

Weak ETag를 사용할 땐 지켜야하는 것이 하나 있는데, W/ prefix를 ETag 값에 붙여줘야만 한다.

  • ex) W/"a1b1c1"

 

근데 왜 종류가 나뉜 것일까?

ETag 핵심은 캐싱인데, 이게 리소스 전체에 대해서 ETag 값을 비교하게 되면 아주 작은/사소한(비즈니스 도메인에서 버전의 차이라고 볼 수 없는) 변화에도 새로 캐싱을 해야만 한다. 즉, 캐싱 성능의 저하를 일으킨다.

즉, 전체 리소스 비교가 필요없는 곳에서는 Weak Etag 값을 이용하여 캐싱 성능 최적화를 이룰 수 있다.

이러한 목적에 따라 의미상의 구분으로 종류를 나눈 것으로 이해했다.

이 부분에 대해서는 의견이 많이 나뉘고, 내가 잘못 이해했을 수도 있으니 참고한 문서를 첨부해놓는다.

 

많이 사용하는 웹 서버 및 프레임워크에서도 ETag를 지원한다.

 

다음 글에서는 Spring에서 ETag를 어떻게 다루고 있는지, 위 방법들에 대해 구현은 어떻게 해두었는지 알아보자.

 

320x100
반응형
댓글
반응형
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함