作: | @voluntas |
---|---|
バージョン: | 0.1.0 |
url: | https://voluntas.github.io/ |
時雨堂という小さい小さい零細企業を経営しています。
Erlang/OTP でネットワークサーバを書いたりしています。
TURN のような TCP から UDP へ中身をいじらずに転送するサーバや、 MQTT と WebRTC SFU といった受け取ったデータ単一のデータを複数の箇所に転送するサーバを主に開発しています。
今回お話しするのは、皆さんがあまりなじみの無い転送サーバのテスト手法です。
転送というのは形を変えずに他の場所へ移動することです。つまり今回お話しするサーバではパケットの書き換えなどは行わず、データ自体はそのまま転送します。
加工せずに事前に決められていたルールに基づきデータを転送する仕組みのサーバに対してどのようなテストを行うべきなのかという話をします。
また転送する場合は複数箇所に転送するという需要があります。これをスケールさせたり冗長構成を取った場合とかのテストも考えられます。
今回は こんな世界もあるんだな というのを皆さんに感じてもらえたら良いなと思います。
- 今回の話は Erlang/OTP を前提としたテストになっています。他の言語でのテスト方法は考慮しておりません
- 実際にまだできていない部分の話も含んでいます
UDP ホールパンチングでは抜けられない NAT 状況からのパケットをリレーして届ける仕組みのプロトコルです。
PubSub モデルで、接続しっぱなしでメッセージを複数箇所に送ったり、複数箇所から受け取ったりプロトコルです。
WebRTC はブラウザでリアルタイムに映像やデータを扱うプロトコルです。
通常はブラウザ同士でやりとりしますが WebRTC SFU はこのやりとりをサーバ経由で行います。
SFU は Selective Forwarding Unit の略で、選んで転送するという意味です。 映像や音声をサーバ経由で複数箇所に配信する仕組みです。
あくまで個人的な意見です。
- mock/stub はできるだけ使わない
- 実際に TCP や UDP などパケットを飛ばす
- 実際にアプリを起動してテストする
- 状態をテストする
これらのサーバをテストする場合、一番先にやることはクライアントを実装する必要があります。 既存のクライアントでいいのでは?と思われがちですが、基本的に既存のクライアントは異常な処理を意図的に起こすことはできません。
そのため、 異常なパケットを意図的に投げられる生データモードを追加したクライアントを実装する必要があります。
投げて、戻ってくるというわけではありません。投げたらいつ戻ってくるかは他の人に依存するためです。
そもそも投げるのと受け取るのは別世界です。そのため非同期でクライアントを実装する必要があります。
- A が B 投げる
- B が A 投げる
- A が受け取って、パケットを確認する
- B が受け取って、パケットを確認する
- C がパケットを受け取ってないことを確認する
同時に投げるというのは残念ながら難しいのですが、いつ受け取るかどうかわからないこともあり非同期でのテストを書けるようにする必要があります。
たとえば TURN クライアントは UDP でも TCP でも TLS でも DTLS でも使える必要があります。 また MQTT とかは MQTT over TLS や MQTT over TCP や MQTT over WebSocket があります。
特に MQTT over TCP と MQTT over WebSocket は地獄です。 実際同じような仕組みなのに MQTT over WebSocket は実際は MQTT over Websocket over TCP なので、間に一個よけなのが入っているわりに、同じようなインターフェースでテストできる必要があるのです。
テストクライアントをテストする方法は基本的には無い。ただ、やりたいことはやりたいため、いくつかの OSS サーバに対してのテストを行うという対応を取っている。
docker ベースでサーバを立て、それに対して仕様を想定したシナリオを流すことで、プロトコルの確認が出来ます。
複数の OSS に対してテストを行うことで、知見を得られたりもします。
あまり、やられてるのを見ることは無いのですが、かなりおすすめの方法です。
テストが増えるとテストが遅くなるという問題がありますが、がんばれば短く出来るパターンもありますが、実は転送サーバではタイムアウトを期待するテストというのが出てきたりします。
それはセキュリティ的なものだったり、実際にタイムアウトさせるべきものだったりと。タイムアウトしてリトライをするなどのテストも入れると時間自体がただかかるようになります。
これは、回避方法はありません。ただ、タイムアウト処理はかなり重要なので、できるだけしておきましょう。
転送サーバの場合は、テストの時間が遅くなるのはあきらめるのが重要です。
結論から先に言うと、ツールを作るところから始めましょう。自分でネットワークサーバを作れる場合は、負荷試験ツールの作り方もよくわかってる事がほとんどです。
Apache 作れる人が ab を作れるくらいの認識でかまいません、実際作った人が一緒かはわかりませんが ... 。
リレーサーバで負荷試験を行う場合は大量のインスタンスが必要になります。それらを自動化しなければ継続的に負荷試験を行えません。
さらに負荷試験の場合はプロファイルやメトリクス、ログなどを確認する必要があります。
理想論で言えば、コミットごとでしょうが、負荷試験は夜間に一回当日のコミットの最新版に対して行う程度で問題ないでしょう。
さらに、そのときのデータはすべて記録しおき、性能が劣化しないことを常に確認すべきです。
これだけは一般的な話です
テストを自動化した場合は、ほとんどの場合でメンテナンスコストが増大します。
テストを自動化すると楽になるという話を聞きますが、テストを自動化してうまくまわるようにしたとしても、守られるのはデグレしなくなる だけ です。
自動テストをメンテナンスするコストは大変重いです。自動テストがコスト削減となるパターンも見えますが、実際は運用が大変になります。
開発速度もテストを修正するコストも考えながら見積もる必要が出てきます。