본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 5. · 10 Views
라우팅과 라우팅 프로토콜 완벽 가이드
네트워크에서 데이터가 목적지를 찾아가는 방법인 라우팅의 개념부터 정적/동적 라우팅, 그리고 RIP, OSPF, BGP 같은 주요 라우팅 프로토콜까지 초급 개발자도 쉽게 이해할 수 있도록 설명합니다.
목차
1. 라우터의 역할
김개발 씨는 회사에서 서버 간 통신이 안 된다는 장애 티켓을 받았습니다. 로그를 살펴보니 "Network unreachable"이라는 메시지가 보입니다.
선배 박시니어 씨에게 물어보니 "라우터 설정을 확인해봤어요?"라는 답이 돌아왔습니다. 라우터가 대체 무엇이길래 이렇게 중요한 걸까요?
**라우터(Router)**는 한마디로 네트워크의 교차로에서 교통정리를 하는 신호등과 같습니다. 서로 다른 네트워크를 연결하고, 데이터 패킷이 목적지까지 가장 효율적인 경로로 전달되도록 안내하는 장치입니다.
라우터가 없다면 우리가 보내는 데이터는 길을 잃고 헤매게 됩니다.
다음 코드를 살펴봅시다.
# 라우터의 기본 동작을 시뮬레이션하는 Python 코드
class SimpleRouter:
def __init__(self, name):
self.name = name
self.routing_table = {} # 라우팅 테이블 저장
def add_route(self, destination, next_hop, interface):
# 목적지 네트워크에 대한 경로 추가
self.routing_table[destination] = {
'next_hop': next_hop,
'interface': interface
}
def forward_packet(self, packet):
# 패킷의 목적지를 확인하고 적절한 경로로 전달
dest = packet['destination']
if dest in self.routing_table:
route = self.routing_table[dest]
print(f"패킷을 {route['interface']}로 전달: {dest}")
return route
print(f"경로를 찾을 수 없음: {dest}")
return None
김개발 씨는 입사 후 처음으로 네트워크 관련 장애를 맡게 되었습니다. 서버 A에서 서버 B로 데이터를 보내야 하는데, 아무리 시도해도 연결이 되지 않았습니다.
에러 메시지는 차갑게 "Network unreachable"만 반복했습니다. 선배 박시니어 씨가 다가와 상황을 살펴봅니다.
"혹시 라우터 설정을 확인해봤어요? 두 서버가 다른 네트워크에 있으면 라우터가 중간에서 연결해줘야 해요." 그렇다면 라우터란 정확히 무엇일까요?
쉽게 비유하자면, 라우터는 거대한 도시의 교차로에 서 있는 교통 경찰관과 같습니다. 수많은 차량이 각자의 목적지를 향해 달려올 때, 교통 경찰관은 각 차량이 어느 방향으로 가야 하는지 안내합니다.
서울에서 부산으로 가는 차량에게는 경부고속도로를, 대전으로 가는 차량에게는 다른 경로를 알려주는 것처럼요. 라우터도 마찬가지입니다.
네트워크에서 발생하는 수많은 데이터 패킷들이 라우터에 도착하면, 라우터는 각 패킷의 목적지 주소를 확인합니다. 그리고 자신이 가지고 있는 지도, 즉 라우팅 테이블을 참조하여 패킷을 어느 방향으로 보내야 할지 결정합니다.
라우터가 없던 시절에는 어땠을까요? 초기 네트워크에서는 모든 컴퓨터가 하나의 네트워크에 연결되어 있어야만 통신이 가능했습니다.
마치 같은 동네에 사는 사람들끼리만 대화할 수 있는 것과 같았습니다. 다른 동네 사람과 이야기하려면 직접 걸어가야 했죠.
하지만 네트워크가 커지면서 문제가 생겼습니다. 전 세계 모든 컴퓨터를 하나의 네트워크로 연결하는 것은 불가능했습니다.
그래서 네트워크를 작은 단위로 나누고, 그 사이를 라우터로 연결하는 방식이 등장했습니다. 위의 코드를 살펴보겠습니다.
SimpleRouter 클래스는 라우터의 핵심 기능을 보여줍니다. add_route 메서드로 "이 목적지로 가려면 이 경로를 사용해라"라는 정보를 추가하고, forward_packet 메서드에서 실제로 패킷을 전달합니다.
실제 현업에서 라우터는 훨씬 복잡한 역할을 수행합니다. 단순히 경로를 안내하는 것 외에도 NAT(Network Address Translation), 방화벽 기능, QoS(Quality of Service) 등 다양한 기능을 담당합니다.
클라우드 환경에서는 가상 라우터가 이 역할을 대신합니다. 주의할 점도 있습니다.
라우터는 네트워크의 핵심 장비이기 때문에, 잘못 설정하면 전체 네트워크가 마비될 수 있습니다. 따라서 라우터 설정을 변경할 때는 항상 백업을 하고, 가능하다면 테스트 환경에서 먼저 검증해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨와 함께 라우터 설정을 확인해보니, 서버 B가 속한 네트워크로 가는 경로가 누락되어 있었습니다.
경로를 추가하자 마법처럼 통신이 되기 시작했습니다.
실전 팁
💡 - 라우터는 OSI 7계층 중 3계층(네트워크 계층)에서 동작하며, IP 주소를 기반으로 경로를 결정합니다
- 가정용 공유기도 라우터의 일종이며, 내부 네트워크와 인터넷을 연결합니다
- 클라우드 환경에서는 VPC 라우팅 테이블로 동일한 역할을 수행합니다
2. 라우팅 테이블 이해
김개발 씨가 라우터의 역할을 이해하고 나니 새로운 궁금증이 생겼습니다. "라우터가 경로를 안내한다고 했는데, 그 경로 정보는 어디에 저장되어 있는 거예요?" 박시니어 씨가 웃으며 대답했습니다.
"좋은 질문이에요. 그게 바로 라우팅 테이블이에요."
**라우팅 테이블(Routing Table)**은 라우터가 참조하는 지도와 같습니다. 각 목적지 네트워크에 도달하기 위해 어떤 경로를 사용해야 하는지 정리해둔 표입니다.
마치 네비게이션이 지도 데이터를 가지고 있는 것처럼, 라우터는 라우팅 테이블을 가지고 패킷을 안내합니다.
다음 코드를 살펴봅시다.
# 라우팅 테이블 구조와 조회 예제
class RoutingTable:
def __init__(self):
# 라우팅 테이블: 목적지, 서브넷 마스크, 게이트웨이, 인터페이스, 메트릭
self.entries = []
def add_entry(self, destination, netmask, gateway, interface, metric):
entry = {
'destination': destination, # 목적지 네트워크
'netmask': netmask, # 서브넷 마스크
'gateway': gateway, # 다음 홉 주소
'interface': interface, # 출력 인터페이스
'metric': metric # 경로의 비용(거리)
}
self.entries.append(entry)
def lookup(self, dest_ip):
# 가장 긴 프리픽스 매칭으로 최적 경로 찾기
best_match = None
for entry in self.entries:
if self._matches(dest_ip, entry):
if not best_match or entry['metric'] < best_match['metric']:
best_match = entry
return best_match
김개발 씨는 터미널에서 netstat -rn 명령어를 입력해보았습니다. 화면에는 숫자와 IP 주소로 가득 찬 표가 나타났습니다.
이것이 바로 라우팅 테이블입니다. 처음 보면 복잡해 보이지만, 구조를 이해하면 의외로 단순합니다.
라우팅 테이블을 이해하기 위해 우체국을 떠올려 봅시다. 우체국에는 각 지역별로 어떤 배송 경로를 사용해야 하는지 정리한 표가 있습니다.
"서울 강남구로 가는 우편물은 A 트럭에", "부산 해운대구로 가는 우편물은 B 트럭에"라고 정리되어 있죠. 라우팅 테이블도 이와 똑같습니다.
라우팅 테이블의 각 행은 하나의 경로를 나타냅니다. 주요 구성 요소를 살펴보겠습니다.
**목적지(Destination)**는 패킷이 도달해야 하는 네트워크 주소입니다. 예를 들어 "192.168.1.0"은 192.168.1.x로 시작하는 모든 IP 주소를 의미합니다.
**서브넷 마스크(Netmask)**는 목적지 주소의 범위를 정의합니다. "/24" 또는 "255.255.255.0"과 같이 표현됩니다.
**게이트웨이(Gateway)**는 다음에 패킷을 전달할 라우터의 주소입니다. 마치 "다음 정거장"과 같습니다.
최종 목적지가 아니라 중간 경유지를 가리킵니다. **인터페이스(Interface)**는 패킷을 내보낼 네트워크 카드를 의미합니다.
eth0, eth1과 같은 이름으로 표시됩니다. 마지막으로 **메트릭(Metric)**은 경로의 비용이나 거리를 나타냅니다.
같은 목적지로 가는 여러 경로가 있을 때, 메트릭이 낮은 경로가 우선적으로 선택됩니다. 위의 코드에서 lookup 메서드를 보면, 라우터가 패킷을 받았을 때 어떻게 경로를 찾는지 알 수 있습니다.
먼저 목적지 IP가 테이블의 어느 항목과 일치하는지 확인합니다. 여러 항목이 일치하면 가장 구체적인(가장 긴 프리픽스) 경로를 선택합니다.
실무에서 라우팅 테이블을 확인하는 상황은 자주 발생합니다. 서버가 특정 네트워크와 통신이 안 될 때, 가장 먼저 확인하는 것이 라우팅 테이블입니다.
리눅스에서는 ip route 명령어로, 윈도우에서는 route print 명령어로 확인할 수 있습니다. 주의할 점은 라우팅 테이블에 **기본 경로(Default Route)**가 반드시 있어야 한다는 것입니다.
기본 경로는 "0.0.0.0/0"으로 표시되며, 다른 모든 경로와 일치하지 않는 패킷을 처리합니다. 기본 경로가 없으면 알려지지 않은 목적지로 향하는 패킷은 모두 버려집니다.
김개발 씨는 라우팅 테이블을 확인하고 문제의 원인을 찾았습니다. 기본 게이트웨이 설정이 잘못되어 있었던 것입니다.
올바른 게이트웨이 주소로 수정하자 모든 것이 정상으로 돌아왔습니다.
실전 팁
💡 - 리눅스에서 ip route show 명령어로 현재 라우팅 테이블을 확인할 수 있습니다
- 가장 구체적인 경로(Longest Prefix Match)가 항상 우선 선택됩니다
- 임시로 경로를 추가할 때는
ip route add명령어를, 영구 설정은 네트워크 설정 파일을 수정합니다
3. 정적 라우팅
박시니어 씨가 김개발 씨에게 물었습니다. "그런데 라우팅 테이블의 경로 정보는 어디서 온 걸까요?" 김개발 씨가 잠시 생각하다가 대답했습니다.
"누군가가 직접 입력한 거 아닌가요?" 박시니어 씨가 고개를 끄덕였습니다. "맞아요, 그게 바로 정적 라우팅이에요."
**정적 라우팅(Static Routing)**은 네트워크 관리자가 직접 경로 정보를 수동으로 입력하는 방식입니다. 마치 종이 지도에 직접 빨간 펜으로 경로를 그려 넣는 것과 같습니다.
단순하고 예측 가능하지만, 네트워크 구조가 변경되면 관리자가 일일이 수정해야 합니다.
다음 코드를 살펴봅시다.
# 정적 라우팅 설정 예제 (Python으로 시뮬레이션)
import subprocess
class StaticRouting:
def __init__(self):
self.routes = []
def add_static_route(self, destination, gateway, interface):
# 수동으로 경로 추가 (관리자가 직접 설정)
route = {
'destination': destination,
'gateway': gateway,
'interface': interface,
'type': 'static' # 정적 라우팅 표시
}
self.routes.append(route)
# 실제 시스템에서는 아래 명령어 실행
# subprocess.run(['ip', 'route', 'add', destination, 'via', gateway])
print(f"정적 경로 추가: {destination} -> {gateway}")
def remove_static_route(self, destination):
# 경로 제거도 수동으로 해야 함
self.routes = [r for r in self.routes if r['destination'] != destination]
print(f"정적 경로 제거: {destination}")
김개발 씨가 처음 네트워크를 구축할 때, 가장 직관적인 방법은 직접 경로를 설정하는 것입니다. "A 네트워크로 가려면 B 라우터를 거쳐라"라고 명시적으로 지정하는 것이죠.
이것이 바로 정적 라우팅입니다. 정적 라우팅을 이해하기 위해 조선시대 역참 제도를 떠올려 봅시다.
한양에서 부산까지 파발을 보내려면, 사전에 정해진 역참 경로를 따라 달려야 했습니다. 중간에 다리가 끊어지거나 길이 막혀도 정해진 경로를 벗어날 수 없었습니다.
경로를 바꾸려면 조정에서 새로운 명령을 내려야 했죠. 정적 라우팅도 마찬가지입니다.
관리자가 "이 목적지로 가려면 이 경로를 사용해라"라고 직접 설정합니다. 라우터는 그 설정을 그대로 따릅니다.
중간 경로에 문제가 생겨도 스스로 다른 경로를 찾지 못합니다. 그렇다면 정적 라우팅의 장점은 무엇일까요?
첫째, 단순함입니다. 설정이 직관적이고 이해하기 쉽습니다.
네트워크 구조가 간단하다면 정적 라우팅만으로도 충분합니다. 둘째, 예측 가능성입니다.
관리자가 설정한 대로만 동작하므로, 패킷이 어떤 경로로 전달되는지 정확히 알 수 있습니다. 보안이 중요한 환경에서는 이것이 큰 장점입니다.
셋째, 낮은 리소스 사용입니다. 동적 라우팅과 달리 라우터끼리 경로 정보를 교환하지 않으므로, CPU와 대역폭을 절약할 수 있습니다.
하지만 단점도 명확합니다. 가장 큰 단점은 확장성 부족입니다.
네트워크가 커질수록 관리해야 할 경로가 기하급수적으로 늘어납니다. 라우터가 10대, 100대가 되면 일일이 설정하는 것이 사실상 불가능해집니다.
또한 장애 대응이 어렵습니다. 중간 경로에 문제가 생겨도 라우터는 스스로 우회 경로를 찾지 못합니다.
관리자가 문제를 발견하고 수동으로 경로를 변경해야 합니다. 실무에서 정적 라우팅은 주로 소규모 네트워크나 특수한 상황에서 사용됩니다.
예를 들어 본사와 지사를 연결하는 전용선이 하나뿐이라면, 굳이 동적 라우팅을 사용할 필요가 없습니다. 또한 보안상 경로가 고정되어야 하는 경우에도 정적 라우팅을 선택합니다.
김개발 씨의 회사는 아직 소규모라서 정적 라우팅으로 충분했습니다. 하지만 박시니어 씨는 말했습니다.
"회사가 성장하면 동적 라우팅을 고려해야 할 거예요."
실전 팁
💡 - 소규모 네트워크나 스텁 네트워크(하나의 출구만 있는 네트워크)에서 정적 라우팅이 적합합니다
- 정적 라우팅은 동적 라우팅보다 관리 우선순위(Administrative Distance)가 낮아 우선 적용됩니다
- 장애 대비를 위해 정적 경로에 백업 경로를 설정해두는 것이 좋습니다
4. 동적 라우팅
회사가 성장하면서 김개발 씨의 고민도 커졌습니다. 지사가 늘어나고 네트워크가 복잡해지면서, 정적 라우팅만으로는 관리가 불가능해졌습니다.
박시니어 씨가 조언했습니다. "이제 동적 라우팅을 도입할 때가 됐어요.
라우터들이 알아서 경로를 찾도록 해야 해요."
**동적 라우팅(Dynamic Routing)**은 라우터들이 서로 정보를 교환하여 자동으로 최적의 경로를 찾는 방식입니다. 마치 택시 기사들이 실시간으로 교통 정보를 공유하며 가장 빠른 길을 찾는 것과 같습니다.
네트워크 구조가 변경되면 라우터들이 스스로 새로운 경로를 학습합니다.
다음 코드를 살펴봅시다.
# 동적 라우팅 기본 개념 시뮬레이션
class DynamicRouter:
def __init__(self, router_id):
self.router_id = router_id
self.neighbors = [] # 이웃 라우터 목록
self.routing_table = {} # 동적으로 학습된 경로
def discover_neighbors(self):
# 이웃 라우터 자동 발견 (Hello 패킷 교환)
print(f"라우터 {self.router_id}: 이웃 탐색 중...")
for neighbor in self.neighbors:
print(f" - {neighbor.router_id} 발견!")
def exchange_routes(self):
# 이웃과 라우팅 정보 교환
for neighbor in self.neighbors:
received_routes = neighbor.get_routes()
for dest, info in received_routes.items():
if dest not in self.routing_table:
self.routing_table[dest] = info
print(f"새 경로 학습: {dest}")
def handle_link_failure(self, failed_link):
# 링크 장애 시 자동으로 대체 경로 탐색
print(f"링크 장애 감지: {failed_link}")
self.recalculate_routes()
김개발 씨가 정적 라우팅으로 100개의 경로를 관리하다 보니 머리가 지끈거렸습니다. 새 지사가 추가될 때마다 모든 라우터의 설정을 변경해야 했고, 링크 장애가 발생하면 새벽에도 전화가 울렸습니다.
분명 더 좋은 방법이 있을 것 같았습니다. 동적 라우팅은 이런 고통에서 벗어나게 해주는 마법 같은 기술입니다.
동적 라우팅을 이해하기 위해 개미의 행동을 관찰해 봅시다. 개미들은 페로몬을 통해 정보를 공유합니다.
한 개미가 먹이를 발견하면 페로몬을 남기고, 다른 개미들은 그 흔적을 따라갑니다. 장애물이 생기면 자연스럽게 우회 경로를 찾아 새로운 페로몬 길을 만듭니다.
동적 라우팅도 비슷합니다. 라우터들은 라우팅 프로토콜이라는 공통 언어로 서로 정보를 교환합니다.
"나는 A 네트워크와 연결되어 있어", "B 네트워크로 가려면 나를 거쳐가면 돼"라는 정보를 주고받죠. 이 과정은 크게 세 단계로 이루어집니다.
첫째, 이웃 발견입니다. 라우터들은 주기적으로 Hello 패킷을 보내 주변에 어떤 라우터가 있는지 파악합니다.
마치 새로 이사 온 집에서 이웃에게 인사를 하는 것과 같습니다. 둘째, 경로 교환입니다.
이웃을 알게 된 라우터들은 자신이 알고 있는 경로 정보를 공유합니다. 처음에는 자신과 직접 연결된 네트워크만 알지만, 시간이 지나면 네트워크 전체의 구조를 파악하게 됩니다.
셋째, 최적 경로 계산입니다. 수집된 정보를 바탕으로 각 목적지까지 가장 효율적인 경로를 계산합니다.
여러 경로가 있다면 가장 비용이 낮은 경로를 선택합니다. 동적 라우팅의 가장 큰 장점은 자동 복구입니다.
중간 경로에 장애가 발생하면, 라우터들은 이를 감지하고 자동으로 우회 경로를 찾습니다. 관리자가 새벽에 일어날 필요가 없습니다.
또한 확장성이 뛰어납니다. 새 네트워크가 추가되어도 해당 라우터만 설정하면 됩니다.
나머지 라우터들은 자동으로 새 경로를 학습합니다. 물론 단점도 있습니다.
라우터들이 정보를 교환하면서 네트워크 대역폭과 CPU 리소스를 사용합니다. 또한 설정이 복잡하고, 잘못 구성하면 라우팅 루프와 같은 문제가 발생할 수 있습니다.
김개발 씨는 동적 라우팅을 도입한 후 훨씬 편안해졌습니다. 새 지사가 추가되어도 해당 라우터 설정만 하면 되었고, 링크 장애가 발생해도 시스템이 알아서 우회 경로를 찾았습니다.
실전 팁
💡 - 동적 라우팅 프로토콜은 IGP(내부)와 EGP(외부)로 크게 나뉩니다
- 컨버전스 타임(모든 라우터가 동일한 경로 정보를 갖게 되는 시간)이 중요한 성능 지표입니다
- 동적 라우팅과 정적 라우팅을 함께 사용하는 하이브리드 방식도 일반적입니다
5. IGP RIP 프로토콜
박시니어 씨가 동적 라우팅 프로토콜에 대해 설명하기 시작했습니다. "가장 오래되고 단순한 프로토콜부터 알아볼까요?
RIP라고 들어봤어요?" 김개발 씨가 고개를 저었습니다. "처음 들어요.
무슨 약자인가요?"
**RIP(Routing Information Protocol)**은 가장 오래된 동적 라우팅 프로토콜 중 하나입니다. 거리 벡터(Distance Vector) 방식을 사용하며, 목적지까지의 **홉 수(hop count)**를 기준으로 최적 경로를 결정합니다.
설정이 간단하지만, 대규모 네트워크에는 적합하지 않습니다.
다음 코드를 살펴봅시다.
# RIP 프로토콜 동작 시뮬레이션
class RIPRouter:
MAX_HOP = 15 # RIP의 최대 홉 수 제한
def __init__(self, router_id):
self.router_id = router_id
self.routing_table = {} # {목적지: {'next_hop': .., 'metric': hop수}}
def receive_update(self, from_router, routes):
# 이웃으로부터 라우팅 업데이트 수신
for dest, metric in routes.items():
new_metric = metric + 1 # 홉 수 1 증가
if new_metric > self.MAX_HOP:
continue # 최대 홉 초과 시 무시 (도달 불가)
if dest not in self.routing_table:
self.routing_table[dest] = {'next_hop': from_router, 'metric': new_metric}
print(f"새 경로 추가: {dest} (홉: {new_metric})")
elif new_metric < self.routing_table[dest]['metric']:
# 더 짧은 경로 발견
self.routing_table[dest] = {'next_hop': from_router, 'metric': new_metric}
print(f"경로 업데이트: {dest} (홉: {new_metric})")
def broadcast_routes(self):
# 30초마다 전체 라우팅 테이블 브로드캐스트
return {dest: info['metric'] for dest, info in self.routing_table.items()}
RIP은 1988년에 표준화된 프로토콜로, 동적 라우팅의 역사에서 원조 격입니다. 단순함이 최대의 장점이자 한계이기도 합니다.
RIP의 동작 원리를 이해하기 위해 입소문을 떠올려 봅시다. 작은 마을에서 소문이 어떻게 퍼지는지 생각해보세요.
A가 B에게 이야기하고, B가 C에게 전달하고, C가 D에게 전달합니다. 각 사람은 "누구에게서 들었고, 몇 번 거쳐서 왔는지"만 기억합니다.
RIP도 마찬가지입니다. 각 라우터는 이웃에게서 받은 경로 정보에 1을 더해서 다시 이웃에게 전달합니다.
이것이 바로 거리 벡터 방식입니다. 목적지까지 "얼마나 멀리 있는지(거리)"와 "어느 방향으로 가야 하는지(벡터)"만 알면 됩니다.
RIP에서 거리를 측정하는 단위는 **홉(hop)**입니다. 홉은 라우터를 하나 거칠 때마다 1씩 증가합니다.
예를 들어 A 라우터에서 D 네트워크까지 가는 데 라우터 3개를 거친다면, 메트릭은 3입니다. 위의 코드에서 receive_update 메서드를 보면 RIP의 핵심 로직을 알 수 있습니다.
이웃에게서 경로 정보를 받으면 홉 수에 1을 더합니다. 그리고 기존 경로보다 홉 수가 적으면 새 경로로 교체합니다.
RIP의 특징적인 동작 방식이 있습니다. 주기적 업데이트입니다.
모든 라우터는 30초마다 자신의 전체 라우팅 테이블을 이웃에게 브로드캐스트합니다. 변경이 없어도 계속 보냅니다.
최대 홉 제한입니다. RIP은 최대 15홉까지만 지원합니다.
16홉은 "도달 불가능"을 의미합니다. 이 때문에 대규모 네트워크에서는 사용할 수 없습니다.
느린 수렴 속도입니다. 네트워크에 변화가 생기면 모든 라우터가 새 정보를 학습하는 데 시간이 걸립니다.
최악의 경우 몇 분이 소요될 수 있습니다. RIP의 가장 큰 문제는 **카운트 투 인피니티(Count to Infinity)**입니다.
링크 장애가 발생했을 때, 잘못된 정보가 네트워크를 계속 돌면서 홉 수가 끊임없이 증가하는 현상입니다. 이를 해결하기 위해 Split Horizon, Poison Reverse 같은 기법이 사용됩니다.
현재 RIP은 거의 사용되지 않습니다. 하지만 라우팅 프로토콜의 기본 원리를 이해하는 데는 좋은 교재입니다.
김개발 씨도 RIP을 먼저 공부함으로써 더 복잡한 프로토콜을 이해할 기반을 다졌습니다.
실전 팁
💡 - RIP v1은 클래스풀 라우팅만 지원하고, RIP v2는 CIDR과 인증을 지원합니다
- 홉 수만 고려하므로 대역폭이 다른 링크를 구분하지 못합니다
- 현재는 교육 목적이나 매우 소규모 네트워크에서만 사용됩니다
6. IGP OSPF 프로토콜
김개발 씨가 RIP의 한계를 알고 나니 궁금해졌습니다. "그럼 실제 기업에서는 어떤 프로토콜을 쓰나요?" 박시니어 씨가 대답했습니다.
"대부분의 기업 네트워크에서는 OSPF를 사용해요. RIP보다 훨씬 똑똑하고 빠르거든요."
**OSPF(Open Shortest Path First)**는 링크 상태(Link State) 방식을 사용하는 라우팅 프로토콜입니다. 각 라우터가 네트워크 전체의 지도를 가지고 있으며, 다익스트라 알고리즘을 사용하여 최단 경로를 계산합니다.
대규모 기업 네트워크의 표준으로 사용됩니다.
다음 코드를 살펴봅시다.
# OSPF 프로토콜 기본 개념 시뮬레이션
import heapq
class OSPFRouter:
def __init__(self, router_id):
self.router_id = router_id
self.link_state_db = {} # 전체 네트워크 토폴로지 정보
self.neighbors = {} # 이웃 라우터와 링크 비용
def add_link(self, neighbor_id, cost):
# 링크 상태 정보 추가 (대역폭 기반 비용)
self.neighbors[neighbor_id] = cost
self.link_state_db[(self.router_id, neighbor_id)] = cost
def calculate_shortest_path(self, destination):
# 다익스트라 알고리즘으로 최단 경로 계산
distances = {self.router_id: 0}
pq = [(0, self.router_id)] # (거리, 노드)
while pq:
current_dist, current = heapq.heappop(pq)
if current == destination:
return current_dist
for (src, dst), cost in self.link_state_db.items():
if src == current:
new_dist = current_dist + cost
if dst not in distances or new_dist < distances[dst]:
distances[dst] = new_dist
heapq.heappush(pq, (new_dist, dst))
return float('inf')
RIP이 소문에 의존하는 방식이라면, OSPF는 모든 사람이 같은 지도를 보는 방식입니다. OSPF를 이해하기 위해 항공사의 운항 시스템을 떠올려 봅시다.
모든 조종사는 동일한 항공 지도를 가지고 있습니다. 공항의 위치, 항로, 각 구간의 비행 시간이 모두 기록되어 있죠.
목적지가 정해지면 지도를 보고 가장 빠른 경로를 계산합니다. OSPF도 마찬가지입니다.
모든 라우터는 **LSDB(Link State Database)**라는 동일한 네트워크 지도를 가집니다. 이 지도에는 모든 라우터와 링크, 그리고 각 링크의 비용이 기록되어 있습니다.
OSPF의 동작 과정을 단계별로 살펴보겠습니다. 첫째, 이웃 관계 수립입니다.
라우터들은 Hello 패킷을 교환하여 이웃을 발견합니다. 이 과정에서 DR(Designated Router)과 BDR(Backup DR)이 선출됩니다.
둘째, LSA 교환입니다. 각 라우터는 자신과 연결된 링크 정보를 담은 **LSA(Link State Advertisement)**를 생성합니다.
이 LSA는 네트워크 전체로 플러딩(flooding)됩니다. 셋째, LSDB 동기화입니다.
모든 라우터가 동일한 LSA를 받으면, 동일한 LSDB를 갖게 됩니다. 마치 모든 사람이 같은 지도를 보는 것과 같습니다.
넷째, SPF 계산입니다. 각 라우터는 자신을 루트로 하는 최단 경로 트리를 계산합니다.
이때 사용되는 것이 바로 다익스트라(Dijkstra) 알고리즘입니다. 위의 코드에서 calculate_shortest_path 메서드가 바로 다익스트라 알고리즘을 구현한 것입니다.
우선순위 큐를 사용하여 가장 가까운 노드부터 탐색합니다. OSPF의 장점은 명확합니다.
빠른 수렴입니다. 변경 사항이 발생하면 해당 LSA만 즉시 전파됩니다.
RIP처럼 30초를 기다릴 필요가 없습니다. 효율적인 대역폭 사용입니다.
변경이 없으면 주기적인 업데이트가 거의 없습니다. 전체 테이블을 매번 보내는 RIP과 다릅니다.
확장성입니다. OSPF는 네트워크를 Area로 나눌 수 있습니다.
각 Area 내에서만 LSA가 전파되므로, 아주 큰 네트워크도 효율적으로 관리할 수 있습니다. 비용 기반 라우팅입니다.
홉 수가 아닌 링크의 대역폭을 고려합니다. 1Gbps 링크와 100Mbps 링크를 구분할 수 있습니다.
김개발 씨의 회사는 OSPF를 도입한 후 네트워크 장애 복구 시간이 획기적으로 줄었습니다. 링크 장애가 발생해도 몇 초 안에 우회 경로가 활성화되었습니다.
실전 팁
💡 - OSPF의 기본 비용 계산 공식은 10^8 / 대역폭(bps)입니다
- Area 0(백본 영역)이 반드시 존재해야 하며, 다른 Area들은 Area 0과 연결되어야 합니다
- OSPFv2는 IPv4, OSPFv3는 IPv6를 지원합니다
7. EGP BGP 프로토콜
김개발 씨가 OSPF까지 이해하고 나니, 한 가지 의문이 생겼습니다. "그런데 우리 회사 네트워크와 인터넷은 어떻게 연결되는 거예요?
OSPF로요?" 박시니어 씨가 고개를 저었습니다. "아니요, 인터넷과 연결할 때는 완전히 다른 프로토콜을 써요.
BGP라고 해요. 인터넷의 척추와도 같은 프로토콜이죠."
**BGP(Border Gateway Protocol)**는 인터넷을 구성하는 자율 시스템(AS) 간의 라우팅을 담당하는 프로토콜입니다. 경로 벡터(Path Vector) 방식을 사용하며, 단순히 최단 경로가 아닌 **정책(Policy)**에 따라 경로를 선택합니다.
인터넷의 핵심 인프라를 이루는 유일한 EGP입니다.
다음 코드를 살펴봅시다.
# BGP 기본 개념 시뮬레이션
class BGPRouter:
def __init__(self, as_number):
self.as_number = as_number # 자율 시스템 번호
self.peers = [] # BGP 피어(이웃 AS)
self.routing_table = {} # 경로 정보
self.policies = {} # 라우팅 정책
def receive_update(self, prefix, as_path, next_hop):
# 경로 정보 수신 및 루프 감지
if self.as_number in as_path:
print(f"루프 감지: AS {self.as_number}가 경로에 존재")
return # 자신의 AS가 경로에 있으면 무시
# 정책에 따른 경로 필터링
if not self.apply_import_policy(prefix, as_path):
return
new_path = [self.as_number] + as_path # AS 경로에 자신 추가
self.routing_table[prefix] = {
'as_path': new_path,
'next_hop': next_hop
}
print(f"경로 수신: {prefix} via {as_path}")
def select_best_path(self, prefix):
# BGP 경로 선택 알고리즘 (간략화)
# 1. 가장 짧은 AS_PATH 선호
# 2. 낮은 ORIGIN 선호
# 3. 정책 기반 Local Preference 등
pass
지금까지 배운 RIP과 OSPF는 모두 **IGP(Interior Gateway Protocol)**입니다. 하나의 조직 내부에서 사용하는 프로토콜이죠.
하지만 인터넷은 수많은 조직의 네트워크가 연결된 거대한 망입니다. 이런 조직 간 연결에는 **EGP(Exterior Gateway Protocol)**가 필요합니다.
그리고 사실상 유일한 EGP가 바로 BGP입니다. BGP를 이해하기 위해 국제 항공 노선을 떠올려 봅시다.
각 나라의 항공사는 자국 내 노선을 자유롭게 운영합니다. 하지만 국제선은 다릅니다.
국가 간 협정, 항공 정책, 비용 등 다양한 요소를 고려해야 합니다. 때로는 가장 짧은 경로가 아닌 다른 경로를 선택하기도 합니다.
BGP도 마찬가지입니다. 인터넷에서 각 조직의 네트워크는 **AS(Autonomous System)**라고 불립니다.
각 AS는 고유한 **ASN(AS Number)**을 가집니다. 구글은 AS15169, 아마존은 AS16509와 같이요.
BGP의 핵심 특징은 경로 벡터(Path Vector) 방식입니다. 단순히 목적지까지의 거리가 아니라, 어떤 AS들을 거쳐 가는지 전체 경로를 기록합니다.
이것을 AS_PATH라고 합니다. 위의 코드에서 receive_update 메서드를 보면, as_path에 자신의 AS 번호가 있는지 확인합니다.
만약 있다면 그 경로는 루프를 형성하므로 무시합니다. 이것이 BGP의 루프 방지 메커니즘입니다.
BGP의 또 다른 특징은 정책 기반 라우팅입니다. OSPF가 항상 최단 경로를 선택한다면, BGP는 관리자가 정의한 정책에 따라 경로를 선택합니다.
비용, 성능, 정치적 이유 등 다양한 요소가 고려됩니다. 예를 들어 한국에서 미국으로 데이터를 보낼 때, 물리적으로는 일본을 거치는 것이 가까울 수 있습니다.
하지만 비용 정책에 따라 홍콩을 경유하는 경로가 선택될 수도 있습니다. BGP에는 두 가지 유형이 있습니다.
**eBGP(External BGP)**는 서로 다른 AS 간의 연결입니다. 인터넷 서비스 제공자(ISP)끼리, 또는 기업과 ISP 간의 연결에 사용됩니다.
**iBGP(Internal BGP)**는 같은 AS 내부에서 BGP 정보를 전달하는 데 사용됩니다. AS 내부의 라우터들이 외부에서 받은 BGP 정보를 공유합니다.
BGP는 인터넷의 안정성에 매우 중요합니다. BGP 설정 오류로 인한 사고는 역사적으로 여러 번 있었습니다.
2008년 파키스탄 텔레콤이 YouTube를 차단하려다 전 세계 YouTube 접속을 마비시킨 사건이 대표적입니다. 김개발 씨는 BGP의 복잡함에 놀랐습니다.
하지만 박시니어 씨가 말했습니다. "BGP를 직접 다루는 경우는 많지 않아요.
하지만 클라우드에서 Multi-Region 아키텍처를 설계하거나 CDN을 이해할 때 BGP 지식이 도움이 됩니다."
실전 팁
💡 - BGP는 TCP 포트 179를 사용하며, 신뢰성 있는 연결을 유지합니다
- 경로 선택 시 AS_PATH 길이가 짧은 경로가 기본적으로 선호됩니다
- 클라우드 환경에서 Direct Connect, ExpressRoute 같은 전용선 연결에도 BGP가 사용됩니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
Spring Cloud Gateway 완벽 가이드
MSA 환경에서 필수적인 API Gateway 패턴을 Spring Cloud Gateway로 구현하는 방법을 배웁니다. 라우팅, 필터, Predicate 등 핵심 개념을 실무 예제와 함께 쉽게 설명합니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.