2012年4月27日金曜日

回線遅延やパケットロスをシュミレートする方法

回線遅延(帯域)を考慮しない負荷試験なんて意味あるの?って思い使ってみました。
負荷試験はLAN内で行う事が殆どだと思いますが実際はインターネット経由でユーザからのアクセスがあり、それぞれ回線速度もバラバラのはずです。

この回線速度の違いはシステムにどのような影響を与えるかというと1アクセスに対して1プロセスが長時間専有されることでシステムリソースを消費するということです。

これらを考慮せずに安易にKeepAliveを有効にしてWebサーバを高速化しよう!なんてしてしまうと高負荷になり返ってレスポンスが遅くなったという人も多いと思います。

Linux2.6系(だったはず)からiproute2などが組み込まれてネットワーク系が強化されました。
その一部としてtc(Traffic Control)コマンドがあります。


tcコマンドでできること


・回線遅延
・パケットロス
・パケット入れ替え
・パケットの破損
・etc...

このコマンドはそのサーバに対して適応されるので、遅延速度を大きくしすぎるとSSHがタイムアウトすることもあるので注意してください。
複数NICがある環境が望ましいです。

eth0を100ms遅延させる場合

#tc qdisc add dev eth0 root netem delay 100ms
//Delete Command
#tc qdisc del dev eth0 root netem delay 100ms


qdisc=>'queueing discipline'
kernelがNICから送信する必要がある場合、一旦qdiscに格納されkernelはqdiscからNICドライバーへと引き渡そうとします。
その順番はキューに入った順に引き渡され、NICはできるだけ速くキューを送信しようとします。
それを操作して送信を遅延させてやろうというコマンドです。

別の端末からCurlを実行してみます。
通常の速度は9000msぐらいです。

# curl -o /dev/null -w time_total 10.0.60.24
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 9 0 9 0 0 2572 0 --:--:-- --:--:-- --:--:-- 9000



tcコマンドを実行すると。
綺麗に100ms遅延した結果が得られました。

# curl -o /dev/null -w time_total 10.0.60.24
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 9 0 9 0 0 44 0 --:--:-- --:--:-- --:--:-- 90



遅延をランダムにさせることもできます。100ms〜10msの遅延。

# tc qdisc add dev eth0 root netem delay 100ms 10ms



パケットロスはランダムにパケットをロスさせることができる。
このランダムというところが厄介なのでNICが1つしかない場合はSSHのパケットとHTTPのパケットが混ざってしまい正確な値の計測が難しい。
NICが1つの場合はlossの確率を10%程度まで上げても殆ど変化がみられないと思う。
NICが2つあり、殆どパケットがながれていない場合1%以下から検証することを勧める。


# tc qdisc del dev eth0 root netem loss 0.00003%


delayと組み合わせて使うこともできます。


# tc qdisc add dev eth0 root netem delay 100ms 10ms loss 0.00003%


パケットの破損はパケットの1bitを破壊する事ができる。TCPの場合は輻輳の機能があるので観測しづらいのでPingで試すのが吉。

# tc qdisc del dev eth0 root netem corrupt 10%


tcpdumpを実行しながらPingを打つとwrong data byteが発生して一定の確率で破損しているのが伺える。

# tcpdump -n -p icmp &
# ping 10.0.60.24
PING 10.0.60.24 (10.0.60.24) 56(84) bytes of data.
20:59:15.942681 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 1, length 64
20:59:15.943743 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 1, length 64
64 bytes from 10.0.60.24: icmp_seq=1 ttl=64 time=2.05 ms
20:59:16.942993 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 2, length 64
20:59:16.943303 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 2, length 64
64 bytes from 10.0.60.24: icmp_seq=2 ttl=64 time=0.342 ms
20:59:17.943496 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 3, length 64
20:59:17.943813 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 3, length 64
64 bytes from 10.0.60.24: icmp_seq=3 ttl=64 time=0.347 ms
20:59:18.943501 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 4, length 64
20:59:18.943841 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 4, length 64
64 bytes from 10.0.60.24: icmp_seq=4 ttl=64 time=0.372 ms
20:59:19.943514 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 5, length 64
20:59:19.943854 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 5, length 64
64 bytes from 10.0.60.24: icmp_seq=5 ttl=64 time=0.372 ms
20:59:20.943554 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 6, length 64
20:59:20.943952 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 6, length 64
64 bytes from 10.0.60.24: icmp_seq=6 ttl=64 time=0.431 ms
wrong data byte #45 should be 0x2d but was 0xd
#16 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c d 2e 2f
#48 30 31 32 33 34 35 36 37
20:59:21.943526 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 7, length 64

0 件のコメント:

コメントを投稿