================================================================================ T93 — DR connectionPool 필드별 "발동" 재현 랩: 번들 킷 전체 생애주기 라이브 실측 실측일 2026-07-05 · cluster homelab (k8s 1.30.6, Calico) · Istio 1.30.0 (client/CP/DP 일치) kubectl context = homelab (setup/run-scenario/cleanup 모두 현재 컨텍스트 자동 감지) 번들 킷: content/docs/istio/egress/dr-connection-settings/files/lab/ 본 실측은 "독자가 files/lab/ 만 받아 s1~s7 발동을 처음부터 재현 가능한가"를 검증한다(=T93 본질). 관측 지점: client istio-proxy 의 outbound cluster stats(누적 카운터 → 판정은 run 내 델타로 격리). ================================================================================ [0] 기존 잔재 철거 — 번들 cleanup.sh (직전 디버깅 잔재가 conn-lab 에 살아있는 상태에서 시작) -------------------------------------------------------------------------------- $ bash files/lab/cleanup.sh → DR/SE 삭제 → ns 삭제 → NotFound (mid-lab 멱등성 확인) [1] 번들 setup.sh — fresh build (context 자동 감지) -------------------------------------------------------------------------------- namespace/conn-lab created · deployment backend/client created · serviceentry blackhole created backend / client 둘 다 2/2 Running (sidecar 주입). cluster domain 자동 발견 = homelab.local. client-574475c99d-htkfj (k8s-worker1) backend-75564b7d74-mfljn (k8s-worker1) 핵심 계측 스위치: client proxyStatsMatcher inclusionRegexps(.*backend.* / .*blackhole.* / .*circuit_breakers.*)로 기본 억제되는 cluster cx/rq·circuit_breakers 게이지를 노출. + DNS capture+auto-allocate(S6 필수). ================================================================================ 시나리오별 실측 델타 (stat 이름 = 실제 노출명; 값은 이 run 내 before→after 델타) ================================================================================ [S1] tcp.maxConnections:1 부하 fortio -c 4 -qps 0 -n 40 (?delay=200ms) -------------------------------------------------------------------------------- mid-load 게이지: circuit_breakers.default.cx_open = 1 (한도 도달 중) 델타: upstream_cx_overflow 0 -> 41 = +41 ★ 커넥션 서킷브레이커 발동 upstream_cx_total 0 -> 2 = +2 (실제 수립 커넥션은 최소치) upstream_rq_total 0 -> 40 = +40 fortio: Sockets 4 · Code 200: 40 (100%) ← 거부 아님, 초과분은 pending 으로 흡수(default pending 무제한) 판정: PASS. maxConnections=1 이 max_connections CB 로 반영, 초과 커넥션 시도가 overflow. [S2] tcp.maxConnections:1 + http.http1MaxPendingRequests:1 부하 -c 3 -qps 0 -n 30 (?delay=200ms) -------------------------------------------------------------------------------- mid-load 게이지: circuit_breakers.default.rq_pending_open = 1 델타: upstream_rq_pending_overflow 0 -> 12 = +12 ★ pending 서킷브레이커 발동(UO) upstream_cx_overflow 41 -> 57 = +16 (maxConnections=1 도 여전히 발동) upstream_rq_total 40 -> 58 = +18 fortio: Sockets 14 · Code 200: 18 (60%) · Code 503: 12 (40%) ← 503 개수(12) = rq_pending_overflow 델타(12) 정확히 일치 = 즉시 거부. 판정: PASS. 공식 circuit-breaking task 패턴. pending 한도 초과 요청이 503/UO 로 즉시 거부. [S3] http.maxRequestsPerConnection:1 부하 -c 1 -qps 0 -n 20 -keepalive -------------------------------------------------------------------------------- 델타: upstream_cx_max_requests 0 -> 20 = +20 ★ 커넥션 turnover(한도로 닫힌 커넥션 수) upstream_cx_total 3 -> 23 = +20 (요청 수만큼 신규 커넥션) upstream_rq_total 58 -> 78 = +20 fortio: Sockets used 1 · Code 200: 20 (100%) ← ★ 함정: fortio(다운스트림)는 커넥션 1개 재사용. turnover 는 UPSTREAM(sidecar→backend) 에서만 일어나 app 에는 안 보임. cx_total 로만 관측됨. 판정: PASS. 거부 아닌 커넥션 재활용 차단. cx_max_requests ≈ 요청 수, cx_total 동반 증가. [S4] http.idleTimeout:2s 요청 1회(keepalive) → 5s idle 대기 -------------------------------------------------------------------------------- 델타: upstream_cx_idle_timeout 0 -> 1 = +1 ★ idle 2s 초과로 풀 커넥션 종료 upstream_cx_total 23 -> 24 = +1 판정: PASS. 활성 요청 없는 풀 커넥션이 idleTimeout(2s) 후 종료. [S5] tcp.maxConnectionDuration:5s keepalive 10s 부하 -------------------------------------------------------------------------------- 델타: upstream_cx_max_duration_reached 0 -> 2 = +2 ★ 5s 수명 도달 → graceful close·재수립 upstream_cx_total 24 -> 26 = +2 fortio: Sockets 1 · Code 200: 100 (100%) ← graceful, 요청 무손실 판정: PASS. 10s 창에서 5s 수명 커넥션이 2회 교체(진행 요청 완료 후 닫힘). 주: 이름은 tcp.* 지만 HTTP 클러스터라 HttpProtocolOptions.max_connection_duration 경로로 반영(S7 확인). [S6] tcp.connectTimeout:1s (blackhole.lab.internal → 198.51.100.10) fortio -c 1 -n 5 -timeout 5s -------------------------------------------------------------------------------- 델타(blackhole 클러스터): upstream_cx_connect_timeout 0 -> 15 = +15 ★ connect 타임아웃 발동 upstream_cx_connect_fail 0 -> 15 = +15 upstream_cx_total 0 -> 15 = +15 fortio: Code 503: 5 (100%) · avg 3033ms client istio-proxy 액세스 로그(response flag): "GET / HTTP/1.1" 503 URX,UF upstream_reset_before_response_started{connection_timeout} ... "blackhole.lab.internal" "198.51.100.10:80" outbound|80||blackhole.lab.internal - 240.240.0.12:80 ... ← auto-VIP 240.240.0.12 → STATIC endpoint 198.51.100.10 판정: PASS. connectTimeout=1s 만료 → 503, response flag UF(+URX), 상세 {connection_timeout}. ★ 신규 발견(연구 인벤토리에 없던 상호작용): 요청 5개인데 cx_connect_timeout 이 15(=5×3). Istio 기본 mesh 재시도 정책(retryOn 기본 2회)이 connect 실패마다 재시도해 요청당 connect 시도 3회 → 3s 지연 → 최종 URX(retry limit exceeded). connectTimeout 단독이 아니라 "기본 retry 정책 × connectTimeout" 이 실제 지연을 만든다. [S7] config 반영 검증 (발동 아님 · istioctl pc cluster --fqdn backend... -o json + jq) -------------------------------------------------------------------------------- S7-full (tcpKeepalive + maxRetries:2 + h2UpgradePolicy:UPGRADE + maxConcurrentStreams:64): ① upstream_connection_options.tcp_keepalive: {"keepaliveProbes":3,"keepaliveTime":300,"keepaliveInterval":30} ✓ 3필드 모두 반영 ② circuit_breakers.thresholds: [{"maxConnections":4294967295,"maxPendingRequests":4294967295, "maxRequests":4294967295,"maxRetries":2}] ✓ maxRetries=2 반영 ③④ explicit_http_config.http2_protocol_options: {"maxConcurrentStreams":64} ✓ 64 반영 S7c (h2UpgradePolicy:UPGRADE 만 — maxConcurrentStreams 미설정): http2_protocol_options = {} ← Istio 가 아무 값도 안 씀 circuit_breakers.thresholds = [{"maxConnections":4294967295,"maxPendingRequests":4294967295, "maxRequests":4294967295,"maxRetries":4294967295}] S7b (useClientProtocol:true): use_downstream_protocol_config = {"httpProtocolOptions":{},"http2ProtocolOptions":{}} ← 존재 explicit_http_config = ABSENT ← h2UpgradePolicy 무력화 확인 판정: PASS. 4개 필드 반영 위치·값 config_dump 로 확인. ================================================================================ 연구 인벤토리(§5) 미결점 3건 — 실측 판정 ================================================================================ §5-1 maxConcurrentStreams 기본값 (문서 2^31-1 vs Envoy proto 1024): → 판정: Istio 는 "미설정 시 아무 값도 주입하지 않는다"(http2_protocol_options={}). 따라서 실효 기본값은 Envoy proto 기본(1024)이 적용되며, config_dump 에는 2^31-1 도 1024 도 "명시되지 않는다". istio.io 문서의 "2^31-1"은 config 에 나타나는 값이 아님. 설정 시(64)만 명시됨. §5-2 circuit breaker 생략 필드 주입값 (istio "2^32-1" vs Envoy native): → 판정: 확정. connectionPool 을 걸고 CB 필드를 생략하면 Istio 가 thresholds 에 4294967295(=2^32-1)를 명시 주입한다(S7-full: maxConnections/maxPendingRequests/maxRequests = 4294967295, S7c: maxRetries 까지 4종 전부 4294967295). 즉 "DR 을 걸면" 사실상 무제한을 명시 주입 → Envoy native 기본(1024/1024/1024/3)은 "DR 을 아예 안 걸 때"만 유효. §5-3 http2MaxRequests overflow stat (upstream_rq_active_overflow 존재 여부): → 부분 판정 + 연구 정정: upstream_rq_active_overflow 는 "존재하지 않는다"던 연구 가정과 달리 실측상 **존재**한다(blackhole·xds-grpc 클러스터에서 값 0 으로 노출 관측). 단 http2MaxRequests "발동" 자체는 S1~S7 범위 밖(H2 업스트림 오버플로 시나리오 미수행)이라 그 발동이 active_overflow 로 집계되는지 pending_overflow 로 집계되는지는 미검증. S2 에서 http1MaxPendingRequests 발동은 upstream_rq_pending_overflow 로 집계됨을 확인. ================================================================================ [8] 번들 cleanup.sh — 철거 + NotFound 재확인 -------------------------------------------------------------------------------- DR/SE 삭제 → namespace 삭제 → kubectl get ns conn-lab = NotFound. 멱등(이미 없어도 에러 없음). ================================================================================ 종합: 번들 킷(files/lab/) 만으로 cleanup→setup→s1~s7→cleanup 전체 생애주기 라이브 재현 완료. S1~S6 발동 6종 전부 예상 stat 으로 관측, S7 config 4종 + §5 미결점 2건(§5-1/§5-2) 실측 확정, §5-3 는 연구 가정 1건 정정(active_overflow 는 존재) + 발동 미검증으로 정직 기록. 발동 요약표 (run 내 델타 / stat = 실제 노출명): 시나리오 필드 발동 stat(델타) 부가 관측 S1 tcp.maxConnections:1 upstream_cx_overflow +41 gauge cx_open=1, 200 100% S2 +http1MaxPendingRequests:1 upstream_rq_pending_overflow +12 503 12건(=델타), rq_pending_open=1 S3 maxRequestsPerConnection:1 upstream_cx_max_requests +20 cx_total +20(turnover) S4 http.idleTimeout:2s upstream_cx_idle_timeout +1 — S5 tcp.maxConnectionDuration:5s upstream_cx_max_duration_reached +2 200 100%(graceful) S6 tcp.connectTimeout:1s upstream_cx_connect_timeout +15 503/UF, +기본retry(URX) S7 (config) — (istioctl pc cluster) §5-1/§5-2 확정 밟은 함정(재현 시 주의): 1. filter=backend 는 타 ns 의 backend.service-a 클러스터도 매칭 → filter=backend.conn-lab 로 스코프. 2. stat 이름에 세미콜론 구분자 존재: cluster.;.: value (파싱 시 '.: ' 로 추출). 3. S6: fortio 가 커넥트 전 DNS 조회 → STATIC SE host 는 NXDOMAIN 으로 abort. sidecar DNS capture+auto-allocate 필수. endpoint 는 route 있는 무응답 대역(198.51.100.10)이라야 timeout(240/4는 즉시 unreachable). 4. cx/rq 카운터는 프록시 기동 이래 누적 → 반드시 run 내 델타로 판정. 파드 재시작 시 미사용 카운터는 lazy 하게 사라졌다 재등장(overflow stat 이 트래픽 전엔 안 보일 수 있음). ================================================================================