도메인의 주소를 바꿨는데 일부 사용자는 예전 서버로 접속합니다. “DNS가 전파되는 중”이라고만 말하면 무엇을 기다리는지 알기 어렵습니다. 이번에는 누가 답을 가지고 있고, 언제까지 재사용할 수 있는지 를 중심으로 보겠습니다. 이름을 묻는 곳과 답을 관리하는 곳 일반적인 이름 조회에서 클라이언트는 재귀 리졸버에 질문합니다. 리졸버가 유효한 캐시를 가지고 있으면 재사용하고, 필요하면 이름 서버를 찾아 답을 구합니다. 권한 있는 이름 서버는 자신이 담당하는 영역의 정보를 제공합니다. DNS의 리졸버·이름 서버·캐시 역할은 RFC 1034 에서 설명합니다. 그림은 중간의 루트·최상위 도메인 서버 조회를 접은 개념 흐름입니다. 모든 요청이 권한 서버까지 가는 것은 아닙니다. TTL은 재사용 시간의 기준 TTL은 캐시한 레코드를 재사용할 수 있는 시간의 기준입니다. TTL=60 인 답을 시각 0에 받았다면, 다음 표처럼 생각할 수 있습니다. 여기서는 전송 시간, 시계 차이와 별도 캐시 정책은 제외합니다. 경과 시간 이 모형에서의 판단 20초 40초 남음 59초 1초 남음 60초 만료, 새 조회가 필요함 const ttl = 60; for (const elapsed of [20, 59, 60]) { const remaining = Math.max(0, ttl - elapsed); console.log(`${elapsed}:remaining=${remaining}`); } 출력은 20:remaining=40 , 59:remaining=1 , 60:remaining=0 입니다. TTL 계산 모형을 검증했고 실제 도메인 설정은 변경하지 않았습니다. TTL을 낮췄는데 바로 안 바뀌는 이유 이전에 더 긴 TTL로 받은 캐시는 그 이전 답의 시간을 기준으로 남아 있을 수 있습니다. 지금 권한 서버의 TTL을 낮췄다고 이미 배포된 캐시의 시간을 소급해서 줄이는 것은 아닙니다. 브라우저, 운영체제, 리졸버 등 어느 계층의 답인지도 구분해야 합니다. TTL을 “전체 인터넷이 이 시각에 바뀐다”는 약속으로 보지 않는 편이 좋습니다. 오류 응답 캐시나 만료된 답의 제한적인 제공처럼 추가 규칙도 있습니다. 이 글은 기본 정상 조회만 설명합니다. 확인 문제 캐시가 유효한데 매번 권한 서버에 물어야 할까요? 기존 답의 TTL이 600초였는데 새 TTL을 60초로 바꾸면 기존 캐시도 바로 줄어들까요? TTL 90초인 답을 받은 뒤 35초가 지나면 이 모형에서 얼마나 남을까요? 답과 해설 기본적으로 유효한 캐시를 재사용할 수 있습니다. 아닙니다. 이미 받은 답의 TTL과 새로 받은 답을 구분해야 합니다. 55초입니다. 실제 운영에서는 조회 계층과 추가 정책도 확인합니다. 오늘은 “내가 보는 답은 어느 계층의 캐시인가?”를 적어보겠습니다. 내일은 TTL을 바꾸기 전후의 시간표를 그리고, 일주일 뒤에는 HTTP 캐시와 무엇이 다른지 비교해보면 좋겠습니다. 자료 확인 기준: RFC 1034의 정상 조회와 캐시 개념, 2026-10-04. 합성 TTL 계산을 제외한 실제 DNS 질의·변경 실험은 하지 않았습니다. 예제 검증 환경: Node.js v24.13.1.
1. 메모리 계층 CPU는 결국 메모리에 올라와 있는 명령어를 실행할 뿐이다. 그래서 메모리를 어떻게 구성하고 관리하느냐가 중요하다. (그림 3-8) 메모리 계층은 위에서부터 레지스터, 캐시, 주기억장치, 보조기억장치로 구성된다. 레지스터: CPU 안에 있는 작은 메모리. 휘발성이며 속도가 가장 빠르지만 용량은 가장 적다. 캐시: L1, L2(+L3) 캐시를 말한다. 휘발성이며 빠르고 용량이 적다. 주기억장치: RAM을 말한다. 휘발성이며 속도와 용량 모두 보통이다. 보조기억장치: HDD, SSD를 말한다. 비휘발성이며 느리지만 용량이 크다. 위로 갈수록 빠르고 비싸고 작아지며, 아래로 갈수록 느리고 싸고 커진다. 전부 빠른 메모리로 채우면 좋겠지만 너무 비싸기 때문에 경제성을 이유로 계층을 나눠서 관리하는 것이다. 게임을 켰을 때 뜨는 "로딩 중"도 이 계층 구조 때문이다. 하드디스크(또는 인터넷)에 있는 데이터를 RAM으로 옮기는 작업이 아직 끝나지 않았다는 의미이다. 2. 캐시 캐시는 데이터를 미리 복사해두는 임시 저장소이자, 빠른 장치와 느린 장치 사이의 속도 차이로 생기는 병목을 줄이기 위한 메모리이다. 이렇게 속도 차이를 메우려고 계층과 계층 사이에 두는 계층을 캐싱 계층 이라고 한다. 예를 들어 캐시 메모리와 보조기억장치 사이에 있는 주기억장치는 보조기억장치의 캐싱 계층이라고 볼 수 있다. 쉽게 말해 CPU라는 일꾼이 매번 창고(디스크)까지 가지 않게 책상 위(캐시)에 자주 쓰는 공구를 올려두는 느낌이다. 지역성의 원리 캐시를 직접 설정할 때는 자주 사용하는 데이터를 기준으로 해야 하는데, 그 근거가 되는 것이 바로 지역성이다. 시간 지역성(temporal locality): 최근에 사용한 데이터에 다시 접근하려는 특성 공간 지역성(spatial locality): 최근 접근한 데이터의 주변 공간에 접근하려는 특성 int[] arr = new int[10]; for (int i = 0; i < 10; i++) { arr[i] = i; } 위 코드에서 변수 i 는 반복할 때마다 계속 접근되므로 시간 지역성, 배열 arr 의 요소들은 연속된 공간에 순서대로 접근되므로 공간 지역성의 예시라고 볼 수 있다. 캐시히트와 캐시미스 (그림 3-9) 캐시에서 원하는 데이터를 찾으면 캐시히트 , 캐시에 없어서 주 메모리까지 가서 찾아와야 하면 캐시미스 라고 한다. 캐시히트는 위치도 가깝고 CPU 내부 버스를 통해 동작해서 빠르지만, 캐시미스는 시스템 버스를 거쳐 메모리에서 가져오기 때문에 느리다. 캐시매핑 캐시는 메모리에 비해 매우 작기 때문에 메모리의 데이터를 캐시의 어느 위치에 둘지, 즉 매핑을 어떻게 하느냐가 캐시히트율에 큰 영향을 준다. 직접 매핑(direct mapping): 메모리의 각 블록이 캐시의 정해진 한 위치에만 들어가는 방식. 처리가 빠르지만 같은 위치를 두고 충돌이 자주 발생한다. 연관 매핑(associative mapping): 위치를 정해두지 않고 캐시의 빈 곳 아무 데나 넣는 방식. 충돌은 적지만 찾을 때 모든 블록을 탐색해야 해서 느리다. 집합 연관 매핑(set associative mapping): 위 둘을 합친 방식. 캐시를 여러 집합으로 나누고 메모리 블록이 들어갈 집합은 정해두되, 집합 안에서는 자유롭게 저장한다. 충돌과 탐색 비용 사이에서 균형을 잡은 방식이다. 웹 브라우저의 캐시 소프트웨어적인 캐시의 대표적인 예로 웹 브라우저의 쿠키, 로컬 스토리지, 세션 스토리지가 있다. 주로 사용자 정보나 인증 관련 정보를 저장해두고 서버에 요청할 때 자신을 식별하거나 중복 요청을 막는 용도로 쓰인다. 쿠키: 만료기한이 있는 키-값 저장소. 최대 4KB. document.cookie 로 접근하지 못하도록 httpOnly 옵션을 거는 것이 중요하고, 만료기한은 보통 서버에서 정한다. 로컬 스토리지: 만료기한이 없는 키-값 저장소. 최대 10MB. 브라우저를 닫아도 유지되며 도메인 단위로 저장된다. 클라이언트에서만 수정 가능하다. 세션 스토리지: 만료기한이 없는 키-값 저장소. 최대 5MB. 탭 단위로 생성되며 탭을 닫으면 삭제된다. 클라이언트에서만 수정 가능하다. 로컬/세션 스토리지는 둘 다 HTML5를 지원하지 않는 브라우저에서는 사용할 수 없다. 데이터베이스의 캐싱 계층 (그림 3-10) DB 시스템을 구축할 때도 메인 DB 앞에 레디스(Redis) 같은 인메모리 DB를 캐싱 계층으로 두어 성능을 높이기도 한다. 3. 메모리 관리 운영체제의 핵심 역할 중 하나가 한정된 메모리를 최대한 효율적으로 쓰도록 관리하는 것이다. 가상 메모리 (그림 3-11) 가상 메모리는 실제 사용 가능한 메모리 자원을 추상화해서 사용자에게 매우 큰 메모리처럼 보이게 만드는 기법이다. 가상적으로 주어진 주소를 가상 주소(logical address) , 실제 메모리상의 주소를 실제 주소(physical address) 라고 한다. 가상 주소는 MMU(메모리 관리 장치)에 의해 실제 주소로 변환되기 때문에 개발자는 실제 주소를 신경 쓰지 않고 프로그램을 만들 수 있다. 가상 주소와 실제 주소의 매핑 정보는 페이지 테이블 로 관리하며, 이 변환 속도를 높이기 위해 TLB를 사용한다. TLB: 메모리와 CPU 사이에 있는 주소 변환용 캐시. 페이지 테이블의 일부를 보관해서 CPU가 매번 페이지 테이블까지 가지 않아도 되게 해준다. 페이지 폴트와 스와핑 페이지 폴트(page fault)는 프로세스의 주소 공간에는 있지만 현재 RAM에는 없는 데이터에 접근할 때 발생한다. 이때 당장 쓰지 않는 메모리 영역을 하드디스크로 내보내고, 필요한 데이터를 디스크에서 불러와 메모리처럼 쓰는 것을 스와핑(swapping) 이라고 한다. 스와핑 덕분에 마치 페이지 폴트가 없었던 것처럼 동작할 수 있다. 페이지 폴트가 발생하면 다음 순서로 처리된다. CPU가 물리 메모리에 해당 페이지가 없음을 확인하면 트랩을 발생시켜 운영체제에 알린다. 운영체제는 CPU 동작을 잠시 멈춘다. 운영체제가 페이지 테이블을 확인하고 물리 메모리에 비어 있는 프레임이 있는지 찾는다. 빈 프레임이 없으면 스와핑이 발동된다. 빈 프레임에 해당 페이지를 로드하고 페이지 테이블을 최신화한다. 멈췄던 CPU를 다시 시작한다. 페이지(page): 가상 메모리를 사용하는 최소 크기 단위 프레임(frame): 실제 메모리를 사용하는 최소 크기 단위 스레싱 (그림 3-12) 스레싱(thrashing)은 페이지 폴트율이 너무 높아져 컴퓨터 성능이 심각하게 떨어지는 현상이다. 메모리에 너무 많은 프로세스가 올라가면 스와핑이 계속 일어나고, CPU는 스와핑을 기다리느라 놀게 된다. 그러면 운영체제는 "CPU가 한가하네?"라고 착각해서 프로세스를 더 올리고, 그 결과 페이지 폴트가 더 늘어나는 악순환이 반복된다. 일꾼이 바쁜 게 아니라 짐 나르느라 바쁜 건데 일을 더 주는 셈이다 하드웨어적으로는 메모리를 늘리거나 HDD를 SSD로 바꾸는 방법이 있고, 운영체제 차원에서는 다음 두 가지 방법이 있다. 작업 세트(working set): 프로세스의 과거 사용 이력(지역성)을 바탕으로 자주 쓰는 페이지 집합을 만들어 미리 메모리에 올려두는 방법. 탐색 비용과 스와핑을 줄일 수 있다. PFF(Page Fault Frequency): 페이지 폴트 빈도에 상한선과 하한선을 두는 방법. 상한선에 도달하면 프레임을 늘리고, 하한선에 도달하면 프레임을 줄인다. 4. 메모리 할당 메모리에 프로그램을 할당할 때는 시작 위치와 할당 크기를 기준으로 하며, 크게 연속 할당과 불연속 할당으로 나뉜다. 연속 할당 (그림 3-13) 메모리에 공간을 연속적으로 할당하는 방식으로, 고정 분할 방식과 가변 분할 방식이 있다. 고정 분할 방식(fixed partition allocation): 메모리를 미리 나눠두고 관리하는 방식. 융통성이 없고 내부 단편화가 발생한다. 가변 분할 방식(variable partition allocation): 프로그램 크기에 맞게 그때그때 동적으로 메모리를 나누는 방식. 내부 단편화는 없지만 외부 단편화가 발생할 수 있다. 가변 분할 방식은 다시 세 가지로 나뉜다. 최초적합(first fit): 위나 아래부터 탐색하다가 들어갈 수 있는 홀을 찾으면 바로 할당 최적적합(best fit): 프로세스 크기 이상인 홀 중 가장 작은 홀에 할당 최악적합(worst fit): 프로세스 크기와 가장 많이 차이 나는(가장 큰) 홀에 할당 내부 단편화: 나눠진 공간보다 프로그램이 작아서 공간 안에 남는 부분이 낭비되는 현상 외부 단편화: 남은 공간을 다 합치면 충분한데, 조각조각 나뉘어 있어서 프로그램이 들어가지 못하는 현상 (예: 100MB를 55MB, 45MB로 나눴는데 70MB 프로그램이 들어가지 못함) 홀(hole): 할당할 수 있는 비어 있는 메모리 공간 불연속 할당 현대 운영체제가 사용하는 방식으로, 메모리를 연속적으로 할당하지 않는다. 페이징(paging): 메모리를 동일한 크기의 페이지(보통 4KB)로 나누고, 프로그램마다 페이지 테이블을 두어 서로 다른 위치에 할당하는 방식. 홀 크기가 제각각인 문제는 없어지지만 주소 변환이 복잡해진다. 세그멘테이션(segmentation): 페이지라는 크기 단위가 아닌 코드, 데이터, 스택, 힙이나 함수 같은 의미 단위(세그먼트)로 나누는 방식. 공유와 보안 측면에서 유리하지만 홀 크기가 균일하지 않은 문제가 생긴다. 페이지드 세그멘테이션(paged segmentation): 공유나 보안은 의미 단위인 세그먼트로 나누고, 물리 메모리는 페이지로 나누는 방식. 둘의 장점을 합친 형태이다. 5. 페이지 교체 알고리즘 메모리는 한정되어 있어서 스와핑은 피할 수 없지만, 최대한 적게 일어나도록 설계해야 한다. 이때 어떤 페이지를 내보낼지 정하는 것이 페이지 교체 알고리즘이다. 오프라인 알고리즘 앞으로 가장 먼 미래에 참조될 페이지를 교체하는 알고리즘으로, 이론상 가장 좋은 방법이다. 하지만 미래에 어떤 페이지가 쓰일지는 알 수 없기 때문에 실제로는 사용할 수 없고, 다른 알고리즘의 성능을 비교하는 기준으로 쓰인다. FIFO(First In First Out) 가장 먼저 들어온 페이지를 가장 먼저 교체하는 방식이다. LRU(Least Recently Used) (그림 3-14) 참조된 지 가장 오래된 페이지를 교체하는 방식이다. '오래됨'을 판단하기 위해 페이지마다 계수기나 스택을 둬야 한다는 단점이 있다. LRU를 코드로 구현할 때는 보통 해시 테이블 + 이중 연결 리스트 를 사용한다. 이중 연결 리스트는 한정된 메모리(캐시) 자체를 나타내고, 해시 테이블은 리스트에서 원하는 노드를 O(1)로 빠르게 찾기 위해 쓴다. 참고로 Java에서는 LinkedHashMap 이 내부적으로 이 구조를 갖고 있어서 간단하게 구현할 수 있다. import java.util.LinkedHashMap; import java.util.Map; public class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int capacity; public LRUCache(int capacity) { // accessOrder = true → 접근할 때마다 해당 요소를 맨 뒤로 이동 super(capacity, 0.75f, true); this.capacity = capacity; } // 크기를 넘으면 가장 오래 참조되지 않은 요소(맨 앞)를 제거 @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > capacity; } public static void main(String[] args) { LRUCache<Integer, Integer> cache = new LRUCache<>(3); int[] refs = {1, 3, 0, 3, 5, 6, 3}; for (int r : refs) { cache.put(r, r); System.out.println(cache.keySet()); } } } /* [1] [1, 3] [1, 3, 0] [1, 0, 3] [0, 3, 5] [3, 5, 6] [5, 6, 3] */ 출력 결과에서 오른쪽일수록 최근에 참조된 페이지이며, 4개째가 들어올 때마다 가장 왼쪽(가장 오래된) 페이지가 빠지는 것을 볼 수 있다. NUR(Not Used Recently) (그림 3-15) LRU를 발전시킨 알고리즘으로 clock 알고리즘이라고도 부른다. 각 페이지에 참조 비트를 두고 1은 최근에 참조됨, 0은 참조되지 않음을 의미한다. 시계 방향으로 돌면서 0인 페이지를 찾으면 그 페이지를 교체하고 해당 비트를 1로 바꾼다. LFU(Least Frequently Used) 참조 횟수가 가장 적은 페이지, 즉 가장 덜 사용된 페이지를 교체하는 방식이다.
이 글에서 다룰 주제 DNS·TCP·Service·Gateway·메시·애플리케이션을 나눠 실패 지점 찾기 404·502·503·504와 Envoy response flag를 함께 읽기 MTU·conntrack·SNAT·종료 중 연결, 가설을 검증하는 장애 실습 주요 단어 · EndpointSlice · SNI · Host · response flag · MTU · conntrack · draining · readiness 목표 — 명령을 많이 외우는 대신, 각 명령이 어떤 가설을 확인하는지 설명한다. 아래 사례는 실제 사고 회고가 아니라 원리 학습을 위해 구성한 가상 장애다. “쿠버네티스 네트워크가 안 됩니다”라는 보고에는 너무 많은 가능성이 들어 있다. 이름을 못 찾은 것인지, TCP 연결을 못 만든 것인지, 프록시가 거절했는지, 애플리케이션이 오류를 반환했는지 먼저 나눠야 한다. 무작정 Pod를 재시작하면 증거가 사라지고 잠깐 회복했다가 같은 문제가 반복될 수 있다. 1. 첫 기록: 출발점과 실패한 단계를 고정하기 요청을 보낸 위치, 목적지 이름과 포트, 프로토콜, 발생 시각, 영향받는 버전·노드·사용자 범위를 적는다. localhost , 클러스터 내부 Pod, 외부 브라우저는 서로 다른 네트워크 경로다. 같은 URL이라도 출발점에 따라 DNS와 인증 정책이 달라질 수 있다. 진단 지도는 반드시 한 방향으로만 따라야 하는 실행 절차가 아니다. 확인된 증거에 따라 해당 계층으로 돌아가 가설을 수정한다. 최소 시작 명령은 조회 위주로 구성한다. <pod-name> 등은 실제 조회 결과로 바꾼다. 이 글의 명령은 공식 문서 기반이며 클러스터에서 실행한 결과는 아니다. kubectl config current-context kubectl -n bookshop get pods -o wide kubectl -n bookshop get svc kubectl -n bookshop get endpointslices kubectl -n bookshop get events --sort-by=.metadata.creationTimestamp Pod가 Running 인 것과 요청을 받을 준비가 된 것은 다르다. READY , 재시작 횟수, Pod IP, 어느 노드에 있는지까지 함께 본다. Service가 존재한다는 사실도 정상 endpoint가 있다는 보장은 아니다. 2. DNS 실패: 이름 문제와 연결 문제를 분리하기 Could not resolve host 라면 아직 목적지 TCP 연결을 시작하지 못했을 가능성이 크다. 실제 호출 Pod에서 /etc/resolv.conf 를 확인하고 짧은 이름, Namespace를 포함한 이름, 전체 도메인을 비교한다. kubectl -n bookshop exec <client-pod> -- cat /etc/resolv.conf # 아래 nslookup은 해당 도구가 설치된 진단 Pod에서 실행 kubectl -n bookshop exec <dns-tools-pod> -- \ nslookup productpage.bookshop.svc.cluster.local kubectl -n kube-system get pods -l k8s-app=kube-dns kubectl -n kube-system get svc kube-dns cluster.local 은 흔한 기본값이므로 실제 cluster domain이 다르면 바꿔야 한다. kube-dns 라벨과 Service 이름도 배포 구성에 맞는지 확인한다. 도구가 없는 distroless 컨테이너에서 nslookup: not found 가 나온 것은 DNS 장애 증거가 아니다. 승인된 진단 이미지를 사용하되 원래 호출자와 동일한 정책 조건인지 구분한다. Kubernetes DNS 진단 NXDOMAIN 은 질의한 이름이 없다는 DNS 응답이고, SERVFAIL 은 resolver가 처리를 완료하지 못했다는 응답이다. timeout은 응답을 받지 못한 상황이다. 셋을 모두 “DNS 서버가 죽음”으로 묶으면 잘못된 조치를 한다. 특정 이름만 실패하는지, 클러스터 내부 이름과 외부 이름이 함께 실패하는지로 문제 범위를 좁힌다. 가상 사례: NetworkPolicy를 배포한 뒤 Service 이름만 실패하고 같은 Pod IP로는 연결된다. 이때 CoreDNS를 재시작하기 전에 호출자의 DNS egress를 확인한다. 데이터 요청 목적지 허용과 DNS 허용은 별개였음을 4편에서 배웠다. 3. Pod IP는 되는데 Service는 안 된다면 서로 다른 요청 경로의 성공·실패를 비교한다. 직접 Pod IP 호출이 메시 정책 등을 완전히 우회한다고 가정하지 않는다. kubectl -n bookshop get service productpage -o yaml kubectl -n bookshop get pods -l app=productpage --show-labels kubectl -n bookshop get endpointslices \ -l kubernetes.io/service-name=productpage -o yaml 읽는 순서는 Service selector → 선택된 Pod → EndpointSlice 주소·포트·condition → 실제 수신 포트 다. port: 80 , targetPort: http 라면 선택된 Pod에 name: http 인 컨테이너 포트가 있는지 확인한다. 애플리케이션 프로세스가 그 포트에서 실제로 수신하는지도 따로 확인한다. containerPort 선언 자체가 프로세스를 열어 주지는 않는다. Endpoint가 비어 있다면 selector·라벨 불일치를 본다. 주소가 있지만 ready: false 라면 readiness 실패 이유를 본다. 개별 Pod IP는 되지만 Service VIP가 안 된다면 서비스 데이터 평면(kube-proxy 또는 대체 구현), 포트 매핑, 정책, 세션 상태로 범위를 좁힌다. Kubernetes Service 진단 kubectl port-forward 가 성공해도 일반 Service 네트워크 경로가 정상이라고 보장하지 않는다. API 서버·kubelet을 통한 터널은 사용자 → LB → Gateway → Service 경로와 다르다. 어떤 경로를 검증했는지 정확히 기록해야 한다. 4. Gateway는 받았는데 404가 난다면 외부 요청은 DNS와 TCP 연결 이후에도 Host·경로·TLS SNI로 나뉜다. HTTPRoute의 hostname이 shop.example.com 인데 IP 주소로 요청하면 다른 Host가 전달되어 경로가 선택되지 않을 수 있다. kubectl -n bookshop get gateways.gateway.networking.k8s.io kubectl -n bookshop get httproutes.gateway.networking.k8s.io -o yaml kubectl -n bookshop describe httproute productpage 객체의 이름은 실제 배포에서 확인한다. Accepted , ResolvedRefs , Gateway의 Programmed 같은 상태와 reason을 읽고, parentRefs·listener·allowedRoutes·backendRefs를 차례로 확인한다. 다른 Namespace를 참조했다면 해당 연결에 필요한 ReferenceGrant 조건도 검토한다. Gateway API HTTPRoute HTTPS 진단에서 -H 'Host: ...' 만 바꿔도 TLS SNI까지 바뀌는 것은 아니다. 이름과 IP를 분리해 테스트하려면 다음처럼 URL의 호스트 이름을 유지하고 접속 IP를 지정할 수 있다. # 203.0.113.10은 문서용 주소다. 실제 Gateway IP로 교체한다. curl --resolve shop.example.com:443:203.0.113.10 \ https://shop.example.com/ -v 이 명령은 정상 인증서 검증을 유지한다. curl -k 로 검증을 끈 결과만 보고 TLS를 고쳤다고 기록하지 않는다. 인증서 SAN에 이름이 포함되는지, 신뢰 체인이 연결되는지, 만료 시간과 실제 제공되는 인증서가 무엇인지 확인한다. curl --resolve 5. 503 하나에도 여러 원인이 있다 HTTP 상태 코드는 출발점이다. 503은 사용 가능한 upstream이 없거나 연결에 실패했거나, 프록시의 처리 한도에 걸렸거나, 앱이 직접 응답했을 수 있다. 어디서 생성한 응답인지 모르면 잘못된 컴포넌트를 수정하게 된다. 관찰 먼저 세울 가설 다음 증거 HTTP 404 + NR 요청에 맞는 HTTP route 없음 Host·경로·listener·route 503 + UH 건강한 upstream 없음 readiness·endpoint·outlier 배제 503 + UF upstream 연결 실패 수신 포트·mTLS·정책·연결 오류 detail 503 + UO upstream overflow connectionPool·pending request·실제 부하 504 + UT upstream 요청 timeout 앱 지연·의존성·timeout budget 이는 Envoy의 대표적인 response flag이며, 프록시 버전과 프로토콜에 따라 세부 결과가 달라질 수 있다. TCP 연결의 NR 는 맞는 filter chain이 없다는 뜻일 수도 있으며, 이 경우 HTTP 404가 반환된다고 가정하지 않는다. 상태 코드만으로 flag를 추정하지 말고 access log의 response_flags , response_code_details , upstream 주소·연결 오류 정보를 함께 읽는다. 애플리케이션이 만든 503은 같은 표의 원인이라고 단정하지 않는다. Envoy access log 공식 설명 sidecar 구성에서는 다음 도구로 선언한 설정과 실제 프록시 상태를 비교할 수 있다. istioctl analyze -n bookshop istioctl proxy-status istioctl proxy-config routes <productpage-pod> -n bookshop istioctl proxy-config clusters <productpage-pod> -n bookshop istioctl proxy-config endpoints <productpage-pod> -n bookshop kubectl -n bookshop logs <productpage-pod> -c istio-proxy --since=10m analyze 는 설정의 문제를 찾는 출발점이고 모든 런타임 연결을 보장하는 테스트가 아니다. proxy-status 로 동기화 상태를 보고, route가 실제로 어느 cluster를 선택하는지, 그 cluster에 어느 endpoint가 들어 있는지 이어 확인한다. ambient에서는 sidecar 컨테이너가 없으므로 ztunnel·waypoint 진단 경로를 사용한다. 없는 istio-proxy 로그를 찾는 것으로 시간을 쓰지 않는다. Istio 프록시 진단 6. 작은 요청은 되는데 큰 응답이 멈춘다면 이때는 MTU와 경로상의 패킷 처리도 후보에 올린다. MTU 는 한 링크에서 보낼 수 있는 패킷 크기의 상한이다. overlay 캡슐화가 헤더를 더하면 내부 패킷에 쓸 수 있는 크기가 줄어든다. ICMP 오류 전달이 막혀 Path MTU Discovery가 제대로 동작하지 않는 상황도 가설이 될 수 있다. 증상만으로 MTU를 확정하지 않는다. 큰 응답의 서버 처리 지연, 프록시 body limit, 업로드 제한도 비슷한 현상을 만든다. 동일 노드/서로 다른 노드, 작은/큰 payload, overlay/외부 egress 경로의 차이를 비교하고 네트워크 담당자와 인터페이스 MTU·재전송을 확인한다. 모든 노드의 MTU를 임의 값으로 낮추는 조치부터 하지 않는다. Calico MTU 구성 원리 같은 노드에서는 성공하고 다른 노드에서만 실패한다면 노드 간 라우팅·캡슐화·방화벽과 해당 노드 CNI 상태를 우선 조사할 이유가 생긴다. 이 역시 조사 우선순위이지 결론은 아니다. 특정 버전 Pod가 특정 노드에만 배치된 상황처럼 애플리케이션 변수가 섞일 수 있다. 7. 부하가 올라갈 때만 실패한다면: 연결도 유한한 자원이다 conntrack 은 Linux에서 연결 상태를 추적하는 기능이고, SNAT 은 출발지 주소·포트를 변환하는 처리다. 노드·NAT 장치의 연결 추적과 포트 자원이 포화되면 애플리케이션 CPU가 여유로워도 새 연결이 실패할 수 있다. 연결 수뿐 아니라 짧은 연결 생성률, keep-alive, 유휴 timeout, 동일 목적지 집중도를 함께 본다. 여기에 애플리케이션 connection pool과 프록시 connection pool도 있다. “DB 연결 한도”와 “Envoy upstream 연결 한도”는 서로 다른 자원이다. 부하가 오를 때 UO 가 보이면 무조건 한도를 올리기 전에 하류 서비스가 더 받을 능력이 있는지 확인한다. 한도를 늘려 overload를 하류로 밀어낼 수 있기 때문이다. 설명용 가정으로 호출이 초당 100개이고 장애 시 매번 총 3회 시도한다면 하류 시도량은 최대 초당 300개까지 늘 수 있다. 여러 계층이 중첩 재시도하면 증폭은 더 커진다. 6편의 timeout·retry budget과 함께 읽어야 한다. 큐 길이, 실제 active connection, 재시도, 오류와 지연이 같은 시점에 어떻게 변했는지 비교한다. Istio circuit breaking 8. 배포할 때만 끊긴다면: 시작보다 종료를 살펴보기 새 Pod가 Ready가 되고 옛 Pod가 종료되는 동안에는 endpoint 상태 변화와 앱 종료, 프록시 설정 전파가 동시에 일어난다. 긴 HTTP/2·WebSocket 연결은 기존 Pod와 계속 연결되어 있을 수 있다. Service의 endpoint 목록이 바뀌었다고 이미 열린 연결이 다른 Pod로 자동 이동하는 것은 아니다. readiness는 신규 요청 대상으로 삼아도 되는지 알려 준다. 종료 중 endpoint는 terminating 상태와 ready · serving 조건을 함께 고려한다. 앱은 SIGTERM 이후 신규 작업을 멈추고 진행 중 작업을 정리하는 graceful shutdown을 구현해야 한다. Pod 종료와 endpoint 흐름 preStop 과 terminationGracePeriodSeconds , 애플리케이션 종료 처리, 프록시 draining 시간을 같이 설계한다. preStop 실행 시간도 종료 유예 시간 안에 포함되므로 긴 sleep만 넣는다고 모든 연결 문제가 해결되는 것은 아니다. 실제 전파 지연과 요청의 최대 지속 시간을 측정해 선택해야 한다. 컨테이너 lifecycle hook 가상 사례: v2 배포 직후 10초 동안 reset이 늘어난다. 새 버전의 코드 오류뿐 아니라 옛 Pod가 진행 중 요청을 기다리지 않고 종료하는지도 조사한다. 오류가 어느 Pod·노드·종료 이벤트와 겹치는지 trace·로그·배포 기록의 시계를 맞춘다. 9. 학습용 장애 실습: 한 번에 변수 하나를 바꾸기 운영이 아닌 전용 클러스터에서 다음 실험을 할 수 있다. 변경 전 manifest를 보관하고, 실험 하나를 복구한 뒤 다음 실험으로 넘어간다. 아래는 실제 실행 결과가 아닌 실험 설계 다. 바꾸는 변수 관찰할 것 복구 확인 Service selector의 라벨 EndpointSlice의 선택 결과 원래 selector 복원 후 실제 요청 NetworkPolicy의 DNS 허용 이름 호출과 직접 IP 호출의 차이 DNS·앱 연결 각각 성공 HTTPRoute hostname Gateway 응답·route 상태 원래 이름으로 경로 일치 reviews의 의도적인 지연 timeout·retry·trace span 지연 제거 후 부하·오류율 회복 앱 종료 처리 배포 중 reset과 종료 시각 반복 배포에서도 연결 정리 실험 기록은 가설 → 변경 → 관찰 → 해석 → 복구 로 남긴다. “503이 났다”보다 “reviews endpoint가 비어 있고 gateway에 UH가 기록되며 selector를 복구한 뒤 요청이 회복됐다”가 더 강한 설명이다. 다만 한 번의 재현이 모든 장애의 원인을 증명하지는 않는다. 10. 운영 설계로 되돌아가기 진단에서 얻은 지식은 다음 배포 설계를 바꿔야 한다. 서비스 간 허용 경로는 정책으로, 기대 지연은 timeout budget으로, 배포 안전성은 readiness와 종료 처리로, 실패 판단은 메트릭과 trace 기준으로 남긴다. 버전 업그레이드 전에는 Kubernetes·CNI·Gateway 구현·Istio·cert-manager의 호환 범위를 각 공식 문서에서 확인한다. 10편을 읽었다면 서점 화면 하나의 요청에 대해 다음 질문을 이어 답할 수 있어야 한다. 이름은 누가 해석하는가, 대상 Pod는 누가 선택하는가, 네트워크와 사용자 권한은 어디서 검사하는가, 인증서는 누가 갱신하는가, 실패 시 어느 신호를 볼 것인가. 이 연결을 설명할 수 있는 것이 도구 이름을 많이 아는 것보다 실제 장애 대응에 도움이 된다. 자료·예제 기준 — 2026-10-04에 링크한 공식 진단 문서를 확인했다. 명령은 미실행, 장애 사례·수치는 설명용이다. Envoy flag 표는 명시한 버전 문서의 대표 의미를 인용했으며 배포 버전의 문서·실제 로그를 우선한다. 모든 그림은 자체 제작 개념도다. 쿠버네티스 네트워크 10편 시리즈 TCP/IP부터 CNI까지, Pod가 통신하는 원리 Service·EndpointSlice·DNS Ingress와 Gateway API, 외부 진입과 연결 NetworkPolicy와 연결 허용 설계 Istio 구조: Sidecar·Ambient·CNI 카나리·재시도·서킷 브레이커 mTLS·JWT·인증과 인가 TLS와 cert-manager의 발급·갱신 Kiali·Jaeger·OpenTelemetry DNS부터 TLS까지 장애 진단 그림과 아이콘 출처 · 도식은 이 시리즈를 위해 직접 제작했다. Kubernetes 리소스 아이콘은 Kubernetes Icons Set (Kubernetes Authors / contributors, CC BY 4.0 )의 원본을 비율대로 축소해 배치했다. 제품 로고는 CNCF Artwork 와 Kiali 공식 자산 을 식별 목적으로 사용했다. 각 이름과 로고의 상표권은 해당 권리자에게 있으며, 공식 후원이나 인증을 뜻하지 않는다. 확인일: 2026-10-04.
이 글에서 다룰 주제 Kiali·Prometheus·Jaeger의 역할과 수집·조회 경로 ServiceMonitor·PodMonitor, Istio 메트릭과 오류율·지연 쿼리 Trace·Span·Context propagation·Sampling, 관측 데이터가 비는 이유 주요 단어 · Kiali · Jaeger v2 · OpenTelemetry · OTLP · RED · p95 · Trace ID · Sampling 선수 지식과 목표 — Service와 Istio의 데이터 평면을 이해했다면, 이번에는 “어느 연결에서 문제가 시작되었는가”를 관측 신호로 좁힌다. 읽고 나면 서비스 지도·메트릭·트레이스를 서로 다른 근거로 해석할 수 있다. 서점 화면이 느리다는 알림이 왔다. productpage Pod의 CPU는 정상이다. 이 정보만으로 productpage가 정상이라고 결론 낼 수 있을까? reviews의 응답을 기다리거나, ratings 호출을 여러 번 재시도하거나, 연결 풀에서 순서를 기다릴 수도 있다. CPU 한 개의 그래프로는 요청이 지나간 경로를 알 수 없다. 1. 관측 지도: 요청과 관측 데이터는 다른 길로 이동한다 앞선 전체도와 같은 배치에서 관측 대상을 강조한 개념도다. 애플리케이션 요청이 Kiali나 Jaeger를 거쳐 전달되는 것은 아니다. Observability — 외부로 내보낸 신호를 통해 시스템 내부에서 무엇이 일어났는지 질문하고 설명하는 능력이다. Kiali는 서비스 메시의 연결 관계와 상태를 보는 콘솔이다. Prometheus의 메트릭과 Kubernetes·Istio 설정을 함께 해석한다. Jaeger는 분산 요청의 트레이스를 저장·조회하는 도구다. Grafana는 메트릭 등 여러 데이터 소스를 조회하는 대시보드로 연결할 수 있다. Kiali 자체를 메트릭 저장소로 생각하면 “Kiali가 비었으니 요청이 없었다”는 잘못된 결론에 도달한다. Kiali 아키텍처 화살표는 범례에 적힌 요청·전송 방향이다. Prometheus가 메트릭 endpoint를 조회하는 것과 앱이 트레이스를 보내는 것을 구분한다. Kiali 화면의 연결이 비었다면 먼저 조회 Namespace와 시간 구간을 확인한다. 그 구간에 트래픽을 발생시켰는지, Istio 메트릭이 수집되는지, Prometheus endpoint에 Kiali가 접근할 수 있는지 순서대로 본다. “선이 없다”는 관찰에는 요청 없음과 수집 실패라는 서로 다른 가능성이 포함된다. 1.1 제품 로고는 역할을 찾는 표식이다 이 시리즈의 제품별 표식이다. 같은 로고를 썼다는 이유만으로 동일 프로세스나 필수 구성요소라는 뜻은 아니다. 아래 그림에서는 수집·저장·조회 화살표를 따라 실제 역할을 구분한다. Kubernetes 리소스 아이콘과 제품 로고도 서로 다른 의미로 사용한다. 2. 메트릭: 어떤 신호를 어느 위치에서 계산하는가 RED — 요청량(Rate), 오류(Errors), 지연(Duration)을 함께 보는 서비스 관측 관점이다. Istio HTTP 메트릭 중 istio_requests_total 은 요청 수 counter이고, istio_request_duration_milliseconds 는 요청 지연 분포다. source 와 destination reporter는 관측한 프록시 위치를 나타낸다. 두 reporter를 구분 없이 더하면 같은 호출을 중복 집계할 수 있다. TLS가 해독되지 않는 통과 트래픽이나 L4만 관측하는 구간에서는 같은 HTTP 지표가 나오리라고 가정하면 안 된다. Istio 표준 메트릭 다음은 Prometheus가 Istio HTTP 메트릭을 수집 중일 때 사용하는 미실행 쿼리 예제 다. 대상은 bookshop Namespace의 reviews Service로 들어온 요청이고 reporter는 수신 측으로 고정한다. Bookinfo처럼 Deployment가 버전별로 나뉘면 destination_workload 는 reviews-v1 , reviews-v2 등이 될 수 있으므로 Service 이름과 workload 이름을 혼동하지 않는다. 다음처럼 실제 라벨 조합부터 조회하고, 아래 식의 Service 이름이 수집값과 맞는지 확인한다. count by (destination_service_name, destination_service_namespace, destination_workload) ( istio_requests_total{ reporter="destination", destination_workload_namespace="bookshop" } ) 이 탐색식의 값은 요청 수가 아니라 해당 라벨 조합의 시계열 개수다. 목적은 이름 확인이다. 버전별 Service를 별도로 사용한다면 실제 Service 이름에 맞춰 필터를 바꾼다. sum(rate(istio_requests_total{ reporter="destination", destination_service_namespace="bookshop", destination_service_name="reviews" }[5m])) 결과는 최근 5분 표본으로 계산한 평균 요청/초 다. counter의 누적값을 그대로 그리면 재시작과 시간 경과가 섞이므로 rate 를 먼저 계산한 뒤 합친다. 그래프를 30분 구간·30초 step으로 표시하면 각 점은 그 시점의 직전 5분을 요약한 값이다. 순간 최대 요청량과 같은 뜻은 아니다. HTTP 5xx 비율은 같은 조건의 전체 요청률을 분모로 사용한다. 100 * sum(rate(istio_requests_total{ reporter="destination", destination_service_namespace="bookshop", destination_service_name="reviews", response_code=~"5.." }[5m])) / sum(rate(istio_requests_total{ reporter="destination", destination_service_namespace="bookshop", destination_service_name="reviews" }[5m])) 결과 단위는 %. 설명용 가정으로 초당 200개 중 4개가 5xx라면 2%다. 이는 실측이 아니다. 요청이 전혀 없으면 분모가 0이거나 시계열이 없을 수 있다. 전체 요청이 있어도 5xx 시계열이 아직 생성되지 않았다면 분자가 비어 식 전체가 빈 결과일 수 있다. 이런 경우 전체 요청의 수집이 확인된 구간에 한해서만 오류 0으로 해석하거나 보정한다. 이를 무조건 0% 성공으로 채우지 않는다. 트래픽 부재·수집 실패·표본 부족을 구분해야 한다. 또한 수신 프록시에 도달하기 전에 실패한 연결은 이 분모에 안 들어갈 수 있어, 호출자와 게이트웨이 지표도 함께 본다. gRPC는 별도 주의가 필요하다. HTTP 상태가 200이어도 gRPC status가 실패일 수 있다. 위 쿼리는 HTTP 5xx 질문에 답하며 모든 업무 실패율을 대표하지 않는다. 업무 오류·gRPC 상태 기준은 서비스의 성공 정의에 맞게 따로 설계한다. 3. p95: 평균이 숨기는 느린 요청을 읽기 classic histogram이 노출된 환경에서는 다음처럼 95번째 백분위수를 추정한다. histogram_quantile( 0.95, sum by (le) ( rate(istio_request_duration_milliseconds_bucket{ reporter="destination", destination_service_namespace="bookshop", destination_service_name="reviews" }[5m]) ) ) 단위는 메트릭 이름 그대로 밀리초 다. le 는 bucket 상한을 나타내므로 집계에서 보존한다. workload별 결과가 필요하면 sum by (le, destination_workload) 처럼 목적에 맞는 그룹도 남긴다. 현재 식은 지정한 reviews Service의 버전들을 합친 지연 분포를 계산한다. p95가 800ms라는 값은 관측 분포상 약 95%가 그보다 빠르다는 의미이지 모든 요청이 800ms 걸렸다는 뜻이 아니다. histogram bucket 경계에 따른 추정 오차도 있다. Pod별 p95를 평균내는 계산은 전체 요청의 p95와 다르다. native histogram을 사용하면 식과 저장 형태가 달라질 수 있으므로 이 예제는 _bucket 이 있는 classic histogram에 한정한다. Prometheus histogram 함수 실무에서는 p95 하나만으로 배포를 판단하기보다 요청량·오류율·p99·버전별 분포를 같이 본다. 예를 들어 표본 10개인 v2와 표본 10만 개인 v1의 p95를 같은 확신으로 비교할 수 없다. 비교 구간의 부하와 요청 종류가 바뀌면 지연 변화의 원인도 달라진다. 4. ServiceMonitor·PodMonitor: 대상을 찾는 선언과 수집 결과 구분 ServiceMonitor / PodMonitor — Prometheus Operator가 읽어 수집 대상을 구성하는 CRD다. 전자는 Service의 라벨을, 후자는 Pod의 라벨을 기준으로 대상을 찾는다. 선택은 보통 두 번 일어난다. Prometheus 리소스가 Monitor 객체를 고르고, 그 Monitor가 Service 또는 Pod를 고른다. 그래서 ServiceMonitor 파일을 만들었는데 Targets에 나타나지 않는다면 serviceMonitorSelector , serviceMonitorNamespaceSelector , Monitor의 대상 selector와 Namespace 범위를 차례로 확인한다. ServiceMonitor endpoint의 port 는 일반적으로 Service 포트의 이름 이다. 앱 컨테이너 포트 숫자나 라벨과 혼동하지 않는다. Prometheus Operator 시작 안내 또한 애플리케이션 메트릭, Envoy 데이터 평면 메트릭, istiod 제어 평면 메트릭은 관측 대상이 다르다. istiod만 잘 수집한다고 reviews의 HTTP 오류율이 생기지 않는다. sidecar의 메트릭 병합 기능을 사용하는지, 프록시 endpoint를 직접 scrape하는지에 따라 포트와 경로도 달라진다. 기존 수집 설정과 새 Monitor를 중복 적용하면 중복 시계열·부하가 생길 수 있다. Istio Prometheus 통합 “Targets가 UP”은 수집 endpoint 응답 성공이라는 좁은 사실이다. 필요한 istio_requests_total 이 존재하고 시간 구간에 샘플이 들어오는지까지 확인해야 원하는 관측이 완성된다. 5. Trace와 Span: 느린 한 요청을 분해하기 Trace — 하나의 작업이 여러 서비스를 거치는 흐름을 연결한 기록이다. Span 은 그 안의 개별 작업 구간으로 시작·종료 시각과 속성을 가진다. 가상의 trace가 다음처럼 보인다고 하자. productpage의 전체 처리는 900ms, reviews 호출은 820ms, 그 안의 ratings 호출은 700ms다. 이 세 시간을 더해 2,420ms라고 해석하면 안 된다. 부모 span은 자식이 실행된 시간을 포함할 수 있기 때문이다. 병렬 호출이 있다면 단순 합이 아니라 전체 완료를 늦춘 경로를 살펴야 한다. 이 경우 ratings가 유력한 조사 대상이지만 “ratings CPU가 원인”이라는 결론까지는 나오지 않는다. ratings 내부 DB 호출, 연결 대기, 스레드 대기처럼 더 세부적인 span이나 로그·프로파일이 필요하다. 네트워크 프록시가 만든 span만으로 함수 내부의 시간을 모두 설명할 수는 없다. 동일 trace의 관계를 이어 주는 것은 시간의 근접성이 아니라 전파된 context다. 프록시가 서로 다른 앱의 업무 인과관계를 자동 추론하지 않는다. Istio 프록시는 span을 보낼 수 있지만, 애플리케이션은 incoming request와 그로 인해 발생한 outgoing request 사이에 context를 전달해야 한다. 설정한 전파 형식에 맞게 W3C의 traceparent · tracestate 또는 B3 헤더와 SDK instrumentation을 확인한다. Istio가 요구하는 x-request-id 전파도 확인하되, 이 값만 전달하는 것으로 trace context 전파를 대신할 수는 없다. 중간 서비스가 새 Trace ID를 만들면 화면에 여러 개의 끊어진 trace가 나타날 수 있다. Istio 추적 개요 , OpenTelemetry context propagation 6. Jaeger v2: 옛 Agent 그림과 현재 수집 경로 구분 Jaeger v2는 OpenTelemetry Collector 프레임워크를 기반으로 한다. collector는 span을 받고 저장하며, query는 저장된 trace를 UI와 API로 조회한다. all-in-one은 역할을 한 프로세스에 모은 배포 형태다. all-in-one이라는 이름과 메모리 저장은 같은 개념이 아니다. 개발용 메모리 저장 구성을 쓰면 재시작 시 데이터가 사라질 수 있으므로 운영의 보존 기간·저장 용량·복구 요구에 맞는 저장소 구성이 필요하다. Jaeger v2 아키텍처 구성 예를 말로 읽으면 앱/프록시 → OTLP 수신 → 처리 → 저장 → query 조회 다. OTLP gRPC와 HTTP는 다른 전송 방식이며 흔히 각각 4317과 4318을 쓰지만, Service의 실제 노출 포트를 확인해야 한다. 16686 같은 UI 포트로 span을 보내는 것은 목적지가 잘못된 것이다. Jaeger API 별도의 OpenTelemetry Collector는 여러 신호를 모으거나 공통 속성 추가·필터링·샘플링을 집중할 때 유용하다. Jaeger 앞에 반드시 추가해야 하는 필수 부품은 아니다. Kafka 버퍼도 모든 배포의 필수 단계가 아니라 순간 유입량과 저장소 처리량 사이를 완충할 필요가 있을 때 검토한다. 구성요소를 늘리면 그만큼 대기·유실·재시도·저장 공간을 관측해야 할 곳도 늘어난다. 구버전 강의의 Jaeger Agent·Thrift·환경변수 설정을 현재 v2 설정에 그대로 섞지 않는다. 제품 버전과 함께 사용 중인 receiver·exporter·storage 설정을 확인한다. Kiali에서 Jaeger를 연결할 때도 ingestion endpoint가 아니라 해당 연동이 요구하는 query endpoint와 API 지원 을 확인한다. Jaeger 구성 , Kiali Jaeger 연동 7. Sampling: trace가 없다는 사실의 해석 Sampling — 모든 요청의 trace를 저장하는 대신 정책에 따라 일부를 선택하는 과정이다. Head sampling은 요청 초기에 선택한다. 비용을 줄이기 쉽지만 뒤늦게 발생할 오류를 미리 알 수 없다. Tail sampling은 여러 span을 받은 뒤 결과를 보고 고를 수 있어 느린 요청이나 오류 보존에 유리하지만 버퍼 메모리·판정 대기·동일 trace의 span을 모으는 설계가 필요하다. OpenTelemetry sampling 설명용으로 독립적인 1% 확률 샘플링을 가정하면, 요청 100개 중 정확히 하나가 남는다고 보장되지 않는다. 희귀 장애는 샘플에서 빠질 수 있다. 그러므로 오류율 메트릭은 상승했지만 Jaeger에 사례가 없다고 오류가 없었다고 결론 내리지 않는다. trace가 비는 이유는 sampling만이 아니다. exporter endpoint·TLS·권한 문제, Collector drop, queue 포화, 저장소 장애, 잘못된 시간 범위와 서비스명도 확인한다. “앱이 span을 생성했다 → Collector가 받았다 → exporter가 전송했다 → 저장됐다 → query가 조회했다”를 단계별로 검증한다. 8. 하나의 장애를 세 화면으로 좁히기 가상의 상황은 “reviews v2를 배포한 뒤 화면 지연 상승”이다. Kiali에서는 어느 edge와 버전에 오류가 집중되는지 본다. 메트릭에서는 같은 시간·workload·reporter로 요청량과 오류율, 지연을 비교한다. Jaeger에서는 해당 구간의 느린 trace를 선택해 reviews 자체 처리와 ratings 대기를 구분한다. 여기서 reviews v2의 ratings client가 context를 전달하지 않으면 가장 필요한 호출이 trace에서 끊겨 보일 수 있다. 이는 네트워크 장애가 아니라 관측 계측의 누락일 수도 있다. 데이터가 뒷받침하는 범위 안에서 가설을 세우고, 다음 확인 명령을 선택한다. 10편에서는 이 관측을 DNS·TCP·Service·Gateway·메시 정책의 진단 순서와 연결한다. 도구를 설치했다는 사실보다 중요한 것은 각 화면이 답할 수 있는 질문과 답할 수 없는 질문을 아는 것이다. 자료·예제 기준 — 2026-10-04에 링크한 공식 문서의 역할·메트릭·설정 의미를 확인했다. Jaeger는 v2 구조를 설명한다. PromQL은 공식 지표·문법 기반·실제 데이터 미실행 예제이며 수치는 설명용이다. 기존 Observability 시리즈 와 함께 읽으면 신호별 역할을 복습할 수 있다. 쿠버네티스 네트워크 10편 시리즈 TCP/IP부터 CNI까지, Pod가 통신하는 원리 Service·EndpointSlice·DNS Ingress와 Gateway API, 외부 진입과 연결 NetworkPolicy와 연결 허용 설계 Istio 구조: Sidecar·Ambient·CNI 카나리·재시도·서킷 브레이커 mTLS·JWT·인증과 인가 TLS와 cert-manager의 발급·갱신 Kiali·Jaeger·OpenTelemetry DNS부터 TLS까지 장애 진단 그림과 아이콘 출처 · 도식은 이 시리즈를 위해 직접 제작했다. Kubernetes 리소스 아이콘은 Kubernetes Icons Set (Kubernetes Authors / contributors, CC BY 4.0 )의 원본을 비율대로 축소해 배치했다. 제품 로고는 CNCF Artwork 와 Kiali 공식 자산 을 식별 목적으로 사용했다. 각 이름과 로고의 상표권은 해당 권리자에게 있으며, 공식 후원이나 인증을 뜻하지 않는다. 확인일: 2026-10-04.
[해커스 한권토익 무료강의] LC 9 10강, RC 13 14강 수강 후기 이번에는 해커스 한권토익 무료강의에서 LC 9 10강과 RC 13 14강을 수강했습니다. 지난 강의에서 LC의 질문 유형별 풀이와 RC 문법을 공부했다면, 이번에는 LC에서 공지·안내·연설과 방송·광고 지문을 다루고 RC에서는 전치사·접속사와 관계사를 공부했습니다. LC 9강 - 공지 / 안내 / 연설 LC 9강에서는 공지, 안내 방송, 연설처럼 한 사람이 비교적 길게 말하는 지문을 공부했습니다. 이런 문제는 모든 문장을 완벽하게 해석하려고 하기보다 누가 말하고 있는지, 어디에서 말하고 있는지, 무엇을 안내하는지를 먼저 파악하는 것이 중요했습니다. 특히 문제와 보기를 미리 읽어두고 장소나 목적, 이후에 해야 할 행동과 관련된 표현을 예상하면서 들으니 핵심 내용을 찾기가 훨씬 수월했습니다. LC 10강 - 방송 / 광고 지문 10강에서는 방송과 광고 유형을 공부했습니다. 광고에서는 어떤 상품이나 서비스를 소개하는지, 장점이 무엇인지, 청자가 어떤 행동을 해야 하는지를 중심으로 듣는 것이 도움이 됐습니다. 가격, 시간, 날짜처럼 숫자가 포함된 정보도 자주 등장하기 때문에 이런 부분은 따로 집중해서 듣는 연습이 필요하다고 느꼈습니다. LC를 계속 공부하면서 들리는 단어 하나에 집중하기보다 지문 전체의 목적과 흐름을 먼저 파악하는 것이 중요하다는 점이 조금씩 익숙해지고 있습니다. RC 13강 - 전치사 / 접속사 RC 13강에서는 전치사와 접속사를 구분하는 방법을 공부했습니다. 둘은 의미가 비슷한 표현이 많아서 헷갈렸는데, 뒤에 명사가 오는지 완전한 문장이 오는지를 확인하면 문제를 훨씬 빠르게 풀 수 있었습니다. 예를 들어 during과 while, despite와 although처럼 의미는 비슷하지만 문장 구조에 따라 정답이 달라지는 표현들을 함께 정리했습니다. 단어의 뜻만 외우기보다 뒤에 어떤 형태가 오는지까지 같이 기억해야겠다고 느꼈습니다. RC 14강 - 관계사 / 빈출어휘 14강에서는 관계대명사와 관계부사를 중심으로 공부했습니다. 관계사 문제에서는 선행사가 무엇인지 확인하고, 관계사 뒤 문장이 완전한지 불완전한지 판단하는 과정이 중요했습니다. who, which, that, whose와 같은 관계대명사와 where, when 등의 관계부사를 구분하면서 문제를 풀어보니 이전보다 기준이 명확해졌습니다. 함께 나온 빈출어휘도 문장 안에서 어떻게 사용되는지 확인하면서 정리했습니다. 이번 강의까지 들으면서 LC는 문제 유형별로 어떤 정보를 먼저 들어야 하는지가 조금씩 보이기 시작했고, RC도 단순 암기보다는 문장 구조를 먼저 확인하는 습관이 중요하다는 것을 느꼈습니다. 다음 강의에서도 틀린 문제를 다시 확인하면서 계속 복습해보려고 합니다. 해커스 토익 800+ 무료강의 https://goulk.kr/rF4KRk #토익인강 #토익한달 #토익800점 #토익무료강의 #토익무료인강 #토익교재추천 #한권토익 #해커스 #한권토익