11.11.4.3 포트 충돌(Binding Address in use) 회피를 위한 프로세스 생명주기 통제

11.11.4.3 포트 충돌(Binding Address in use) 회피를 위한 프로세스 생명주기 통제

마이크로서비스화된 ROS2 시스템에서 각각의 분산 구역을 독립시키려 하다 보면 종종 우매한 런북 구동 탓에 치명적인 오셀로 보드판 오작동이 터진다. 대표적인 참사가 zenoh-bridge-dds 라우터를 실행시켰는데, 터미널 모니터 위로 끔찍하게도 붉은 글씨의 [ERROR] Cannot bind to address: Address already in use (os error 98) 비명이 작렬하며 프로세스가 그 자리에서 자살(Crash)해버리는 현상이다.

네트워크 인터페이스 카드(NIC)와 리눅스 커널의 권위적 규칙 아래서, 단 하나의 TCP 혹은 UDP 포트(예: 7447)에는 오직 단 하나의 주권 프로세스(Process)만이 닻(Bind)을 내릴 수 있다. 본 절에서는 분산 클러스터를 가동할 때 빈발하는 포트 충돌(Collision)의 근원적 원흉을 지목하고, 피투피 망의 생명주기(Lifecycle)를 칼같이 가르는 프로세스 통제 파라다임을 정립한다.

1. 섀도우(Shadow) 프로세스의 생존과 고스트 포트 점유

포트 충돌의 80%는 개발자의 난잡한 종료 습관에서 연유한다.
개발자가 터미널 창에서 Zenoh 브릿지를 Ctrl+C (SIGINT) 로 종료했다고 철석같이 믿은 후 다시 zenoh-bridge-dds 데몬을 위로 띄워 올리려 시도했다. 그러나 이전 프로세스가 메모리 힙 덤프를 디스크에 내리거나 내부 스레드의 우아한 종료(Graceful Shutdown)를 마무리하지 못하고 좀비(Zombie) 상태로 백그라운드에 고립되어버린 상태다. 이 고스트 프로세스는 여전히 커널에게 “내 7447 포트를 열어두라“고 멱살을 쥐고 있다.

다음의 척살(Extermination) 런북을 거행하여 그림자 데몬의 목숨을 완전히 끊어내라.

# 1. 7447 포트를 점령하고 있는 진범 프로세스의 PID를 색출
sudo lsof -i :7447
# 혹은 
sudo netstat -tulpn | grep 7447

# (출력) tcp 0 0 0.0.0.0:7447 0.0.0.0:* LISTEN 15904/zenohd

# 2. 색출된 PID (15904) 무자비하게 터미네이트 (SIGKILL 급소 파괴)
kill -9 15904

운영 스크립트를 작성할 때는 반드시 앞단에 pkill -f zenoh-bridge-dds || true 와 같은 소독(Sanitization) 로직을 삽입하여, 이전 구동체의 망령을 말끔히 소제한 후에야 신규 라우터의 심장을 부팅시키는 설계 사상(Idempotent Startup)을 체화해야 한다.

2. 다중 브릿지(Multiple Bridges) 간섭과 포트 매핑 회피

단일 컴퓨터 내부에서 여러 대의 드론 시뮬레이터(SITL) 등을 구동해야 하는 상황이라 치자. 여러 ROS2 네임스페이스 격리 공간 각각에 Zenoh 브릿지를 개별적으로 띄우면 1개의 호스트 PC에서 다중 브릿지가 전개된다. 이때 아무런 설정 파라미터 조치 없이 기본 zenoh-bridge를 2번 연속 치면 두 번째 브릿지는 즉시 충돌 사사당한다.

이 파멸을 우회하는 해법은, 기본값 포트인 7447에 얽매이지 않고 각 데몬이 수신 대기(Listen)하는 엔드포인트 공간을 물리적으로 찢어분리(Segregation)하는 것이다.

# 시뮬레이션용 로봇 1 파이프라인의 브릿지는 7447 확보
zenoh-bridge-dds -e tcp/0.0.0.0:7447

# 시뮬레이션용 로봇 2 파이프라인의 브릿지는 다른 빈 포트(7448)로 영토 이전
zenoh-bridge-dds -l tcp/0.0.0.0:7448

이로써 단 1대의 인공 서버 안에서도 수백 개의 격리된 Zenoh 스위치 노드 스웜을 충돌 없이 직조(Weaving)할 수 있는 가상화 체계가 탄생한다.

3. 타 프로세스 침식 차단 조치: TIME_WAIT 소켓 오버헤드

마지막으로 간과하기 쉬운 맹점은 커널의 TIME_WAIT 함정이다. 프로세스가 정상 종료되었음에도 불구하고, 리눅스의 TCP 통신 규약은 혹시 모를 지연 패킷의 도달을 염려하여 소켓을 완전히 폭파시키지 않고 수십 초 간 반시체 상태(TIME_WAIT)로 점유 상태를 묶어둔다. (이때 재빠르게 데몬을 재기동시키면 Address in use 에러가 똑같이 발발한다).

이 커널의 과보호를 뚫기 위해 Zenoh 코어 빌더 및 시스템 통합 설계자들은 C나 Go 환경에서 소켓 옵션인 SO_REUSEADDR을 활성화시켜야 하며, 리눅스 자체 인프라를 지배하기 위해서라면 커널 튜닝 스위치를 발동시켜야 한다.

# TCP 커넥션 TIME_WAIT 대기열의 재사용 속도 극대화 런북
sudo sysctl -w net.ipv4.tcp_tw_reuse=1

이러한 단 몇 바이트 텍스트 줄 체계의 치밀함이, 스크립트 재실행 시마다 60초간 손을 놓고 있어야 했던 기형적인 인프라 지연(Downtime) 사태를 파쇄시키고 매초 무결점의 즉각 스핀-업(Spin-up)을 보증해 낸다.