昨年から在宅勤務継続中ですが、もういいかげん自宅で仕事するのに飽きたので、今年の夏は少し離れた場所からリモートワークしたいなーと思ったりしてます。しかし、問題が1つあって、夏の間滞在しようと思っている場所にはリモートワークに必須のインターネットへの接続環境が無いのです。
Contents
日本で一般人がインターネット接続環境を準備する時にとれる選択肢は下記3つくらいでしょうか。
-
- フレッツ + ISP契約
- ケーブルテレビ局のインターネット接続
- WiMAX や 4G 、 5Gのモバイルネットワーク接続
どれも一長一短がありますが、「夏の間だけ」という短期間での利用ならば、最低利用期間の縛りがないサービスが理想です。しかし、大部分のサービスで2年縛りを要求されてしまいます。
そこで、最低利用期間が短いサービスを探してみると、足回りに(3)を使い、基本料金が少し割高な代わりに最低利用期間が1ヶ月というサービスを見つけました。さっそく試してみようか?と詳細を見ていると、転送量の縛りがきつめに設定されていることに気づきました。
一般的に(3)のモバイル回線サービスは、一定期間内に決められた転送量を超えた場合、翌日は帯域制限がかかる、という規約になっている事が多いようです。上記の最低利用期間が1ヶ月のサービスは、3日で10GBytesを転送すると翌日は1Mbpsに帯域を絞られてしまうのだとか。近頃は各種データをクラウドストレージに保存している人も多いことでしょう。そのような使い方の場合、10GBytesなんてあっというまに転送してしまいます。
幸いな事に、ぼくの職場では、リモートワークといっても常時テレビ会議状態なわけではなく、基本的にsshかWebベースのチケットシステムを利用し、極稀にオフィスに置いてあるWindowsPCにRDPで接続する程度です。普段どれくらいのデータを送受信しているのかを今まで測定した事がありませんでした。これは良い機会ですので、転送量を計測するスクリプトを仕込んでみました。
OS | Debian Stable(10.10) |
Internet接続 | PPPoE + NAT (訳あってPPPoEなのです) |
インターネット <-> 自宅の総通信量を集計する
このblogで何度か登場している絵ですが、インターネットと宅内LANのゲートウェイにLinuxサーバ(ルータ)を設定しています。
まずは、このLinuxサーバ(ルータ)のインターネット側の口を通る全ての通信総量を測定して、毎時/毎日どのくらいのデータを流しているのかを調査します。うちの場合だとppp0とppp1のトラフィックを集計しますが、CATVやIPoEで接続している場合は、NICの転送量を集計する事になります。
集計方法詳細
Linuxではネットワークインターフェイスを通して送受信したトラフィック量を/proc/net/dev
で参照できます。トラフィック量だけでなく、エラーパケット数等のカウンタもありますが、今、興味があるのはppp0またはppp1で送受信したバイト数です。
1 2 3 4 5 6 |
root@pooh:~# cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed (略) ppp0: 742869140381 589137967 0 0 0 0 0 0 93494424838 311736321 0 0 0 0 0 0 ppp1: 148003224336 120368019 0 0 0 0 0 0 13201089168 51344194 0 0 0 0 0 0 |
この値はただのカウンタなので、転送量を調べるには定期的に値を取得し、差分を計算すれば良いわけですね。
/var/log/traffic/
以下に YYYY-MM-DD-インターフェイス名.log
という名前のファイルを作成し、そこにデータを溜めるスクリプトを作ってみました。ごちゃごちゃしてますが、やってることは単純です。
-
/proc/net/dev
からppp0とppp1のトラフィック統計値を取得- 前の集計値との差分を計算(ついでに単位をメガバイトに)
- それぞれをファイルに書き出し保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#!/usr/bin/env bash _BASE='/var/log/traffic' _DATE=$(date '+%Y-%m-%d') _TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') FLAG=false function get_last_rx(){ tail -n 1 ${_BASE}/${2}-${1}.log| awk -F, '{print $2}' } function get_last_tx(){ tail -n 1 ${_BASE}/${2}-${1}.log| awk -F, '{print $3}' } if [ ! -f ${_BASE}/${_DATE}-ppp0.log ];then touch ${_BASE}/${_DATE}-ppp0.log touch ${_BASE}/${_DATE}-ppp1.log FLAG=true fi for i in ppp0 ppp1;do TX=$(cat /proc/net/dev |grep ${i}| awk '{print $10}') RX=$(cat /proc/net/dev |grep ${i}| awk '{print $2}') if "${FLAG}";then TARGET_DATE=$(date '+%Y-%m-%d' --date='1 day ago') else TARGET_DATE="${_DATE}" fi LRX=$(get_last_rx ${i} ${TARGET_DATE}) LTX=$(get_last_tx ${i} ${TARGET_DATE}) DRX=$(echo "${RX} - ${LRX}" |bc) DTX=$(echo "${TX} - ${LTX}" |bc) DRX_M=$(echo "${DRX} / 1000 / 1000"|bc) # Mega-Bytes DTX_M=$(echo "${DTX} / 1000 / 1000"|bc) echo "${_TIMESTAMP},${RX},${TX},${DRX},${DTX},${DRX_M},${DTX_M}" >> ${_BASE}/${_DATE}-${i}.log done |
毎時間データを取りたいので、cronから毎時00分に実行するように設定します。
1 2 3 |
root@pooh:~# crontab -l (略) 0 * * * * bash /somewhere/aggregate_traffic.sh |
データはCSV形式で出力され左からそれぞれ
-
- タイムスタンプ
- 受信カウンタ(Bytes)
- 送信カウンタ(Bytes)
- 受信カウンタの前回からの差分(Bytes)
- 送信カウンタの前回からの差分(Bytes)
- 受信量差分(MBytes)
- 送信量差分(MBytes)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
root@pooh:/var/log/traffic# cat 2021-07-14-ppp1.log 2021-07-14 00:00:01,146349238822,13077146875,408987294,16968910,390,16 2021-07-14 01:00:01,146467147814,13088265982,117908992,11119107,112,10 2021-07-14 02:00:01,146562283198,13109978951,95135384,21712969,90,20 2021-07-14 03:00:01,146630329542,13122492877,68046344,12513926,64,11 2021-07-14 04:00:01,146791715485,13143063205,161385943,20570328,153,19 2021-07-14 05:00:01,146838061436,13158545166,46345951,15481961,44,14 2021-07-14 06:00:01,146850250471,13160667947,12189035,2122781,11,2 2021-07-14 07:00:01,146855055207,13162146795,4804736,1478848,4,1 2021-07-14 08:00:01,147880887467,13178480696,1025832260,16333901,978,15 2021-07-14 09:00:01,147889192718,13180361169,8305251,1880473,7,1 2021-07-14 10:00:01,147895284251,13182354234,6091533,1993065,5,1 2021-07-14 11:00:01,147902949805,13184689386,7665554,2335152,7,2 2021-07-14 12:00:01,147916679542,13186623727,13729737,1934341,13,1 2021-07-14 13:00:01,147940104361,13189511970,23424819,2888243,22,2 2021-07-14 14:00:01,147945449185,13192341680,5344824,2829710,5,2 2021-07-14 15:00:01,147983898716,13196337336,38449531,3995656,36,3 2021-07-14 16:00:01,147993371105,13198246103,9472389,1908767,9,1 2021-07-14 17:00:01,148000611141,13200341644,7240036,2095541,6,1 2021-07-14 18:00:01,148015446515,13203227346,14835374,2885702,14,2 2021-07-14 19:00:01,148032358424,13206210836,16911909,2983490,16,2 2021-07-14 20:00:01,148053239964,13207936300,20881540,1725464,19,1 2021-07-14 21:00:01,148056733264,13209098569,3493300,1162269,3,1 2021-07-14 22:00:01,148109024259,13211432589,52290995,2334020,49,2 2021-07-14 23:00:01,148113079010,13212726987,4054751,1294398,3,1 |
毎日の転送量集計
モバイル回線での利用帯域集計がどのような時間枠で計算されるのかわかりませんが、毎時間でのデータは細かすぎます。一日単位の転送量を自動集計するようにしました。
/var/log/traffic/daily/
以下に YYYY-MM.log
という名前で、1日単位での転送量を毎日集計し追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/usr/bin/env bash _BASE='/var/log/traffic' _DATE=$(date +%Y-%m-%d --date='1 day ago') _IN_FNAME=${_BASE}/${_DATE} _OUT_FNAME=${_BASE}/daily/$(date +%Y-%m --date='1 day ago').log _TMP=/tmp/aggregate_traffic.$$ for i in ppp0 ppp1;do cat ${_IN_FNAME}-${i}.log| \ awk -F , 'BEGIN{rx=0;tx=0}{rx+=$6;tx+=$7}END{print(rx,tx)}' \ >> ${_TMP} done echo -n "${_DATE} " >> ${_OUT_FNAME} cat ${_TMP} | \ while read i;do echo -n "$i " done >> ${_OUT_FNAME} echo "" >> ${_OUT_FNAME} rm -f ${_TMP} |
こちらは1日1回実行されるようにcronに登録します。
1 2 3 |
root@pooh:~# crontab -l (略) 0 2 * * * bash /somewhere/aggregate_traffic_per_day.sh |
左から、日付, ppp0(IPv4)の受信,送信量,ppp1(IPv6)の受信,送信量です。
1 2 3 4 5 6 7 8 9 |
root@pooh:/var/log/traffic# cat ./daily/2021-07.log 2021-07-13 2358 365 1095 55 2021-07-14 5005 771 2060 131 2021-07-15 10380 955 3234 143 2021-07-16 1946 875 1787 86 2021-07-17 4543 842 2870 109 2021-07-18 3284 859 1892 72 2021-07-19 30892 1523 4564 154 2021-07-20 12485 1392 4390 145 |
適当にawkで集計してみると・・受信11GB/day, 1GB/day。結構つかってるなぁ。
1 2 3 4 5 6 7 |
root@pooh:/var/log/traffic# cat ./daily/2021-07.log | \ > awk '{rx4+=$2;tx4+=$3;rx6+=$4;tx6=$5} > END{print("IPv4:RX = ",rx4," TX = ",tx4,"\nIPv6:RX = ",rx6," TX = ",tx6,"\nTotal RX = ",rx4+rx6,"\nTotal TX = ",tx4+tx6)}' IPv4:RX = 70893 TX = 7582 IPv6:RX = 21892 TX = 145 Total RX = 92785 Total TX = 7727 |
ただし、これは自宅の出入り口を通るすべてのトラフィック総計です。
amazon prime video等のストリーミングトラフィックや深夜に取得しているリモートサーバのバックアップトラフィック、windowsアップデートや携帯アプリのアップデート等も含まれています。
そう考えると「リモートワークでどのくらいのトラフィックを使うのか?」を正確に調べるには、仕事用PCに的を絞ってトラフィックの集計する必要ありますね。
ターゲットを絞って総通信量を計測する
ターゲットを絞って、つまり、ある特定のIPアドレスを持つデバイスの通信を監視するのにはいろいろなツールが利用できます。例えば、tcpdump, wireshark, ntopとか?
でも今回は、通信の中身を見たいのではなく、通過するトラフィック量を測りたい「だけ」なので、パケットの中身を全部みるようなツールはオーバースペックです。
バケットの操作ならば、kernel内部で行わせればサーバへの負荷も少なくてすむはず。Linuxに用意されているパケットフィルタの機能を利用して仕事用マシンの通信量をカウントすることにしました。
準備
-
- 仕事用PCのIPv4アドレスを固定
IPアドレスでターゲットを指定するので、IPアドレスが変わらないようにします。DHCPで取得している場合でも、IPアドレスが変わらなければ問題ありません。 - IPv6を無効
データ収集を楽にするためIPv6を無効にしました。
- 仕事用PCのIPv4アドレスを固定
仕組み
仕事用PCのIPv4アドレスを調べると192.168.0.239が割り当てられていました。Linuxルータ側で、このIPv4アドレスがsrc, dstになっているパケットをひっかけます。
1 2 |
root@pooh:~# iptables -t mangle -A FORWARD -s 192.168.0.239 -j MARK --set-mark 1 root@pooh:~# iptables -t mangle -A FORWARD -d 192.168.0.239 -j MARK --set-mark 2 |
マーク番号は他で使っていなければなんでも良いです。
集計スクリプト
Linux kernelでこのルールに引っかかったパケットをカウントしてくれるので、その値を集計していきます。ごちゃごちゃしていますが、さきほどのスクリプトの使いまわしです。
-
- mark された通信の転送量を取得
- 前に取得したデータからの差分を計算し、メガバイトに変換
- まとめてファイルへ書き出し
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#!/usr/bin/env bash _BASE='/var/log/work-traffic' _DATE=$(date '+%Y-%m-%d') _TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') FLAG=false if [ ! -f ${_BASE}/${_DATE}.log ];then touch ${_BASE}/${_DATE}.log FLAG=true fi _OUT=$(/sbin/iptables -t mangle -vxnL FORWARD| grep '0x1' |awk '{print $2}') _IN=$(/sbin/iptables -t mangle -vxnL FORWARD| grep '0x2' |awk '{print $2}') if "${FLAG}";then TARGET_DATE=$(date '+%Y-%m-%d' --date='1 day ago') else TARGET_DATE="${_DATE}" fi LRX=$(tail -n 1 ${_BASE}/${TARGET_DATE}.log| awk -F, '{print $2}') LTX=$(tail -n 1 ${_BASE}/${TARGET_DATE}.log| awk -F, '{print $3}') DRX=$(echo "${_IN} - ${LRX}"| bc) DTX=$(echo "${_OUT} - ${LTX}"| bc) DRX_M=$(echo "${DRX} / 1000 / 1000"| bc) # Mega-Bytes DTX_M=$(echo "${DTX} / 1000 / 1000"| bc) echo "${_TIMESTAMP},${_IN},${_OUT},${DRX},${DTX},${DRX_M},${DTX_M}" >> ${_BASE}/${_DATE}.log |
毎時の集計値は細かすぎるので、1日単位でまとめます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#!/usr/bin/env bash _BASE='/var/log/work-traffic' _DATE=$(date +%Y-%m-%d --date='1 day ago') _IN_FNAME=${_BASE}/${_DATE}.log _OUT_FNAME=${_BASE}/daily/$(date +%Y-%m --date='1 day ago').log _TMP=/tmp/work_traffic.$$ cat ${_IN_FNAME}| \ awk -F , 'BEGIN{rx=0;tx=0}{rx+=$6;tx+=$7}END{print(rx,tx)}' \ >> ${_TMP} echo -n "${_DATE} " >> ${_OUT_FNAME} cat ${_TMP} | \ while read i;do echo -n "$i " done >> ${_OUT_FNAME} echo "" >> ${_OUT_FNAME} rm -f ${_TMP} |
集計結果
仕込んでから5日目。更に土日を挟んでいるので、実質2営業日分しか集計できていませんが、1.7GB/day くらいのようです。
1 2 3 4 5 |
root@pooh:/var/log/work-traffic# cat ./daily/2021-07.log 2021-07-17 0 0 2021-07-18 0 0 2021-07-19 1855 142 2021-07-20 1656 168 |
結論
思ったよりもずっと通信量が少なめでした。朝のテレビ会議で少し通信を行いますが、その後はターミナルで作業、ローカルで編集したコードをgitで同期、メッセンジャーでチャット、Webブラウザでチケット操作、メール送受信等の作業ならば、3日で10Gバイト以下という制限は全く問題にならないレベルである。と集計した結果から読み取れます。むしろ、隙間時間に見ているニュースサイトの方がトラフィックを消費していたり・・・
自宅のゲートウェイをLinuxで構築するというのは時代遅れかもしれません。しかし、今回のような要望がでてきた場合でも柔軟に対応できるところは便利で素晴らしいです。
1日3GB生活は、インターネット経由の動画などを鑑賞するのは無理そうですが、庭の野菜の世話をしたり、裏山を散歩したりと街中ではできない生活を楽しもうと思います。
今週から梅雨が明けて毎日暑いです。今月の定期メンテナンス作業が終わったら、避暑地へゴーの予定です 🙂