From dba0c3975c42cac46b86a3b6f2f1641b9bfbd021 Mon Sep 17 00:00:00 2001 From: DongHyeonka Date: Fri, 4 Sep 2026 13:18:10 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20A-6=20=E2=80=94=20200ms=20of=20network?= =?UTF-8?q?=20delay=20becomes=2022=20seconds=20of=20user=20latency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nine database round trips per login multiply the injected delay to 1.9 seconds, and connection pool queueing multiplies it again under twenty concurrent requests. The readiness probe joins the same queue and times out, so the node leaves the load balancer and pushes its load onto the one still standing. Two injections missed first: the guest interface is enp1s0 rather than eth0, and a filter on it can never match a pod IP because flannel has already encapsulated the packet. The delay has to go on flannel.1, before encapsulation. The predicted rise in optimistic lock conflicts did not happen, because logins insert new rows rather than contending for one. That belongs to B-3. Co-Authored-By: Claude Opus 5 --- .../console-2026-09-04T03-43-55-141Z.log | 26 ++ .../console-2026-09-04T04-16-32-330Z.log | 12 + .../page-2026-09-04T04-16-33-535Z.yml | 145 ++++++++ .../a6-latency-injection/01-baseline.txt | 22 ++ .../02-delay-injected.txt | 25 ++ .../03-flannel-injection.txt | 20 ++ .../04-pool-under-load.txt | 37 ++ .../a6-latency-injection/05-recovery.txt | 12 + docs/evidence/a6-latency-injection/README.md | 20 ++ .../a6-connection-pool-blocking.png | Bin 0 -> 70811 bytes docs/experiment-a6-latency-injection.md | 338 ++++++++++++++++++ 11 files changed, 657 insertions(+) create mode 100644 .playwright-mcp/console-2026-09-04T04-16-32-330Z.log create mode 100644 .playwright-mcp/page-2026-09-04T04-16-33-535Z.yml create mode 100644 docs/evidence/a6-latency-injection/01-baseline.txt create mode 100644 docs/evidence/a6-latency-injection/02-delay-injected.txt create mode 100644 docs/evidence/a6-latency-injection/03-flannel-injection.txt create mode 100644 docs/evidence/a6-latency-injection/04-pool-under-load.txt create mode 100644 docs/evidence/a6-latency-injection/05-recovery.txt create mode 100644 docs/evidence/a6-latency-injection/README.md create mode 100644 docs/evidence/a6-latency-injection/a6-connection-pool-blocking.png create mode 100644 docs/experiment-a6-latency-injection.md diff --git a/.playwright-mcp/console-2026-09-04T03-43-55-141Z.log b/.playwright-mcp/console-2026-09-04T03-43-55-141Z.log index 8b28483..16c4739 100644 --- a/.playwright-mcp/console-2026-09-04T03-43-55-141Z.log +++ b/.playwright-mcp/console-2026-09-04T03-43-55-141Z.log @@ -22,3 +22,29 @@ [ 1661576ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 [ 1665269ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 [ 1682669ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1689435ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1704385ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1706314ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1724551ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1743701ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1758339ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1769299ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1789478ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1795415ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1815382ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1820392ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1822445ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1839035ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1840162ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1847739ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1861419ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1880381ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1893315ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1911434ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1922701ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1933868ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: HTTP Authentication failed; no valid credentials available @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1944951ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1948001ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1952503ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1953320ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1955369ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 diff --git a/.playwright-mcp/console-2026-09-04T04-16-32-330Z.log b/.playwright-mcp/console-2026-09-04T04-16-32-330Z.log new file mode 100644 index 0000000..765c675 --- /dev/null +++ b/.playwright-mcp/console-2026-09-04T04-16-32-330Z.log @@ -0,0 +1,12 @@ +[ 585ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 1132ms] [WARNING] is deprecated. Please include @ https://app2.hyeonworks.com/explore?schemaVersion=1&panes=%7B%22o68%22%3A%7B%22datasource%22%3A%22PBFA97CFB590B2093%22%2C%22queries%22%3A%5B%7B%22refId%22%3A%22A%22%2C%22expr%22%3A%22agroal_blocking_time_max_milliseconds%22%2C%22range%22%3Atrue%2C%22instant%22%3Afalse%2C%22editorMode%22%3A%22code%22%2C%22legendFormat%22%3A%22blocking+max+-+%7B%7Bpod%7D%7D%22%2C%22datasource%22%3A%7B%22type%22%3A%22prometheus%22%2C%22uid%22%3A%22PBFA97CFB590B2093%22%7D%7D%5D%2C%22range%22%3A%7B%22from%22%3A%22now-30m%22%2C%22to%22%3A%22now%22%7D%7D%7D&orgId=1:0 +[ 1555ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 3604ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 6373ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 9135ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 19066ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 24595ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 47125ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 52154ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 67608ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 +[ 86965ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362 diff --git a/.playwright-mcp/page-2026-09-04T04-16-33-535Z.yml b/.playwright-mcp/page-2026-09-04T04-16-33-535Z.yml new file mode 100644 index 0000000..878985e --- /dev/null +++ b/.playwright-mcp/page-2026-09-04T04-16-33-535Z.yml @@ -0,0 +1,145 @@ +- generic [active] [ref=f15e1]: + - generic [ref=f15e4]: + - link "Skip to main content" [ref=f15e5] [cursor=pointer]: + - /url: "#pageContent" + - banner [ref=f15e7]: + - generic [ref=f15e8]: + - link [ref=f15e10] [cursor=pointer]: + - /url: / + - img "Grafana" [ref=f15e11] + - generic [ref=f15e14]: + - button "Search or jump to..." [ref=f15e18] [cursor=pointer] + - generic [ref=f15e19]: ctrl+k + - generic [ref=f15e23]: + - button "New" [ref=f15e24] [cursor=pointer] + - button "Help" [ref=f15e30] [cursor=pointer] + - button "News" [ref=f15e33] [cursor=pointer] + - button "Profile" [ref=f15e36] [cursor=pointer]: + - img "User avatar" [ref=f15e37] + - generic [ref=f15e38]: + - button "Open menu" [ref=f15e40] [cursor=pointer] + - navigation "Breadcrumbs" [ref=f15e43]: + - list [ref=f15e44]: + - listitem [ref=f15e45]: + - link "Home" [ref=f15e46] [cursor=pointer]: + - /url: / + - listitem [ref=f15e50]: + - link "Explore" [ref=f15e51] [cursor=pointer]: + - /url: /explore + - listitem [ref=f15e55]: + - generic "Prometheus" [ref=f15e56] + - generic [ref=f15e57]: + - generic [ref=f15e60]: + - button "Copy shortened URL" [ref=f15e61] [cursor=pointer] + - button "Open copy link options" [ref=f15e64] [cursor=pointer] + - button "Toggle top search bar" [ref=f15e68] [cursor=pointer] + - main [ref=f15e74]: + - generic [ref=f15e76]: + - heading "Explore" [level=1] [ref=f15e77] + - generic [ref=f15e82]: + - navigation "Explore toolbar" [ref=f15e84]: + - navigation "Search links" [ref=f15e86]: + - generic [ref=f15e87]: + - button "Content outline" [expanded] [ref=f15e89] [cursor=pointer]: + - generic [ref=f15e92]: Outline + - generic [ref=f15e97] [cursor=pointer]: + - img "Prometheus logo" [ref=f15e99] + - textbox "Select a data source" [ref=f15e100]: + - /placeholder: "" + - generic [ref=f15e104]: + - button "Split the pane" [ref=f15e106] [cursor=pointer]: + - generic [ref=f15e109]: Split + - button "Add" [ref=f15e111] [cursor=pointer] + - generic [ref=f15e116]: + - 'button "Time range selected: Last 30 minutes" [ref=f15e117] [cursor=pointer]' + - button "Zoom out time range" [ref=f15e122] [cursor=pointer] + - generic [ref=f15e126]: + - button "Run query" [ref=f15e127] [cursor=pointer] + - button "Auto refresh turned off. Choose refresh time interval" [ref=f15e131] [cursor=pointer] + - generic [ref=f15e135]: + - generic [ref=f15e139]: + - button "Collapse outline" [expanded] [ref=f15e141] [cursor=pointer]: + - img "arrow-from-right" [ref=f15e142] + - button "Queries" [ref=f15e145] [cursor=pointer]: + - img "arrow" [ref=f15e146] + - button "Graph" [ref=f15e150] [cursor=pointer]: + - img "graph-bar" [ref=f15e151] + - generic [ref=f15e158]: + - generic [ref=f15e160]: + - generic "Query editor row" [ref=f15e163]: + - generic [ref=f15e164]: + - generic [ref=f15e166]: + - generic [ref=f15e167]: + - button "Collapse query row" [expanded] [ref=f15e168] [cursor=pointer] + - generic [ref=f15e171]: + - button "Query editor row title A" [ref=f15e172] [cursor=pointer]: + - generic [ref=f15e173]: A + - emphasis [ref=f15e174]: (Prometheus) + - generic [ref=f15e175]: + - button "Show data source help" [ref=f15e177] [cursor=pointer] + - button "Duplicate query" [ref=f15e181] [cursor=pointer] + - button "Hide response" [ref=f15e185] [cursor=pointer] + - button "Remove query" [ref=f15e189] [cursor=pointer] + - button "Drag and drop to reorder" [ref=f15e192]: + - img "Drag and drop to reorder" [ref=f15e193] + - generic [ref=f15e196]: + - generic [ref=f15e197]: + - button "Kick start your query" [ref=f15e198] [cursor=pointer] + - generic [ref=f15e201]: + - generic [ref=f15e202] [cursor=pointer]: Explain + - generic [ref=f15e203]: + - checkbox "Explain Toggle switch" [ref=f15e204] + - generic "Toggle switch" [ref=f15e205] [cursor=pointer] + - radiogroup [ref=f15e210]: + - generic [ref=f15e211]: + - radio "Builder" [ref=f15e212] [cursor=pointer] + - generic [ref=f15e213] [cursor=pointer]: Builder + - generic [ref=f15e214]: + - radio "Code" [checked] [ref=f15e215] [cursor=pointer] + - generic [ref=f15e216] [cursor=pointer]: Code + - generic [ref=f15e218]: + - generic [ref=f15e220]: + - button "Loading metrics..." [disabled] [ref=f15e221] [cursor=pointer] + - code [ref=f15e228]: + - generic [ref=f15e229]: + - generic [ref=f15e234]: agroal_blocking_time_max_milliseconds + - textbox "Editor content;Press Alt+F1 for Accessibility Options." [ref=f15e239]: agroal_blocking_time_max_milliseconds + - 'button "Options Legend: blocking max - {{pod}} Format: Time series Step: auto Type: Range Exemplars: false" [ref=f15e245] [cursor=pointer]': + - generic [ref=f15e249]: + - heading "Options" [level=6] [ref=f15e250] + - generic [ref=f15e251]: + - generic [ref=f15e252]: "Legend: blocking max - {{pod}}" + - generic [ref=f15e253]: "Format: Time series" + - generic [ref=f15e254]: "Step: auto" + - generic [ref=f15e255]: "Type: Range" + - generic [ref=f15e256]: "Exemplars: false" + - generic [ref=f15e257]: + - button "Add query" [ref=f15e258] [cursor=pointer] + - button "Query history" [ref=f15e262] [cursor=pointer] + - button "Query inspector" [ref=f15e266] [cursor=pointer] + - main [ref=f15e270]: + - region [ref=f15e272]: + - generic [ref=f15e273]: + - heading "Graph" [level=2] [ref=f15e275] + - radiogroup [ref=f15e278]: + - generic [ref=f15e279]: + - radio "Lines" [checked] [ref=f15e280] [cursor=pointer] + - generic [ref=f15e281] [cursor=pointer]: Lines + - generic [ref=f15e282]: + - radio "Bars" [ref=f15e283] [cursor=pointer] + - generic [ref=f15e284] [cursor=pointer]: Bars + - generic [ref=f15e285]: + - radio "Points" [ref=f15e286] [cursor=pointer] + - generic [ref=f15e287] [cursor=pointer]: Points + - generic [ref=f15e288]: + - radio "Stacked lines" [ref=f15e289] [cursor=pointer] + - generic [ref=f15e290] [cursor=pointer]: Stacked lines + - generic [ref=f15e291]: + - radio "Stacked bars" [ref=f15e292] [cursor=pointer] + - generic [ref=f15e293] [cursor=pointer]: Stacked bars + - generic [ref=f15e294]: Loading plugin panel... + - generic [ref=f15e299]: + - alert + - alert + - complementary + - complementary \ No newline at end of file diff --git a/docs/evidence/a6-latency-injection/01-baseline.txt b/docs/evidence/a6-latency-injection/01-baseline.txt new file mode 100644 index 0000000..1b7c242 --- /dev/null +++ b/docs/evidence/a6-latency-injection/01-baseline.txt @@ -0,0 +1,22 @@ +=== 배치 — 왜 A/B 가 되는가 === + postgres 10.42.1.76 (kc-lab-2) + keycloak-0 10.42.1.77 (kc-lab-2) → DB 와 같은 노드, cni0 로 직행 + keycloak-1 10.42.0.42 (kc-lab-1) → DB 와 다른 노드, VXLAN 을 건넌다 ← 여기에 지연을 건다 + +=== 사용 가능한 커넥션 풀 지표 === +agroal_acquire_count_total +agroal_active_count +agroal_available_count +agroal_awaiting_count +agroal_blocking_time_average_milliseconds +agroal_blocking_time_max_milliseconds +agroal_blocking_time_total_milliseconds +agroal_creation_count_total +agroal_creation_time_average_milliseconds +agroal_creation_time_max_milliseconds +agroal_creation_time_total_milliseconds +agroal_destroy_count_total + +=== 기준선 지연 — 각 노드에서 로그인 20회 === + keycloak-0 평균 70 ms + keycloak-1 평균 66 ms diff --git a/docs/evidence/a6-latency-injection/02-delay-injected.txt b/docs/evidence/a6-latency-injection/02-delay-injected.txt new file mode 100644 index 0000000..388e3b3 --- /dev/null +++ b/docs/evidence/a6-latency-injection/02-delay-injected.txt @@ -0,0 +1,25 @@ +=== 주입: postgres(10.42.1.76) 가 보내는 패킷만 200ms 지연 (kc-lab-2 eth0) === + prio qdisc 로 밴드를 나누고, u32 필터로 출발지 IP 가 postgres 인 것만 3번 밴드로 보낸다 +Cannot find device "eth0" +Cannot find device "eth0" +적용완료 +Cannot find device "eth0" +Cannot find device "eth0" + 주입: 13:14:55 + +=== [검증] 지연이 실제로 걸렸는가 — 두 노드 비교 === + keycloak-0 평균 43 ms 최대 64 ms + keycloak-1 평균 47 ms 최대 70 ms + +=== 커넥션 풀 상태 === +--- keycloak-0 --- + agroal_blocking_time_max_milliseconds 102.0 + agroal_active_count 0.0 + agroal_awaiting_count 0.0 + agroal_blocking_time_average_milliseconds 0.0 + agroal_available_count 2.0 + agroal_blocking_time_max_milliseconds 164.0 + agroal_active_count 0.0 + agroal_awaiting_count 0.0 + agroal_blocking_time_average_milliseconds 0.0 + agroal_available_count 2.0 diff --git a/docs/evidence/a6-latency-injection/03-flannel-injection.txt b/docs/evidence/a6-latency-injection/03-flannel-injection.txt new file mode 100644 index 0000000..cd47170 --- /dev/null +++ b/docs/evidence/a6-latency-injection/03-flannel-injection.txt @@ -0,0 +1,20 @@ +=== 오버레이 인터페이스 확인 === +flannel.1 UNKNOWN a6:b2:62:04:c1:a4 +cni0 UP 5a:77:1a:e2:b0:a4 + +=== flannel.1 에 주입 — 여기서는 파드 IP 가 보인다 (캡슐화 전) === +qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 +qdisc netem 30: parent 1:3 limit 1000 delay 200ms + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + +=== [검증] 필터에 패킷이 걸리는가 === + qdisc netem 30: parent 1:3 limit 1000 delay 200ms + Sent 18388 bytes 150 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + +=== 두 노드 지연 비교 (기준선: k0=70ms k1=66ms) === + keycloak-0 평균 41 ms 최대 57 ms + keycloak-1 평균 1872 ms 최대 1887 ms diff --git a/docs/evidence/a6-latency-injection/04-pool-under-load.txt b/docs/evidence/a6-latency-injection/04-pool-under-load.txt new file mode 100644 index 0000000..e04a1ba --- /dev/null +++ b/docs/evidence/a6-latency-injection/04-pool-under-load.txt @@ -0,0 +1,37 @@ +=== 동시 부하 20건을 keycloak-1 에 — 커넥션 풀이 견디는가 === + 1 200 1.911191 + 1 200 1.913766 + 1 200 1.958374 + 1 200 1.981620 + 1 200 10.539402 + 1 200 11.951943 + 1 200 13.351102 + 1 200 14.785832 + 1 200 16.189533 + 1 200 17.625166 + 1 200 19.053724 + 1 200 20.495883 + 1 200 21.905932 + 1 200 22.228466 + 1 200 22.230871 + 1 200 3.441366 + 1 200 4.841075 + 1 200 6.257489 + 1 200 7.704608 + 1 200 9.104792 + +=== 부하 직후 커넥션 풀 === + agroal_blocking_time_max_milliseconds 20000.0 + agroal_max_used_count 19.0 + agroal_acquire_count_total 672.0 + agroal_active_count 0.0 + agroal_awaiting_count 0.0 + agroal_blocking_time_average_milliseconds 281.0 + agroal_available_count 19.0 + +=== readiness 가 흔들렸는가 === +keycloak-0 1/1 Running 0 60m +keycloak-1 1/1 Running 1 (51m ago) 3h24m +52m Normal TaintManagerEviction pod/keycloak-1 Cancelling deletion of Pod keycloak-lab/keycloak-1 +32m Warning Unhealthy pod/keycloak-1 Readiness probe failed: HTTP probe failed with statuscode: 503 +89s Warning Unhealthy pod/keycloak-1 Readiness probe failed: Get "http://10.42.0.42:9000/health/ready": context deadline exceeded (Client.Timeout exceeded while awaiting headers) diff --git a/docs/evidence/a6-latency-injection/05-recovery.txt b/docs/evidence/a6-latency-injection/05-recovery.txt new file mode 100644 index 0000000..b8ad9a9 --- /dev/null +++ b/docs/evidence/a6-latency-injection/05-recovery.txt @@ -0,0 +1,12 @@ +=== 지연 해제 === +해제완료 +qdisc noqueue 0: root refcnt 2 + +=== 회복 확인 === + keycloak-0 평균 43 ms + keycloak-1 평균 51 ms +keycloak-0 1/1 Running 0 61m +keycloak-1 1/1 Running 1 (52m ago) 3h24m + +=== 낙관적 락 충돌이 늘었는가 — 지연 중 로그 === + 관련 로그 줄수: 0 diff --git a/docs/evidence/a6-latency-injection/README.md b/docs/evidence/a6-latency-injection/README.md new file mode 100644 index 0000000..9d7d8f5 --- /dev/null +++ b/docs/evidence/a6-latency-injection/README.md @@ -0,0 +1,20 @@ +# A-6 — 지연 주입 증거 + +2026-09-04 13:10–13:35 KST +해설: [`docs/experiment-a6-latency-injection.md`](../../experiment-a6-latency-injection.md) + +| 파일 | 무엇을 보여주는가 | +|---|---| +| `01-baseline.txt` | 배치 설명(A/B 가 되는 이유), `agroal_*` 지표 목록, **기준선 70ms / 66ms** | +| `02-delay-injected.txt` | 첫 시도 실패 — **`Cannot find device "eth0"`** (Debian 은 `enp1s0`) | +| `03-flannel-injection.txt` | **성공** — `flannel.1` 에 걸어야 파드 IP 가 보인다. netem `Sent 150 pkt` 로 검증. **k0=41ms vs k1=1872ms** | +| `04-pool-under-load.txt` | 동시 20건 — 응답이 1.9초에서 **22.2초**까지 계단. `blocking_time_max=20000ms`, `max_used_count=19`, **readiness 프로브 타임아웃** | +| `05-recovery.txt` | 해제 즉시 43ms / 51ms 회복. **낙관적 락 충돌 0건**(예측 빗나감) | +| `a6-connection-pool-blocking.png` | Grafana — `agroal_blocking_time_max_milliseconds` | + +## 핵심 네 줄 + +1. **200ms 가 1,872ms 가 된다.** 로그인 트랜잭션의 왕복이 9번이라 지연이 곱해진다. +2. **동시 부하에서 22초까지 늘어난다.** 커넥션 풀 큐잉으로 한 번 더 곱해진다. +3. **헬스체크도 같은 줄에 선다** — 프로브가 타임아웃되어 노드가 로드밸런서에서 빠지고, 남은 노드로 부하가 몰린다. +4. **낙관적 락 충돌은 없었다.** 로그인은 새 행을 만들 뿐 같은 행을 다투지 않는다 — B-3 의 영역. diff --git a/docs/evidence/a6-latency-injection/a6-connection-pool-blocking.png b/docs/evidence/a6-latency-injection/a6-connection-pool-blocking.png new file mode 100644 index 0000000000000000000000000000000000000000..d70bdcf4ab04e2f5b1bd32eb21f38525e76a4d3a GIT binary patch literal 70811 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 **A-1·A-5 와 같은 교훈이 세 번째로 나왔다.** +> 주입을 넣은 것과 걸린 것은 다르다. **카운터를 봐야 한다.** + +### 개념 — `tc` 의 계층 구조 + +``` + qdisc (큐 규율) 인터페이스에 붙는 패킷 스케줄러 + ├─ prio 우선순위 밴드 3개로 나눈다 + │ ├─ 1:1 (기본) + │ ├─ 1:2 (기본) + │ └─ 1:3 ← 여기에 netem 을 붙인다 + └─ filter 어떤 패킷을 어느 밴드로 보낼지 +``` + +`netem` 을 root 에 바로 붙이면 **모든 트래픽**이 느려진다. +`prio` + `filter` 를 쓰면 **고른 트래픽만** 느려진다. + +--- + +## 3. 결과 — 지연은 곱해진다 + +``` +=== 두 노드 지연 비교 (기준선: k0=70ms k1=66ms) === + keycloak-0 평균 41 ms 최대 57 ms ← 영향 없음 + keycloak-1 평균 1872 ms 최대 1887 ms ← 28배 +``` + +### 왜 200ms 가 1,872ms 가 되는가 + +A-0 에서 잡은 로그인 트랜잭션의 SQL 이 답이다. + +``` +BEGIN +select ... from OFFLINE_USER_SESSION ... +select VERSION ... for no key update skip locked +select ... from OFFLINE_CLIENT_SESSION ... +select VERSION ... for no key update skip locked +insert into OFFLINE_USER_SESSION ... +insert into OFFLINE_CLIENT_SESSION ... +SET LOCAL synchronous_commit TO OFF +COMMIT +``` + +**왕복이 아홉 번이다.** + +``` + 200 ms × 9 왕복 ≈ 1,800 ms 실측 1,872 ms +``` + +> **네트워크 지연은 왕복 횟수만큼 증폭된다.** +> "DB 가 200ms 느려졌다"는 "애플리케이션이 200ms 느려졌다"가 아니다. +> **쿼리 수를 줄이는 것이 지연 환경에서 결정적인 이유**가 이것이다. + +--- + +## 4. 동시 부하 — 여기서 진짜 고장이 난다 + +동시 20건을 `keycloak-1` 에 보냈다. + +``` + 200 1.911 200 1.913 200 1.958 200 1.981 + 200 3.441 200 4.841 200 6.257 200 7.704 + 200 9.104 200 10.539 200 11.951 200 13.351 + 200 14.785 200 16.189 200 17.625 200 19.053 + 200 20.495 200 21.905 200 22.228 200 22.230 +``` + +**전부 성공(200)했지만 응답 시간이 1.9초에서 22.2초까지 계단으로 늘어난다.** + +``` + 1.9 → 3.4 → 4.8 → 6.2 → 7.7 → 9.1 → 10.5 → ... + ──── ──── ──── ──── + 약 1.4초 간격 — 앞 요청이 커넥션을 놓아줄 때까지 줄을 선다 +``` + +**전형적인 큐잉이다.** 커넥션 수는 유한하고, 각 요청이 커넥션을 1.9초씩 +붙잡고 있으므로 뒤에 온 요청은 그만큼 기다린다. + +### 커넥션 풀 지표가 증언한다 + +``` + agroal_blocking_time_max_milliseconds 20000.0 ← 20초를 기다린 요청이 있다 + agroal_blocking_time_average_milliseconds 281.0 + agroal_max_used_count 19.0 ← 풀이 19개까지 늘었다 + agroal_acquire_count_total 672.0 + agroal_active_count 0.0 ← 부하가 끝나 지금은 0 +``` + +![커넥션 획득 대기 시간](evidence/a6-latency-injection/a6-connection-pool-blocking.png) + +### 그리고 헬스체크가 무너진다 + +``` +Warning Unhealthy pod/keycloak-1 Readiness probe failed: + Get "http://10.42.0.42:9000/health/ready": context deadline exceeded +``` + +**readiness 프로브 자체가 타임아웃됐다.** + +### 연쇄 고장의 모양 + +``` + DB 가 느려진다 + ↓ + 요청이 커넥션을 오래 붙잡는다 + ↓ + 커넥션 풀이 고갈된다 + ↓ + 새 요청이 줄을 선다 (최대 20초) + ↓ + 헬스체크도 줄에 선다 → 타임아웃 → NotReady + ↓ + 그 노드가 로드밸런서에서 빠진다 + ↓ + ★ 남은 노드로 트래픽이 몰린다 → 그 노드도 같은 길을 간다 +``` + +**마지막 화살표가 무서운 부분이다.** 느려짐은 **전파된다.** +A-2(DB 완전 정지)는 즉시 503 으로 드러나 오히려 명확했지만, +**느려짐은 살아 있는 노드를 하나씩 무너뜨린다.** + +--- + +## 5. 빗나간 예측 — 낙관적 락 충돌은 늘지 않았다 + +계획서에 이렇게 적었다. + +> **낙관적 락 충돌 증가** — 트랜잭션이 길어져 `VERSION` 충돌이 늘어야 한다 + +``` + 관련 로그 줄수: 0 +``` + +**하나도 없었다.** 이유가 명확하다. + +``` + 로그인 → 매번 새 세션 행을 INSERT → 다툴 상대가 없다 + refresh → 같은 세션 행을 UPDATE → 여기서 다툰다 +``` + +**충돌은 같은 행을 동시에 고칠 때만 일어난다.** 로그인 부하로는 재현되지 +않는다. 이건 **B-3(refresh 토큰 경쟁)의 영역**이며, 거기서 지연을 함께 주면 +충돌률이 올라갈 것이다. + +> 예측을 적어두지 않았다면 "충돌이 없네" 하고 넘어갔을 것이다. +> **빗나간 예측이 다음 실험의 설계를 정해준다.** + +--- + +## 6. 복구 + +```bash +ssh kc-lab-2 'sudo tc qdisc del dev flannel.1 root' +``` + +``` + keycloak-0 평균 43 ms + keycloak-1 평균 51 ms ← 즉시 정상 +``` + +**파드 재시작 없이 즉시 회복.** 커넥션 풀도 스스로 정상화됐다. + +--- + +## 7. 운영에 주는 것 + +| 알게 된 것 | 함의 | +|---|---| +| 지연은 **왕복 횟수만큼 곱해진다** | DB 지연 대책은 "쿼리 수 줄이기"가 먼저다 | +| 커넥션 풀에서 **한 번 더 곱해진다** | 풀 크기와 타임아웃이 장애 반경을 정한다 | +| **헬스체크도 줄에 선다** | 프로브 타임아웃이 풀 대기보다 짧아야 격리가 제때 된다 | +| 느려짐은 **전파된다** | 노드를 빼면 남은 노드가 더 빨리 무너진다 | +| `up` 도 readiness 도 **늦게 반응** | **응답 시간 분포(p95/p99)를 봐야 한다** | + +### 이 실험대에 없는 알림 + +지금 관측 스택에는 **지연 분포 지표가 없다.** `agroal_blocking_time_*` 은 +있지만 히스토그램이 아니라 평균/최대뿐이다. + +```promql +# 있으면 좋았을 것 +histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m])) +``` + +**A-2 에서 `kube-state-metrics` 가 빠진 것을 찾았고, 여기서는 응답 시간 +히스토그램이 빠진 것을 찾았다.** 둘 다 보완 항목이다. + +--- + +## 8. 재현 절차 (명령어) + +```bash +# 1. 인터페이스 이름 확인 — eth0 이 아니다 +ssh kc-lab-2 'ip -brief link show | grep -E "flannel|cni|enp"' + +# 2. 오버레이 인터페이스에 건다 (enp1s0 에서는 파드 IP 가 안 보인다) +ssh kc-lab-2 ' + sudo tc qdisc add dev flannel.1 root handle 1: prio + sudo tc qdisc add dev flannel.1 parent 1:3 handle 30: netem delay 200ms + sudo tc filter add dev flannel.1 protocol ip parent 1:0 prio 3 \ + u32 match ip src /32 flowid 1:3' + +# 3. 걸렸는지 카운터로 확인 — Sent 가 0 이면 해석 금지 +ssh kc-lab-2 'sudo tc -s qdisc show dev flannel.1 | grep -A2 netem' + +# 4. 단일 요청 지연 (대조군은 같은 노드의 keycloak-0) +kubectl -n keycloak-lab run t --rm -i --restart=Never --image=curlimages/curl:8.11.1 \ + --command -- curl -s -o /dev/null -w '%{time_total}\n' -X POST http://:8080/realms/master/protocol/openid-connect/token ... + +# 5. 동시 부하로 풀 고갈 재현 +# ( curl ... ) & 를 20개 띄우고 wait + +# 6. 풀 지표 +curl -s http://:9000/metrics | grep -E '^agroal_(blocking_time|max_used|awaiting)' + +# 7. 해제 +ssh kc-lab-2 'sudo tc qdisc del dev flannel.1 root' +``` + +--- + +## 9. 다음 실험에 남기는 것 + +| 실험 | 이 실험이 준 것 | +|---|---| +| **B-3** refresh 경쟁 | **지연을 함께 주면 낙관적 락 충돌이 재현될 것** — 여기서는 안 됐다 | +| **B-1** 저장소 지연 (Q3 제약) | 같은 기법을 Redis 앞에 쓴다 | +| 관측 보완 | **응답 시간 히스토그램**이 없다 | +| 구성 | **프로브 타임아웃 < 커넥션 풀 대기**여야 격리가 제때 된다 |