티스토리 뷰
HTTP Message, Entity
HTTP Message는 서버와 클라이언트가 HTTP 통신 내에서 서로 주고받는 데이터를 의미한다.
- 보통 클라이언트에서 서버로 '요청'하는 메시지를 HTTP Request Message라고 하고, 반대로 서버가 클라이언트에게 응답하는 메시지를 HTTP Response Message라고 한다.
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가지 용도로 사용된다.
- 리소스 캐싱
- 리소스에 변화가 없으면, 클라이언트 측에 캐싱 된 데이터를 사용하라고 알려준다.
- 충돌 방지
- 리소스 변화 요청을 수행하기 이전에 클라이언트가 갖고 있는 데이터가 현재 데이터와 다르면 변화 요청을 수행하지 않는다.
리소스 캐싱 (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 값도 새로 계산해 내려준다)
유의할 점은 “캐싱”이라는 것에 맞게 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를 지원한다.
- nginx: http://nginx.org/en/docs/http/ngx_http_core_module.html#etag
- apache: https://httpd.apache.org/docs/2.4/caching.html
다음 글에서는 Spring에서 ETag를 어떻게 다루고 있는지, 위 방법들에 대해 구현은 어떻게 해두었는지 알아보자.
'Development > Server' 카테고리의 다른 글
Trace Sampling / 트레이스 샘플링 (1) | 2025.01.17 |
---|---|
HTTP ETag - 2. Spring에서 사용하기 (0) | 2023.04.18 |
Figma 원리: How Figma’s multiplayer technology works (0) | 2023.02.23 |
[OpenTelemetry] 2. OpenTelemetry란 무엇일까? (0) | 2022.07.06 |
[OpenTelemetry] 1. Observability와 용어들 (0) | 2022.07.06 |
- Total
- Today
- Yesterday
- 클린 아키텍처
- 쿠버네티스
- Spring boot
- Intellij
- MySQL
- c++
- Log
- Spring
- Clean Architecture
- jasync
- 일상
- java
- Algorithm
- tag
- 로그
- k8s
- HTTP
- docker
- 백준
- OpenTelemetry
- boj
- gradle
- 알고리즘
- python
- WebFlux
- 비동기
- Istio
- container
- 하루
- Kubernetes
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |