« 2014年3月 | メイン | 2014年5月 »

2014年4月

2014年4月30日 (水)

SalesforceのMeetupに行ってきた

4/28にSalesforce Developer User Group Meetup #5に行ってきました。

今回先に行われたHack Challengeの成果発表がメインコンテンツだと思って行ったんですが、実際に行ってみると真のメインコンテンツはこれでした。

ごちそうさまでした。(^^;

 

さて、今回FLECTも発表の場をいただけたのですが、発表自体は@i556がやってくれました。その渾身の資料がこちら

 

http://www.slideshare.net/kokorojw/inside-quizar

 

持ち味でてて良かったです。(^^;

動画も是非大音量でお楽しみください。

 

途中実際にSalesforceのクイズをやったんですが、その結果はこちら。

 

http://www.quizar.info/room/3/ranking

 

(個別イベントへのパーマリンクはないので、上記ページ表示後「4/28」の行をクリックしてください。)

 

ここでも優勝は(Hack Challengeで100万円をGETした)@a_kurataniさんです。さすがです。

クイズに参加した方は

 

マイページ > 参加ルーム > イベント > 問題

 

と辿ることで出題された問題を振りかえることができます。そこには問題の解説や参考リンクも含まれているので、時間が足りなくて良く見れなかった方はご確認ください。

 

こうした勉強会で使うのはそこそこ面白いんじゃないかと思ってますが、課題もまだまだあるというのが今回の感想です。。今回気が付いただけでも

 

  • 10秒は短すぎるので制限時間はある程度選択できる方が良い
  • 制限時間のゲージがまだ動いているのに回答すると「時間切れ」と言われるバグがある

 

などがあるので、これは近日直します。(GWの宿題(^^;;)

 

ちなみに後者のバグは原因だけは調べましたが、AndroidのChromeではJavaScriptのsetTimeoutが端末がスリープしたり、ホームボタン押してバックグラウンドに行ったりすると停止するのが原因です。(ゲージはsetTimeoutで100msごとに動かしているが、制限時間のチェックは実際の時間を計測している)

この辺ブラウザ毎に動作が違うようなので、これもそのうちブログねたにします。(^^v

2014年4月24日 (木)

WebSocket通信のメリットを考える

何故だか昨日のエントリが意外なほど読まれている。(^^;;;


Twitterでの言及も過去最大級かも。特に、


サーバーとの通信はAjax併用でも良いんですが、多分全部WebSocketでやる方がシンプルだし速度面やセキュリティ面でも優位があります。

 

この文章に引っ掛かった人が多いようで、これについてもうちょっと掘り下げてみます。


★ Ajaxの代替としてのWebSocket

そもそもの話として、素のWebSocketではリクエスト(この場合クライアント→サーバのメッセージの意)とレスポンス(サーバ→クライアント)を対応付けることができません。これを実現するためには自力でサーバ/クライアントの双方にメッセージをハンドリングするための仕組みを実装しならず、それは結構めんどうな作業です。

今回、その部分をフレームワーク化しようとしているので、それが実現できた場合のメリットを考えてみます。
ざっと思いつくのは以下です。

  • KeepAliveかつ、httpヘッダのパースも不要になるので速い
  • 特に断続的なリクエストが大量にある場合大きな優位となる(実験結果)
  • 冗長構成でサーバが複数台ある場合も単一クライアントからのリクエストは常に同一サーバに送信される
  • 単一接続からのリクエストは常に同一クライアントからのリクエストであることが保証される


速度メリットは実はおまけみたいなもので、重要なのは最後の2つです。これ、言い換えればWebSocketをAjaxの代替として使うことでステートフルな通信が可能になるということなんです。

既存のWebサーバーではリクエストルーティング機構のインスタンスはサーバー単位で1つなので、リクエスト処理の流れは

  1. リクエスト受信
  2. Cookieを使用してユーザーを同定
  3. 必要ならMemcache等からステート情報を取得
  4. リクエストを処理


のようになりますが、WebSocketの場合接続毎にリクエストルーティングのインスタンスを作ることができるので、2、3の手順がまるまる不要になります。

リクエスト処理のパフォーマンスを出すためになんらかのキャッシュを行う場合もオンメモリだけで間に合いますし、Cookieやhiddenパラメータを使って情報を引き回すことも不要になります。

# ただし、意図しない切断はありえるので長時間ステートを保持することや常にステートが維持されていることを前提としたプログラミングをすることはお勧めしません。この辺のベストプラクティスはまだ確立されていないので当面は自分のバランス感覚だけが頼りになります。(^^;


★ WebSocketとセキュリティ

前述の通り、WebSocketでは単一接続からのリクエストは同一クライアントからのものであることが保証されます。

近年のJavaScriptプログラミングでは処理全体をdocument#readyのクロージャで括るのが一般的ですが、その場合仮にXSSの脆弱性があったとしても外部から接続済みのWebSocketインスタンスにアクセスすることは不可能です。

つまり、最初の接続時にクライアントの確認をしっかりと行っておけば以降のリクエストは攻撃ではないと見なすことができます。なのでCSRFのチェック等は不要です。

問題は接続時の確認を、どのように行うかですがこれはこの資料が参考になります。

http://www.slideshare.net/muneakinishimura/webhtml5-31749532

ほとんどの場合はくログイン認証自体は従来のhttp(s)接続で行ってその後はCookie併用でクライアントを同定することになると思います。
http接続とws接続が同じオリジンであればこれで十分なはずです。


次節で紹介するWebSocketにはSame Origin Policyがないことを利用したスケールアウトを行う場合はもう少し考慮が必要になります。


★ WebSocketとスケール

とりあえずルームモデルでも単純な水平スケールが可能であることは確認済みです。


ただ、この方法には効率の悪い部分があります。

というのは、サーバ100台に対して100人のユーザが1つのルームに入室した場合、最悪100人全員が異なるサーバに接続する可能性があるからです。
ユーザがばらけるとバックエンドのRedisの負荷が上がるので同じルームのユーザは1台とは言わないまでも極力小数のサーバに集中してほしいのです。

HerokuやELBなどフロントにロードバランサがいる場合、こうしたリクエストを適切にふりわけることはできません。(パス毎にリクエストを振り分けるロードバランサがあれば、可能ですがあまり筋の良い解決方法とは思えません。)

が、実はもっと簡単な解決方法があります
WebSocketにはSame Origin Policyがないので単純にサーバを分けてしまえば良いのです。

ページをリクエストするホストが「http://www.quizar.info/...」だったとしても、その中でws接続するホストは「ws://room1.quizar.info/...」であっても良いわけですね。

この場合、接続時のクライアント認証をどうするかが課題になりますが、Cookieのドメインを明示するとかバックエンドキャッシュを使うとかいくつか方法はあると思います。(必要に迫られたらちゃんと考えます。(^^;)

このアーキテクチャを採用する場合、同一のコードベースから簡単に複数のアプリケーションを作成できるHerokuは最強のWebSocketプラットフォームだと思いますが、実際にやって良いかどうかはまた別の話です。(少なくとも課金を減らす目的でやるのはアウトだと思います。実際に必要になったら問い合わせますが、パッケージ買いでその範囲で行う分には問題ないだろうと思います。)


★ 課題

最大の課題はやはり切断時の対処です。HerokuもELBも無通信状態が長く続くと切断されますし、スマホの場合スリープやブラウザから別アプリに切り替えることも当たり前の操作なのでそれも考慮しなければなりません。また、Herokuを使う場合はデイリー再起動への考慮も必要になります。

この部分もフレームワークで吸収できればと思っていますが、もうちょっと試行錯誤が必要なのでそれはまたおいおい。(^^;

□□□□
以上、現時点でのWebSocketに対する考察でした。
WebSocket。既存のhttp通信の延長で考えている人が多いと思いますが、うまく使えば劇的なパラダイムシフトが発生するかもしれません。

どこに辿りつくのかわかりませんが、もうちょっとこの道を進んでみたいと思います。(^^;;;

2014年4月22日 (火)

WebSocketアプリのモデルを考える

ども。  
Salesforce Hackチャレンジに参加していたQuizarは安定の選外でした。。。 
ま、Salesforce1まったく関係なかったから無理もない。(^^;  

さて、それはさておきQuizarの製作を通してWebSocketを使えば今まで世の中に存在しなかったようなアプリを作れる可能性があるということを実感したわけですが、現実にはほとんどWebSocketアプリは開発されていません。

こうした状況の最大の原因は世の中にWebSocketアプリ開発のためのモデルやフレームワークがほとんど存在しないためだと思っています。

現状では低レベルのAPIだけはあるものの、それしかないからその上のモノは全部自分で作らないといけないわけです。
Quizarの開発過程でやったことだけでも、メッセージのルーティング、リクエスト/レスポンスの対応付けなど通常のWeb開発ではやらないようなプログラミングをかなり行っています。

状況としてはhttp/1.0の頃にServlet APIだけで開発していた極初期のWebアプリ開発に近いかな?
あるいは、ひと固まりのメッセージがあるだけでそこに何の付帯情報もないということを考えると生ソケットで直接メッセージを読み書きしている状況に近いという気も。(^^;

いずれにせよこの状態から一本のアプリを作り上げるのは結構な労力なわけで、逆に言えば、になんらかのモデルとフレームワークがあればWebSocketアプリ開発のハードルは一気に下がる気がします。

いくつかのアプリ開発を通してなんとなくその形が見えてきはじめているので、今回はそれをざっくりまとめてみます。


★ モデル

多分WebSocketアプリのモデルはほとんどすべてルームモデルに収まります。

「ルームモデル」という言葉は小西の造語ですが、とりあえず以下のように定義します

  • アプリ空間に複数のルームがあり、
  • ルームには複数の人が入室でき、
  • ルーム内にいる人同士がリアルタイムにコラボレーションできるアプリケーション

シンプルな定義ですが、それだけにほとんどのWebSocketアプリはこのモデルにあてはまるはずです。

Quizarは典型的なルームモデルアプリケーションですが、ルームの中にいるのはクイズの出題者と回答者という役割の違う2種類の人達です。
このようにルームに入室した各人の役割は複数あり得るので

  • ルーム内にはロールの異なる複数の人が存在して良い


というのも定義に加えて良いかもしれません。


★ フレームワークに必要な機能

次にルームモデルアプリケーションを作成するために必要な機能を考えてみます。
サーバー側にルームを管理する機能が必要なのはもちろんですが、最低限メッセージのフォーマットを決めておかないとリクエストのハンドリングもままなりません。
また、クライアント側も必然的にSPA(Single Page Application)となるのでWebSocket以外にも多くの機能が欲しくなります。

ここではとりあえずメッセージ、サーバー、クライアントの3つにわけて必要と思われる機能を列挙してみます。(細かく説明し始めるとあまりにも長くなりそうなので。。。)

ちなみにこのリストもQuizarの開発経験からの逆引きです。

● メッセージ

  • JSON形式のエンベロープとする
  • リクエスト毎にIDを持つ
  • リクエストのコマンドが識別できる
  • 任意複数のパラメータが渡せる
  • レスポンスのエラーが識別できる
  • JSON、HTML、Textなど複数の形式のレスポンスを返すことができる


● サーバー

  • 複数のWebSocket接続を束ねるルームを持つ
  • ルームの永続化(RDB等へのルーム情報の保存)機能は範囲外
  • スケールアウトするための外部のPub/Sub機能を利用できる
  • ルーム内ユーザーへのメッセージブロードキャスト
  • ブロードキャストメッセージのフィルタリング
  • メッセージのルーティング
  • メッセージのロギング


外部のPub/Subは今のところRedis以外に知りませんが、差し替えられるように抽象化はした方が良さそうです。

● クライアント
クライアント側ではルームモデルに限らずSPA全般で必要となる機能も含みますが、それぞれの機能は独立して使えるモノとします。

  • WebSocketをAjaxライクに使用できる(リクエストに対応するレスポンスを取得できる)
  • メッセージのエラーハンドリング
  • リクエストにひもづかないメッセージのルーティング
  • サーバーサイドからの切断時の再接続
  • アイドル状態の識別とイベントハンドリング
  • プラグイン可能なデバッグログ
  • ポーリング
  • WebStorageでのテンプレート管理
  • PushState対応


サーバーとの通信はAjax併用でも良いんですが、多分全部WebSocketでやる方がシンプルだし速度面やセキュリティ面でも優位があります。(これはそのうち別に書きます。)

逆に面倒な部分としては切断時の対応とデバッグ(ブラウザのWebコンソールでメッセージを見ることができない)があるんですが、これらをうまくフレームワーク側で吸収できればメリットだけを享受することもできるはずです。

□□□□
とりあえず、こんなところでしょうか。
なんか忘れてる気もしますが、まぁそれはおいおい(^^;

実際にはQuizar開発当初からフレームワーク化を意識していたので、上に書いた内容は概ね実装イメージがあります。(もちろんブラッシュアップや再考が必要な部分も多々ありますが。。。)

サーバーサイドはWebSocketとRedisのPub/Subが使えれば何でも良いんですが、とりあえずPlayで。(他でも作るとしたら多分次はNode.js)

というわけで、6月末を目途にフレームワークとなんか適当なルームモデルアプリを作ります。(^^v



2014年4月16日 (水)

HerokuのWebSocketでC10Kに挑戦(後篇)

割り込みによって書けてなかったHeroku C10Kの続きです。


テスト実施から少し時間が空いてしまったため、改めてまとめようとすると疑問点や追試したいこともあるんですが、当面これ以上時間を割くことができそうにないのでざっくりとまとめてしまいます。

 

★前篇のおさらい

前篇の内容から今回ポイントとなる点をピックアップすると以下のようになります。

  • 1Dynoでさばける同時接続数は400前後。
  • それを越えるとH11の接続エラーが返ってくるようになる。
  • 雑なテストプログラムで25台のDynoに1万クライアント接続を試みたところ少なくとも5600位は繋がったっぽい。


「繋がったっぽい」というあいまいな表現になっているはテストプログラム側で何を持って成功とみなすかという点をはっきりと決めていなかったためです。
エラーが発生しなければ試行数をそのまま成績と判断できますが、途中でエラーが発生した場合そのテストがどの程度の成績を残したのかということを判断する基準がなかったんですね。

なので、それを踏まえてテストのレギュレーションは以下のように決めました。

  • ルームを100個用意する
  • 各部屋に3秒に1人ずつ、100人(100クライアント)入室する(最大時同時接続1万クライアント)
  • 各クライアントは5秒に1回チャットメッセージを投げる(合計100万メッセージ)
  • 各ルームに最初に入室したクライアントの受信したメッセージ数の合計をテストの得点とする(満点は100万点)


各部屋では100人が100回発言するのでエラーがなければ最初に入室した人は1万回メッセージを受信するはずです。
負荷があがってくると入室(WebSocket接続)時にエラーとなる可能性がありますが、負荷のかかっていない最初の入室者がエラーとなることはほとんどありません。

つまりエラーが全く起こらなかった場合の各クライアントの得点は10000点(100メッセージ × 100クライアント)で、クライアントの接続エラーが起きた場合は-100点(そのクライアントは一度もメッセージを発信しないから)、個別メッセージの送受信でエラーが発生した場合は-1点となります。
なんらかの理由でこのクライアントのWebSocket接続が途中で切断された場合は、以降のメッセージは受け取れないので、この場合は極端に低い得点となる可能性もありますがここまでの経験則から一度確立したWebSocket接続はかなり安定して動作することがわかっているので、その場合もそれをそのまま得点とすることにします。

ちなみにテストプログラムは前回使用したものから以下の改良を行いました。

  • WebSocketクライアントをjava_websocketからAsyncHttpClientに変更
  • 接続エラー時には最大10回のリトライを行うようにした


ノーマルSocket + Thread監視のjava_websocketはやはりメモリ消費量が多かったので1プロセス内でたくさんの接続を作れなかったのと、前回のテストからH11はリトライである程度回避できるのではないかと予想したからです。

テストは25Dyno(1X)と30Dyno(1X)の2回行いました。


★ 1回目 25 Dyno(1X)

得点: 795555

ぎりぎり8割いかなかった。。。(--
しかし、意外と良い数字という気もします。
傾向としては以下のような感じです。

  • 各クライアントの最低点は4152、最高点は9687.
  • 得点分布は5200点半以下(24クライアント)と8300点以上(76クライアント)にわかれている
  • 6000点台、7000点台を取ったクライアントは何故かいない
  • 満点(100000点)を取ったクライアントもいない
  • H11は少し発生しているがリトライで接続できているらしい
  • 多分接続自体は1万クライアント全部成功している
  • IOException多数


得点の低いクライアントは途中で接続が切断されています。サーバ側のログを見るとその頃に複数のDynoでIOExceptionが多数記録されていますが原因は不明です。
その後しばらくはエラーなくテストが進行していますがその理由も謎です。

また、10000点を取ったクライアントがいなかったことも特徴的です。はっきりとした数字は数えていませんが前回のテストでは10000点を取ったクライアントがかなりあったはずです。
これはクライアントをjava_websocketからAsyncHttpClientに変更した影響かと思っているんですが、過負荷な状況ではNonBlocking I/Oはメッセージの一部を取りこぼすことがあるんでしょうか???

どなたか知見のある人は教えてください。(^^;;;


★ 2回目 30 Dyno(1X)

考察もそこそこに2回目のテストへ。今回テストサーバも結構な数のDynoを使っていますが、負荷をかけるクライアントの方では2XDynoを100台使っていたり、Redisもいいお値段のものをテスト実行中のみ追加していたりする関係でテスト実行にかかる時間は1秒でも短い方が良いのです。(^^;

2回目は変更した条件はサーバ側のDyno数のみ30台。結果は。。。。


得点:999976

おー?!マジでか???
まさかのフォーナイン!ほとんどのメッセージが拾えています。

傾向としては以下のような感じ

  • IOException激減
  • 発生しているIOExceptionは「broken pipe」とか「connection reset by peer」とか
  • H11未発生


1Dynoあたりの平均接続数は400クライアント(10000 / 25)から333クライアント(10000 / 30)に下がってますが、それでこんなにも結果が違うんですね。

ちなみにRedisの負荷はサーバ数が増えれば大きくなるはずですが、こちらは何の問題もなくリクエストを捌いていたようです。

これ、タイトルにある「HerokuのWebSocketでC10Kに挑戦」はとりあえず達成と言っても良いんじゃないでしょうか?
まぁ金で解決しただけと言われればその通りなんですが、IOExceptionはアプリ側の問題なのでチューンすればもうちょっと少ないDyno数でC10Kを達成できそうな気はします。
あとWebSocketアプリ限定で使えるもっと効率的に負荷分散する方法も思いついているのでこれは多分そのうち書きます。


★ その他補足事項

どこに書こうか迷ったんですが、収まりの良いところがなかったのでここで。

前回、「1dynoあたりの接続数をもっと増やせないか?」という問い合わせをHerokuに対して行っているということをちらっと書きましたが、その回答が実は来ています。
回答を要約すると


とりあえず同時接続数増やしたよ。我々の目標とする数値には届いていないのでまだルーターの改修は続けるけど、前よりは格段に接続数増えたはず。試してみれ


て言う感じです。
で、上のテスト結果はおそらくその改修が効いた状態でのテストです。(どこかでもう全部のアプリで有効になっているという文章を読んだ気がするけど、探しても見当たらないので見間違いだったかも。ChangeLogにはあがってないので、ルーター改修はまだ作業中かもしれません。)

1Dynoで追試を行ったところH11に対してリトライをかければ800~1000位は繋がるようなので、たしかに以前よりはずっと同時接続性があがっているようなんですが、いまいち結果が安定していない気がするので、とりあえず結論は保留です。

2X Dynoや PX Dynoを使ったテストもそのうちするかもしれませんが、早くても来月以降になると思います。(何故なら2X Dyno100台を3時間あげるとそれだけで600Dyno Hourの消費になるから。。。(^^;;;)

2014年4月 9日 (水)

続OpenSSL祭り - 現在の状況は多分こんな感じ

昨日ブログを書きあげた後で素晴らしいまとめ記事を見つけました。

http://d.hatena.ne.jp/nekoruri/20140408/heartbleed

もうHeartbleedに関してはこれだけ読んでおけば良いんじゃないかと。(^^;

昨日書いた自分の理解はおおむね合ってたようですねぇ。。(^^v
ハッハッハッハッ。。。最悪です。

特に攻撃を受けた側が、攻撃されたかどうかを判断する術がないというあたりがいかんともしがたい。(--

技術情報に関しては上記でもう十分な気がしますが、イマイチ世間(非IT含む)に今回の件の深刻さが伝わってない気がするのでちょっとたとえ話をしてみたいと思います。
若干大袈裟な表現と感じるところがあるかもしれませんが、それはワザとです。
不安になったら自力で調べてみてください。


あなたは自分の大切なモノを保管するために部屋を借りました。その部屋には世界で一番売れている錠前が付いているので安心です。(^^v

ところが!

その錠前には必殺のピッキング技があって全ての錠前を鍵なしで開けることが可能だったのです。ナニ―(+o+)

あなたはあわてて錠前屋を呼んでピッキング対策をを行ったので、現在ではそのピッキング技は使えません。しかし、そのピッキング技が有効だった期間は約2年あります。。。
なにしろ世界中で使われている錠前だったのでもう世界中大パニックです。今のところ実際に被害があったという話は聞かれませんが、今まで安全と信じていたものが実はそうではなかったということが問題です。

あなたは改めて部屋を見渡してみます。どこにも侵入者があった形跡はありません。しかし部屋の中にはマスターキーもあるので、侵入者がそれを持ち出して合鍵を作った可能性は否定できません。

さて、あなたは錠前を交換するべきでしょうか。。。。




。。。というのが、現在の状況であるというのが僕の認識です。

その部屋が自分のものしか置いていない場所であれば、鍵を取り変えないという選択もあるかもしれません。実際のところ本当に侵入者があって鍵を持ち出した可能性というのは極めて低いだろうとも思います。

では、これが自分の部屋ではなく貸倉庫のような場所だったとしたらどうでしょうか?

あなたは貸倉庫を運営していてお客に保管スペースを提供しています。その部屋には世界で一番売れている錠前が付いているので安心です。(^^v

ところが!

(以下同文)

さて、あなたはこの倉庫の錠前を交換するべきでしょうか。。。。




いかがでしょう?普通の感覚であれば鍵が交換されない限りこの倉庫を使おうとは誰も思わないんじゃないでしょうか。。。僕の感覚では鍵を交換しないという選択肢はありません。

さらに付け加えるとすぐにピッキング対策を行ったあなたはまだ良心的な方で、実際にはピッキング対策を行わないままその錠前を使い続けている人が山ほどいるのです。。

。。。あー、書いててまた憂鬱になってきた。。。(--

実際のところ自分の使っている銀行やクレカのサイトでは現時点でこの問題に対して何のアナウンスも出ていないので、そろそろ「お前らのところは本当に大丈夫なのか?!」と問い合わせようかと思っているところです。(このブログのURLつけて)

ちなみにMoneyTreeという銀行口座のまとめサービスは現在サービスを停止しています。
お金を扱うサービスではこれ位の配慮は欲しいですよね。(他人事ではないのですが。。。)



もう本当に世の中のすべてのサイトでHeartbleed対応がどうなっているのかを明記してほしいですわ。。。(--


ところでCA(ここでいう錠前屋)は証明書(鍵)の無償交換に応じているところが多いようですが、あんたの所のリクエストフォームはHeartbleed対応されているの?っていうこともとても気になります。。。(--

(4/10追記)

若干文章修正しました。テクノロジー色の強いサービスを中心に徐々にパスワード変更を推奨というメールが届き始めています。(自分がほとんど使っていないので)ショップ系のサイトの対応がどうなっているかはわかりませんが、何のアナウンスも無いところには自分から問い合わせても良いでしょう。

2014年4月 8日 (火)

OpenSSL祭り(CVE-2014-0160)

ども。
本当はC10Kの後篇を書こうと思ってたんだけど世間はOpenSSL祭りなので、それに乗っかったエントリを書いてみる。

なお、これから書く内容はあくまでも小西の個人的な理解なので、正しいという保証はどこにもありません。

言っちゃなんですが、セキュリティとか暗号とかはどっちかと言うと苦手分野です。(^^;;;

しかし、書くことによって自分の理解が進んだり新たに気付くことがある。という経験則があるので、とりあえず書いてみることにします。

いつにもまして、ツッコミ歓迎


★概要

http://heartbleed.com/

にまとまってます。
ざっと僕の理解(くどいようですがあくまで個人的理解)をまとめると以下のような感じです。(上記サイトに書いてあることだけでなく、他のサイトで見た内容も含まれています。)

  • OpenSSLに深刻な脆弱性が見つかった
  • この問題はSSL/TLSプロトコルの問題ではなくあくまでOpenSSLの実装の問題
  • 過去2年間のOpenSSLリリースすべてにこの脆弱性が存在する(1.0.1以降)
  • この脆弱性を利用するとSSL通信を行っているホストのメモリを読むことができる(一度に読めるのは64Kまでだが、繰り返し何度も実行することができる)
  • OpenSSLを使っている著名なWebサーバとしてはApacheやnginxがある
  • 問題のあるバージョンのOpenSSLがバンドルされているOS多数


。。。ダメじゃん。。。(--

コンピュータ上のすべての処理は一度メモリを経由するわけで、それを考えるとSSL証明書とかクライアントから送信したユーザー名とパスワードとかクレジットカードの番号なんかまで全部どこかのタイミングでメモリに載るわけで、可能性としてはそれら全部を盗むことができるわけです。

。。。ホンマかいな。。。(--

 

★サーバがJavaなら大丈夫?

いいえ、そんなことはありません。
クライアントから直接Java製のサーバに繋いでいるのであれば大丈夫なはずですが、

  • フロントにApacheがいる
  • ELBをhttpモードで使っている
  • Herokuを使っている


全部アウトです。
Apacheは言わずもがな、Herokuのフロントエンドはnginxのはずですし、ELBも問題があることがアナウンスされています。

ロードバランサに脆弱性がある場合、攻撃者が読めるのはロードバランサのメモリまででバックエンドにあるアプリサーバのメモリは読めません。

しかし、HerokuもELBもSSLをロードバランサがほどいてバックエンドとの通信はhttpで行っていたりするので、そこでの通信内容はメモリに載ります。

逆に言うと

  • 一度も通信に載らないHerokuの環境変数などが漏洩することはない(言語は関係ない)
  • ELBをTCPモードで使用している場合は問題ない


と思ってるんですが、今のところ誰からも同意を得られていません。。。

。。。ホントにそうか???。。。

★ベンダの対応状況など

ネット上の情報によるとAmazon Linuxはパッチがでたようですね。

http://qiita.com/tachiba/items/83e5fd31d06e6577abb3

ELBはまだのようです。

Herokuの対応状況はstatus.heroku.comで確認できますが、SSLアドオンが影響受けるので対応終わったら証明書を再発行しろとか書いてあります。

https://status.heroku.com/incidents/606

。。。マジでか。。。(--

Heroku Postgresを再起動するというメールも来てるらしいですが、そういえばPostgreSQLとの通信もSSLでした。。。(--

 AWSとかSalesforceのアクセスキーなんかを全部Regenerateしろ、とか言われそうでかなり憂鬱。。。(--

 (4/9 追記)

例えばAWSのアクセスキーが環境変数に設定されている場合、Herokuルーターのルートからそれが外部に漏洩しなかったとしても、肝心のAWSサーバーに脆弱性があれば、やっぱり再生成が必要なわけで、結局のところアクセスキーの類は全部再生成が必要な気がします。


★その他個人としての対応など

サーバー側の心配もありますが、個人で使用しているアカウント類の心配もした方が良いのかもしれません。脆弱性のあるサーバにログインするとそのユーザー名、パスワードを盗まれている可能性があるわけで。。。

パスワードを変更した方が良いとは思うんですが、今それをやってもそのパスワード変更リクエストが盗まれる可能性があるので、どないせーっちゅーねん。。。(--

とりあえずはベンダーからのアナウンスがあるまではアクションを起こすべきではないんじゃないですかね。。。

おいおいGoogleとかEvernoteとかからパスワードを変更しろっていうメールが届き始める気がしますが、絶対フィッシングとかしかける奴がいる気がするので、ドメインとかちゃんと確認した方が良いですよ。


心の底から思うんですが、誰か間違ってると指摘してください。(--

続きを読む "OpenSSL祭り(CVE-2014-0160)" »

2014年4月 4日 (金)

HerokuのWebSocketでC10Kに挑戦(前篇)

前回SalesforceハッカソンにWebSocketのクイズアプリを出してきたよ~という話をしたわけだが今のところ身内以外からはほとんどアクセスされてないっぽい。
まぁほとんど宣伝してないからそれは別に構わないんだけど、審査されている形跡もないのは大丈夫なのか。。。(^^;


さて、それはさておきWebSocketアプリを作ったら是非試してみたいと思っていたことのひとつにC10K問題の検証と言うのがあります。
C10Kとはクライアント1万台問題の略で平たく言うと「WebSocketってクライアントとずっとソケット繋ぎっぱにするわけだよね。そんなのクライアントの数がちょっと増えたらあっという間に破綻するんじゃね?」という問題のことです。


★検証シナリオ

今回作ったアプリにはルーム毎にチャットの機能があるのでそれを利用することにします。
具体的な目標数値としてはとりあえず以下のように設定しました。

  • ルームを100個用意する
  • 各部屋に3秒に1人ずつ、100人(100クライアント)入室する(最大時同時接続1万クライアント)
  • 各クライアントは5秒に1回チャットメッセージを投げる(合計100万メッセージ)


とりあえず1万クライアント。全員を同じルームにいれちゃうとチャットのブロードキャストがえらいことになってしまうので、ルームだけは分けることにします。

3秒とか5秒とか段階的に負荷を増やしているのはWebSocket接続はだいたい1接続が1人の人間に対応するので、人間の操作としてそこまでの連続リクエストはこないだろうと思われるからです。(先にDevSumiで行ったデモは特殊な例です。(^^;)

この数字をもう少し細かく見ていくと以下のような負荷になります。

  • 最大時秒間2000メッセージ(1万人が5秒に1回メッセージ送信するから)
  • その時のブロードキャストメッセージが20万件(1メッセージはルーム内の100人にブロードキャストされるから)
  • 1クライアントが1秒間に受信するメッセージは20件(ルーム内の100人が5秒に1回メッセージ送信するから)


。。。やりすぎ?。。。

しかし、普段負荷テストをする時はJMeterでぶんぶんリクエスト投げてるわけだから、3秒に1人追加とか5秒に1回のメッセージとかもの凄く手加減してる気分なんだが。。。。(--

それに1クライアントあたり秒間20件のダウンロードがあると言っても、チャットのメッセージなんか1000個あってもそこらのHTMLページのサイズよりも小さいだろうから、通信のコスト自体はどう考えてもhttpアプリのJMeterテストよりも低いはず。
そもそもWebSocketアプリの負荷テストのセオリーがわからないし、テストツールも自作するんだからとりあえずやっとけやっとけ。

Herokuはこの程度の負荷ではおかしくならない!(多分)


★とりあえず1dynoでテスト

いきなり高負荷のテストをしようにもどの位のDynoを用意すれば良いのかまったく見当がつかないのでまずは1dynoの臨界点を見極めることにします。

手始めに

- 1ルームに100人入室、100メッセージ送信

というテストをしてみたところ、何の問題もなく正常終了しました。
まぁNon-Blocking I/Oを使っているんだからこれくらいはやってもらわないと、という感じです。(^^;
ちなみにこの時点でテスト環境で使っているRedisはRedisCloudの無償版です。無料枠でもこの程度のリクエストは捌けるってことですね。

ここから人数とメッセージ数はそのままでルームを増やしていきます。



- 2ルームに100人入室、100メッセージ送信

まだ何のエラーも起こりません。
メモリ使用量も200MB未満なのでかなり優秀です。
Play(というよりもNettyとAkkaのActor)はかなり筋が良いんだろうと感じました。


- 3ルームに100人入室、100メッセージ送信

接続できないクライアントがでてきました。
が。。。サーバー側にエラーログが出ていないところを見るとどうやら限界を迎えたのはクライアント側っぽい。
テストクライアントはjava_websocketを使ったPlayアプリケーションとして作っているんですが、このライブラリが内部的に使っているのは通常のSocketクラスなので、この辺がNon-Blocking I/OとNormal I/Oの差でしょうか。またjava_websocketはSocketの監視のために接続毎にスレッドを作っているのでその辺もメモリ使っちゃって臨界が早い原因になっていると思います。

ここから先はテストクライアントもHeroku上で複数dynoを立ててのテストとなります。テストクライアントをHerokuにあげて実行したらこれもクリアしました。

本当に優秀。。。ていうか予想ではそろそろエラーになるはずなのになんで動いてるの?って感じ。。。(^^;;;


- 4ルームに100人入室、100メッセージ送信

ここにきてようやく2種類のエラーが発生しました。

まずそろそろ来ると思っていたRedisの最大接続数到達エラーがでました。
無料枠のRedisの接続数はたったの10個しかありません。RedisClientはコネクションプールから取るようにしていますが同時接続数が増えると当然並列で使われる件数が増えます。また、それ以上に影響が大きいと思われるのはルームの数だけRedisのSubscriberが必要になる点です。4つのルームがアクティブなら4つのコネクションがそれぞれのルームに占有されます。つまり同時接続数は増えているにも関わらず使えるコネクション数は減っているわけでむしろよくここまで持ったと思います。
本番環境ではRedisGreenを使ってますが、この先のテストでは接続数無制限のRedisCloud(2.5GB)を使うことにします。


またHerokuのRouterがH11を返すようになりました。このエラーの意味はDevCenterのドキュメント、Request queueingのあたりに書いてあります。


HerokuのRouterは1dynoに対して50同時接続しか行わずそれ以降はキューに入ります。そのキューがあふれた場合にこのエラーが発生するわけです。
しかし実際には400近くの接続が1dynoで行われています。これが何でかというとルーター自体が複数台あるからです。結果からの推測では1アプリで少なくとも8台ルーター使ってる計算になります。
なので、H11が発生した場合でもリトライすると別のルーターに繋がってあっさりと接続できたりします。(はっきりと裏を取ったわけではありませんが高負荷時にブラウザからアクセスした際にそれらしき現象を確認しました。)

この動作はWebSocketに限らずhttpアクセスの場合も同じはずです。Httpクライアントからのアクセスがエラーとなった場合に直後にリトライするのって意味あるんだろうか?と思ってましたが、少なくともHerokuでは意味があると言えます。(まぁH11が発生しているなら素直にdynoを増やせっていう話ではありますけど。)


★1dynoの限界

ここまでの結果からH11が発生する400前後が限界となります。
ただしサーバー側のメモリ使用量を見ると300MB前後なので、ルーターさえリクエストを回してくれればもっと多くのリクエストを1dynoで捌けるだろうとは思います。

ちなみに2X dynoの場合でもこのルーターの制限値は変わらないようで、これはもうちょっとなんとかならんのか?あるいはWebSocket有効のルーターでは制限値を引き上げられないか?ということをサポートに問い合わせ中です。

どうやら現在ちょうどルーター周りの改修を行っているらしく、うまくいけば近々対応されるかもしれません。(みたいな返事が来ているが実際のところはどうなのか謎。。。)

この結果を受けて1万クライアントを捌くには25dynoくらいだろうと辺りを付けて実際試してもいるんですが続きはまた今度。
これ書きながら追試したいことやサーバーサイドを直したいところも出てきているので。(Herokuに問い合わせ中のモノもあるし)

ちなみに現在のところ、完全にノーエラーで接続できていると確認できたクライアント数は5600台位です。

傾向としては1度接続が確立したクライアントの動作は安定しておりパフォーマンスもほとんど悪くならないようです。(何故ならソケット繋ぎっぱだから。)

負荷がかかってくると接続時にエラーになることが多いようで、そこをなんとかすれば7,8000まではすぐに行くんじゃないかという気もしてます。(1回のテストで2GB以上のログが出るんで雑な検証しかしてませんが。。。(^^;;;)

後篇がいつになるか(あるいは本当に書かれるのか?)は未定です。(^^;;;

2014年4月 1日 (火)

WebSocketクイズアプリを作りました

約3週間ぶりのエントリですね。(^^;
気が付けば新年度。道理で電車が混んでるわけだ。。。(--

この一ヵ月ずっとSalesforce1 Mobile Hack Challengeに出す用のアプリを作ってました。

んで、作ったアプリがこちら

複数の人が集まってクイズ大会ができるパーティアプリみたいな感じのものですね。(自分の行動範囲の中では)主にIT系の勉強会での使用を想定してます。

コンテスト的にはSalesforceを使ってないという時点でもうアウトなんじゃないかという気がしなくもありませんけど。。。(^^;

コンテストの結果はともかく、このアプリの最大のテーマは、

業務アプリの作成ではまだまだリスクがありそうに感じる最新技術を使い倒す

ことだったので、それはそれで価値のある仕事だったんじゃないかと思います。
もちろん、このアプリがどこぞの勉強会で使われるのであればそれはとても嬉しいことです。

★WebSocketアプリの可能性の話

今回クイズアプリとして「出題者 vs. 参加者」というモデルのアプリケーションを開発したわけですが、個人的にはこうした「ルームマスター vs. 参加者」というモデルのアプリケーションが存在するということに気が付いたことが最大の収穫でした。

これまでずっと「WebSocket、理屈はわかるけどどういうところで使うんだろ?ゲームとかか?」みたいなことを思ってたんですが大間違いでしたね。

そんな風に思うのは既存のhttpの枠組みでのWebアプリに慣らされすぎているための視野狭窄だったと今にして思います。無意識のうちにこれまで存在したアプリの中でどこにWebSocketを適用するのが有効なんだろう?という方向に思考が制限されていたわけですね。

WebSocketの例としてよくチャットが引き合いに出されることもその視野狭窄推進に一役買っていると思っていて、これなんかも結局は「今までこうだったものが、こう変わります。」という説明でしかないわけです。そしてその説明が納得感の高い物であるが故にそこから先に進むことが難しくなっていた気がします。

WebSocketを考えるのであれば、むしろ今まで世の中に存在しなかったモデルのアプリケーションを作る、という方向で考えた方が良いと思います。
多分そこには宝が眠っています。(^^;


★クライアントサイド技術要素の話

このアプリで使用しているクライアントサイドの技術要素にはだいたい以下のモノがあります。

  • WebSocket
  • SessionStorage
  • PushState
  • CSS3 Animation


本当はあとWebWorkerを使ってみたかったんですが使いどころを思いつかなかった。(^^;

ひとつひとつは既に日本語での詳細解説ページも多数あるので目新しい物ではないですが、お試し程度に使っているのではなくちゃんと一つのアプリを作るために協調的に使われているというのがミソです。

例えば

  • Ajaxは一切使わずに通信は全部WebSocketで行っている
  • テンプレートは全部SessionStorageに入れて使いまわしている


というようなことをやっているんですが、このあたりは理屈ではできると思ってもなかなか実案件には適用しにくいモノなんじゃないかと想像します。(一昔前のAjaxがそうであったように)

実際のところ、これらのことをアプリ開発の度に作りこむのは辛すぎるので何かしらのフレームワーク的なモノを使いたくなるんですが、現状ではそうしたライブラリもほとんどないので全部自作です。(^^;;;

次回以降こうした部分についてのノウハウを書いていきたいと思います。

乞うご期待!(全然関係ないですが今日は4月1日ですね)

採用情報

株式会社フレクトでは、事業拡大のため、
Salesforce/Force.comのアプリケーション
開発
HerokuやAWSなどのクラウドプラッ
トフォーム上でのWebアプリケーション開発

エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみた
い方、是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、
セールスフォースパートナーです。
heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。
Powered by Six Apart