Segment Routing กับ Distributed System ทำงานร่วมกันอย่างไร
Distributed System ต้องการ network ที่มีความน่าเชื่อถือสูง latency ต่ำ และสามารถ route traffic ไปยังปลายทางที่ถูกต้องได้อย่างรวดเร็ว Segment Routing ตอบโจทย์เหล่านี้ด้วยการลดความซับซ้อนของ control plane กำจัด protocol state ที่ไม่จำเป็นออก และให้ความสามารถ Traffic Engineering ผ่าน source routing
ใน Data Center Fabric ที่รัน distributed system เช่น Kubernetes cluster, Kafka cluster หรือ Cassandra ring การใช้ Segment Routing ช่วยให้ network engineer สามารถกำหนด path ของ traffic ได้ชัดเจน ลด hop count สำหรับ latency-sensitive workload และทำ load balancing ข้าม multiple paths ได้อย่างมีประสิทธิภาพ
SR-MPLS เหมาะสำหรับ Data Center ที่มี MPLS infrastructure อยู่แล้ว ส่วน SRv6 เหมาะสำหรับ Data Center ใหม่ที่ต้องการ Network Programming capability เช่น Service Function Chaining ที่ traffic ต้องผ่าน Firewall, Load Balancer และ DPI ตามลำดับที่กำหนด
สถาปัตยกรรมทั่วไปสำหรับ Distributed System ที่ใช้ Segment Routing ประกอบด้วย Spine-Leaf Fabric, BGP-based Underlay, SR-MPLS หรือ SRv6 Overlay และ SDN Controller ที่จัดการ SR Policy
ออกแบบ Network Topology สำหรับ Distributed System
Spine-Leaf Topology เป็นรูปแบบมาตรฐานสำหรับ Data Center ที่รัน distributed system เพราะให้ predictable latency และ equal-cost paths ระหว่างทุก leaf switch
# network-topology.yaml — Containerlab Topology สำหรับ Distributed System Lab
name: sr-distributed-lab
topology:
kinds:
linux:
image: frrouting/frr:v9.1.0
nodes:
# Spine Layer
spine1:
kind: linux
binds:
- configs/spine1/frr.conf:/etc/frr/frr.conf
- configs/spine1/daemons:/etc/frr/daemons
spine2:
kind: linux
binds:
- configs/spine2/frr.conf:/etc/frr/frr.conf
- configs/spine2/daemons:/etc/frr/daemons
# Leaf Layer
leaf1:
kind: linux
binds:
- configs/leaf1/frr.conf:/etc/frr/frr.conf
- configs/leaf1/daemons:/etc/frr/daemons
leaf2:
kind: linux
binds:
- configs/leaf2/frr.conf:/etc/frr/frr.conf
- configs/leaf2/daemons:/etc/frr/daemons
leaf3:
kind: linux
binds:
- configs/leaf3/frr.conf:/etc/frr/frr.conf
- configs/leaf3/daemons:/etc/frr/daemons
leaf4:
kind: linux
binds:
- configs/leaf4/frr.conf:/etc/frr/frr.conf
- configs/leaf4/daemons:/etc/frr/daemons
# Compute Nodes (Distributed System Nodes)
kafka1:
kind: linux
image: alpine:latest
kafka2:
kind: linux
image: alpine:latest
kafka3:
kind: linux
image: alpine:latest
links:
# Spine-Leaf Full Mesh
- endpoints: ["spine1:eth1", "leaf1:eth1"]
- endpoints: ["spine1:eth2", "leaf2:eth1"]
- endpoints: ["spine1:eth3", "leaf3:eth1"]
- endpoints: ["spine1:eth4", "leaf4:eth1"]
- endpoints: ["spine2:eth1", "leaf1:eth2"]
- endpoints: ["spine2:eth2", "leaf2:eth2"]
- endpoints: ["spine2:eth3", "leaf3:eth2"]
- endpoints: ["spine2:eth4", "leaf4:eth2"]
# Compute Connections
- endpoints: ["leaf1:eth3", "kafka1:eth1"]
- endpoints: ["leaf2:eth3", "kafka2:eth1"]
- endpoints: ["leaf3:eth3", "kafka3:eth1"]
# Deploy lab
# sudo containerlab deploy -t network-topology.yaml
IP Addressing Plan สำหรับ Segment Routing Fabric
# IP Addressing Plan
# =============================================
# Device | Loopback | SRGB Range | Node SID
# =============================================
# spine1 | 10.0.0.1/32 | 16000-23999 | 16001
# spine2 | 10.0.0.2/32 | 16000-23999 | 16002
# leaf1 | 10.0.0.11/32 | 16000-23999 | 16011
# leaf2 | 10.0.0.12/32 | 16000-23999 | 16012
# leaf3 | 10.0.0.13/32 | 16000-23999 | 16013
# leaf4 | 10.0.0.14/32 | 16000-23999 | 16014
# =============================================
#
# P2P Links: 10.1.x.y/31
# spine1-leaf1: 10.1.1.0/31 (spine=.0, leaf=.1)
# spine1-leaf2: 10.1.1.2/31
# spine1-leaf3: 10.1.1.4/31
# spine1-leaf4: 10.1.1.6/31
# spine2-leaf1: 10.1.2.0/31
# spine2-leaf2: 10.1.2.2/31
# spine2-leaf3: 10.1.2.4/31
# spine2-leaf4: 10.1.2.6/31
#
# Server Subnets:
# leaf1: 10.10.1.0/24 (kafka1: 10.10.1.10)
# leaf2: 10.10.2.0/24 (kafka2: 10.10.2.10)
# leaf3: 10.10.3.0/24 (kafka3: 10.10.3.10)
ตั้งค่า SR-MPLS บน FRRouting สำหรับ Data Center Fabric
FRRouting (FRR) เป็น routing suite แบบ open source ที่รองรับ Segment Routing ทั้ง SR-MPLS และ SRv6 ใช้ได้กับ Linux host และ container
# configs/spine1/daemons
zebra=yes
bgpd=no
ospfd=no
ospf6d=no
ripd=no
ripngd=no
isisd=yes
pimd=no
ldpd=no
nhrpd=no
eigrpd=no
babeld=no
sharpd=no
pathd=yes
pbrd=no
bfdd=yes
fabricd=no
vrrpd=no
# configs/spine1/frr.conf — Spine1 FRRouting Configuration
frr version 9.1
frr defaults datacenter
hostname spine1
!
interface lo
ip address 10.0.0.1/32
ip router isis FABRIC
isis passive
!
interface eth1
description to-leaf1
ip address 10.1.1.0/31
ip router isis FABRIC
isis network point-to-point
isis hello-interval 1
isis hello-multiplier 3
!
interface eth2
description to-leaf2
ip address 10.1.1.2/31
ip router isis FABRIC
isis network point-to-point
isis hello-interval 1
isis hello-multiplier 3
!
interface eth3
description to-leaf3
ip address 10.1.1.4/31
ip router isis FABRIC
isis network point-to-point
!
interface eth4
description to-leaf4
ip address 10.1.1.6/31
ip router isis FABRIC
isis network point-to-point
!
router isis FABRIC
net 49.0001.0100.0000.0001.00
is-type level-2-only
metric-style wide
log-adjacency-changes
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 10.0.0.1/32 index 1
!
! TI-LFA สำหรับ fast reroute
interface eth1
isis ti-lfa
!
interface eth2
isis ti-lfa
!
interface eth3
isis ti-lfa
!
interface eth4
isis ti-lfa
!
Configuration สำหรับ Leaf Switch
# configs/leaf1/frr.conf — Leaf1 FRRouting Configuration
frr version 9.1
frr defaults datacenter
hostname leaf1
!
interface lo
ip address 10.0.0.11/32
ip router isis FABRIC
isis passive
!
interface eth1
description to-spine1
ip address 10.1.1.1/31
ip router isis FABRIC
isis network point-to-point
isis hello-interval 1
isis hello-multiplier 3
isis ti-lfa
!
interface eth2
description to-spine2
ip address 10.1.2.1/31
ip router isis FABRIC
isis network point-to-point
isis hello-interval 1
isis hello-multiplier 3
isis ti-lfa
!
interface eth3
description to-kafka1
ip address 10.10.1.1/24
!
router isis FABRIC
net 49.0001.0100.0000.0011.00
is-type level-2-only
metric-style wide
log-adjacency-changes
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 10.0.0.11/32 index 11
!
ip route 10.10.1.0/24 eth3
# ตรวจสอบ SR-MPLS status
# vtysh -c "show isis segment-routing node"
# vtysh -c "show mpls table"
# vtysh -c "show isis neighbor"
ใช้ SR Policy สำหรับ Traffic Engineering ระหว่าง Cluster
SR Policy ใช้สำหรับกำหนดเส้นทางเฉพาะสำหรับ traffic ที่ต้องการ latency ต่ำหรือ bandwidth สูง เช่น Kafka replication traffic ระหว่าง broker
# SR Policy Configuration ผ่าน FRR pathd
# configs/leaf1/frr.conf — เพิ่ม SR Policy
segment-routing
traffic-eng
segment-list SL_LEAF1_TO_LEAF3_VIA_SPINE1
index 10 mpls label 16001
index 20 mpls label 16013
!
segment-list SL_LEAF1_TO_LEAF3_VIA_SPINE2
index 10 mpls label 16002
index 20 mpls label 16013
!
policy color 100 endpoint 10.0.0.13
name KAFKA_REPLICATION_TO_LEAF3
binding-sid 1100
candidate-path preference 200 name PRIMARY explicit segment-list SL_LEAF1_TO_LEAF3_VIA_SPINE1
candidate-path preference 100 name BACKUP explicit segment-list SL_LEAF1_TO_LEAF3_VIA_SPINE2
!
policy color 200 endpoint 10.0.0.12
name LOW_LATENCY_TO_LEAF2
binding-sid 1200
candidate-path preference 100 name DIRECT explicit segment-list SL_LEAF1_TO_LEAF2
!
!
!
# ตรวจสอบ SR Policy
# vtysh -c "show segment-routing traffic-eng policy"
# Output:
# Policy color 100 endpoint 10.0.0.13
# Name: KAFKA_REPLICATION_TO_LEAF3
# Status: Active
# Binding SID: 1100
# Candidate Path:
# Preference 200 (PRIMARY): Active
# Segment List: 16001 -> 16013
สร้าง script สำหรับจัดการ SR Policy แบบ dynamic
#!/usr/bin/env python3
# sr_policy_manager.py — จัดการ SR Policy สำหรับ Distributed System
import subprocess
import json
import sys
class SRPolicyManager:
def __init__(self, router_host="localhost"):
self.router = router_host
def vtysh(self, commands):
if isinstance(commands, str):
commands = [commands]
cmd_str = "\n".join(commands)
result = subprocess.run(
["vtysh", "-c", cmd_str] if len(commands) == 1 else ["vtysh"],
input=cmd_str if len(commands) > 1 else None,
capture_output=True, text=True
)
return result.stdout
def get_isis_database(self):
output = self.vtysh("show isis database detail")
return output
def get_sr_node_info(self):
output = self.vtysh("show isis segment-routing node")
return output
def get_mpls_table(self):
output = self.vtysh("show mpls table json")
try:
return json.loads(output)
except json.JSONDecodeError:
return {}
def get_policy_status(self):
output = self.vtysh("show segment-routing traffic-eng policy")
return output
def create_policy(self, color, endpoint, name, segment_list, binding_sid):
commands = [
"configure terminal",
"segment-routing",
" traffic-eng",
f" segment-list SL_{name}",
]
for idx, (i, label) in enumerate(enumerate(segment_list, 10)):
commands.append(f" index {i*10} mpls label {label}")
commands.extend([
" !",
f" policy color {color} endpoint {endpoint}",
f" name {name}",
f" binding-sid {binding_sid}",
f" candidate-path preference 100 name PRIMARY explicit segment-list SL_{name}",
" !",
" !",
"!",
"end",
])
return self.vtysh(commands)
def delete_policy(self, color, endpoint):
commands = [
"configure terminal",
"segment-routing",
" traffic-eng",
f" no policy color {color} endpoint {endpoint}",
" !",
"!",
"end",
]
return self.vtysh(commands)
def health_check(self):
node_info = self.get_sr_node_info()
mpls_table = self.get_mpls_table()
policy_status = self.get_policy_status()
print("=== SR Health Check ===")
print(f"\n[Node Info]\n{node_info[:500]}")
print(f"\n[MPLS Table Entries]: {len(mpls_table) if isinstance(mpls_table, list) else 'N/A'}")
print(f"\n[Policy Status]\n{policy_status[:500]}")
if __name__ == "__main__":
mgr = SRPolicyManager()
if len(sys.argv) > 1 and sys.argv[1] == "health":
mgr.health_check()
elif len(sys.argv) > 1 and sys.argv[1] == "create":
mgr.create_policy(
color=100, endpoint="10.0.0.13",
name="TEST_POLICY",
segment_list=[16001, 16013],
binding_sid=1100
)
else:
print("Usage: sr_policy_manager.py [health|create]")
ตั้งค่า SRv6 Network Programming สำหรับ Service Chaining
SRv6 ใช้ IPv6 address เป็น Segment Identifier ทำให้สามารถ encode function (เช่น End, End.DT4, End.DX6) ไว้ใน SID ได้ เหมาะสำหรับ Service Function Chaining
# SRv6 Configuration สำหรับ FRRouting
# configs/spine1/frr.conf — SRv6 Section
segment-routing
srv6
locators
locator MAIN
prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
behavior usid
!
!
!
!
router isis FABRIC
segment-routing srv6
locator MAIN
!
!
# SRv6 SID Table จะถูกสร้างอัตโนมัติ:
# fc00:0:1:: End (node SID)
# fc00:0:1:1:: End.X (adjacency SID to leaf1)
# fc00:0:1:40:: End.DT4 (decap and lookup in IPv4 table)
# fc00:0:1:41:: End.DT6 (decap and lookup in IPv6 table)
# ตรวจสอบ SRv6 SID Table
# vtysh -c "show segment-routing srv6 sid"
# SID Behavior Context
# fc00:0:1:: End -
# fc00:0:1:1:: End.X eth1
# fc00:0:1:40:: End.DT4 default
# Service Function Chaining Example:
# Traffic จาก kafka1 ไป kafka3 ต้องผ่าน:
# 1. Firewall (leaf2)
# 2. DPI (leaf4)
# 3. ถึง kafka3 (leaf3)
#
# SRv6 Segment List:
# [fc00:0:12::, fc00:0:14::, fc00:0:13:40::]
#
# สร้าง SRv6 Policy
# ip -6 route add 10.10.3.0/24 encap seg6 mode encap \
# segs fc00:0:12::, fc00:0:14::, fc00:0:13:40:: dev eth1
สร้าง Service Chain สำหรับ Distributed System Traffic
#!/bin/bash
# setup_srv6_service_chain.sh — ตั้งค่า SRv6 Service Chain
# Enable SRv6 บน Linux kernel
sysctl -w net.ipv6.conf.all.seg6_enabled=1
sysctl -w net.ipv6.conf.default.seg6_enabled=1
sysctl -w net.ipv6.conf.eth1.seg6_enabled=1
# สร้าง SRv6 Service Chain สำหรับ Kafka Replication Traffic
# Path: leaf1 -> leaf2(firewall) -> leaf3(kafka3)
ip -6 route add fc00:0:13:40::/128 encap seg6 mode encap \
segs fc00:0:12::, fc00:0:13:40:: dev eth1 \
table 100
# สร้าง policy routing rule
ip rule add from 10.10.1.0/24 to 10.10.3.0/24 \
ipproto tcp dport 9092 table 100
# ตรวจสอบ routing table
ip -6 route show table 100
ip rule show
# Monitor SRv6 traffic
tcpdump -i eth1 -n 'ip6 proto 43' -c 10
# ตรวจสอบ SRv6 counters
cat /proc/net/segment_routing/hmac_info
ip -6 route show cache
Monitoring Segment Routing ด้วย Prometheus และ gNMI
ใช้ gNMI (gRPC Network Management Interface) เพื่อเก็บ SR metrics จาก router แล้วส่งไปยัง Prometheus
# gnmi-exporter-config.yaml — gNMI Collector Configuration
subscriptions:
- name: sr-mpls-counters
paths:
- "/network-instances/network-instance[name=default]/segment-routing/sr-mpls"
- "/network-instances/network-instance[name=default]/mpls/label-blocks"
mode: sample
sample-interval: 30s
- name: isis-adjacency
paths:
- "/network-instances/network-instance[name=default]/protocols/protocol[name=ISIS]/isis/interfaces"
- "/network-instances/network-instance[name=default]/protocols/protocol[name=ISIS]/isis/levels"
mode: on-change
- name: interface-counters
paths:
- "/interfaces/interface/state/counters"
mode: sample
sample-interval: 10s
targets:
spine1:
address: 10.0.0.1:57400
username: admin
password: admin
skip-verify: true
spine2:
address: 10.0.0.2:57400
username: admin
password: admin
skip-verify: true
outputs:
prometheus:
type: prometheus
listen: ":9273"
path: "/metrics"
metric-prefix: "sr_"
export-timestamps: true
# รัน gnmic collector
# gnmic --config gnmi-exporter-config.yaml subscribe
Prometheus Alert Rules สำหรับ SR monitoring
# sr-prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: sr-alerts
spec:
groups:
- name: segment-routing
rules:
- alert: ISISAdjacencyDown
expr: sr_isis_adjacency_state != 1
for: 30s
labels:
severity: critical
annotations:
summary: "ISIS adjacency down on {{ $labels.interface }}"
- alert: SRPolicyInactive
expr: sr_te_policy_state != 1
for: 2m
labels:
severity: warning
annotations:
summary: "SR Policy {{ $labels.policy_name }} is inactive"
- alert: HighPacketLoss
expr: rate(sr_interface_counters_in_discards[5m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "High packet loss on {{ $labels.interface }}"
- alert: MPLSLabelExhaustion
expr: (sr_mpls_srgb_size - sr_mpls_srgb_used) / sr_mpls_srgb_size < 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "MPLS label pool below 10% on {{ $labels.node }}"
FAQ คำถามที่พบบ่อย
Q: FRRouting รองรับ SR-MPLS features อะไรบ้าง?
A: FRR รองรับ IS-IS SR Extensions, Prefix SID, Adjacency SID, TI-LFA, SR Policy ผ่าน pathd, Flex-Algo (experimental) และ SRv6 ผ่าน kernel integration ยังไม่รองรับบาง feature เช่น SR-MPLS OAM และ PCE-initiated SR Policy แต่กำลังพัฒนาอยู่
Q: Segment Routing ช่วยลด latency ของ Distributed System ได้จริงไหม?
A: SR ไม่ได้ลด latency โดยตรงแต่ช่วยให้ engineer กำหนดเส้นทางของ traffic ได้แม่นยำขึ้น เช่นบังคับให้ Kafka replication traffic ใช้เส้นทางที่สั้นที่สุด หรือแยก latency-sensitive traffic ออกจาก bulk transfer traffic นอกจากนี้ TI-LFA ลด convergence time เหลือต่ำกว่า 50ms ทำให้ distributed system ไม่กระทบเมื่อเกิด link failure
Q: ควรใช้ IS-IS หรือ OSPF เป็น IGP สำหรับ Segment Routing?
A: แนะนำ IS-IS เพราะรองรับ SR Extensions ได้ดีกว่า scale ได้ดีกว่าสำหรับ large fabric และเป็น protocol ที่ vendor ส่วนใหญ่ focus พัฒนา SR features ไว้ OSPF ก็รองรับ SR แต่ feature set อาจตามหลัง IS-IS
Q: SRv6 มี overhead เท่าไหร่เมื่อเทียบกับ SR-MPLS?
A: SR-MPLS ใช้ 4 bytes ต่อ label ส่วน SRv6 ใช้ 16 bytes ต่อ segment (IPv6 address) บวก SRH header อีก 8 bytes สำหรับ path ที่มี 3 segments SR-MPLS ใช้ 12 bytes ส่วน SRv6 ใช้ 56 bytes ดังนั้น SRv6 มี overhead สูงกว่า 4-5 เท่า ซึ่งสำคัญสำหรับ packet ขนาดเล็กใน distributed system ที่มี high packet rate
