2/14にDevSumiでHerokuとWebSocketを使ったデモをやってきました。
今回はそのデモの総括です。
★概要(本番前)
今回僕が担当したのは吉田パクエ氏のネタセッションでのデモです。
年末に10分の持ち時間でHerokuの良いところをアピールできるデモをなんかやってくれないかというお話をいただきました。
その頃僕はちょうど初めて自分でWebSocketアプリを実装してみたところで、この技術がどの程度実用的なものなのかという点に興味を持っていました。
なので、何かしらWebSocketを使ったデモをやろうと思い作ってみたのがこれです。
http://ws-vote.herokuapp.com/rooms/demo
ボタンを押すと数字がカウントアップされるだけの極単純なアプリですが、WebSocketを使っているので誰かがボタンを押すと同じ画面を見ている全員の端末で数字がカウントアップされます。
会場にいる人にスマホで画面を開いてもらい数字がくるくる回るところを見せられれば結構面白いかなぁと思いました。(^^;
もうひとつのポイントはこれがネット上に良くあるWebSocktサンプルと違いスケールアウト可能な作りになっているという点です。
裏でRedisを使っているのでHerokuのDyno数をあげれば、それだけで負荷分散できます。
それなりに負荷テストも行ってましたし、当日は20Dynoあげるつもりだったのでどっからでもかかってこーい!と、むしろ誰も参加してくれなくて数字が回らなかったらどうしようかとそっちの方を心配していました。
★本番
さて迎えた本番、僕は3人のデモ担当者の中でトップバッターだったんですが、前に立ったら話そうと思ってたことを予定通りすっかり忘れて何喋ったかあんまり覚えてません。。。が、多分そんなに問題はなかったです。何故なら誰も僕の話なんか聞いてなかったから。。。(^^;;;
今回プレゼン資料もHeroku上のWebアプリとして作成しました。
http://flect-devsumi2014.herokuapp.com/
で、中に埋まっているのがセッション中約2時間弱投票を受け付けた画面での結果です。(本当は1時間の予定でしたがバグがあって指定の時間に投票が締め切られませんでした。。。(--)
数字をよく見てください。なんと合計で201万5487回もクリックされています!
スループットにして実に300回/秒!!(セッション終了後はほとんど参加者がいなかったはずなので実際にはその倍近く)
想定してた数字と2桁違いますがな。。。
いったい何が起こったんだよ。。。(--
★テロリスト達
数字が伸びた要因はいくつかあるんですが、それはおそらく以下の内容です。
PCではボタンにフォーカスあててENTERキーを押しっぱなしにするだけで連打できた
。。。(--
これ言われてみればなんで気がつかなかったんだろうという話なんですが、スマホメインで考えていたのでまったく気がついていませんでした。
PCで参加した人はほとんどこの方法で連打していたと思います。
まぁ盛り上がったので結果オーライです。(^^;
一瞬でSeleniumスクリプトを組み上げるスーパーハッカーの存在
僕の隣ではSeleniumでループまわして余裕でPC画面を眺めているツワモノが。。。(--
ていうかあなたついさっきまでデモ2番手としてAzureのデモやってましたよね?(^^;
この短時間でそんなこと思いつく発想力には感動すら覚えます。
Twitter見てるとSeleniumを投入したツワモノは他にもいたようです。
何故かピンクを勝たせようと暗躍するHeroku A氏
デブサミ #devsumiE でHerokuのWebSocketのデモを 実施中です。ピンクが勝ったら手元にあるHerokuステッカーをAsk the Speakerで配布します。みんなで連打してください! http://t.co/2z6pzND2k2
— Ayumu AIZAWA (@ayumin) 2014, 2月 14
。。。(--
言っとくけどこのデモが落ちて一番切ない思いするのはお前だからな。。。(--
しかし、これらの攻撃にも負けずリクエストを捌ききったHerokuは素晴らしかったです。(これでA氏にドヤ顔されるのはなんだか不本意ですが。。。)
★WebSocket連続リクエストの話
さてさて、このように予想外にクリック数の伸びた今回のデモですが、実は事前の負荷テストから1セッションでの連続リクエストはほとんど負荷にはならないだろうという予想がありました。デモの結果を受けてそれはほとんど確信に変わっています。
何故そう思うかというとソケット繋ぎっぱで連続でリクエストを投げ続けるWebSocket通信は通信の性質だけを考えるとファイルアップロードと似たようなものだろうと思うからです。
今回一回のボタンクリックで送信するデータはホンの数バイト。WebSocket自体のオーバーヘッドがあるにしても1リクエストの転送量は10バイト程度でしょう。
「連続1万回のWebSocketリクエスト」というと結構な負荷のように感じますが、「100KBのファイルアップロード(10B × 10000回)」と考えると全然たいしたことないですよね。
もちろん10バイト毎に処理が挟まるのでまったく同じに考えることはできませんが、一番コストの高い通信部分において大きな優位があることは間違いありません。
今回複数の端末から連続リクエストが発行されていたと思いますが、20台もDynoをあげていたおかけでそれらは良い感じにばらけていたはずです。なので1Dynoあたりの負荷は実はそれ程大きくはなかったと思われます。
ちなみにデモサイトは現在1Dynoしかあげていませんが、それでもENTER押しっぱで数字がくるくると回る様子が確認できます。(複数端末で同時に実行するとアウトだと思いますが)
これが「Ajaxリクエスト連続1万回」であれば、コネクションの接続、Httpヘッダの解析とはるかに1リクエストの負荷が大きくなります。
連続リクエストに強いというWebSocketの性質は多くの場面で活用可能と思うので、もっと大きくクローズアップされて良いものだと思いました。
★Papertrailの話
すいません。。。舐めてました。。。(--
まったくログサイズの計算をせずに500MBもあれば十分だろうとタカをくくっていたらわずか15分で転送リミットに到達。。。(--
ほんの数時間だけなんだからもっと良いプラン使っておけば良かったー(--
(Herokuのアドオンは完全従量課金なので、高額のプランを一時的に使用しても請求額は使った時間分だけ秒単位で日割り計算されます。)
ていうか、むしろTreasure Dataを使っておけば良かったですね。。。時間帯ごとの各色の伸び方とかをグラフ化できれば面白かったのに。。。
惜しいことをしました。。。(--
★Redisの話
今回一番負荷のかかるコンポーネントはRedisでしたが、これも極めて優秀でした。
1回のボタンクリックにつきRedisリクエストは2回(数字のINCRとPUBLISH)発行されるので2時間弱で400万回以上のリクエストを捌いた計算です。
RedisGreenの管理画面で見るとSlowRequest(閾値は多分50ms)のログはかなりてていますが一番遅いものでも300ms程度なのでまぁ許容範囲でしょう。
Redisも実はそんなに高いプランを使ってないんですがこんだけ動いてくれれば十分満足です。
僕はこれまではキャッシュとしてはRedisよりもMemcacheを使うことが多かったんですが、これからは多分Redisに乗り換えます。
速度もほとんど遜色ないと思いますし、Memcacheが外からステータスを知る方法がほとんどないのに対しRedisはCLIで色々な情報が取れるのが大きな優位です。(サービス使えばWebコンソールも使えます。)
ちなみに今回HerokuのDyno数を100まであげずに20という半端な数字に抑えたのはそれ以上あげるとRedisのコネクション数が足りなくなる不安があったからです。
★スマホの話
すみませんすみませんすみません。m(_ _)m
今回のデモは皆さんのスマホに「赤、赤、ピンク、ピンク、黄、紫、緑。。。」みたいな感じにほとんど攻撃のようにデータを転送していました。
データ転送量は多分大きめのアプリをダウンロードする程度だったと思いますが、CPUもそれなりに喰っていたはずで僕の端末(ELUGA P02E)は17時前に電池切れました。。。(--
僕のところでは割りとクルクルと数字動いていましたが皆さんの端末はどうだったでしょうか?
こればっかりは端末性能と通信環境によって大きなバラつきがあったはずで、ものによってはかなりカクカクした動作になっていたと思います。
実際、パクエさんが途中経過を発表していた時も僕の手元とは割と大きな数字の開きがあったりもしました。
個人的にはスマホのWebSocketも十分実用レベルと思いますが、Androidの標準ブラウザが対応していないなど別の評価もあるとは思います。
★まとめ
以上、個人的にはかなり満足な成果がありましたが皆さん面白かったですかね?(^^;
残念だったのはしょぼいバグがあって投票が指定の時間(16時)に終了しなかったことです。タイムテーブルの変更で投票終了時間がセッション終了時間よりも後になったため、ほとんどの人は気づかなかったと思いますが、最後まで見ていた人は僕が強制的に終了させた時になんらかのエラー画面を見たかもしれません。
そのエラーはHerokuのせいではなく人為的なものであったことは書き添えておきます。
チャレンジングな所は全部ちゃんと動いただけに、日付と比較して分岐すれば良いだけみたいなところでバグを仕込んでしまったのは結構悔しいです。。。(--
以下、今回の成果のまとめです。
- WebSocketは既に実験的な技術ではなく十分に実用レベル
- WebSocketはリクエスト連投に強く、Ajaxの代替として使うのもアリ
- WebSocketをRedis併用でスケールアウトさせることは可能
- Redisは優秀。今後はMemcacheに替えて使いたい。
- スケールアウトの効果は絶大。Herokuがなければ多分こんな実験できてない。
- Herokuが日本にあればもっと速かったんだろうなぁ
- テロリスト怖い
- 本当は赤が勝ってたんですよ
軽い気持ちで引き受けたデモでしたが、予想以上に収穫のある実験(というよりむしろテロ)となりました。(^^;
セッションに誘ってくれたパクエさん、DevSumi運営者の方々に心より感謝します。
★リソース
最後に今回のデモのソース、WebSocket関連で書いたブログへのリンクをまとめておきます。
- HerokuとWebSocket
- PlayとRedisでスケーラブルWebSocket
- PlayとRedisでスケーラブルWebSocket(実装編)
- HerokuでスケーラブルWebSocket
- デモアプリソース(ws-vote)
- Redis WebSocket用ラッパー(play-redis-submodule)
Redisを使ってWebSocketをスケーラブルにするためのモジュールはアプリとは分離して作っています。興味ある方は使ってみてください。
デモアプリはルームを作成する機能を作っちゃえばパーティアプリとしてそこそこ面白そうな気がしてますが、誰か一緒に作りたい人はいませんかー(^^;
(もう一捻りあればSalesforce Mobile Hackに出しても良いかも)