infra
Platform

모듈 맵

[Network] 웹 서버에서 DB 접속 실패 시 원인 격리 프로세스

0 / 35 완료

펼치기
0 / 35 완료0%

Networking · 33 / 35

[Network] 웹 서버에서 DB 접속 실패 시 원인 격리 프로세스

ping/nc/netstat/ip route를 순서대로 사용해 장애 구간을 논리적으로 좁힙니다

🚨INCIDENT ALERT
HIGH

웹 서버에서 DB 연결 실패가 발생했지만 원인은 한 가지가 아닙니다. DNS, 라우팅, 포트, DB 데몬, 방화벽 중 하나만 놓쳐도 같은 에러처럼 보입니다.

장애 대응은 감으로 명령어를 치는 일이 아닙니다. 계층별로 배제하면서 증거를 쌓아야 합니다.

[종합 실습] 웹→DB 연결 장애 격리

"웹 서버에서 DB 연결이 안 됩니다." 이 한 마디로 시작되는 장애 상황. 어디서부터 봐야 할지 막막할 때 논리적인 장애 격리 방법론이 필요합니다. 이 챕터에서는 ping → nc → ss → ip route 순서로 장애 구간을 좁혀나가는 체계적인 접근법을 익히고, 실제 시나리오를 통해 훈련합니다.


1. 장애 격리 방법론

이번 챕터에서 배울 것
  • 1OSI 레이어 기반 4단계 장애 격리 방법론(ping → nc → ss → ip route)
  • 2책임 구간 분리 원칙과 레이어별 담당 팀 에스컬레이션
  • 3ping 성공/실패로 L3 라우팅 생사 확인
  • 4nc로 L4 포트·방화벽 차단 여부 검증
  • 5ss로 데몬 리스닝 여부 확인 및 디폴트 게이트웨이 장애 시나리오 대응
실습 환경 준비
진단 대상 DB 서버 IP 확인

실습 환경의 웹 서버와 DB 서버 IP를 미리 메모해 두세요

L3 연결 확인
ping -c 4 <DB_IP>
L4 포트 연결 확인
nc -zv -w 3 <DB_IP> 3306
DB 서버 리스닝 상태 확인
ss -tulnp | grep 3306
💡개념

장애 격리 4단계 사고방식

웹 서버에서 DB 서버로 연결이 안 됩니다. 애플리케이션 로그엔 "Connection timeout"이 찍혀있고, 팀 채널은 "왜 안 되나요?" 로 가득합니다. 방화벽인지, DB가 죽었는지, 네트워크가 끊겼는지, 설정이 잘못됐는지 — 동시에 여러 가설을 갖고 뛰어들면 시간만 낭비됩니다. 하위 레이어부터 차례로 좁혀가는 체계적인 방법이 있어야 원인을 30분 안에 찾을 수 있습니다.

장애 격리 4단계 사고방식

네트워크 장애를 진단할 때 하위 레이어에서 상위 레이어로 올라가는 원칙을 따릅니다. 하위 레이어가 정상임을 확인해야 상위 레이어 문제라고 단정할 수 있기 때문입니다.

OSI 레이어 기반 4단계 진단 순서

하위 레이어가 정상임을 확인한 뒤에야 상위 레이어 문제라고 단정할 수 있습니다. 아래 흐름이 실무에서 쓰는 순서입니다.

[장애 발생] 웹 서버에서 DB 서버(3306) 연결 불가

1단계: ping DB_IP
   ↓ 목적: L3(네트워크/라우팅) 생사 확인
   ↓ 성공 → 2단계로
   ↗ 실패 → 라우팅/물리 연결 문제 → 네트워크팀 에스컬레이션

2단계: nc -zv DB_IP 3306
   ↓ 목적: L4(방화벽 + 포트 개방) 확인
   ↓ 성공 → 애플리케이션 레이어 문제 (인증, SQL 등)
   ↗ 실패 → 3단계로

3단계: DB서버에서 ss -tulnp | grep 3306
   ↓ 목적: 데몬 기동 여부 확인
   ↓ 리스닝 있음 → 방화벽 차단 문제 → 방화벽 정책 점검
   ↗ 리스닝 없음 → MySQL 데몬 다운 → systemctl start mysqld

4단계: ip route show / cat /etc/resolv.conf
       목적: 라우팅 설정 꼬임, DNS 오설정 확인

이 방법론의 핵심 가치

  1. 재현 가능한 검증: 각 단계가 명확한 명령어와 기대 출력을 가짐
  2. 책임 구간 분리: L3 문제면 네트워크팀, L4 방화벽이면 보안팀, 데몬이면 서버팀
  3. 불필요한 재작업 방지: "방화벽부터 열자"가 아니라 문제 위치를 먼저 특정
  4. 에스컬레이션 근거: "ping은 되는데 nc 3306이 안 됩니다"라는 명확한 정보 제공

💡개념

책임 구간 분리 원칙과 레이어별 담당

장애 격리에서 가장 중요한 원칙은 어느 레이어의 문제인지 특정한 뒤 조치하는 것입니다.

레이어마다 진단 도구가 다르고 담당 팀도 다릅니다. "어느 레이어에서 막혔는가"를 특정해야 정확한 팀에 에스컬레이션할 수 있습니다.

레이어진단 도구장애 증상담당
L1/L2 (물리/데이터링크)ip link, ethtoolNIC 다운, 케이블 단선네트워크/인프라팀
L3 (네트워크/라우팅)ping, traceroute, ip routeping 실패, 라우팅 없음네트워크팀
L4 (방화벽/포트)nc, telnet, 방화벽 로그nc 실패, 포트 차단보안팀/서버팀
L7 (애플리케이션)mysql -h, curl, 앱 로그인증 실패, SQL 오류개발팀/DBA

책임 구간 분리 실천 예시

[잘못된 접근]
담당자: "DB 접속이 안 되니 방화벽부터 열겠습니다"
→ 방화벽 열었지만 사실 MySQL이 죽어 있었음
→ 불필요한 보안 정책 변경 발생

[올바른 접근]
담당자: "ping 성공, nc 3306 실패, ss에 3306 없음
        → MySQL 데몬이 죽어 있는 것입니다"
→ systemctl start mysqld 로 즉시 해결
→ 방화벽 건드릴 필요 없음

에스컬레이션 메시지 품질 비교

[나쁜 에스컬레이션]
"DB 접속이 안 됩니다. 확인해 주세요."

[좋은 에스컬레이션]
"웹 서버(192.168.1.100)에서 DB 서버(192.168.1.200)로 연결 실패.
 ping: 성공 (L3 정상)
 nc -zv 192.168.1.200 3306: 실패 (L4 차단 또는 데몬 다운)
 DB 서버 ss 결과: 3306 리스닝 없음
 → MySQL 데몬 미실행 가능성 높음. DBA 확인 요청."

2. 실습: 4단계 장애 격리 수행

로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part6/exam_33 && cd /tmp/networking/part6/exam_33

mkdir -p /tmp/networking/part6/isolation && cd /tmp/networking/part6/isolation
cat > scenario.sh << 'EOF'
#!/bin/bash
# 웹→DB 연결 장애 시뮬레이션 환경 구성
echo "=== 장애 시나리오 환경 설정 ==="
# 로컬 mock 서비스 포트 정보
echo "Web layer: :8080 → Backend: :3000 → DB: :5432"
cat > check_layers.sh << 'INNER'
#!/bin/bash
echo "--- Layer 1: DNS ---"
nslookup localhost 2>/dev/null || echo "DNS: using /etc/hosts"

echo "--- Layer 2: Network Reachability ---"
ping -c 1 -W 1 127.0.0.1 &>/dev/null && echo "Loopback: OK" || echo "Loopback: FAIL"

echo "--- Layer 3: Port Check ---"
for port in 8080 3000 5432; do
  if nc -z -w1 127.0.0.1 $port 2>/dev/null; then
    echo "Port $port: OPEN"
  else
    echo "Port $port: CLOSED (service not running)"
  fi
done

echo "--- Layer 4: HTTP Check ---"
curl -sf --max-time 2 http://127.0.0.1:8080/health && echo "HTTP: OK" || echo "HTTP: not responding"
INNER
chmod +x check_layers.sh
echo "준비 완료. ./check_layers.sh 로 각 레이어 점검 시작"
EOF
chmod +x /tmp/networking/part6/isolation/scenario.sh
🔍실행 후 확인할 것
  • 핵심 출력명령 결과에서 성공/실패를 가르는 값을 먼저 확인합니다
  • 대상 식별IP, 포트, 인터페이스, 프로세스명처럼 다음 조치를 결정하는 필드를 봅니다
  • 다음 분기결과가 기대와 다르면 어느 계층을 이어서 점검할지 정합니다
1단계: ping — L3 라우팅 생사 확인

가장 먼저 DB 서버에 L3(IP) 레이어로 도달 가능한지 확인합니다. ping이 성공하면 물리 연결, 라우팅, ARP는 모두 정상입니다.

로컬 터미널
# 웹 서버에서 실행
ping -c 4 192.168.1.200

# 성공 케이스 — L3 정상
# PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data.
# 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.412 ms
# 64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=0.389 ms
# ...
# 4 packets transmitted, 4 received, 0% packet loss
# → ping 성공 → L3 정상 → 2단계로 진행

# 실패 케이스 — L3 문제
# PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data.
# ...
# 4 packets transmitted, 0 received, 100% packet loss
# → ping 실패 → L3 문제 확인 필요

ping 실패 시 추가 진단

로컬 터미널
# 라우팅 테이블 확인 — DB IP로 가는 경로 있는지
ip route show
ip route get 192.168.1.200

# 같은 서브넷인데 ping 실패라면 ARP 확인
arp -n | grep 192.168.1.200
# 항목 없음 → ARP 미해석 → 스위치/VLAN 문제

# 다른 서브넷이면 게이트웨이 경로 확인
ip route show | grep default
# default via 192.168.1.1 dev eth0 → 게이트웨이 확인

# 게이트웨이로 ping 테스트
ping -c 2 192.168.1.1

판정 기준

  • ping 성공 → "L3 정상, 2단계(L4)로 진행"
  • ping 실패 + 같은 서브넷 → "L2/스위치 문제 가능, 네트워크팀 확인"
  • ping 실패 + 다른 서브넷 → "게이트웨이/라우팅 문제, 네트워크팀 확인"
2단계: nc — L4 방화벽+포트 확인

ping이 성공했다면 실제 3306 포트로 TCP 연결이 가능한지 확인합니다.

로컬 터미널
# 웹 서버에서 실행
nc -zv -w 3 192.168.1.200 3306

# 성공 케이스 — 포트 열려 있음
# Connection to 192.168.1.200 3306 port [tcp/mysql] succeeded!
# → L4 정상 → 이 단계에서 문제가 없으면 애플리케이션 레이어(L7) 확인

# 실패 케이스 — 방화벽 차단 (DROP)
# nc: connect to 192.168.1.200 port 3306 (tcp) timed out: Operation now in progress
# → 타임아웃 = 방화벽 DROP → 방화벽 점검

# 실패 케이스 — 포트 닫힘 (REJECT 또는 데몬 없음)
# nc: connect to 192.168.1.200 port 3306 (tcp) failed: Connection refused
# → 즉시 거부 = 포트에 리스닝 없음 → 데몬 확인(3단계)

타임아웃 vs Connection Refused 구분이 중요한 이유

타임아웃 → 방화벽 DROP → DB 서버에서 패킷 자체를 못 받음
         → 방화벽 담당자에게 "3306 인바운드 허용" 요청

Connection Refused → 패킷은 DB 서버에 도달함 → DB 서버 OS가 거부
                  → 데몬이 없거나 다른 바인딩 주소 → 3단계로 진행

여러 포트 한번에 점검

로컬 터미널
# MySQL 기본 포트 외 다른 포트도 확인
for port in 3306 33060 33061; do
  echo -n "포트 $port: "
  nc -zv -w 3 192.168.1.200 $port 2>/dev/null && echo "열림" || echo "닫힘"
done
3단계: ss — DB 서버 데몬 기동 확인

nc가 실패했을 때 DB 서버에 직접 접속해 MySQL 프로세스가 3306 포트에서 리스닝 중인지 확인합니다.

로컬 터미널
# DB 서버에서 실행
ss -tulnp | grep 3306

# 정상 케이스 — MySQL 리스닝 중
# tcp LISTEN 0 128 0.0.0.0:3306 0.0.0.0:* users:(("mysqld",pid=1234,fd=21))
# → 데몬 정상 기동 → 방화벽이 차단 중인 것

# 문제 케이스 — 아무 출력 없음
# (출력 없음)
# → MySQL 데몬 미실행 → 서비스 시작 필요

# 문제 케이스 — 루프백에만 바인딩
# tcp LISTEN 0 128 127.0.0.1:3306 0.0.0.0:*
# → 바인딩 주소 문제 → bind-address = 0.0.0.0 으로 변경 필요

데몬 미실행 시 복구

위험 명령어

이 명령은 실행 중인 서비스 상태를 바꿔 순간적인 중단이나 설정 반영 실패를 만들 수 있습니다. 운영 트래픽 영향과 재시작 후 확인 명령을 먼저 준비하세요.

서버 터미널
# MySQL 상태 확인
systemctl status mysqld

# MySQL 시작
systemctl start mysqld

# 시작 후 리스닝 확인
ss -tulnp | grep 3306

# 자동 시작 설정
systemctl enable mysqld

# 시작 실패 시 오류 로그 확인
journalctl -u mysqld -n 50
# 또는
tail -50 /var/log/mysqld.log
tail -50 /var/log/mysql/error.log

포트는 리스닝 중인데 nc가 타임아웃인 경우 — 방화벽 확인

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# DB 서버에서 방화벽 규칙 확인
firewall-cmd --list-all         # CentOS
ufw status verbose              # Ubuntu
iptables -L INPUT -n -v | grep 3306

# 방화벽에 3306 추가 (CentOS)
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload
4단계: ip route + resolv.conf — 설정 꼬임 확인

앞선 3단계로 해결이 안 되거나, 간헐적 장애 또는 특정 방향만 안 되는 복잡한 상황에서는 라우팅과 DNS 설정을 확인합니다.

위험 명령어

이 명령은 서버의 라우팅 또는 인터페이스 설정을 바꿔 원격 접속이 끊길 수 있습니다. 콘솔 접근과 현재 라우팅 백업을 확보한 뒤 실행하세요.

로컬 터미널
# [라우팅 확인]
# 웹 서버에서 DB 서버로 가는 경로 확인
ip route show
# 기대 출력:
# default via 192.168.1.1 dev eth0        ← 기본 게이트웨이
# 192.168.1.0/24 dev eth0 proto kernel    ← 로컬 서브넷

ip route get 192.168.1.200
# 192.168.1.200 dev eth0 src 192.168.1.100  ← 직접 연결
# 또는
# 192.168.1.200 via 10.0.0.1 dev eth0       ← 게이트웨이 경유

# 비정상 케이스 — 기본 게이트웨이 없음
ip route show | grep default
# (아무 출력 없음)
# → 기본 게이트웨이 누락 → 다른 서브넷으로 못 감

# 게이트웨이 임시 추가
ip route add default via 192.168.1.1 dev eth0

# 영구 설정 (CentOS — /etc/sysconfig/network-scripts/ifcfg-eth0)
# GATEWAY=192.168.1.1

# 영구 설정 (nmcli)
nmcli connection modify eth0 ipv4.gateway 192.168.1.1
nmcli connection up eth0

# [DNS 확인]
cat /etc/resolv.conf
# nameserver 8.8.8.8     ← DNS 서버
# search company.com     ← 도메인 검색 접미사

# DNS로 DB 서버 이름 해석 테스트
nslookup db.internal
dig db.internal

# 호스트명으로 접속 시 IP 매핑 확인
cat /etc/hosts | grep db
# 192.168.1.200 db.internal  ← /etc/hosts에 직접 등록

3. 롤플레잉 시나리오

시나리오 1: 방화벽 차단

상황: 웹 서버를 새 서버로 이전 후 DB 연결 장애 발생

환경:
  웹 서버: 192.168.1.100 (신규)
  DB 서버: 192.168.1.200

단계별 진단 실행

로컬 터미널
# 웹 서버에서 실행

# 1단계: ping
ping -c 3 192.168.1.200
# 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.4 ms
# → ping 성공 ✓ L3 정상

# 2단계: nc
nc -zv -w 3 192.168.1.200 3306
# nc: connect to 192.168.1.200 port 3306 (tcp) timed out
# → 타임아웃! → 방화벽 DROP 의심

# 3단계: DB 서버에서 ss 확인 (DB 서버 로그인 후)
ss -tulnp | grep 3306
# tcp LISTEN 0 128 0.0.0.0:3306 0.0.0.0:*
# → 데몬 정상 리스닝 ✓

# 방화벽 확인
firewall-cmd --list-all
# ports: 22/tcp   ← 3306이 없다!

# 진단 결론: DB 서버 방화벽에서 3306이 차단됨
# 단, 예전 웹 서버(구 IP)는 rich rule로 허용되어 있었을 수 있음
firewall-cmd --list-rich-rules
# rule family="ipv4" source address="192.168.1.50" port port="3306" protocol="tcp" accept
# → 192.168.1.50(구 웹 서버)만 허용, 신규 192.168.1.100은 없음!

해결

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# DB 서버에서 신규 웹 서버 IP 허용 추가
firewall-cmd --zone=public \
  --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port protocol="tcp" port="3306" accept' \
  --permanent
firewall-cmd --reload

# 웹 서버에서 연결 재테스트
nc -zv -w 3 192.168.1.200 3306
# Connection to 192.168.1.200 3306 port [tcp/mysql] succeeded!
시나리오 2: MySQL 데몬 다운

상황: 새벽 정기 배치 작업 후 오전에 웹 서비스 DB 연결 오류 발생

로컬 터미널
# 웹 서버에서 단계별 진단

# 1단계: ping
ping -c 3 192.168.1.200
# 64 bytes from ... time=0.3 ms
# → ping 성공 ✓

# 2단계: nc
nc -zv -w 3 192.168.1.200 3306
# nc: connect to 192.168.1.200 port 3306 (tcp) failed: Connection refused
# → 즉시 거부! → DROP이 아니라 REJECT → 포트에 아무것도 없음

# 3단계: DB 서버에서 ss 확인
ss -tulnp | grep 3306
# (출력 없음)
# → MySQL이 전혀 리스닝하지 않음!

# MySQL 서비스 상태 확인
systemctl status mysqld
# ● mysqld.service - MySQL Server
#    Loaded: loaded (/usr/lib/systemd/system/mysqld.service)
#    Active: failed (Result: exit-code) since Mon 2024-01-15 03:42:11
# ...
# → 오전 3시 42분에 MySQL이 비정상 종료됨

# MySQL 오류 로그 확인
journalctl -u mysqld --since "2024-01-15 03:00:00" -n 50
# InnoDB: Table space file './ib_logfile0' size ...
# InnoDB: Could not find a valid checkpoint
# → 디스크 꽉 참으로 인한 InnoDB 손상 의심

해결

위험 명령어

이 명령은 실행 중인 서비스 상태를 바꿔 순간적인 중단이나 설정 반영 실패를 만들 수 있습니다. 운영 트래픽 영향과 재시작 후 확인 명령을 먼저 준비하세요.

로컬 터미널
# 디스크 확인
df -h
# /dev/sda1  100G  100G  0  100%  /   ← 꽉 참!

# 불필요한 파일 정리
find /var/log -name "*.log" -mtime +30 -delete
journalctl --vacuum-time=7d

# 공간 확보 후 MySQL 시작
systemctl start mysqld

# 시작 확인
ss -tulnp | grep 3306
# tcp LISTEN 0 128 0.0.0.0:3306 0.0.0.0:*  ← 복구됨

# 웹 서버에서 연결 확인
nc -zv -w 3 192.168.1.200 3306
# Connection to 192.168.1.200 3306 port [tcp/mysql] succeeded!
시나리오 3: 게이트웨이 날아감

상황: 네트워크 설정 변경 후 일부 서버에서 DB 접속 불가. 웹 서버와 DB 서버가 서로 다른 서브넷에 있는 경우.

환경:
  웹 서버: 10.0.1.100/24  (서브넷 A)
  DB 서버: 10.0.2.200/24  (서브넷 B — 다른 서브넷!)
  게이트웨이: 10.0.1.1
로컬 터미널
# 웹 서버에서 단계별 진단

# 1단계: ping
ping -c 3 10.0.2.200
# PING 10.0.2.200 (10.0.2.200) 56(84) bytes of data.
# ...
# 3 packets transmitted, 0 received, 100% packet loss
# → ping 실패! → L3 문제

# 같은 서브넷은 되는지 확인
ping -c 2 10.0.1.1    # 게이트웨이
# 64 bytes from 10.0.1.1 ... → 게이트웨이 ping 성공

ping -c 2 10.0.1.50   # 같은 서브넷의 다른 서버
# 64 bytes from 10.0.1.50 ... → 같은 서브넷 ping 성공

# 다른 서브넷(10.0.2.x)만 안 됨 → 라우팅 문제

# 4단계: 라우팅 테이블 확인
ip route show
# 10.0.1.0/24 dev eth0 proto kernel
# (default 항목 없음! 또는 게이트웨이가 다른 IP로 설정됨)
# → 기본 게이트웨이 누락!

ip route get 10.0.2.200
# RTNETLINK answers: Network is unreachable
# → 경로 없음 확인됨

# 라우팅 이력 확인
ip route show table all
journalctl -u NetworkManager --since "1 hour ago" | grep gateway

해결

위험 명령어

이 명령은 서버의 라우팅 또는 인터페이스 설정을 바꿔 원격 접속이 끊길 수 있습니다. 콘솔 접근과 현재 라우팅 백업을 확보한 뒤 실행하세요.

로컬 터미널
# 현재 설정된 게이트웨이 확인 (영구 설정 파일)
# CentOS
cat /etc/sysconfig/network-scripts/ifcfg-eth0 | grep GATEWAY
# (설정 없음 또는 잘못된 IP)

# nmcli로 확인
nmcli connection show eth0 | grep gateway

# 임시 게이트웨이 추가 (즉시 적용)
ip route add default via 10.0.1.1 dev eth0

# ping 재테스트
ping -c 3 10.0.2.200
# 64 bytes from 10.0.2.200 ... → 복구됨!

# 영구 적용
nmcli connection modify eth0 ipv4.gateway 10.0.1.1
nmcli connection up eth0

# DB 접속 최종 확인
nc -zv -w 3 10.0.2.200 3306
# Connection to 10.0.2.200 3306 port [tcp/mysql] succeeded!

4. 장애 사례 분석

증상

웹 개발자 신고: "DB 연결 오류납니다. jdbc:mysql://db.internal:3306"

단계별 진단

로컬 터미널
# 웹 서버에서
ping db.internal        # 성공 (DNS 해석 + L3 정상)
nc -zv -w 3 db.internal 3306
# timed out (타임아웃 — 방화벽 DROP)

# DB 서버에서
ss -tulnp | grep 3306
# (아무 출력 없음 — MySQL도 죽어 있음)

# 방화벽 상태
firewall-cmd --list-ports
# 22/tcp  (3306 없음)

분석

두 가지 문제가 동시 발생:

  1. MySQL 데몬 다운
  2. 방화벽에서 3306 미허용

타임아웃이 나타난 이유: 방화벽이 DROP하므로 MySQL 데몬 상태와 무관하게 타임아웃.

해결 순서

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

서버 터미널
# 1. MySQL 시작
systemctl start mysqld

# 2. 방화벽 3306 허용
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload

# 3. 최종 확인
ss -tulnp | grep 3306
nc -zv -w 3 db.internal 3306

교훈: 장애는 단일 원인이 아닐 수 있습니다. 각 단계를 모두 검증한 후 모든 문제를 확인하고 한꺼번에 해결해야 같은 작업을 반복하지 않습니다.

증상

로컬 터미널
# 웹 서버에서
ping 192.168.1.200      # 성공
nc -zv -w 3 192.168.1.200 3306  # 성공

# 그런데 앱 서버 로그
# Access denied for user 'appuser'@'192.168.1.100' (using password: YES)

원인 분석

L3, L4 레이어는 모두 정상입니다. MySQL의 사용자 권한 문제입니다 — L7 레이어.

DB 클라이언트
# DB 서버에서 MySQL 접속
mysql -u root -p
mysql> SELECT user, host FROM mysql.user WHERE user = 'appuser';
# +----------+-----------+
# | user     | host      |
# +----------+-----------+
# | appuser  | localhost |   ← localhost만 허용!
# +----------+-----------+
# 192.168.1.100(웹 서버)에서의 접속 권한이 없음

해결

DB 클라이언트
# MySQL에서 외부 접속 권한 추가
mysql> CREATE USER 'appuser'@'192.168.1.100' IDENTIFIED BY 'yourpassword';
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'192.168.1.100';
mysql> FLUSH PRIVILEGES;

# 또는 서브넷 전체 허용
mysql> CREATE USER 'appuser'@'192.168.1.%' IDENTIFIED BY 'yourpassword';

교훈: L3~L4 점검만으로 충분하지 않은 경우도 있습니다. "연결은 되지만 거부됨"은 L7(애플리케이션) 레이어 문제입니다. 장애 격리 4단계를 끝까지 수행하되, 앱 로그의 오류 메시지를 꼼꼼히 읽는 습관이 중요합니다.


5. 실무 현장 관점

💼
실무 맥락
현업 패턴

실무 현장에서의 장애 격리 습관

경험 많은 인프라 엔지니어들은 장애 신고를 받으면 무작정 "재시작해 보자"나 "방화벽 열어 보자"부터 하지 않습니다.

[시니어 엔지니어의 사고 흐름]

신고 접수: "DB 연결 안 됨"
    ↓
"언제부터? 변경 사항 있었나?" → 장애 시각 특정
    ↓
"ping부터 확인" → L3 결과 확인
    ↓
"nc로 포트 확인" → L4 결과 확인
    ↓
(결과에 따라) "DB 서버 ss 확인" 또는 "방화벽 확인"
    ↓
근본 원인(Root Cause) 특정 → 조치 → 재발 방지

장애 대응 중 기록 습관

로컬 터미널
# 실시간으로 기록하며 진단 (임시 파일)
exec > >(tee -a /tmp/incident-$(date +%Y%m%d-%H%M%S).log) 2>&1

echo "=== 장애 조사 시작: $(date) ==="
echo "신고 내용: 웹→DB 연결 불가"

echo "[1] ping 테스트"
ping -c 4 192.168.1.200

echo "[2] nc 포트 테스트"
nc -zv -w 3 192.168.1.200 3306

echo "[3] 라우팅 확인"
ip route show

# 이렇게 기록해 두면 사후 장애 보고서 작성이 쉬워짐

장애 보고서(Post-Mortem)에 포함되는 항목

  1. 장애 발생 시각 및 복구 시각 (분 단위)
  2. 영향 범위 (어떤 서비스, 몇 명의 사용자)
  3. 발견 경위 (자동 알림? 사용자 신고?)
  4. 진단 과정 (어떤 명령어로 원인을 찾았는지)
  5. 근본 원인 (방화벽 미설정, 디스크 부족, 게이트웨이 날아감 등)
  6. 조치 내용 (무엇을 어떻게 해결했는지)
  7. 재발 방지 (모니터링 추가, 자동화, 문서화 등)

커리어 관점에서

장애 격리 능력은 주니어와 시니어를 구분하는 핵심 역량 중 하나입니다. 논리적인 진단 과정을 문서화해서 보여줄 수 있는 엔지니어는 팀에서 신뢰를 얻습니다. 이 챕터의 4단계 방법론을 실제 장애 상황에서 반복 훈련하면 자연스럽게 몸에 배게 됩니다.


6. 장애 격리 4단계 명령어 요약

단계목적명령어성공 기준
1단계L3 라우팅 확인ping -c 4 [DB_IP]0% packet loss
2단계L4 방화벽+포트nc -zv -w 3 [DB_IP] 3306succeeded!
3단계데몬 기동 확인ss -tulnp | grep 3306리스닝 항목 있음
4단계라우팅/DNS 설정ip route show + cat /etc/resolv.confdefault via 항목 있음

추가 진단 명령어

목적명령어
특정 IP로 가는 경로 확인ip route get [IP]
DNS 이름 해석nslookup [호스트명]
게이트웨이 임시 추가ip route add default via [GW_IP] dev eth0
MySQL 재시작systemctl start mysqld
방화벽 3306 허용 (CentOS)firewall-cmd --add-port=3306/tcp --permanent && firewall-cmd --reload

정리

  • 장애 격리는 L3(ping) → L4(nc) → L7(ss/앱 로그) 순서로 올라간다
  • ping 성공 + nc 타임아웃 = 방화벽 DROP
  • ping 성공 + nc Connection Refused = 포트에 리스닝 없음
  • ss에 3306 없음 = 데몬 미실행 → systemctl start mysqld
  • ip route show에 default 없음 = 게이트웨이 누락 → 라우팅 추가
  • 책임 구간 분리: 정확한 레이어 특정 후 해당 담당자에게 에스컬레이션
  • 진단 과정을 기록하는 습관이 사후 보고서와 팀 신뢰를 만든다

지식 확인

퀴즈 — 5문제

Q1

웹 서버에서 DB 서버로 연결이 안 될 때, 첫 번째로 실행해야 할 진단 명령은?

Q2

ping은 성공하는데 `nc -zv DB_IP 3306`이 실패할 때 가능한 원인은?

Q3

DB 서버에서 `ss -tulnp | grep 3306` 출력이 없을 때의 의미와 조치는?

Q4

장애 격리의 핵심 원칙인 '책임 구간 분리'의 의미는?

Q5

게이트웨이 장애 시나리오에서 `ip route show`의 어떤 출력이 문제를 나타내는가?

0 / 5 답변

🧪 실습으로 확인하기

포트는 열렸다는데 왜 안 되지? — ss/netstat/telnet으로 TCP 진단

초급

"포트 8080 열었는데요?"와 "왜 안 돼요?" 사이의 간극을 메우는 실습. ss로 바인딩 상태를 확인하고, telnet/nc으로 원격 연결을 테스트하고, iptables 방화벽을 진단하고, 바인딩 주소(0.0.0.0 vs 127.0.0.1)까지 수정하는 4단계 TCP 포트 진단 플로우를 완성한다.

35📋 4단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

networking고급 · 60
[Network] 전통적인 VPN 한계 극복과 제로 트러스트(Zero Trust) 아키텍처
Networking 트랙 계속
docker입문 · 30
[Docker] 백엔드 개발자에게 Docker와 컨테이너 가상화가 필수인 이유
Docker 트랙 시작점