Raspberry Pi 3 (Raspbian Jessie) で bonding を試してみた
Raspberry Pi 3本体のEthenetと Gigabit Ethenet-USBアダプタを束ねて、通信性能を上げられないか試してみました。
参考URL
<https://wiki.debian.org/Bonding>:Debian Wiki。Bondingに関する説明内容はDebian 6(squeeze), 7(Wheezy)がベースの様子。
Raspberry Pi 3のファイルサーバーですが、Gigabit Ethernet-USBアダプタを使用することで 20MB/sec程のI/O性能が出るようになりました。でも、USB2.0の論理通信性能の半分以下ですから、この程度ではまだ性能的に物足りないですね。そこで、本体の 10/100base-T と Gigabit Ethernet を束ねることで性能を向上させることができないか試してみました。
ネットワークデバイスを束ねる事をチーミング(Teaming)、またはLinuxではドライバ名からボンディング(Bonding)と言うそうです。
複数のNICを束ねて1つの仮想ネットワークデバイスを構成しますので、1つのNICが故障したり通信経路が切断されても、他のNICによって通信が確保され(これを可用性と言う)、複数のネットワークデバイスに分散して通信することで通信帯域を広くしたり、負荷を分散させることができます。
bondingの方法についてはネット検索すれば多くの事例が見つかるのですが、Raspbian Jessie(Debian 8)についてはまだ事例が少なく、内容が薄くて信頼性も低いものばかりでした(*1)。途中かなりハマったので、まだ少し味見した程度ですが、結論から言うと通信性能(スループット)を向上させることはできず、かえって性能低下してしまいました。ですから、負荷分散や可用性が目的であれば試す価値はあるかもしれませんが、通信性能(スループット)の向上が目的なら徒労に終わる可能性大ですので、そのつもりでお読みください。
大まかな手順は以下のようになります。OSは Raspbian Jessie で、作業は root ユーザーで行います。
- ifenslaveのインストール
"/etc/modules" の編集
"/etc/network/interfaces" の編集
"/etc/dhcpcd.conf" の編集
- 再起動
しかし、この後にトラブルの発生と、その対処の内容が続きます。トラブルが起きないように整理した手順にはなっていませんので、ご自分で手順を整理して実施することをお勧めします。
さて、NICを束ねる方法には以下の7種類があります。
mode | 名称 | 負荷分散 | 説明 |
0 | balance-rr | 送信時 | 全スレーブを順番(ラウンドロビン)に使いパケットを送信。
リンクアグリケーション(EtherChannel)に対応しているスイッチが必要。 |
1 | active-backup | なし | 1つのスレーブのみを active interfaceとしパケットを送信。
active interfaceに障害が発生した場合、他の backup slave を active interfaceに切り替え、冗長性を確保。 |
2 | balance-xor | 送信時 | 送信元/先のMACアドレスを元に送信スレーブを決定しパケットを送信。
リンクアグリケーション(EtherChannel)に対応しているスイッチが必要。 |
3 | broadcast | 送信時 | 全スレーブに同一パケットを送信。(通常は使用しない) |
4 | 802.3ad | 送受信 | IEEE 802.3ad(LACP)に準拠したリンクアグリゲーション。
802.3adに対応しているスイッチが必要。 |
5 | balance-tlb | 送信時 | 各スレーブの負荷に応じて送信スレーブを決定しパケットを送信。受信は現在のスレーブで行う。 |
6 | balance-alb | 送受信 | balance-tlbの機能に加え、受信も負荷分散。 |
どのモードを使用するかですが、今回の目的は通信性能向上ですから、モード 1, 3は除外します。ウチのは単なるスイッチングハブなので、スイッチに条件があるモード 0, 2, 4もダメなので、スイッチの条件が不要な balance-tlb(モード 5)か balance-alb(モード 6)で動くようにしたいのですが、今のところモード 5でしか成功していません。
先ずは味見として、Raspberry Pi 3本体の eth0(10/100base-T)と eth1(Gigabit Ethernet-USBアダプタ)を balance-rr(モード0)で束ねてみます。ただし balance-rr で複数台のスイッチを使用している場合には、NIC切り替え時にパケットの順序の入れ替わりが起こるという、かなり致命的な問題があるという事なので、注意してください。(*2)
ifenslaveというボンディングモジュールをインストールします。
# apt-get update
# apt-get install ifenslave
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが新たにインストールされます:
ifenslave
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 8 個。
15.6 kB 中 0 B のアーカイブを取得する必要があります。
この操作後に追加で 27.6 kB のディスク容量が消費されます。
以前に未選択のパッケージ ifenslave を選択しています。
(データベースを読み込んでいます ... 現在 142280 個のファイルとディレクトリがインストールされています。)
.../archives/ifenslave_2.6_all.deb を展開する準備をしています ...
ifenslave (2.6) を展開しています...
man-db (2.7.0.2-5) のトリガを処理しています ...
ifenslave (2.6) を設定しています ...
|
カーネルモジュールに bondingドライバーを追加します。
# echo "bonding" >> /etc/modules
# cat /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
bonding
|
ネットワーク設定を任意のエディタ(vi等)で編集し、bond0 という仮想的なネットワークデバイスを作成します。
# cd /etc/network
# cp -p interfaces interfaces.bak ※バックアップを作成しておきます
# vi interfaces
|
編集結果は以下のようになります。
# interfaces(5) file used by ifup(8) and ifdown(8)
# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
auto lo
iface lo inet loopback
# The bonding interface
auto bond0
iface bond0 inet manual
slaves eth0 eth1
bond_mode 0
bond_miimon 100
bond_downdelay 200
bond_updelay 200
#auto eth0
#allow-hotplug eth0
#iface eth0 inet manual
#auto eth1
#allow-hotplug eth1
#iface eth1 inet manual
auto wlan0
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
#allow-hotplug wlan1
#iface wlan1 inet manual
# wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
|
ポイントは以下の2点です。
- eth0, eth1スタンザは全てコメントアウトする(*3)
- ボンディングデバイス bond0 を追加し、その中で
slaves eth0 eth1 と記述する
また、Wi-Fi(wlan0)にもdhcpでIPアドレスが割り当てられるように設定しています。もし設定に間違いがあってEthernet経由でsshログインできなくなっても、Wi-Fi経由でログインできるようにするためです。(*4)
ネットワークデバイスに静的なIPアドレスを割り付ける(IPアドレスを固定する)には、Raspbian Jessieから"/etc/dhcpcd.conf" に記述するようになりましたので、bond0 にIPアドレスを割り付ける場合にも"/etc/dhcpcd.conf" に記述します。
# cd /etc
# cp -p dhcpcd.conf dhcpcd.conf.bak ※こちらもバックアップを作成しておきます
# vi dhcpcd.conf
|
# A sample configuration for dhcpcd.
# See dhcpcd.conf(5) for details.
# Allow users of this group to interact with dhcpcd via the control socket.
#controlgroup wheel
〜略〜
#interface eth1
# static ip_address=192.168.0.nnn/24
# static routers=192.168.0.1
# static domain_name_servers=192.168.0.1 8.8.8.8
interface bond0
static ip_address=192.168.0.nnn/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1 8.8.8.8
|
eth1に割り付けていたIPアドレスを bond0 の方に割り付けるように修正しました。
Raspberry Pi 3本体の10/100base-T Ethernetと、Gigabit Ethenetの両方にケーブル
を繋いで rebootしてみます。すると・・・
ダメでした orz。eth1 にだけケーブルを繋げている状態でなら通信(ssh)できますが、eth0 にもケーブルを繋げると途端に通信できなくなり、有線だけでなく wlan0(Wi-Fi)側も同じく通信できなくなります。
ifconfig で見ると、bond0 にはIPアドレス192.168.0.nnn が割り付けられているのですが、eth1 にもルーターのDHCPサーバーから取得したと思われるIPアドレス192.168.0.7 が割り付けられていました。
# ifconfig
bond0 Link encap:イーサネット ハードウェアアドレス b8:27:eb:68:01:0a
inetアドレス:192.168.0.nnn ブロードキャスト:192.168.0.255 マスク:255.255.255.0 ※これはOK
inet6アドレス: fe80::3891:dce4:2e67:3ece/64 範囲:リンク
UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 メトリック:1
RXパケット:2223 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:2180 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:866606 (846.2 KiB) TXバイト:619078 (604.5 KiB)
eth0 Link encap:イーサネット ハードウェアアドレス b8:27:eb:68:01:0a ※MACアドレスがbond0と同じなのは正しい
UP BROADCAST SLAVE MULTICAST MTU:1500 メトリック:1
RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:0 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:0 (0.0 B) TXバイト:0 (0.0 B)
eth1 Link encap:イーサネット ハードウェアアドレス b8:27:eb:68:01:0a ※MACアドレスがbond0と同じなのは正しい
inetアドレス:192.168.0.7 ブロードキャスト:192.168.0.255 マスク:255.255.255.0 ※これは何かおかしい
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 メトリック:1
RXパケット:2223 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:2180 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:866606 (846.2 KiB) TXバイト:619078 (604.5 KiB)
lo Link encap:ローカルループバック
inetアドレス:127.0.0.1 マスク:255.0.0.0
inet6アドレス: ::1/128 範囲:ホスト
UP LOOPBACK RUNNING MTU:65536 メトリック:1
RXパケット:643 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:643 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1
RXバイト:223829 (218.5 KiB) TXバイト:223829 (218.5 KiB)
wlan0 Link encap:イーサネット ハードウェアアドレス b8:27:eb:3d:54:5f
inetアドレス:192.168.0.8 ブロードキャスト:192.168.0.255 マスク:255.255.255.0
inet6アドレス: fe80::85a3:217a:fde:5e04/64 範囲:リンク
UP BROADCAST RUNNING MULTICAST MTU:1500 メトリック:1
RXパケット:135 エラー:0 損失:51 オーバラン:0 フレーム:0
TXパケット:55 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:23853 (23.2 KiB) TXバイト:7813 (7.6 KiB)
|
eth1 へのIPアドレス割り付けは、
とすると解除されます。しかし再起動すると復活してしまいます。でも、bond0 と eth0, eth1 のMACアドレスは同じだし、以下を見ても bonding はできている様子なのですが・・・(eth0 はケーブルを繋げてないので status が down になっています)
# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 200
Down Delay (ms): 200
Slave Interface: eth0
MII Status: down
Speed: 10 Mbps
Duplex: half
Link Failure Count: 1
Permanent HW addr: b8:27:eb:68:01:0a
Slave queue ID: 0
Slave Interface: eth1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 34:95:db:2b:e0:90
Slave queue ID: 0
|
このトラブルで数日はまっていました。色々ネット検索しても、同じようなトラブル事例が見つかりません。そもそも Raspbian Jessieでボンディングした事例自体が少なく、ましてトラブルに関する事例は全くと言って良いほど無いのです。
どう考えても何かが勝手にルーターのDHCPサーバーからIPアドレスを取得して eth0, eth1 に割り当てているように思えます。IPアドレスを固定するのに"/etc/dhcpcd.conf" などという設定ファイルを使用していることから、辿り着いた仮説が「こんな事をするのは dhcpcd(dhcp client daemon)で、こいつが悪さをしているのではなかろうか?それなら"/etc/dhcpcd.conf" で
eth0, eth1には何もするな!と設定すれば良いのではないか?」でした。では、その具体的な方法は?
denyinterfaces eth0 eth1
#interface eth0
#interface eth1
# static ip_address=192.168.0.152/24
# static routers=192.168.0.1
# static domain_name_servers=192.168.0.1 8.8.8.8
interface bond0
static ip_address=192.168.0.152/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1 8.8.8.8
|
"/etc/dhcpcd.conf" 内の interface eth0, eth1 スタンザを無くすようコメントアウトするだけでなく、"denyinterfaces eth0 eth1" を追加してみます。これで再起動してみたら、できました!
# ifconfig
bond0 Link encap:イーサネット ハードウェアアドレス b8:27:eb:68:01:0a
inetアドレス:192.168.0.nnn ブロードキャスト:192.168.0.255 マスク:255.255.255.0
inet6アドレス: fe80::3891:dce4:2e67:3ece/64 範囲:リンク
UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 メトリック:1
RXパケット:4244 エラー:0 損失:1 オーバラン:0 フレーム:0
TXパケット:7452 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:1312921 (1.2 MiB) TXバイト:2751912 (2.6 MiB)
eth0 Link encap:イーサネット ハードウェアアドレス b8:27:eb:68:01:0a ※eth0にIPアドレスが割り当てられていない
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 メトリック:1
RXパケット:2215 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:3731 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:703429 (686.9 KiB) TXバイト:1386844 (1.3 MiB)
eth1 Link encap:イーサネット ハードウェアアドレス b8:27:eb:68:01:0a ※eth1にIPアドレスが割り当てられていない
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 メトリック:1
RXパケット:2029 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:3721 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:609492 (595.2 KiB) TXバイト:1365068 (1.3 MiB)
lo Link encap:ローカルループバック
inetアドレス:127.0.0.1 マスク:255.0.0.0
inet6アドレス: ::1/128 範囲:ホスト
UP LOOPBACK RUNNING MTU:65536 メトリック:1
RXパケット:1485 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:1485 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1
RXバイト:562067 (548.8 KiB) TXバイト:562067 (548.8 KiB)
wlan0 Link encap:イーサネット ハードウェアアドレス b8:27:eb:3d:54:5f
inetアドレス:192.168.0.8 ブロードキャスト:192.168.0.255 マスク:255.255.255.0
inet6アドレス: fe80::85a3:217a:fde:5e04/64 範囲:リンク
UP BROADCAST RUNNING MULTICAST MTU:1500 メトリック:1
RXパケット:533 エラー:0 損失:107 オーバラン:0 フレーム:0
TXパケット:60 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:75896 (74.1 KiB) TXバイト:11885 (11.6 KiB)
# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 200
Down Delay (ms): 200
Slave Interface: eth0 ※eth0がスレーブになっている
MII Status: up
Speed: 100 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: b8:27:eb:68:01:0a
Slave queue ID: 0
Slave Interface: eth1 ※eth1がスレーブになっている
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 34:95:db:2b:e0:90
Slave queue ID: 0
# cat /sys/class/net/bond0/bonding/mode
balance-rr 0 ※balance-rr(モード 0)になっている
# ip route show table main
default via 192.168.0.1 dev bond0 metric 203
default via 192.168.0.1 dev wlan0 metric 304
192.168.0.0/24 dev bond0 proto kernel scope link src 192.168.0.152 metric 203
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.8 metric 304
|
7. 性能測定
せっかくですので、性能を測定してみます。
# iperf -c 192.168.0.xxx
------------------------------------------------------------
Client connecting to Titan, TCP port 5001
TCP window size: 70.0 KByte (default)
------------------------------------------------------------
[ 3] local 192.168.0.nnn port 55592 connected with 192.168.0.xxx port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0-10.0 sec 224 MBytes 188 Mbits/sec
|
かえって遅くなりました(^^;)。これじゃ意味な〜い!(負荷分散や可用性はできているのではないかと思いますが、通信スループットは低下してしまいました。まぁリンクアグリケーションに対応していないフツーのスイッチングハブ1台に繋いでいるのですから、当然の結果と言えますが。)一旦設定を元に戻して bond0 をお掃除(削除)します。Wi-Fi側からログインして、
# ifdown bond0
# echo "-bond0" > /sys/class/net/bonding_masters
# rmmod bonding
|
上記では一時的にボンディングデバイス(bond0)と、bondingドライバを削除しただけですから、再起動(reboot)すると元に戻ってしまいます。永続的にボンディングデバイス(bond0)を削除したい場合は、この後"/etc/modules" から bonding を削除(またはコメントアウト)してから再起動します。
8. モードを変えてみる
balance-rr (モード 0)はリンクアグリケーション(EtherChannel)に対応しているスイッチが必要ですので、スイッチの条件がない balance-tlb (モード 5)に変えてみます。
"/etc/network/interfaces" を編集し、設定を変更します。このモードの場合、スレーブデバイス(eth0, eth1)のスタンザを有効にしています。そうしないと bond0だけ作成されて eth0, eth1 が無い状態になり、有線(Ethernet)で通信できなくなってしまいましたので。
"/etc/dhcpcd.conf" は「4. "/etc/dhcpcd.conf" の編集」と同じです。
# interfaces(5) file used by ifup(8) and ifdown(8)
# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
auto lo
iface lo inet loopback
# The bonding interface
auto bond0
iface bond0 inet manual
bond-slaves eth0 eth1
bond-mode 5
bond-miimon 100
bond-downdelay 200
bond-updelay 200
auto eth0
allow-hotplug eth0
iface eth0 inet manual
auto eth1
allow-hotplug eth1
iface eth1 inet manual
auto wlan0
allow-hotplug wlan0
iface wlan0 inet manual
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
|
再起動後、ifconfigや"/sys/class/net/bond0/bonding/mode" 等を見て設定変更が反映されていることを確認し、性能を測定してみます。
# iperf -c 192.168.0.xxx
------------------------------------------------------------
Client connecting to Titan, TCP port 5001
TCP window size: 43.8 KByte (default)
------------------------------------------------------------
[ 3] local 192.168.0.nnn port 57950 connected with 192.168.0.xxx port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0-10.0 sec 238 MBytes 200 Mbits/sec
|
balance-rr (モード 0) よりは良い性能ですが、Gigabit Ethernet-USBアダプタ 1本と同じか少し遅いという結果になりました。
次に balance-alb (モード 6) にしてみた(bond-mode を 6に変えただけ)ところ、再起動したらネットワークが全滅になってしまいました(;_;)。起動用MicroSDカードをバックアップから書き戻して復旧させましたが、実験はここまでとしましょう。(これだけいじり倒して色々試せるってのもRaspberry Piの魅力の一つですよね。)
と言うことで、今回の結論。サーバーとしての可用性や使い勝手を良くする(例えば、有線(eth0)と無線(wlan0)を束ねて同じIPアドレスにし、どちらの経路でも一つの単一のIPアドレスでアクセス可能にする)目的であれば NICをボンディングする意味はありましょうが、通信性能(スループット)の向上が目的なら意味は無いでしょう。(リンクアグリケーション対応の高価なスイッチを複数所有しているなら話は別かもしれませんが・・)
(*1):とは言うものの、自分も良く理解できてないので、この記事も「こうしたら何とかうまくいった」に過ぎないのではありますが・・・
(*2):一般的には、balance-rr (モード 0)は使用せず balance-xor (モード 2)の方を使用するそうです。またサーバー用途では可用性を重視するので、active-backup(モード 1)が一般的だそうです。
(*3):理由は良く分かってません。Debian Wikiの「Configuration - Example 1」に準じただけでして、スレーブデバイス(eth0, eth1)のスタンザを記述しなくても自動的に作成してくれるようです。
(*4):Wi-Fi(wlan0)を管理ネットワーク的に使用して、ボンディングがうまくできなかった場合には、Wi-Fiからログインして復旧させようとの目論みだったのですが、アホでした。Wi-Fiもボンディングデバイスと同じサブネット(セグメント)のIPアドレスが割り当てられるのですから、きちんとルーティング設定しないとダメですね。最悪、Wi-Fi(wlan0)から入ってボンディングデバイスから出るというルーティングになり、出力のボンディングデバイス設定がダメダメだとネットワーク全滅ってことになるでしょうな。また後日に、きちんとルーティング設定してから再チャレンジしてみようか。
|