Istio Sidecar Proxy Access Log
1. Istio Sidecar Proxy Access Log
Istio 환경에서 다양한 Case에 따른 Sidecar Proxy의 Access Log를 살펴본다.
1.1. Test 환경 구성
![[Figure 1] Test Environment](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/test-environment.png)
[Figure 1] Test Environment
[Figure 1]은 Istio Sidecar Proxy Access Log Test 환경을 나타내고 있다. 2개의 Worker Node로 구성되어 있고 각각의 Node에 Client 역할을 수행하는 shell Pod와 Server 역할을 수행하는 mock-server Pod가 위치한다. shell Pod는 mock-server Pod와 같이 설정된 Service, Destination Rule, Virtual Service를 통해서 접근한다. HTTP Protocol을 통해서 접근하는 경우에는 shell Pod 내부에서 curl 명령어를 이용하여 접근하고, gRPC Protocol을 통해서 접근하는 경우에는 shell Pod 내부에서 grpcurl 명령어를 이용하여 접근한다.
1.1.1. Kubernetes, Istio 환경 구성
# Create kubernetes cluster with kind
$ kind create cluster --config=- <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
# Install istio
$ istioctl install --set profile=demo -y
# Enable sidecar injection to default namespace
$ kubectl label namespace default istio-injection=enabled[Shell 1]은 Kubernetes, Istio 환경을 구성하는 Script를 나타내고 있다. kind를 활용하여 Kubernetes Cluster를 구성하고 Istio를 설치한다. 그리고 default Namespace에 Sidecar Injection을 활성화한다.
| |
[Text 1]은 Istio Sidecar Proxy Access Log의 Format을 변경하기 위한 Istio의 Mesh Config를 나타내고 있다. Access Log의 기본 Format은 Plain Text 형식으로 되어 있어 가독성이 좋지 않으며, JSON 형식으로 변경하기 위해서 accessLogFormat Field를 이용하여 설정한다.
1.1.2. Workload 구성
| |
[File 1]은 mock-server Workload의 Manifest를 나타내고 있다. mock-server Image를 이용하여 mock-server Pod을 생성하며, 8080 Port를 열어서 HTTP 서비스를 제공하고, 9090 Port를 열어서 gRPC 서비스를 제공한다. Virtual Service에는 Timeout은 60s로 설정되어 있고, 재시도는 기본값과 동일하게 2번 재시도를 설정하여 최대 3번 요청을 시도하도록 설정되어 있다. 또한 재시도 조건은 기본값인 connect-failure, refused-stream, unavailable, cancelled 4가지 Error 조건에 502 Status Code를 추가하여 설정되어 있다.
Circuit Breaking을 Test를 위해서 Destination Rule이 설정되어 있다. outlierDetection Field는 비정상 상태를 판단하는 기준을 정의하며 기본값으로 구성되어 있다. 5번 연속으로 10초 간격으로 5xx 에러가 발생하면 Circuit Breaking이 동작하며, Circuit Breaking 적용 시간은 30초로 설정되어 있다. connectionPool Field는 HTTP/GRPC 요청의 동시 처리 개수를 제한하는 설정을 명시하며, 동시에 한개의 요청만 처리할 수 있도록 설정되어 있다.
동시 처리 개수를 제한하는 방법은 크게 최대 TCP Connection을 기반으로 제한하는 방법과 최대 동시 HTTP/GRPC 요청 처리의 개수를 제한하는 방법이 있다. TCP Connection 기반의 방법은 tcp.maxConnections Field를 이용하여 최대 TCP Connection의 개수를 제한하는 방법이다. [File 1]에서는 tcp.maxConnections Field를 1로 설정하여 최대 TCP Connection의 개수를 1개로 제한하고 있으며, http.http1MaxPendingRequests Field를 1로 설정하여 TCP Connection이 Ready 상태가 되기전까지 Pending 할 수 있는 요청의 개수도 최대 1개까지로 제한하고 있다.
GRPC의 경우에는 하나의 TCP Connection에서 HTTP/2의 Stream 기능을 활용하여 다수의 요청을 동시에 처리할 수 있다. 따라서 http.maxConcurrentStreams Field를 1로 설정하여 하나의 TCP Connection에서 최대 1개의 Stream만 처리할 대 있도록 강제하여 손쉽게 GRPC 요청 Pending을 발생시킬 수 있도록 설정되어 있다. 만약에 http.maxConcurrentStreams Field가 명시되어 있지 않으면 하나의 TCP Connection에서 무제한으로 Stream 처리가 가능하기 때문에 GRPC 요청 Pending이 발생하지 않는다.
| |
HTTP/GRPC 요청의 최대 동시 처리 개수를 제한하는 방법은 http.http2MaxRequests Field를 이용하면 된다. [File 2]에서는 http.http2MaxRequests Field를 1로 설정하여 최대 HTTP/GRPC 요청 처리의 개수를 1개로 제한하고 있다. 또한 나머지 connectionPool Field는 설정하지 않아 Request가 Pending 되지 않도록 설정되어 있다. 대부분의 Case에서는 [File 1]에서 설정한 Destination Rule을 이용하며, [File 2]의 Destination Rule은 일부 Circuit Breaking Case에서 이용한다.
| Endpoint | Description |
|---|---|
| /status/{code} | Return specific HTTP status code |
| /bytes/{bytes} | Return specified number of bytes |
| /delay/{ms} | Delay response by milliseconds |
| /reset-before-response/{ms} | Server sends TCP RST before response after delay |
| /reset-after-response/{ms} | Server sends dummy data, then TCP RST after delay |
| /close-before-response/{ms} | Server closes connection before response after delay |
| /close-after-response/{ms} | Server sends dummy data, then closes connection after delay |
| Function | Description |
|---|---|
| /mock.MockService/Status | Return specific gRPC status code |
| /mock.MockService/Delay | Delay response by milliseconds |
| /mock.MockService/ResetBeforeResponse | Server sends TCP RST before response after delay |
| /mock.MockService/ResetAfterResponse | Server sends dummy data, then TCP RST after delay |
| /mock.MockService/CloseBeforeResponse | Server closes connection before response after delay |
| /mock.MockService/CloseAfterResponse | Server sends dummy data, then closes connection after delay |
[Table 1]과 [Table 2]는 mock-server Workload의 HTTP Endpoint, gRPC Function별 동작을 나타내고 있다. mock-server에서 제공하는 Endpoint들을 다양한 Case를 재현하기 위해서 사용한다.
| |
| |
| |
[File 3]은 shell Pod의 Manifest를 나타내고 있다. netshoot Image를 이용하여 shell Pod을 생성하며, Network Admin 권한을 부여하여 iptables 명령어를 이용할 수 있도록 한다. [File 4]는 grpcurl 명령어를 이용하여 mock-server gRPC Service를 호출하기 위한 Proto 파일을 나타내고 있다. [Shell 2]은 Proto 파일을 shell Pod에 복사하는 예시를 나타내고 있다.
1.2. HTTP Cases
1.2.1. OK Case
![[Figure 2] HTTP OK Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-ok-case.png)
[Figure 2] HTTP OK Case
| |
[Figure 2]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /status/200 Endpoint에 GET 요청을 전달하고, 200 OK 응답을 받는 HTTP OK Case를 나타내고 있다. [Shell 3]은 [Figure 2]의 내용을 실행하는 예시를 나타내고 있다.
| |
| |
[Text 2]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 3]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /status/200 Endpoint에 접근하는 내역와 200 OK 응답도 확인이 가능하다.
1.2.2. Service Unavailable Case
![[Figure 3] HTTP Service Unavailable Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-service-unavailable-case.png)
[Figure 3] HTTP Service Unavailable Case
| |
[Figure 3]은 shell Pod에서 curl 명령어를 이용하여 mock-server의 /status/503 Endpoint에 GET 요청을 전달하고, 503 Service Unavailable 응답을 받는 HTTP Service Unavailable Case를 나타내고 있다. [Shell 4]은 [Figure 3]의 내용을 실행하는 예시를 나타내고 있다.
| |
| |
[Text 4]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 5]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /status/503 Endpoint에 접근하는 내역와 503 Service Unavailable 응답도 확인이 가능하다.
1.2.3. Downstream TCP Close Case
![[Figure 4] Downstream TCP Close Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-downstream-tcp-close-case.png)
[Figure 4] Downstream TCP Close Case
| |
[Figure 4]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /delay/5000 Endpoint에 GET 요청을 전달하고, 5000ms가 지나기 전에 Ctrl+C 명령어를 이용하여 요청을 강제로 종료하는 Downstream TCP Close Case를 나타내고 있다. [Shell 5]은 [Figure 4]의 내용을 실행하는 예시를 나타내고 있다.
curl 명령어 실행 중 강제로 종료하면 curl 명령어는 내부적으로 Connection을 종료하면서 TCP FIN Flag를 shell Pod의 istio-proxy에게 전송하며, TCP FIN Flag를 받은 shell Pod의 istio-proxy는 처리중인 요청을 중단하고 TCP FIN Flag를 mock-server Pod에게 전송하여 최종적으로 mock-server Container에게 전달된다. 이후에 mock-server Container가 5000ms 뒤에 응답을 전송하면 Connection이 이미 종료된 상태이기 때문에 mock-server Pod의 istio-proxy는 TCP RST Flag를 mock-server Container에게 전송한다.
| |
| |
[Text 6]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 7]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /delay/5000 Endpoint에 접근하는 내역와 response_code가 0으로 나타나는 것을 확인할 수 있다. 또한 response_flags가 DC (DownstreamConnectionTermination)로 나타나는 것을 확인할 수 있다.
1.2.4. Downstream TCP RST Case
![[Figure 5] Downstream TCP RST Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-downstream-tcp-rst-case.png)
[Figure 5] Downstream TCP RST Case
| |
[Shell 6]은 shell Pod에서 mock-server의 /delay/5000 Endpoint에 GET 요청을 전달하고, 5000ms가 지나기 전에 TCP FIN Flag가 아닌 TCP RST Flag를 전송하여 요청을 강제로 종료하는 Downstream TCP RST Case를 나타내고 있다. curl 명령어는 Socket의 SO_LINGER Option을 제어할 수 없어 TCP RST Flag를 전송할 수 없기 때문에, python3 명령어를 이용하여 요청 전송 1000ms 이후에 SO_LINGER Option을 0으로 설정하고 Socket을 닫아 TCP RST Flag를 전송한다.
TCP RST Flag를 수신한 shell Pod의 istio-proxy는 TCP RST Flag를 mock-server Pod에게 그대로 전달하지 않고, Downstream TCP Close Case와 동일하게 TCP FIN Flag를 전송하여 Connection을 종료한다. istio-proxy는 Downstream Connection과 Upstream Connection을 별도의 TCP Connection으로 관리하기 때문에, Downstream Connection이 TCP RST Flag를 통해서 비정상적으로 종료되어도 Upstream Connection은 TCP FIN Flag를 통해서 정상적으로 종료한다. TCP FIN Flag를 수신한 mock-server Pod의 istio-proxy도 TCP FIN Flag를 mock-server Container에게 전송한다. 이후에 mock-server Container는 5000ms 뒤에 응답을 전송하지만 Connection이 이미 종료된 상태이기 때문에 mock-server Pod의 istio-proxy로부터 TCP RST Flag를 수신한다.
| |
| |
[Text 8]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 9]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 Downstream TCP Close Case와 동일하게 response_code가 0, response_flags가 DC (DownstreamConnectionTermination), response_code_details가 downstream_remote_disconnect로 나타나는 것을 확인할 수 있다. 즉 istio-proxy는 Downstream으로부터 TCP FIN Flag를 수신하는 경우와 TCP RST Flag를 수신하는 경우를 Access Log에서 구분하지 않는것을 확인할 수 있다.
1.2.5. Downstream TCP RST with Backpressure Case
![[Figure 6] Downstream TCP RST with Backpressure Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-downstream-tcp-rst-with-backpressure-case.png)
[Figure 6] Downstream TCP RST with Backpressure Case
| |
[Shell 7]은 shell Pod에서 mock-server의 /bytes/50000000 Endpoint에 GET 요청을 전달하여 50MB 응답을 수신하는 도중에, 응답을 읽지 않고 4000ms 대기한 이후에 TCP RST Flag를 전송하여 요청을 강제로 종료하는 Downstream TCP RST with Backpressure Case를 나타내고 있다.
Client가 응답을 읽지 않으면 shell Pod의 istio-proxy는 Client에게 전달하지 못한 데이터를 내부 Buffer에 보관하며, Buffer가 가득 차면(High Watermark) Upstream 데이터 읽기를 중단하는 Backpressure가 동작한다. 이후 mock-server Pod에서 전송된 데이터는 istio-proxy가 읽어가지 않기 때문에 Upstream Socket의 Kernel Receive Buffer에 쌓인다. [Shell 7]의 ss 명령어 출력에서 istio-proxy의 Upstream Socket(10.244.1.10:8080)의 Recv-Q에 약 1.8MB의 읽지 않은 데이터가 쌓여있는 것을 확인할 수 있다.
이 상태에서 TCP RST Flag를 수신한 shell Pod의 istio-proxy는 Upstream Connection을 종료하는데, Downstream TCP RST Case와 다르게 Kernel Receive Buffer에 읽지 않은 데이터가 남아있는 Socket을 닫기 때문에 TCP 규칙에 따라 TCP FIN Flag가 아닌 TCP RST Flag가 mock-server Pod에게 전송된다. 즉 istio-proxy가 Upstream Connection을 종료할 때 전송하는 Flag는 종료 시점에 Kernel Receive Buffer에 읽지 않은 데이터가 존재하는지 여부에 따라서 결정된다. TCP RST Flag를 수신한 mock-server Pod의 istio-proxy도 동일한 이유로 mock-server Container에게 TCP RST Flag를 전송한다. Backpressure로 인해서 mock-server Pod의 istio-proxy도 mock-server Container가 전송한 데이터를 읽지 않고 있었기 때문에, mock-server Container와 연결된 Socket의 Kernel Receive Buffer에도 읽지 않은 데이터가 남아있기 때문이다.
| |
| |
[Text 10]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 11]은 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log 모두 Downstream TCP RST Case와 동일하게 response_flags가 DC (DownstreamConnectionTermination), response_code_details가 downstream_remote_disconnect로 기록되며, 응답 전송 도중에 중단되었기 때문에 response_code는 200으로 기록된다. bytes_sent를 통해서 중단 전까지 각 istio-proxy가 Downstream에게 전송한 데이터의 크기도 확인할 수 있다.
즉 Access Log에서는 Downstream TCP RST Case와 Downstream TCP RST with Backpressure Case가 구분되지 않으며, istio-proxy가 Upstream에게 TCP FIN Flag 대신 TCP RST Flag를 전송하는 차이는 Packet Dump를 통해서만 확인이 가능하다.
1.2.6. Upstream Request Retry Case
![[Figure 7] Upstream Request Retry Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-request-retry-case.png)
[Figure 7] Upstream Request Retry Case
[File 1]의 Virtual Service에는 retryOn Field에 502 Status Code가 포함되어 있기 때문에, 502 Status Code 응답을 받는 경우 최대 2번의 재시도를 수행하여 최대 3번의 요청이 전송된다.
| |
[Shell 8]은 shell Pod에서 curl 명령어를 이용하여 mock-server의 /status/502 Endpoint에 GET 요청을 전달하는 Upstream Request Retry Case를 나타내고 있다. mock-server는 모든 요청에 502 Bad Gateway 응답을 반환하기 때문에, shell Pod의 istio-proxy는 2번의 재시도를 모두 수행한 이후에 마지막으로 받은 502 Bad Gateway 응답을 curl 명령어에게 전달한다.
| |
| |
[Text 12]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 13]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. [Text 12]에서는 upstream_request_attempt_count가 첫번째 시도와 2번의 재시도를 모두 포함한 3으로 기록된 것을 확인할 수 있으며, response_flags도 재시도 한도를 모두 소진했음을 나타내는 URX (UpstreamRetryLimitExceeded)로 기록된 것을 확인할 수 있다.
[Text 13]에서는 동일한 request_id를 갖는 3개의 Log가 기록된 것을 확인할 수 있다. 재시도는 Client 역할을 수행하는 shell Pod의 istio-proxy에서 수행되기 때문에, mock-server Pod의 istio-proxy는 각 재시도를 별개의 요청으로 처리하여 모든 Log에 upstream_request_attempt_count가 1로 기록된다.
1.2.7. Upstream TCP RST before Response Case
![[Figure 8] Upstream TCP RST before Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-tcp-rst-before-response-case.png)
[Figure 8] Upstream TCP RST before Response Case
| |
[Figure 8]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /reset-before-response/1000 Endpoint에 GET 요청을 전달하고, 1000ms 후에 mock-server Pod가 TCP RST Flag를 전송하여 Connection을 강제로 종료하는 Upstream TCP RST before Response Case를 나타내고 있다. [Shell 9]은 [Figure 8]의 내용을 실행하는 예시를 나타내고 있다.
mock-server Pod의 istio-proxy는 mock-server Container로부터 TCP RST Flag를 수신하면 TCP RST Flag를 shell Pod에게 전송하지 않고, 503 Service Unavailable 응답을 전송하기 때문에 shell Pod의 istio-proxy의 Access Log에는 response_flags가 존재하지 않고 503 Service Unavailable 응답만 확인이 가능하다.
| |
| |
[Text 14]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 15]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /reset-before-response/1000 Endpoint에 접근하는 내역와 503 Service Unavailable 응답도 확인이 가능하다. 또한 response_flags가 UC (UpstreamConnectionTermination)로 나타나는 것을 확인할 수 있으며, response_code_details에 upstream_reset_before_response_started{connection_termination}, 즉 응답을 시작하기전에 TCP RST Flag가 Upstream에서 전송되었음을 나타내는 상세 내역도 확인할 수 있다.
1.2.8. Upstream TCP RST after Response Case
![[Figure 9] Upstream TCP RST after Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-tcp-rst-after-response-case.png)
[Figure 9] Upstream TCP RST after Response Case
| |
[Figure 9]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /reset-after-response/1000 Endpoint에 GET 요청을 전달하고, 1000ms 후에 mock-server Pod가 응답을 일부 전송한 후에 TCP RST Flag를 전송하여 Connection을 강제로 종료하는 Upstream TCP RST after Response Case를 나타내고 있다. [Shell 10]은 [Figure 9]의 내용을 실행하는 예시를 나타내고 있다.
TCP RST Flag를 받은 mock-server Pod의 istio-proxy는 TCP FIN Flag를 shell Pod에게 전송하여 TCP Connection을 종료한다. 또한 예상치 못한 Connection 종료였기 때문에 TCP RST Flag도 TCP RST Flag 이후에 전송한다.
| |
| |
[Text 16]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 17]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /reset-after-response/1000 Endpoint에 접근하는 내역와 200 OK 응답도 확인이 가능하다. 또한 response_flags가 UPE (UpstreamProtocolError)로 나타나는 것을 확인할 수 있있다.
response_code_details에 upstream_reset_after_response_started{protocol_error}, 즉 일부 응답 전송후에 TCP RST Flag가 Upstream에서 전송되었음을 나타내는 상세 내역도 확인할 수 있다. Protocol Error가 발생하는 이유는 완전한 HTTP 응답을 전송하기 전에 TCP RST Flag가 Upstream에서 전송되었기 때문이다.
1.2.9. Upstream TCP Close before Response Case
![[Figure 10] Upstream TCP Close before Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-tcp-close-before-response-case.png)
[Figure 10] Upstream TCP Close before Response Case
| |
[Figure 10]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /close-before-response/1000 Endpoint에 GET 요청을 전달하고, 1000ms 후에 mock-server Pod가 Connection을 강제로 종료하는 Upstream TCP Close before Response Case를 나타내고 있다. [Shell 11]은 [Figure 10]의 내용을 실행하는 예시를 나타내고 있다.
mock-server Pod의 istio-proxy는 mock-server Container로부터 TCP FIN Flag를 수신하면 503 Service Unavailable 응답을 shell Pod에게 전송하여 요청이 비정상적으로 종료된것을 알린다.
| |
| |
[Text 18]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 19]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /disconnect/1000 Endpoint에 접근하는 내역와 503 Service Unavailable 응답도 확인이 가능하다. 또한 response_flags가 UC (UpstreamConnectionTermination)로 나타나는 것을 확인할 수 있다.
response_code_details에 upstream_reset_before_response_started {connection_termination}, 즉 응답을 시작하기전에 TCP FIN Flag가 Upstream에서 전송되었음을 나타내는 상세 내역도 확인할 수 있다. 이는 [Figure 8]에서 TCP RST Flag를 받을때와 동일한 상세 내역이며, mock-server Pod의 istio-proxy는 응답이 전송되기 전에 TCP FIN Flag 또는 TCP RST Flag를 수신하면 동일한 response_code_details를 남기는것을 확인할 수 있다.
1.2.10. Upstream TCP Close after Response Case
![[Figure 11] Upstream TCP Close after Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-tcp-close-after-response-case.png)
[Figure 11] Upstream TCP Close after Response Case
| |
[Figure 11]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /close-after-response/1000 Endpoint에 GET 요청을 전달하고, 1000ms 후에 mock-server Pod가 응답을 전송한 후에 Connection을 강제로 종료하는 Upstream TCP Close after Response Case를 나타내고 있다. [Shell 12]은 [Figure 11]의 내용을 실행하는 예시를 나타내고 있다.
mock-server Pod의 istio-proxy는 mock-server Container로부터 TCP FIN Flag를 수신하면 503 Service Unavailable 응답을 shell Pod에게 전송하여 요청이 비정상적으로 종료된것을 알린다.
| |
| |
[Text 20]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 21]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /close-after-response/1000 Endpoint에 접근하는 내역과 200 OK 응답도 확인이 가능하다. 또한 response_flags가 UPE (UpstreamProtocolError)로 나타나는 것을 확인할 수 있다.
response_code_details에 upstream_reset_after_response_started {protocol_error}, 즉 응답을 시작한 후에 Protocol Error가 발생하여 Connection을 강제로 종료한 것을 나타내는 상세 내역도 확인할 수 있다. 이는 [Figure 9]에서 TCP RST Flag를 받을때와 동일한 상세 내역이며, mock-server Pod의 istio-proxy는 응답을 일부 전송한 상태에서 TCP FIN Flag 또는 TCP RST Flag를 수신하면 동일한 response_code_details를 남기는것을 확인할 수 있다.
1.2.11. Circuit Breaking with Upstream Connection Pool Overflow Case
![[Figure 12] Circuit Breaking with Upstream Connection Pool Overflow Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-circuit-breaking-with-upstream-connection-pool-overflow-case.png)
[Figure 12] Circuit Breaking with Upstream Connection Pool Overflow Case
| |
[Figure 12]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /delay/5000 Endpoint에 GET 요청을 3번 연속으로 전달하여 Upstream Connection Pool Overflow를 발생시켜 Circuit Breaking을 동작시키는 Case를 나타내고 있다. [Shell 13]은 [Figure 12]의 내용을 실행하는 예시를 나타내고 있다.
[File 1]의 Destination Rule에 의해서 첫번째 요청은 바로 mock-server Pod로 전달되며, 5000ms 동안 대기 이후에 200 OK 응답과 함께 종료된다. 두번째 요청은 첫번째 요청이 처리중이기 때문에 Pending되어 첫번째 요청이 끝나기 전까지 대기 이후에 mock-server Pod에 전달된다. 따라서 두번째 요청이 처리되는데 걸리는 시간은 5000ms + 5000ms = 10000ms가 된다. 세번째 요청은 Pending도 불가능하기 때문에 istio-proxy는 Upstream Overflow라 간주하고 Circuit Breaking을 동작시키고, 503 Service Unavailable 응답을 전송한다.
| |
| |
[Text 22]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 23]는 mock-server의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 istio-proxy의 Access Log에는 가장 먼저 남는 Log는 Upstream Connection Pool Overflow로 인해서 요청과 동시에 처리에 실패한 세번째 요청에 대한 Log이다. response_flags가 UO (UpstreamOverflow)로 나타나는 것을 확인할 수 있으며, start_time도 나머지 Log와 비교하면 가장 나중에 시작된 것도 확인할 수 있다. 두번째로 남는 Log는 첫번째 요청에 대한 Log이며, 세번째로 남는 Log는 두번째 요청에 대한 Log이다. response_duration이 각각 5000ms, 10000ms인걸 확인할 수 있다.
mock-server Pod의 istio-proxy의 Access Log에는 첫번째 요청과 두번째 요청에 대한 Log만 남아 있는것을 확인할 수 있으며, response_duration이 모두 5000ms인걸 확인할 수 있다. 세번째 요청은 shell Pod의 istio-proxy에서 Upstream Connection Pool Overflow로 인해서 mock-server Pod로 전달되지 않았기 때문에 mock-server Pod의 istio-proxy에도 세번째 요청에 대한 Log가 존재하지 않는다.
1.2.12. Circuit Breaking with Upstream Request Limit Overflow Case
![[Figure 13] Circuit Breaking with Upstream Request Limit Overflow Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-circuit-breaking-with-upstream-request-limit-overflow-case.png)
[Figure 13] Circuit Breaking with Upstream Request Limit Overflow Case
| |
[Figure 13]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /delay/5000 Endpoint에 GET 요청을 3번 연속으로 전달하여 Upstream Request Limit Overflow를 발생시키는 Case를 나타내고 있다. 이 Case를 재현하기 위해서는 [File 2]에서 설정한 Destination Rule을 적용해야한다. [Shell 14]은 [Figure 13]의 내용을 실행하는 예시를 나타내고 있다.
[File 2]의 Destination Rule의 설정에 의해서 최대 동시에 처리할 수 있는 요청이 하나이고 요청 Pending도 불가능하기 때문에, 두번째와 세번째 요청은 Upstream Overflow로 인해서 mock-server Pod에 전달되지 않는다.
| |
| |
[Text 24]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 25]은 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 istio-proxy의 Access Log에는 먼저 남는 Log는 Upstream Request Limit Overflow로 인해서 요청과 동시에 처리에 실패한 두번째, 세번째 요청에 대한 Log이다. 첫번째 Log가 두번째 요청에 대한 Log이고, 두번째 Log가 세번째 요청에 대한 Log이다. 둘다 response_flags가 UO (UpstreamOverflow)로 나타나는 것을 확인할 수 있다. 마지막 Log는 첫번째 요청에 대한 Log이며, 정상적으로 mock-server Pod에 전달되어 처리된 것을 확인할 수 있다.
1.2.13. Circuit Breaking with No Healthy Upstream Case
![[Figure 14] Circuit Breaking with No Healthy Upstream Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-circuit-breaking-with-no-healthy-upstream-case.png)
[Figure 14] Circuit Breaking with No Healthy Upstream Case
| |
[Figure 14]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /status/503 Endpoint에 GET 요청을 8번 연속으로 전달하여 No Healthy Upstream을 통한 Circuit Breaking을 발생시키는 Case를 나타내고 있다. [Shell 15]는 [Figure 14]의 내용을 실행하는 예시를 나타내고 있다.
[File 1]의 Destination Rule에 의해서 5번의 연속적인 5XX Error가 발생하면 Circuit Breaking이 동작한다. 따라서 shell Pod의 첫 5번의 요청은 모두 mock-server Pod에게 전달되지만, 이후에 3번의 요청은 Circuit Breaking으로 인해서 mock-server Pod에 전달되지 않는다.
| |
| |
[Text 26]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 27]은 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 istio-proxy의 Access Log에는 마지막 3개의 요청에만 response_flags가 UH (NoHealthyUpstream)와 함께 요청이 mock-server Pod에 전달되지 않은 것을 확인할 수 있다. 또한 mock-server Pod의 istio-proxy의 Access Log에는 처음 5개의 요청에 대한 Log만 남아있는것도 확인할 수 있다.
1.2.14. Upstream Connection Failure with Timeout Case
![[Figure 15] Upstream Connection Failure with Timeout Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-connection-failure-case-with-timeout.png)
[Figure 15] Upstream Connection Failure with Timeout Case
| |
[Figure 15]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /status/200 Endpoint에 접속시 Timeout에 의해서 연결에 실패하여 Retry되는 Upstream Connection Failure with Timeout Case를 나타내고 있다. [Shell 16]은 [Figure 15]의 내용을 실행하는 예시를 나타내고 있다. Timeout을 발생시키기 위해서 iptables 명령어를 이용하여 shell Pod의 IP Address로부터 들어오는 트래픽을 DROP하는 Rule을 추가한 다음, curl 명령어를 이용하여 요청을 전송한다.
[File 1]의 Virtual Service의 connect-failure 의해서 2번의 재시도가 발생하여 총 3번의 요청이 전송된다. 따라서 shell Pod의 첫번째 요청은 shell Pod의 istio-proxy에 의해서 3번의 재시도를 수행한 다음 connection timeout 오류가 출력된다. shell Pod의 두번째 요청은 1번의 재시도가 발생하여 총 2번의 요청이 전송되는데, 이유는 [File 1]의 Destination Rule에 의해서 5번 연속적인 5XX Error가 발생하면 Circuit Breaking이 동작하기 때문이다.
첫번째 요청의 3번의 요청과 두번째 요청의 2번째 요청, 총 5번의 요청이 발생했고 모두 Timeout에 의해서 실패하였기 때문에 Healthy Upstream이 없다고 판단하고 Circuit Breaking이 동작한다. 따라서 두번째 요청의 2번째 재시도는 Circuit Breaking에 의해서 mock-server Pod에 전송되지 않으며, 두번째 요청의 결과로 no healthy upstream 오류가 출력된다. 세번째 요청은 Circuit Breaking에 의해서 즉시 no healthy upstream 오류 출력과 함께 종료된다.
| |
[Text 28]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 요청이 istio-proxy에 의해서 mock-server Pod에 전달되지 않기 때문에 mock-server Pod의 istio-proxy의 Access Log에는 아무것도 남지 않는다. 첫번째 요청에는 response_flags에 URX (UpstreamRetryLimitExceeded)와 UF (UpstreamConnectionFailure)가 함께 나타나는 것을 확인할 수 있으며, response_code_details에 upstream_reset_before_response_started {connection_timeout}, 즉 Connection Timeout이 발생한 사실을 확인할 수 있다. upstream_request_attempt_count가 3으로 나타나는 것을 확인할 수 있다.
두번째, 세번째 요청에는 Circuit Breaking에 의해서 response_flags에 UH (NoHealthyUpstream)가 나타나는 것을 확인할 수 있으며, response_code_details에 no_healthy_upstream가 나타나는 것을 확인할 수 있다. 두번째 요청에는 upstream_request_attempt_count가 3으로 나타나는 것을 확인할 수 있다. 세번째 요청에는 upstream_request_attempt_count가 1으로 나타나는 것을 확인할 수 있다.
1.2.15. Upstream Connection Failure with TCP Reset Case
![[Figure 16] Upstream Connection Failure with TCP Reset Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-connection-failure-case-with-tcp-reset.png)
[Figure 16] Upstream Connection Failure with TCP Reset Case
| |
[Figure 16]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /status/200 Endpoint에 접속시 TCP Reset에 의해서 연결에 실패하여 Retry되는 Upstream Connection Failure with TCP Reset Case를 나타내고 있다. [Shell 17]은 [Figure 16]의 내용을 실행하는 예시를 나타내고 있다. TCP Reset을 발생시키기 위해서 iptables 명령어를 이용하여 shell Pod의 IP Address로부터 들어오는 트래픽을 REJECT하는 Rule을 추가한 다음, curl 명령어를 이용하여 요청을 전송한다. Connection Refused 오류 내용을 제외하고는 Timeout에 의해서 Retry를 수행하는 Case와 동일한 결과를 보여준다.
| |
[Text 29]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 요청이 istio-proxy에 의해서 mock-server Pod에 전달되지 않기 때문에 mock-server Pod의 istio-proxy의 Access Log에는 아무것도 남지 않는다. response_code_details에 upstream_reset_before_response_started{remote_connection_failure|delayed_connect_error:_Connection_refused}, 즉 Remote Connection Failure와 Delayed Connect Error가 발생한 사실을 확인할 수 있다. 이 부분을 제외하고는 Timeout에 의해서 Retry를 수행하는 Case와 동일한 결과를 보여준다.
1.2.16. Upstream Request Timeout Case
![[Figure 17] Upstream Request Timeout Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/http-upstream-request-timeout-case.png)
[Figure 17] Upstream Request Timeout Case
| |
[Figure 17]는 shell Pod에서 curl 명령어를 이용하여 mock-server의 /delay/70000 Endpoint에 GET 요청을 전달하였지만, mock-server Pod의 istio-proxy에서 60000ms 대기후에 응답이 오지 않아 Request를 Timeout 처리하는 Upstream Request Timeout Case를 나타내고 있다. [Shell 18]은 [Figure 17]의 내용을 실행하는 예시를 나타내고 있다.
[File 1]의 Virtual Service에 의해서 mock-server Pod로 전송된 요청은 최대 60000ms 대기할 수 있다. 하지만 mock-server Pod의 /delay/70000 Endpoint에 전송한 요청은 70000ms가 필요하기 때문에 Timeout이 발생한다. mock-server Pod의 istio-proxy는 Timeout 발생시 TCP FIN Flag와 TCP RST Flag를 차례로 전송하여, mock-server Pod와의 연결을 종료한다. 또한 504 Gateway Timeout 응답을 shell Container에게 전송한다.
| |
| |
[Text 30]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 31]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 istio-proxy에는 response_flags에 UT (UpstreamTimeout)를 확인할 수 있다. mock-server Pod의 istio-proxy에는 response_flags에 DC (DownstreamConnectionTermination)를 확인할 수 있다.
1.3. GRPC Cases
1.3.1. OK Case
![[Figure 18] OK Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-ok-case.png)
[Figure 18] OK Case
| |
[Figure 18]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Status 함수에 code: 0 요청을 전달하고, OK 응답을 받는 OK Case를 나타내고 있다. [Shell 19]은 [Figure 18]의 내용을 실행하는 예시를 나타내고 있다.
| |
| |
[Text 32]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 33]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/Status 함수에 접근하는 내역과 grpc_status가 OK로 나타나는 것을 확인할 수 있다.
1.3.2. Internal Case
![[Figure 19] Internal Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-internal-case.png)
[Figure 19] Internal Case
| |
[Figure 19]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Status 함수에 code: 13 요청을 전달하고, Internal 응답을 받는 Internal Case를 나타내고 있다. [Shell 20]은 [Figure 19]의 내용을 실행하는 예시를 나타내고 있다.
| |
| |
[Text 34]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 35]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/Status 함수에 접근하는 내역과 grpc_status가 Internal로 나타나는 것을 확인할 수 있다. 또한 response_code가 200 OK로 나타나는 것을 확인할 수 있으며, gRPC 이용시 gRPC의 결과와 상관없이 response_code는 항상 200 OK로 나타난다. INTERNAL (13) Status Code는 [File 1]의 Virtual Service의 retryOn Field에 포함되어 있지 않기 때문에 재시도가 발생하지 않으며, upstream_request_attempt_count도 1로 기록된다.
1.3.3. Downstream TCP Close Case
![[Figure 20] Downstream TCP Close Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-downstream-tcp-close-case.png)
[Figure 20] Downstream TCP Close Case
| |
[Figure 20]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Delay 함수에 milliseconds: 5000 요청을 전달하고, 5000ms가 지나기 전에 Ctrl+C 명령어를 이용하여 요청을 강제로 종료하는 Downstream TCP Close Case를 나타내고 있다. [Shell 21]은 [Figure 20]의 내용을 실행하는 예시를 나타내고 있다.
grpcurl 명령어 실행 중 강제로 종료하면 grpcurl 명령어는 내부적으로 Connection을 종료하면서 TCP FIN Flag를 shell Pod의 istio-proxy에게 전송하며, TCP FIN Flag를 받은 shell Pod의 istio-proxy는 HTTP/2 RST_STREAM Frame을 mock-server Pod에게 전송하여 최종적으로 mock-server Container에게 전달하여 요청을 종료한다. HTTP/1.1 Protocol과 다르게 HTTP/2 Protocol을 이용하는 Pod 사이의 TCP Connection은 Stream 다중화를 통해서 다수의 요청이 공유하기 때문에, shell Pod의 istio-proxy는 Pod 사이의 TCP Connection을 종료하지 않고 HTTP/2 RST_STREAM Frame을 통해서 해당 요청의 Stream만 종료한다.
| |
| |
[Text 36]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 37]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/Delay 함수에 접근하는 내역과 response_code가 0, grpc_status가 -로 나타나는 것을 확인할 수 있다.
또한 shell Pod의 istio-proxy에서는 grpcurl 명령어로부터 TCP FIN Flag를 수신하기 때문에 response_flags가 DC (DownstreamConnectionTermination)로 나타나는 것을 확인할 수 있으며, mock-server Pod의 istio-proxy에서는 HTTP/2 RST_STREAM Frame을 수신하기 때문에 response_flags가 DR (DownstreamRemoteReset)로 나타나는 것을 확인할 수 있다.
1.3.4. Downstream TCP RST Case
![[Figure 21] Downstream TCP RST Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-downstream-tcp-rst-case.png)
[Figure 21] Downstream TCP RST Case
| |
[Shell 22]은 shell Pod에서 mock-server의 /mock.MockService/Delay 함수에 milliseconds: 5000 요청을 전달하고, 5000ms가 지나기 전에 TCP FIN Flag가 아닌 TCP RST Flag를 전송하여 요청을 강제로 종료하는 Downstream TCP RST Case를 나타내고 있다. grpcurl 명령어는 Socket의 SO_LINGER Option을 제어할 수 없어 TCP RST Flag를 전송할 수 없기 때문에, python3 명령어를 이용하여 HTTP/2 Frame과 gRPC Message를 직접 구성하여 요청을 전송하고, 요청 전송 1000ms 이후에 SO_LINGER Option을 0으로 설정하고 Socket을 닫아 TCP RST Flag를 전송한다.
TCP RST Flag를 수신한 shell Pod의 istio-proxy는 Downstream TCP Close Case와 동일하게 TCP RST Flag를 mock-server Pod에게 그대로 전달하지 않고, HTTP/2 RST_STREAM Frame을 전송하여 해당 요청의 Stream만 종료한다. 즉 Downstream Connection이 TCP FIN Flag를 통해서 정상적으로 종료되거나 TCP RST Flag를 통해서 비정상적으로 종료되는 것과 무관하게, Pod 사이의 TCP Connection은 그대로 유지되며 HTTP/2 RST_STREAM Frame만 전송된다.
| |
| |
[Text 38]은 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 39]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 Downstream TCP Close Case와 동일하게 shell Pod에서는 response_flags가 DC (DownstreamConnectionTermination), response_code_details가 downstream_remote_disconnect로 나타나며, mock-server Pod에서는 response_flags가 DR (DownstreamRemoteReset), response_code_details가 http2.remote_reset으로 나타나는 것을 확인할 수 있다. 즉 HTTP/1.1 Protocol의 경우와 동일하게 gRPC Protocol의 경우에도 istio-proxy는 Downstream으로부터 TCP FIN Flag를 수신하는 경우와 TCP RST Flag를 수신하는 경우를 Access Log에서 구분하지 않는것을 확인할 수 있다.
1.3.5. Upstream Request Retry Case
![[Figure 22] Upstream Request Retry Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-request-retry-case.png)
[Figure 22] Upstream Request Retry Case
[File 1]의 Virtual Service의 retryOn Field에는 gRPC의 재시도 조건인 unavailable, cancelled가 포함되어 있다. 따라서 UNAVAILABLE (14) Status Code 응답을 받는 경우 최대 2번의 재시도를 수행하여 최대 3번의 요청이 전송된다.
| |
[Shell 23]은 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Status 함수에 code: 14 (Unavailable) 요청을 전달하는 Upstream Request Retry Case를 나타내고 있다.
| |
| |
[Text 40]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있다. upstream_request_attempt_count가 첫번째 시도와 2번의 재시도를 모두 포함한 3으로 기록된 것을 확인할 수 있으며, response_flags도 재시도 한도를 모두 소진했음을 나타내는 URX (UpstreamRetryLimitExceeded)로 기록된 것을 확인할 수 있다.
[Text 41]에서는 동일한 request_id를 갖는 3개의 Log가 기록된 것을 확인할 수 있다. 재시도는 Client 역할을 수행하는 shell Pod의 istio-proxy에서 수행되기 때문에, mock-server Pod의 istio-proxy는 각 재시도를 별개의 요청으로 처리하여 모든 Log에 upstream_request_attempt_count가 1로 기록된다.
1.3.6. Upstream TCP RST before Response Case
![[Figure 23] Upstream TCP RST before Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-tcp-rst-before-response-case.png)
[Figure 23] Upstream TCP RST before Response Case
| |
[Figure 23]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/ResetBeforeResponse 함수에 milliseconds: 1000 요청을 전달하고, 1000ms 대기후에 TCP RST Flag를 전송하여 Connection을 강제로 종료하는 Upstream TCP RST before Response Case를 나타내고 있다. [Shell 24]은 [Figure 23]의 내용을 실행하는 예시를 나타내고 있다.
TCP RST Flag를 받은 mock-server Pod의 istio-proxy는 Unavailable 상태 코드를 반환하여 요청이 비정상적으로 종료된것을 shell Pod의 istio-proxy에게 알린다. [File 1]의 Virtual Service에 unavailable 설정에 의해서 shell Pod의 istio-proxy는 2번의 재시도를 수행하여 총 3번의 요청을 전송한다.
| |
| |
[Text 42]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 43]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/ResetBeforeResponse 함수에 접근하는 내역과 response_code가 200, grpc_status가 Unavailable로 나타나는 것을 확인할 수 있다. 또한 두 Access Log에서 모두 response_flags가 UC (UpstreamConnectionTermination)로 나타나는 것을 확인할 수 있다.
shell Pod의 istio-proxy가 3번의 요청을 전송하기 때문에 shell Pod의 istio-proxy의 Access Log에서 upstream_request_attempt_count가 3으로 나타나는 것을 확인할 수 있다. 또한 mock-server Pod의 istio-proxy의 Access Log가 3번이 남아있는것을 확인할 수 있다.
1.3.7. Upstream TCP RST after Response Case
![[Figure 24] Upstream TCP RST after Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-tcp-rst-after-response-case.png)
[Figure 24] Upstream TCP RST after Response Case
| |
[Figure 24]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/ResetAfterResponse 함수에 milliseconds: 1000 요청을 전달하고, 1000ms 후에 mock-server Pod가 응답을 일부 전송한 후에 TCP RST Flag를 전송하여 Connection을 강제로 종료하는 Upstream TCP RST after Response Case를 나타내고 있다. [Shell 25]은 [Figure 24]의 내용을 실행하는 예시를 나타내고 있다.
| |
| |
[Text 44]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 45]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/ResetAfterResponse 함수에 접근하는 내역과 response_code가 200, grpc_status가 Unknown로 나타나는 것을 확인할 수 있다. shell Pod의 istio-proxy의 Access Log에서 response_flags가 UR (UpstreamRemoteReset)로 나타나는 것을 확인할 수 있으며, mock-server Pod의 istio-proxy의 Access Log에서 response_flags가 UC (UpstreamConnectionTermination)로 나타나는 것을 확인할 수 있다.
1.3.8. Upstream TCP Close before Response Case
![[Figure 25] Upstream TCP Close before Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-tcp-close-before-response-case.png)
[Figure 25] Upstream TCP Close before Response Case
| |
[Figure 25]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/CloseBeforeResponse 함수에 milliseconds: 1000 요청을 전달하고, 1000ms 후에 mock-server Pod가 Connection을 강제로 종료하는 Upstream TCP Close before Response Case를 나타내고 있다. [Shell 26]은 [Figure 25]의 내용을 실행하는 예시를 나타내고 있다.
mock-server Container에서 TCP FIN Flag를 전송한다는 부분만 제외하고 TCP RST Flag를 받는 [Figure 23]과 동일한 과정을 수행한다는 것을 알 수 있다.
| |
| |
[Text 46]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 47]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/CloseBeforeResponse 함수에 접근하는 내역과 response_code가 200, grpc_status가 Unavailable로 나타나는 것을 확인할 수 있다. TCP RST Flag를 받는 [Figure 23]과 동일한 과정을 수행한다는 것을 알 수 있다.
1.3.9. Upstream TCP Close after Response Case
![[Figure 26] Upstream TCP Close after Response Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-tcp-close-after-response-case.png)
[Figure 26] Upstream TCP Close after Response Case
| |
[Figure 26]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/CloseAfterResponse 함수에 milliseconds: 1000 요청을 전달하고, 1000ms 후에 mock-server Pod가 응답을 일부 전송한 후에 Connection을 강제로 종료하는 Upstream TCP Close after Response Case를 나타내고 있다. [Shell 27]은 [Figure 26]의 내용을 실행하는 예시를 나타내고 있다.
mock-server Container에서 TCP FIN Flag를 전송한다는 부분만 제외하고 TCP RST Flag를 받는 [Figure 24]과 동일한 과정을 수행한다는 것을 알 수 있다.
| |
| |
[Text 48]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 49]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. 두 Access Log에서 모두 /mock.MockService/CloseAfterResponse 함수에 접근하는 내역과 response_code가 200, grpc_status가 Unknown로 나타나는 것을 확인할 수 있다. TCP RST Flag를 받는 [Figure 24]과 동일한 과정을 수행한다는 것을 알 수 있다.
1.3.10. Circuit Breaking with Upstream Connection Pool Overflow Case
![[Figure 27] Circuit Breaking with Upstream Connection Pool Overflow Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-circuit-breaking-with-upstream-connection-pool-overflow-case.png)
[Figure 27] Circuit Breaking with Upstream Connection Pool Overflow Case
| |
[Figure 27]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Delay 함수에 milliseconds: 5000 요청을 3번 연속으로 전달하여 Upstream Connection Pool Overflow를 발생시키는 Case를 나타내고 있다. [Shell 28]은 [Figure 27]의 내용을 실행하는 예시를 나타내고 있다. GRPC로 요청과 응답이 온다는 부분을 제외하고는 [Figure 12]에서 설명한 것과 동일한 과정을 수행한다.
| |
| |
[Text 50]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 51]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고 [Text 22], [Text 23]과 동일한 과정을 수행한다는 것을 알 수 있다.
1.3.11. Circuit Breaking with Upstream Request Limit Overflow Case
![[Figure 28] Circuit Breaking with Upstream Request Limit Overflow Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-circuit-breaking-with-upstream-request-limit-overflow-case.png)
[Figure 28] Circuit Breaking with Upstream Request Limit Overflow Case
| |
[Figure 28]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Delay 함수에 milliseconds: 5000 요청을 3번 연속으로 전달하여 Upstream Request Limit Overflow를 발생시키는 Case를 나타내고 있다. 이 Case를 재현하기 위해서는 [File 2]에서 설정한 Destination Rule을 적용해야한다. [Shell 29]은 [Figure 28]의 내용을 실행하는 예시를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고는 [Figure 13]에서 설명한 것과 동일한 과정을 수행한다.
| |
| |
[Text 52]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 53]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고 [Text 24], [Text 25]과 동일한 과정을 수행한다는 것을 알 수 있다.
1.3.12. Circuit Breaking with No Healthy Upstream Case
![[Figure 29] Circuit Breaking with No Healthy Upstream Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-circuit-breaking-with-no-healthy-upstream-case.png)
[Figure 29] Circuit Breaking with No Healthy Upstream Case
| |
[Figure 29]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Status 함수에 code: 13 요청을 8번 연속으로 전달하여 No Healthy Upstream을 통한 Circuit Breaking을 발생시키는 Case를 나타내고 있다. [Shell 30]은 [Figure 29]의 내용을 실행하는 예시를 나타내고 있다.
[File 1]의 Destination Rule에 의해서 5번의 연속적인 5XX Error가 발생하면 Circuit Breaking이 동작한다. 따라서 shell Pod의 첫 5번의 요청은 모두 mock-server Pod에게 전달되지만, 이후에 3번의 요청은 Circuit Breaking으로 인해서 mock-server Pod에 전달되지 않는다. 따라서 첫번째 5번의 요청에 대한 응답은 Internal로 나타나고, 이후에 3번의 요청에 대한 응답은 Unavailable로 나타난다.
| |
| |
[Text 54]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 55]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 istio-proxy의 Access Log에는 마지막 3개의 요청에만 response_flags가 UH (NoHealthyUpstream)와 함께 요청이 mock-server Pod에 전달되지 않은 것을 확인할 수 있다. 또한 mock-server Pod의 istio-proxy의 Access Log에는 처음 5개의 요청에 대한 Log만 남아있는것도 확인할 수 있다.
1.3.13. Upstream Connection Failure with Timeout Case
![[Figure 30] Upstream Connection Failure with Timeout Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-connection-failure-case-with-timeout.png)
[Figure 30] Upstream Connection Failure with Timeout Case
| |
[Figure 30]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Status 함수에 code: 0 요청을 3번 연속으로 전달하여 Timeout에 의해서 Retry되는 Upstream Connection Failure with Timeout Case를 나타내고 있다. [Shell 31]은 [Figure 30]의 내용을 실행하는 예시를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고는 [Figure 15]에서 설명한 것과 동일한 과정을 수행한다.
| |
[Text 56]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고는 [Text 28]와 동일한 과정을 수행한다.
1.3.14. Upstream Connection Failure with TCP Reset Case
![[Figure 31] Upstream Connection Failure with TCP Reset Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-connection-failure-case-with-tcp-reset.png)
[Figure 31] Upstream Connection Failure with TCP Reset Case
| |
[Figure 31]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Status 함수에 code: 0 요청을 3번 연속으로 전달하여 TCP Reset에 의해서 Retry되는 Upstream Connection Failure with TCP Reset Case를 나타내고 있다. [Shell 32]은 [Figure 31]의 내용을 실행하는 예시를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고는 [Figure 16]에서 설명한 것과 동일한 과정을 수행한다.
| |
[Text 57]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있다. GRPC로 요청과 응답이 발생한다는 부분을 제외하고는 [Text 29]와 동일한 과정을 수행한다.
1.3.15. Upstream Request Timeout Case
![[Figure 32] Upstream Request Timeout Case](/blog-software/docs/theory-analysis/istio-sidecar-proxy-access-log/images/grpc-upstream-request-timeout-case.png)
[Figure 32] Upstream Request Timeout Case
| |
[Figure 32]는 shell Pod에서 grpcurl 명령어를 이용하여 mock-server의 /mock.MockService/Delay 함수에 milliseconds: 70000 요청을 전달하였지만 mock-server Pod의 istio-proxy에서 60000ms 대기후에 응답이 오지 않아 Request를 Timeout 처리하는 Upstream Request Timeout Case를 나타내고 있다.
[File 1]의 Virtual Service에 의해서 mock-server Pod로 전송된 요청은 최대 60000ms 대기할 수 있다. 하지만 mock-server Pod의 /mock.MockService/Delay 함수에 milliseconds: 70000과 함께 전달할 요청은 70000ms가 필요하기 때문에 Timeout이 발생한다. mock-server Pod의 istio-proxy는 Timeout 발생시 HTTP/2 RST_STREAM Frame을 전송하여, mock-server Pod와의 연결을 종료한다. 또한 Unavailable 상태 코드를 반환하여 요청이 비정상적으로 종료된것을 shell Pod의 istio-proxy에게 알린다.
| |
| |
[Text 58]는 shell Pod의 istio-proxy의 Access Log를 나타내고 있으며, [Text 59]는 mock-server Pod의 istio-proxy의 Access Log를 나타내고 있다. shell Pod의 istio-proxy에는 response_flags에 UT (UpstreamTimeout)를 확인할 수 있다. mock-server Pod의 istio-proxy에는 response_flags에 DR (DownstreamRemoteReset)를 확인할 수 있다.