사내 프로젝트 진행 중 네트워크 트래픽을 제한해야할 일이 생겨 Traffic Control을 사용해보고, 해당 내용을 정리하였다.
Traffic Control?
-
언제 사용할까?
- 네트워크 사용량이 정해져 있을 때( 호스팅을 사용할 때 ) upload / download throughput을 제한할 때 사용.
- latency 추가 등 기타 네트워크 에뮬레이션 기능이 필요할 때
- traffic shaping
-
qdisc, class, filter
- qdisc : qdisc로 classfy된 트래픽들이 해야할 행동 같은것을 정의. 다양한게 있지만, tc-net-emul 모듈을 이용하여 딜레이를 줘보자.
- class : 생성된 qdisc를 거쳐가는 트래픽을 분류하여 classfying 한다.
- filter : filter를 통해 트래픽을 분류하여 class로 보냄
- 간략히 분류 한것이지만, 실제로는 더 많은 내용을 가지고 있다.
Script 작성해보기
요구사항
- web-service에 band-width를 256kbps로 제한한다.
- web-service에 latency 200ms 딜레이를 추가한다.
- ssh는 느려지지 않았으면 좋겠다.
How to?
-
클래스를 2개 생성한다.
- WebService 클래스
- SSH 클래스
- WebService 클래스에 256KBps 제한, 200ms 딜레이 추가
- SSH 클래스는 제한 없음.
- filter를 정의할 때 들어온 포트로 해당 클래스를 분기한다.
스크립트
아래 Reference script 참고.
#!/bin/bash
IF=eth0
SPEED=256
PORT=8080
start() {
echo "==================================================="
echo "Start Traffic control script"
echo "==================================================="
#
# qdisc
#
### define root qdisc
tc qdisc add dev $IF root handle 1:0 htb default 10
#
# class
#
# define default class bitrate 1Gbit
tc class add dev $IF parent 1:0 classid 1:10 htb rate 1024mbit burst 15k
# define ssh class bitrate 1Mbit
tc class add dev $IF parent 1:0 classid 1:20 htb rate 1mbit burst 15k
# define web-service class bitrate 256Kbit and add latency delay 200ms
tc class add dev $IF parent 1:0 classid 1:30 htb rate 256kbit burst 10k
tc qdisc add dev $IF parent 1:30 handle 30: netem delay 200ms
#
# filter
#
### filter ssh
tc filter add dev $IF protocol ip parent 1:0 prio 1 u32 match ip sport 22 0xffff flowid 1:20
### filter 8080 for web service
tc filter add dev $IF protocol ip parent 1:0 prio 1 u32 match ip sport 8080 0xffff flowid 1:30
}
stop() {
echo "==================================================="
echo "Stop Traffic control script"
echo "==================================================="
tc qdisc del dev $IF root
}
status() {
printf "\n--------------------------------------------------"
printf "\n[ qdisc ] : \n"
tc qdisc show dev $IF
printf "\n[ class ] : \n"
tc class show dev $IF
printf "\n[ filter ] : \n"
tc filter show dev $IF
printf "\n--------------------------------------------------\n"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start)
start
status
;;
stop)
stop
status
;;
status)
status
;;
*)
pwd=$(pwd)
echo "Usage: ./ctl {start|stop|restart|status}"
;;
esac
exit 0
Reference link
- https://wiki.linuxfoundation.org/networking/netem
- https://github.com/magnific0/wondershaper
- http://www.sauru.so/blog/traffic-control-by-tc/
- http://skylit.tistory.com/217
- http://moyaria.tistory.com/entry/%EB%A6%AC%EB%88%85%EC%8A%A4-%EC%84%9C%EB%B2%84-%EC%9E%90%EC%B2%B4-%ED%8A%B8%EB%9E%98%ED%94%BD-%EC%A0%9C%ED%95%9C%ED%95%98%EA%B8%B0-tc-%EB%AA%85%EB%A0%B9%EC%96%B4-Traffic-Control
- http://www.tinola.com/blog_posts/adding_latency/latency
Reference script
#!/bin/bash
#
# Copyright LMAX
#
# chkconfig: 345 99 01
# description: Add routing and traffic control rules so that we can
# add latency and bandwidth limitations to performance tests.
# processname: latency
#
# To understand traffic control see the linux advanced routing and traffic
# control how to http://www.lartc.org/
#
export PATH=/sbin:$PATH
## configuration.
SEASIAIP=172.16.10.10
SEASIAPORT=9091
EUIP=172.16.10.10
EUPORT=9092
INTERFACE=bond0.30
LOCKFILE="/var/lock/subsys/latency"
## end of configuration
function start()
{
## outbound.
tc qdisc add dev $INTERFACE root handle 1:0 htb default 10
# default class
tc class add dev $INTERFACE parent 1:0 classid 1:10 htb rate 1024mbit
# "europe" traffic class - outbound bandwidth limit
tc class add dev $INTERFACE parent 1:0 classid 1:11 htb rate 512kbit
# "se asia" traffic class - outbound bandwidth limit
tc class add dev $INTERFACE parent 1:0 classid 1:12 htb rate 128kbit
# network emulation - add latency.
tc qdisc add dev $INTERFACE parent 1:11 handle 11:0 netem delay 20ms 5ms 25% distribution normal
tc qdisc add dev $INTERFACE parent 1:12 handle 12:0 netem delay 330ms 10ms 25% distribution normal
# filter packets into appropriate traffic classes.
tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip dst $SEASIAIP match ip dport $SEASIAPORT 0xffff flowid 1:12
tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip dst $EUIP match ip dport $EUPORT 0xffff flowid 1:11
## inbound
# inbound qdisc.
tc qdisc add dev $INTERFACE handle ffff: ingress
# attach a policer for "se asia" class.
tc filter add dev $INTERFACE protocol ip parent ffff: prio 1 u32 match ip src $SEASIAIP match ip sport $SEASIAPORT 0xffff \
police rate 128kbit burst 10k drop flowid :1
# attach a policer for "europe" traffic class.
tc filter add dev $INTERFACE protocol ip parent ffff: prio 1 u32 match ip src $EUIP match ip sport $EUPORT 0xffff \
police rate 512kbit burst 10k drop flowid :2
#
touch $LOCKFILE
}
function stop ()
{
# remove any existing ingress qdisc.
tc qdisc del dev $INTERFACE ingress
## remove any existing egress qdiscs
tc qdisc del dev $INTERFACE root
rm -f $LOCKFILE
}
function status ()
{
echo " [1m Active Queue Disciplines for $INTERFACE [m"
tc -s qdisc show dev $INTERFACE
echo
echo " [1m Active Queueing Classes for $INTERFACE [m"
tc -s class show dev $INTERFACE
echo
echo " [1m Active Traffic Control Filters for $INTERFACE [m"
tc -s filter show dev $INTERFACE
}
# main
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
stop
start
;;
condrestart)
if [ -f $LOCKFILE ]; then
stop
start
fi
;;
status)
status
;;
*)
echo $"Usage: $0 {start|stop|restart|condrestart|status}"
exit 1
esac
exit 0;