LabHub
배우기 러닝패스 코스

연결 하나가 느려지자 나머지가 전부 멈췄다 · 운영자의 연결 진단기: 예산·원인·회수 · 이론

운영자의 연결 진단기: 예산·원인·회수 이해하기

LabHub 에서 이어서 보기

한 줄 요약

운영 가능한 소켓 코드는 성공 바이트만이 아니라 종료 원인·자원 상한·취소와 예외의 회수까지 증거로 설명할 수 있어야 합니다.

왜 이게 필요했나

진단기를 열 번 실행했는데 매번 결과가 나왔습니다. 그런데 실행할 때마다 FD가 두 개씩 남는다면 짧은 시연은 성공하고 오래 켜 둔 운영 도구는 언젠가 실패합니다. 반대로 모든 오류를 timeout으로 묶으면 그래프는 그럴듯해도 포트 거절과 사용자의 취소를 구분할 수 없습니다. 코드를 통과시키는 시험과 사용자의 판단을 돕는 증거 사이에 빠진 조건이 없는지 확인해야 합니다.

이번 마지막 모듈은 앞에서 배운 연결 상태, 준비 큐, 제어 채널을 하나의 진단기로 묶습니다. 성능 경쟁 도구나 임의 주소를 훑는 스캐너가 아닙니다. 수업의 통신은 자기 실습 환경의 loopback에서만 재현하며 다른 사람의 서버를 대상으로 실행하지 않습니다. 외부 통신과 capability를 추가하지 않고도 중요한 경계 조건을 만들 수 있습니다.

어떻게 동작하나

상한은 여러 층에 있습니다. run(limit=8)은 진행 중인 연결을 최대 8개로 제한합니다. 하지만 Dial을 만들 때 소켓을 미리 열었다면 나머지 대기 항목도 FD를 갖고 있습니다. 이 실습은 총목록을 128개로 제한하고 제어 소켓 두 개와 selector의 자원도 별도로 계산합니다. limit을 8로 썼으니 전체 FD가 8개라는 보고는 틀립니다.

[Python resource](https://docs.python.org/3/library/resource.html)의 RLIMIT_NOFILE은 프로세스가 열 수 있는 파일 서술자의 한도입니다. 이것을 올리는 것은 누수 해결이 아닙니다. 소켓뿐 아니라 파일·제어 채널·selector까지 어떤 경로에서 열고 닫는지 먼저 조사해야 합니다. 이 수업은 호스트 설정이나 프로세스 한도를 바꾸지 않습니다. 학습자의 파일을 채점기가 수정하거나 지우지도 않습니다.

실행 예산을 따로 센다

한 턴에 새 연결을 budget개만 시작하고, 완료 준비 작업도 budget개만 처리합니다. 둘은 별도의 카운터입니다. 모든 연결이 즉시 완료하는 환경만 시험하면 두 예산이 같아 보입니다. 채점기의 결정적 스케줄 시험은 처음 두 턴에 완료 이벤트를 보류했다가 여러 개를 한꺼번에 돌려줍니다. 그래서 시작은 제한했지만 완료 큐는 전부 비우는 잘못된 코드도 드러납니다.

입력 목록은 유한하므로 마감 검사는 목록 전체를 순회해도 이번 상한 안에 있습니다. 이 구조를 수십만 연결로 확대하려면 마감 힙이나 타이머 구조, 이벤트 배치의 메모리 비용도 검토해야 합니다. 작은 실습의 선형 순회를 대규모 시스템에 그대로 적용하는 것을 권하지 않습니다.

결과를 있는 그대로 집계한다

각 항목은 connected, failed, timed_out, cancelled 중 하나와 error 정수를 남깁니다. connected의 0은 누락이 아닙니다. error or 기본값처럼 쓰면 성공을 없는 정보로 바꿀 수 있습니다. timed_out은 이 진단기의 마감 초과이고 cancelled는 사용자의 중단입니다. failed의 errno는 운영자가 다음 조사 대상을 고르는 단서지만 그것만으로 방화벽·애플리케이션·네트워크 중 누가 원인인지 확정하지 않습니다.

최종 집계는 총수와 네 상태의 개수를 보여 주고, 실패 계열 errno별 건수를 따로 모읍니다. 완료되지 않은 pending을 성공률 분모에 조용히 섞지 않도록 집계 입력에서 거절합니다. 이 결과는 한 번의 실행 요약입니다. 시간에 따른 누적 메트릭이나 지연 히스토그램을 구현한 것은 아닙니다.

| 증거 | 확인하는 것 | 확인하지 못하는 것 |
| --- | --- | --- |
| 실제 TCP listen/bind 대조 | 연결 수립 성공과 거절 | TLS·HTTP·업무 처리 |
| 가득 찬 socketpair의 대기 | 마감과 제어 깨우기 | 실제 원격 SYN 유실 |
| 합성 완료 이벤트 묶음 | 턴별 예산과 준비 큐 순서 | 커널의 공정성 보장 |
| close 오류 주입 | 뒤쪽 자원까지 정리하는가 | 모든 OS 오류 조합 |

채점기의 PendingSocket은 실제 연결이 지연된 원격 서버가 아닙니다. connect 결과만 진행 중으로 돌려주고, 가득 찬 로컬 소켓으로 쓰기 준비가 없는 조건을 만듭니다. 이 구분을 교재에 남기는 이유는 모의 시험 결과를 실제 네트워크 검증이라고 과장하지 않기 위해서입니다.

finally 하나만으로 충분하지 않다

정리 반복문의 첫 close에서 예외가 나면 뒤 소켓은 닫히지 않을 수 있습니다. 각 소켓의 회수를 시도하고 최초 정리 오류를 보관한 뒤 나머지와 제어 채널까지 정리해야 합니다. 오류는 숨기지 않고 마지막에 전파합니다. 정상 결과가 반환되었는지뿐 아니라 실패 뒤에도 열린 FD가 남지 않았는지를 확인하세요. 등록 목록에서 제거할 때도 close보다 먼저 unregister합니다.

현장에서 만나는 모습

장애 보고에는 '테스트 통과' 대신 조건을 적습니다. 대상 수, 동시 상한, 작업 예산, 성공·거절·취소·마감 수, 끝난 뒤 FD 회수 여부를 남깁니다. CPU가 낮다는 것만으로 빠르다고 할 수 없고 처리량이 높다는 것만으로 작은 요청이 공정하게 처리됐다고 할 수 없습니다. 이번 실습은 운영 지표 설계의 출발점이며 실제 서비스의 SLO나 부하 용량을 보증하지 않습니다.

다음 실습에서 할 것

90분 종합 실습에서 연결 진단기를 8단계로 완성합니다. 정답이 통과하는지, 각 계약을 하나씩 망가뜨린 오답이 실패하는지 함께 봅니다. 세션이 끝나면 파일이 사라지므로 +시간으로 연장하고 중요한 작업물은 종료 전에 별도로 보관하세요.