勝手に連載しております、Rustで業務アプリを開発する基盤を考える記事。
普段は当社の営業業務に没頭するため、Rustプログラミングはかすりもしません....
プログラミングのためには概ね休みの日に取り組むしかなく、Rustを主務にされている世界中の方々から遅れていることこの上ないのですが、それでもいつか研究の日の目を見るときが来ると信じ、この年末年始もRustに取り組みました。
今回超概要をご紹介するのは、RustでのWebsocket通信の実現方法です。
なぜ業務アプリの基盤を検討するのにWebsocketを視野に入れたかというと、応答性能を極限まで高めてみたいからです。
文字情報を中心にやり取りするWEBアプリは、httpヘッダー情報やパラメータとともにWEBサーバの特定URLに対してGETやPOSTで通信する方式をとることが多いと思います。
GETやPOSTの都度、httpヘッダー情報がやり取りされ、オーバーヘッドもかかるので、Websocket通信と比べると遅くなるのでしょう。
ですが、開発側としてはシンプルに設計できる上、普通にホームページを作成する方式と概ね変わらず、仕組みを理解している技術者が多いので、わざわざWebsocketでは開発しないでしょう。
Websocketより遅いといっても、普通にホームページを閲覧するのと同じ応答性能です。
Websocketはほんの少しの遅延も許しがたい、例えばゲームに用いられることが多いようです。
私が販売している当社製品の
「monipet」も、センサーで取得した動物の体動をリアルタイムでグラフ化する機能に用いられています。
あと、やはりサーバとクライアント間の双方向通信ができるのもWebsocketの特徴と思います。
(業務アプリでは....あまり積極的には必要ないかもですが....)
さて、このWebsocketの性能を業務アプリなど、文字情報中心のアプリでも生かすことができないかと考えています。
応答性能など0.1秒でも早いにこしたことはないので。
代わりに犠牲になることとしては、ブラウザからURLを入力して特定画面へ直接アクセスする仕組みの開発が難しくなることでしょう。
例えば、ある受注管理システムで自分がよく使う受注入力画面があったとし、その画面を開いてお気に入りに入れておきます。
その画面はメニュー→受注検索画面→受注入力画面に遷移する必要があるなら、お気に入りから直接遷移することで遷移手順を省略できるようにWEBアプリを作ることができます。(もちろん、ログインは省略できないようにする必要はありますが)
しかし、Websocketはクライアント(ブラウザ等)からバックグラウンドでサーバと通信することが通常であり、ブラウザ上のURLは変わらないため、遷移画面のお気に入り登録ができません。
(ただ、JavaScriptで意図的にブラウザ上のURLを変えることができたかな....と)
前置きが長くなりましたが、RustでWebsocketを実装する話です。
やはりライブラリ(クレート)を利用しますが、Websocketのサーバまたはクライアントだけを実装するなら、そのままの名前の
「websocket」または
「ws」というクレートを利用するのが一般的なようで、メンテナンスも続いています。
ですが、今回はWebsocket以外にもWEBサーバとして様々な機能がすでにあり、ドキュメントもまま存在する
「actix-web」で試しました。
これはJavaでいうところの
「Spring Boot」のようなもので、WEBサーバとして起動させることができ、特定のURLにhttpでPOSTやGETを行うと特定の処理を実行させて結果を返すといったことを、最小限の労力で開発できるフレームワークになっています。
多くの
「actix-web」のサンプルがあり、実践に役立つと思います。
サンプルには、データベースの操作、クッキーの操作、JSONでのデータ送受信、SSLでの通信、セッション管理、CORS(Cross-Origin Resource Sharing)によるセキュリティ対策、ひな形によるWEB画面生成方法といったものがあり、
Websocketのサンプルもあります。
こちらは単純にクライアントからサーバにメッセージを送信すると、そのメッセージをただ返すだけのものです。
こちらはチャットの機能を持たせたサンプルです。
例えば「/join room1」というメッセージを送信すると「room1」というチャット部屋を作成または入室し、その後は接続を維持している間、同じチャット部屋に入室した人だけに送信したメッセージがサーバからクライアントへプッシュ通知される仕組みになっています。(特定の部屋へ入室せずにメッセージを送信すると、WEBサーバにアクセスしている人全員にメッセージが配信されます)
データベースは使われず、非常にシンプルな構成です。
「main.rs」「server.rs」という2つのソースが配置されており、合わせて500行くらいで、最初は何書いてるか面を食らいました。
ですが、実際にツール(Visual Studio Code)でデバッグ実行させ、ブレイクポイントを要所に置いて1ステップずつ見ていくと、概ね理解できました。
死活監視(ping/pong)もサンプルに入っており、これを使うとログアウトを厳密に制御できるなと思いました。
また、「actix-web」のSSL対応と含め、WebsocketをSSLで接続する(wss://~)ことも確認できました。
という感じで、RustでのWebsocketサーバを実装する方法を確認しました。
ですが、Websocket自体、ロードバランサによる負荷分散のしにくさ、ブラウザでタブを大量に開くとコネクションもその数だけ貼ってサーバーに負荷がかかる問題も指摘されています。
なので、従来の「http/1」の信頼性を維持しつつ、データ圧縮による通信量削減や双方向通信も可能で、タブを大量に開いても1コネクションにまとめられるという「http/2」を採用するWEBアプリも多いようです。
「actix-web」はこの
「http/2」にも対応しており、SSLを実装し、POSTやGETを特定のURLで待ち受けられるようにプログラムして、あとはブラウザなどクライアントさえ対応していれば自動で「http/2」で通信をしてくれるようになっています。これも動作確認しました。
ということで、ここまでやっておきながらではありますが、今なら信頼性やスケーラビリティを考えると無理にWebsocketにせず、「http/2」を採用してもそれなりに高速レスポンスの仕組みを開発できるのかもしれません。
「WebSocket over HTTP/2」という技術もRFC 8441で標準化されているようですが、ネットで調べる限りあまり流行っていないように見えます。
あと、Googleが主導している「gRPC」という、バイナリで通信することで通信量が削減され、高速化する方式もあります。
HTTP/2をベースにした仕組みですが、こちらも今後少し調べてみようと思っています。
所見、httpsのようにクライアントがWEBブラウザである場合の暗号化通信する方法が、よくわかりませんでした....
Rustでは
「Tonic」などgRPCのライブラリがあるようです。
actixシリーズにも
「actix-protobuf」なる、gRPCっぽいものが!これも調べてみます。
ちなみに、上記の動作確認を行ったときに利用したRustや各ライブラリのバージョンは、2020年1月5日時点で最新のものです。
(酒)
moniswitch
今お使いの離床センサーがそのまま使える!
離床センサーのスイッチ入れ忘れ事故を防止するスマートスイッチ
monipet
動物病院の犬猫の見守りをサポート
病院を離れる夜間でも安心
ASSE/CORPA
センサー、IoT、ビッグデータを活用して新たな価値を創造
「できたらいいな」を「できる」に
OSGi対応 ECHONET Lite ミドルウェア
短納期HEMS開発をサポート!
WhitePlug
手のひらサイズのLinuxサーバ
株式会社ジェイエスピー
横浜に拠点を置くソフトウェア開発・システム開発・
製品開発(monipet)、それに農業も手がけるIT企業