ApacheにGoogle謹製の高速化モジュールmod_spdyを入れる

SPDY

あんまりプロトコルについて調べてないので何ともいえないですが、HTTP Pipeliningをさらに改善したようなプロトコルです。
ひとつのTCP接続において複数のストリームが束ねられ、それらについてプライオリティをつけることができます。
ほかにもヘッダなどが圧縮・最適化されます。たとえば、User-Agentなどは一度のセッションにおいて変更されることはないといっていいので、それを省いたりします。
ファイアウォールをすり抜けられない可能性があるので、HTTPSのなかで隠蔽することでこの問題を回避します。

前準備

sudo apt-get install subversion curl g++ patch binutils make
mkdir modssl
cd ~/modssl/
svn export http://mod-spdy.googlecode.com/svn/trunk/src/build_modssl_with_npn.sh
./build_modssl_with_npn.sh
sudo cp mod_ssl.so /usr/lib/apache2/modules/
sudo a2enmod ssl

depot_tools

cd ~
cd depot_tools/
svn co http://src.chromium.org/svn/trunk/tools/depot_tools
cd ..
export PATH="$PATH":$HOME/depot_tools
echo $HOME
cd ~

いよいよmod_spdyのビルド

mkdir mod_spdy
cd mod_spdy/
~/depot_tools/depot_tools/gclient config http://mod-spdy.googlecode.com/svn/trunk/src
~/depot_tools/depot_tools/gclient sync --force
cd src/
make BUILDTYPE=Release
sudo cp out/Release/libmod_spdy.so /usr/lib/apache2/modules/mod_spdy.so

設定

sudo echo "LoadModule spdy_module /usr/lib/apache2/modules/mod_spdy.so" | sudo tee /etc/apache2/mods-available/spdy.load
sudo echo "SpdyEnabled on" | sudo tee /etc/apache2/mods-available/spdy.conf
sudo a2enmod spdy
sudo /etc/init.d/apache2 restart

設定が終わったら、サーバにアクセスして chrome://net-internals/#spdy でSPDYが有効かどうか確かめましょう。
たぶんブラウザの設定だと思いますが、SSLでないとSPDYが有効になりません。

コンテンツ保護用の難読化jQueryプラグインを公開

HTML5が流行っていますが、割と社会ではFlashが好まれます。なぜかというと、難読化なんかのノウハウがFlashでたまっているとか、そういう理由があります。

MissingLinkではHTML5のノベルゲームエンジンを作ってましたが、それはコンテンツ保護はできず、シナリオを抜こうと思えばいくらでも抜ける、そんな状態でした。
一応コピペはできない(右クリックはおろか、選択もできないし、JSをオフにすると文字がでない)ようになっていましたが、問題はコンテンツの部分でした。コンテンツはJSONで書かれており、ダウンロードしようと思えばできます。
その生データを読みにくくできないかということで、1時間くらいで書いたのがこれです。
ぶっちゃけ、ブラウザのHTML要素の部分をエンドポイントまで難読化しているもので、HTMLソースを見ていただけるとわかるように、XOR難読化されています。解読をするには、jQueryプラグインで$.javascrypt()というメソッドを実行する必要があります。
それによって難読化された要素が動的に復号化され、表示上は平文が表示されます。
以下のデモでは、クリックをすることによって解読処理がなされますが、もちろん$(document).ready()で読み込み直後にメソッドを実行することが可能です。

デモとソースコード

デモ: https://web.missinglink.co.jp/keiya/javascrypt/
ソースコード: https://github.com/MissinglinkCorp/javasCrypt
ライセンスは修正BSDです。

サーバ側のPHPソースコード例

全文: https://github.com/MissinglinkCorp/javasCrypt/blob/master/index.php

<div><span class='_k_javascrypt'><?php echo $encrypted ?></span></div>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
<script src="https://web.missinglink.co.jp/keiya/javascrypt/jquery.javascrypt.js"></script>
<script>
		$('#dec').click(function(e){
			$('._k_javascrypt').javascrypt();
			$(this).hide();
		});
</script>

仕組み上、サーバとクライアントの時計がたぶん99秒以上ずれるとコンテンツの解読ができなくなります。この値はもっと厳しくすることが可能です。ソースコードを改造すると、1秒までしか許容できないようにすることが可能です。PHP側のコードを工夫すれば1msでもできるかもしれませんが、ネットワークの遅延があるので実用できないと思います。
この仕組みによってサーバから送信され時間が経ったコンテンツ、つまり保存したコンテンツを解読するのは難しくなります(ただ読み込んだ時間を控えていれば解読は可能です)。解読するにはブラウザのエクステンションなどで読み込んだ直後に難読化のシード(種)と難読化文を読み取る仕組みが必要となるわけです。

HTML5ノベルゲームの例では、暗号化JSONをJavaScriptで動的に読み込んで解読させるコードを追加する予定ですが、これによってChromeでInspectorを起動して何のJSONが読み込まれているのか判断し、ダウンロードして読もうとすると、わけのわからない数字の配列があるためにあきらめる、くらいにはできると思います。まぁ、これは暗号ではないので、すぐに解読できますし、ある程度のスキルがあればブラウザエクステンションなどをつくっていくらでもほじくりまわせるとは思います。
これに関しては「私的利用上の」DVDのリッピングや「私的利用上の」ノベルゲームからのシナリオ抽出と同じ部類に入ると思いますし、いたちごっこですので仕方ないと思います。(何せ、クライアント側のソースコードがオープンなのですからね。。)

注意点ですが、もちろんコンテンツの安全性を保障するわけではないので、クレカや住所などにつかわないでください。

今後は、JPEGやPNG、MP3などを独自のフォーマットにするコンテンツ保護を考えてみようと思います。幸い、HTML5のAPI(というか次世代のECMAScriptの仕様?)にArrayBufferという、バイナリを扱うクラスがありますので、それがつかえるんじゃないかと、適当に考えています。

MongoDBのメモ

コレクション

テーブルに相当するのがコレクション。
コレクションには普通のコレクション以外にcappedコレクションというコレクションの種類がある。高速で、コレクションに挿入された順を保持する。コレクションを作る際にサイズを指定しなければならない。

サイズに到達すると古いものから消される。
cappedコレクションからデータを削除できない。コレクションごとdropする必要がある。

インデックス

RDBおなじみのインデックス。使い勝手は似ているっぽい。

インデックスの文字列評価はcase-sensitive

http://www.mongodb.org/pages/viewpage.action?pageId=5800049

MongoDBさわってみて思ったこと

感じとしてはJSONのキーの部分で検索ができるようになった、というところ。スキーマを気にせずデータを放り込めるし、それでいて検索は楽にできる。これは素晴らしい。

この性質は、Facebook APIやTwitter APIのJSONをほうり投げる際に便利で、RDBでやっていた面倒なことすべてがばからしく思える。

問題はデータの整合性。RASISのI:Integrityの部分。なんか基本オンメモリで、数十秒に一度のディスクへのflushするらしいので、それでプロセスがコケるとデータが飛ぶとか。最近のバージョン1.8からはjournalingがついたようなんだが、それでデータ破損は抑えられたのだろうか。

あとAuto-sharding周りが不安定だと聞く。前にFoursquareで起きたトラブルもそれに起因するとか。

いずれにせよあと数年は人柱の覚悟が必要だろうなー、まあ次作るサイトで使うんだけど。

SSLの導入

まず、サーバにOpenSSLが入っていることを確認します。

Debian

秘密鍵とCSR

まず秘密鍵の作成です。秘密鍵にパスフレーズを設定できますが、設定するとサーバの起動ごとにパスフレーズの入力が必要になるようです(未確認)。
一つ目のコマンドで秘密鍵を生成し、二つ目のコマンドはCSR(署名要求)で、公開鍵に対する署名を証明書の発行会社に要求します。
ここでは、256bit AESの強力な暗号を利用します。

$ openssl genrsa -out private-mlssl-2011.pem 2048 -aes256
$ openssl req -new -key private-mlssl-2011.pem -out csr-mlssl-2011.pem

これによって生成したCSRを証明書の発行会社に送ります。数日で中間証明書と証明書が来ます。それをApacheの設定で読み込ませ、サーバーをリスタートさせます。
CSRのファイルをなくしても秘密鍵からCSRを作成できますが、秘密鍵をなくしてしまうとSSL通信もできないばかりか、CSRも作成できなくなります。
Cf. https://www.verisign.co.jp/ssl/help/csr/capache_new.html

サーバの設定

# vim /etc/apache2/sites-available/default-ssl
# 証明書
SSLCertificateFile    /etc/ssl/certs/missinglink-ssl-cert2011
# 秘密鍵
SSLCertificateKeyFile /etc/ssl/private/private-mlssl-2011.pem
# 中間証明書
SSLCertificateChainFile /etc/apache2/ssl.crt/mlssl-ca.crt

変更点はこれだけでした。この設定をバーチャルホストごとに行います。

CentOS

# yum -y install mod_ssl

で、/etc/httpd/conf.d/ssl.confをDebianのApacheに対して行ったように変更します。

Google ChromeのSame Origin Policyを無効化する

開発などで、JavaScript/XHR(XMLHttpRequest)のセキュリティのために実装されているSame-origin Policyを無効にしたい場合があります。
OSXではターミナルで以下のようにChromeを起動させます。

open -a Google\ Chrome --args --disable-web-security

Windowsではコマンドプロンプトで以下のようにします。

chrome.exe --disable-web-security

ローカルのファイルへXHRをしたい場合は以下の引数も追加します。

-–allow-file-access-from-files

HTML5を用いたノベルゲームエンジン試用版公開

MissingLink社で近日リリースする新規事業、ノベルゲームエンジン、ノベルゲームエディタ。これはHTML5を用いているため、通常のPC環境だけでなく、タブレットPC、スマートフォンでも利用する事ができます。

ノベルゲームエディタは、このエンジンで駆動する言語を直接記述するのではなく、グラフィカルな画面(WYSIWYG)で制作できるためクリエイターにとってノベルゲームの制作を容易にします。

また、ブラウザ環境下で動くアプリーションなので、URLひとつで起動可能です。TwitterやFacebookとの親和性の高さが特徴の一つです。

こちらから体験できます。

http://web.missinglink.co.jp/novelgame/

Luaでサーバサイドつくったら速いと思う(1)

Apache 2.4からmod_luaというLua言語のモジュールが組み込まれるようです。Lua言語は型がないLightweight Languageでは最速で、素のRubyやPython、Perlはとうてい敵いません。

これは1から100万までの数に対して素数判定(試し割りアルゴリズム)を行ったものです。Perlの3倍の速度です。

  • http://shootout.alioth.debian.org/
  • http://attractivechaos.github.com/plb/

また、上に示したURLの各種ベンチマークでも、LuaはLLのなかで最速です。

最速を誇っていながらも言語仕様は小さく、そのtar.gzアーカイブは200KBちょっとしかありません。

そんなLuaはC言語と連携しながら組み込み用言語として使われたりしています(マニアックな話ですが、ヤマハ製のルータRTX1200などにも組み込まれています。欲しいなぁ)。

Lua vs Perl (vs PHP)

そこで、CGIとしてLuaとPerlのパフォーマンス比較をしてみました。ただし、単純なコードで、渡されたクエリ文字列を返すだけの簡単なコードです。

Perl 高速化(mod_perl)無し 191.28 req/sec

keiya@s002:~$ ab -c 10 -n 1000 http://192.168.24.170/~keiya/run.pl
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.24.170 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.2.19
Server Hostname:        192.168.24.170
Server Port:            80

Document Path:          /~keiya/run.pl
Document Length:        1 bytes

Concurrency Level:      10
Time taken for tests:   5.228 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      167340 bytes
HTML transferred:       1000 bytes
Requests per second:    191.28 [#/sec] (mean)
Time per request:       52.279 [ms] (mean)
Time per request:       5.228 [ms] (mean, across all concurrent requests)
Transfer rate:          31.26 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:    22   52   9.4     51      96
Waiting:       22   52   9.4     51      95
Total:         23   52   9.4     51      96

Percentage of the requests served within a certain time (ms)
  50%     51
  66%     54
  75%     56
  80%     58
  90%     64
  95%     69
  98%     78
  99%     82
 100%     96 (longest request)

Lua 高速化無し 396.88 req/sec

keiya@s002:~$ ab -c 10 -n 1000 http://192.168.24.170/~keiya/run.lua
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.24.170 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.2.19
Server Hostname:        192.168.24.170
Server Port:            80

Document Path:          /~keiya/run.lua
Document Length:        5 bytes

Concurrency Level:      10
Time taken for tests:   2.520 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      172233 bytes
HTML transferred:       5000 bytes
Requests per second:    396.88 [#/sec] (mean)
Time per request:       25.196 [ms] (mean)
Time per request:       2.520 [ms] (mean, across all concurrent requests)
Transfer rate:          66.75 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     8   25  14.3     22     118
Waiting:        7   25  14.0     21     117
Total:          8   25  14.3     22     118

Percentage of the requests served within a certain time (ms)
  50%     22
  66%     25
  75%     27
  80%     29
  90%     39
  95%     49
  98%     75
  99%     95
 100%    118 (longest request)

この結果が示す時間の大部分は、それぞれの言語のインタプリタ起動にかかる時間が占めていると思われます。この結果と各種ベンチマーク結果を総合すると、Luaインタプリタの起動にかかる時間も、実行速度も速いといえそうです。

php 標準モジュール (php5_module) 2297.63 req/sec

ここでPHPのベンチマークです。

keiya@s002:~$ ab -c 10 -n 1000 http://192.168.24.170/~keiya/run.php?test=hoge
This is ApacheBench, Version 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.24.170 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.2.19
Server Hostname:        192.168.24.170
Server Port:            80

Document Path:          /~keiya/run.php?test=hoge
Document Length:        5 bytes

Concurrency Level:      10
Time taken for tests:   0.435 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      214000 bytes
HTML transferred:       5000 bytes
Requests per second:    2297.63 [#/sec] (mean)
Time per request:       4.352 [ms] (mean)
Time per request:       0.435 [ms] (mean, across all concurrent requests)
Transfer rate:          480.17 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    4   4.5      3      51
Waiting:        1    4   4.4      3      51
Total:          1    4   4.5      3      51

Percentage of the requests served within a certain time (ms)
  50%      3
  66%      4
  75%      5
  80%      5
  90%      8
  95%     12
  98%     20
  99%     26
 100%     51 (longest request)

お話にならないほど高速です。これは、Apacheの中にPHPのモジュールが組み込まれているからです。

僕はPerlerですし、負けていられないので同じ条件で計測します。Apacheにmod_perlを組み込み、バイトコードのキャッシュにより高速化を図ります。

Perl mod_perl2 3136.54 req/sec

keiya@s002:~$ ab -c 10 -n 1000 http://192.168.24.170/perl/run.pl?test=hoge
This is ApacheBench, Version 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.24.170 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.2.19
Server Hostname:        192.168.24.170
Server Port:            80

Document Path:          /perl/run.pl?test=hoge
Document Length:        9 bytes

Concurrency Level:      10
Time taken for tests:   0.319 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      216000 bytes
HTML transferred:       9000 bytes
Requests per second:    3136.54 [#/sec] (mean)
Time per request:       3.188 [ms] (mean)
Time per request:       0.319 [ms] (mean, across all concurrent requests)
Transfer rate:          661.61 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       0
Processing:     1    3   1.1      3       8
Waiting:        1    3   1.1      2       8
Total:          2    3   1.1      3       8

Percentage of the requests served within a certain time (ms)
  50%      3
  66%      3
  75%      3
  80%      4
  90%      5
  95%      6
  98%      7
  99%      7
 100%      8 (longest request)

かなり高速で勝者です。とはいってもPHPは所詮標準モジュールですので、PHPアクセラレータなどを入れるとこのPerlといい勝負ができると思います。

ところで、Luaの組み込みの結果に関してはApache 2.4待ちとなります。とはいってもApache 2.3 betaがあるので、それで試してみようかなと考えています。次回にでも・・・

もしLuaモジュールの実装がちゃんとしていれば、上に書いた言語のベンチマークから考えて、PerlやPHPやその他のLLをぶっちぎって最速になるんじゃないかと考えられます。

LuaRocksというPerlでいうCPAN、PHPでいうPEARのようなライブラリアーカイブも存在します。

LuaJITというやたら速い実装もあり、JavaScriptのV8といい勝負をしています。

まぁ、世の中node.jsヤベーとかいろいろいわれていますが、ApacheにLuaモジュールが組み込まれたらそれはそれで速度的にヤベーと思います。Apacheもevent mpmでイベントドリブンのプロセス・モデルがありますし。

速度を求めるならJava Servlet使え、とかいわれそうですが:p