--- id: ca36f0db-9028-4761-91a8-afb7eb30f2b9 kind: REFERENCE slug: verify-the-network-path-before-blaming-the-application title: Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다 topic: network-virtualization topicName: 네트워크 가상화 project: virtualization status: 초안 studio: "https://hyeonworks.com/studio/documents/ca36f0db-9028-4761-91a8-afb7eb30f2b9/edit" sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다 source: - final/document.md#120-keycloak-refresh-token-실험과의-관계 - final/document.md#117-이-구조에서-발생할-수-있는-문제-117-7 - final/document.md#124-핵심-claim - final/document.md#89-문서-목적 - final/document.md#116-현재-keycloak-k3s-테스트-환경과-연결 - final/document.md#102-packet이-keycloak까지-올라오는-과정 --- # Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다 Refresh Token 경쟁 자체는 virtio-net 문제가 아니다. 다만 그 실험에서는 클라이언트에서 Nginx 와 가상 머신, K3s, Keycloak 을 거쳐 PostgreSQL 또는 Redis 까지 가는 경로를 여러 노드가 함께 쓴다. 그 경로 위의 네트워크 가상화 문제는 애플리케이션 동시성 문제와 비슷한 증상으로 나타난다. ## 관계 - **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge** 이 기준이 「따로 검증한다」고 말하는 계층을 세운 글이다. - **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다** 이 기준이 문제가 네트워크인지 아닌지를 가른다면, 그 절차는 네트워크 안에서 어느 구간인지를 가른다. - **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가** 검증 순서의 첫 항목이다. 경로를 모르면 무엇을 관측할지도 정해지지 않는다. - **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가** 검증 순서의 마지막 항목이고, 네트워크 처리와 CPU 경쟁을 가르는 관측이다. - **Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가** 같은 실험을 CPU 쪽에서 본 물음이다. 두 계층이 같은 지연으로 보이므로 함께 기록한다. ## 목적 이 기준은 실험 결과를 잘못된 원인에 붙이는 일을 막는다. Keycloak 멀티 노드 실험에서 관측되는 지연과 실패에는 네트워크 가상화 쪽 원인이 섞일 수 있다. 노드 하나만 지연되는 경우, 가상 머신 하나에서만 패킷이 유실되는 경우, 호스트 브리지 구성이 잘못된 경우, NAT(Network Address Translation) 나 conntrack 문제, 호스트 CPU 경쟁 때문에 vhost 처리가 밀리는 경우가 여기 들어간다. 이 원인들을 확인하지 않은 채 결과를 Refresh Token 경쟁이나 데이터베이스 락으로 적으면, 고칠 곳이 아닌 곳을 고치게 된다. 이 분리는 실험 결과를 보고 나서 세운 규칙이 아니다. 원문 문서는 이 실험 기반으로 검증하려는 항목을 일곱 개 적어 두었고, 그 마지막이 「네트워크 계층 문제와 애플리케이션/저장소 문제의 분리」였다. ## 규칙 ### 1. 실험이 지나는 경로를 먼저 적고 시작한다 요청은 클라이언트에서 Nginx 로 가고, 거기서 가상 머신 두 대 중 하나로, 그 안의 K3s 를 지나 Keycloak 으로, 다시 PostgreSQL 또는 Redis 로 간다. 이 경로를 노드들이 공유한다. 경로를 적지 않으면 어느 관측이 어느 구간을 덮는지 정해지지 않는다. 이 실험대에서 그렇게 어긋난 확인이 한 번 있었다. 04 단계의 확인 명령을 엣지 가상 머신 안에서 tailnet 주소로 쳤더니 connection refused 가 돌아왔는데, 엣지에서 나간 패킷은 호스트의 virbr0 으로 들어가고, 들어온 패킷의 도착지 주소를 바꿔 넘기는 호스트의 DNAT(Destination NAT, 도착지 주소 변환) 규칙은 tailscale0 으로 들어온 것만 매칭해서 안 걸렸기 때문이다(§190 · §182). 「설정 문제가 아니라 친 위치 문제다」가 그 단계가 남긴 한 줄이다. ### 2. 노드 하나에서만 나는 증상을 애플리케이션 동시성으로 먼저 읽지 않는다 노드 하나만 지연되거나 가상 머신 하나에서만 실패하는 증상은 그 노드로 가는 경로 쪽에서도 나올 수 있다. 호스트 브리지 구성 오류, NAT 와 conntrack 문제, 그 가상 머신 쪽 패킷 유실이 같은 모양으로 관측된다. 증상이 노드별로 갈리면 그 노드까지 가는 경로를 먼저 확인한다. ### 3. 애플리케이션 로그만으로 네트워크 계층을 배제하지 않는다 Keycloak 은 virtqueue 와 vhost-net, TAP, Bridge, 물리 NIC(Network Interface Card) 를 직접 알지 못하고, 게스트가 주는 소켓 위에서만 동작한다. 아래 계층이 어긋나도 애플리케이션 로그에는 느렸다는 것과 실패했다는 것만 남는다. 그래서 애플리케이션 쪽 관측을 아무리 늘려도 이 계층이 원인인지 아닌지는 갈리지 않는다. ### 4. 네트워크 처리가 쓰는 호스트 CPU 를 실험과 같은 시간축에 기록한다 vhost-net 과 QEMU 스레드, softirq 도 호스트 CPU 를 쓴다. 그래서 네트워크 문제처럼 보이는 지연이 CPU 스케줄링 문제일 수도 있다. 앞의 세 규칙이 애플리케이션 증상을 네트워크 쪽으로 되돌린다면 이 규칙은 네트워크 증상을 CPU 쪽으로 되돌린다. 방향이 반대라서 둘을 한 기준에 둔다. 부하 실험을 돌릴 때 QEMU 와 vhost 의 CPU 사용량, 호스트와 게스트의 CPU, 네트워크 지연을 같은 시간축에 남긴다. 나중에 따로 재면 그때의 부하를 다시 만들어야 한다. ### 5. 세 가지 검증을 마친 뒤에 원인을 적는다 경로가 무엇인지, 그 경로가 끊기지 않았는지, 네트워크 처리가 호스트 CPU 를 얼마나 쓰는지 셋을 확인한다. 첫째는 호스트 Nginx 에서 Keycloak 까지의 실제 패킷 경로를 추적해서, 둘째는 계층마다 캡처해서, 셋째는 부하 중 CPU 사용량을 재서 답한다. ## 적용 조건 여러 노드가 같은 네트워크 경로를 공유하는 실험의 결과를 원인에 귀속할 때. 노드별로만 나타나는 지연을 볼 때. 특정 가상 머신에서만 나는 실패를 볼 때. 부하 구간에서만 커지는 지연을 애플리케이션 동시성이나 저장소 lock 으로 결론내려 할 때. ## 예외 애플리케이션 쪽 관측을 늘리는 것으로는 이 기준을 적용할 수 없다. Keycloak 이 게스트 소켓 위에서만 동작하므로 애플리케이션 로그로는 이 계층이 원인인지 가릴 수 없다. 네트워크 계층이 깨끗하다고 해서 이 기준이 애플리케이션 결함을 배제해 주지는 않는다. 여기서 나오는 것은 네트워크가 원인이 아니라는 것까지다. 가상 머신 위 K3s 안쪽은 이 기준의 범위 밖이다. CNI(Container Network Interface) 와 Service, Pod 네트워크는 별도 계층으로 두고 따로 분석한다. 원문 문서가 이 테스트 환경에 얹어 그린 경로는 확인된 것이 아니라 기준 구조를 그대로 옮겨 놓은 그림이다. 이 저장소에는 이 기준으로 원인을 실제로 가른 실험이 아직 없다. 가까운 것은 실험대를 세울 때 한 번 있었다. 밖에서 온 요청만 엣지에 닿지 않았는데 원인은 게스트 안이 아니라 호스트의 libvirt 방화벽 규칙이었고, 그때 엣지 nginx 는 호스트에서 친 요청에 404 로 응답하고 있었다(§180). ## 예시 - Keycloak 노드 하나만 응답이 느림 : 그 노드가 있는 가상 머신까지의 경로부터 확인한다 - 가상 머신 하나에서만 요청이 실패 : 호스트 브리지 구성과 그 가상 머신의 tap 연결을 본다 - 부하를 올릴수록 지연이 커짐 : QEMU 와 vhost 의 CPU 사용량을 같은 시간축에서 함께 본다 - 동시 갱신 실험에서 두 번째 요청이 거부됨 : 네트워크 검증 셋을 마친 뒤에 Refresh Token 경쟁으로 적는다 - 네트워크 검증이 전부 깨끗함 : 네트워크가 원인이 아니라는 것까지만 적고 애플리케이션 쪽을 계속 본다