はじめに
パフォーマンスチューニングといえば、DBのインデックスやN+1クエリの解消を思い浮かべることが多いですが、ネットワークレイテンシについても考慮する必要があります。
特にローカル環境での開発ではネットワークレイテンシがほとんど発生しないため、本番環境と比べるとパフォーマンスが大幅に向上している傾向があります。
開発環境ではdocker composeを使って単一ホストでコンテナ間通信をさせることが多いと思いますが、この通信に対してネットワークレイテンシ等の設定をする方法が気になったので調べます。
tc
Linuxだとtc(Traffic Control)コマンドを使うことによって、トラフィックを制御することができます。
今回の目的であるネットワークレイテンシの設定だけでなく、パケットロス割合の設定などもできます。
tcコマンドはkernelとNetwork Interceの間に特定のキューを設定することで、トラフィックを制御します。
このキューはqdisc(queueing discipline)
と呼ばれています。
process -[socket]-> kernel -[device driver]-> NIC
↓
process -[socket]-> kernel - qdisc -> -[device driver]-> NIC
環境
2コンテナ間での通信に対してネットワークレイテンシの設定をします。
compose.yaml
ファイルは以下のような設定です。
services:
host-1:
image: ubuntu:latest
container_name: host-1
tty: true
cap_add:
- NET_ADMIN
host-2:
image: ubuntu:latest
container_name: host-2
tty: true
cap_add:
- NET_ADMIN
ポイントとしては、コンテナにNET_ADMIN
のcapabilityを追加しているところです。
デフォルトではCAP_NET_ADMIN
のcapabilityが抑えられた状態でコンテナを起動するので、tcコマンドが実行できないためです。
CAP_NET_ADMIN
を付与することによって以下の操作が可能になります。
https://man7.org/linux/man-pages/man7/capabilities.7.html
CAP_NET_ADMIN
Perform various network-related operations:
- interface configuration;
- administration of IP firewall, masquerading, and accounting;
- modify routing tables;
- bind to any address for transparent proxying;
- set type-of-service (TOS);
- clear driver statistics;
- set promiscuous mode;
- enabling multicasting;
- use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE.
今回の検証に必要なpackageを入れていきます。
-
iproute2
- tc
-
iputils-ping
- ping
$ docker compose exec host-1 bash
$ apt update -y && apt install -y iproute2 iputils-ping
レイテンシの設定
ネットワークレイテンシの設定をせずに、初期状態でhost-1からhost-2に対してpingを実行すると以下のような結果になります。
$ ping -c 5 host-2
PING host-2 (172.18.0.2) 56(84) bytes of data.
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=1 ttl=64 time=0.197 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=3 ttl=64 time=0.131 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=4 ttl=64 time=0.138 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=5 ttl=64 time=0.113 ms
--- host-2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4106ms
rtt min/avg/max/mdev = 0.113/0.139/0.197/0.030 ms
qdisc
はNetwork Interfaceごとに作ることができるので、host-1
, host-2
それぞれで使われている仮想Network Interfaceのeth0
に対してqdiscを作成します。
500msのネットワークレイテンシを設定する場合以下のようになります。
tc
qdisc add
-
dev eth0
- ネットワークデバイスの
eth0
に対して追加
- ネットワークデバイスの
-
root
- 指定したdeviceのrootにattachする
-
In the absence of classful qdiscs, classless qdiscs can only be attached at the root of a device.
- https://man7.org/linux/man-pages/man8/tc.8.html
-
netem
- Network Emulatorとしてのqdiscを追加
-
Network Emulator is an enhancement of the Linux traffic control facilities that allow one to add delay, packet loss, duplication and more other characteristics to packets outgoing from a selected network interface.
-
delay 500ms
$ tc qdisc add dev eth0 root netem delay 500ms
ネットワークレイテンシの設定をしてから再度pingを実行すると、ネットワークレイテンシが追加されていることを確認できます。
root@f6459af85b82:/# ping -c 5 host-2
PING host-2 (172.18.0.2) 56(84) bytes of data.
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=1 ttl=64 time=506 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=2 ttl=64 time=506 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=3 ttl=64 time=506 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=4 ttl=64 time=506 ms
64 bytes from host-2.sandbox_default (172.18.0.2): icmp_seq=5 ttl=64 time=501 ms
--- host-2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4024ms
rtt min/avg/max/mdev = 501.273/504.945/506.072/1.846 ms
参考