isucon4予選問題のLua(Lapis)バージョンを書いてみた

isuconアプリを書いてみましたシリーズ。
生でOpenresty+Luaで書いても良かったんですが
せっかくなのでLapisというWebフレームワークを使ってみました。
実は自分も初触り。

最初にLapisの概要など

http://leafo.net/lapis/


LuaのWebアプリケーションフレームワークです。*1
バックエンドはOpenresty(Nginx)を利用しています。既に速そうな感じがしますね…!
WebFrameworkBenchmarksでも割と上位にいます。

Lapis、実は生のLuaスクリプトではなく moonscript で書くのを推奨しているようです。
JavaScriptにおけるCoffeeScriptのようなものですね。
構文も似ているのでJS書いている人には取っ付き易いかもしれません。

コーディング/サーバ起動

moonスクリプトを書いたあとに

moonc *.moon

を実行するとコンパイルされます。
その後

lapis server <env>

を実行すると nginx.conf を nginx.conf.compiled にコンパイルし、
Webサーバを起動します。

もっと便利にコーディング
moonc -w *.moon

を実行しておくと、カレントディレクトリ以下をウォッチして
moonscript > luascript に自動コンパイルをしてくれます。
また、nginx.confに

lua_code_cache off;

を設定しておくと
サーバリロードしなくてもLuaスクリプトを反映してくれるので便利です。
開発中は offにしておくとよいでしょう。



isucon4 Lapis版ソースコード

こちら。
https://github.com/toritori0318/isucon4

また、Gistにitamaeレシピを置いておきました。
こちらを実行すると Openresty+Luarocks+Lapis がインストールされますので
試したい方はお使いください。

# itamaeインストール
gem install itamae

# レシピダウンロード
wget https://gist.githubusercontent.com/toritori0318/2f2e080f906dbbbd0dea/raw/b0de3d7e8ece81fc81514b074e49549d0975da16/isucon4_lapis_recipe.rb

# レシピ実行
itamae ssh isucon4_lapis_recipe.rb -h xxx.xxx.xxx.xxx -u ec2-user -i /path/to/aws.pem
isucon4 Lapisバージョンを動かすための手順

1. isucon4アプリを上記ソースコードに置き換えます
2. /etc/supervisord.confのminfdsを増やしておき、 service supervisord restart を実行します。

[supervisord]
logfile=/tmp/supervisord.log
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=false
minfds=100000
minprocs=200

3. /etc/supervisord.confに以下を追記し、supervisorctl reload を実行します。

[program:isucon_lua]
directory=/home/isucon/webapp/lua
command=/opt/openresty/nginx/sbin/nginx -p /home/isucon/webapp/lua -c "nginx.conf.compiled"
#command=/home/isucon/env.sh /usr/bin/lapis server production
user=isucon
environment=LAPIS_OPENRESTY="/opt/openresty",PATH="/opt/openresty/nginx/sbin:$PATH"
stdout_logfile=/tmp/isucon.lua.log
stderr_logfile=/tmp/isucon.lua.log
autostart=true

ベンチマーク

kazeburoさんの "ISUCON4 予選でアプリケーションを変更せずに予選通過ラインを突破するの術" を参考にし、
サーバに対してほぼ同じ修正をした後のベンチマークです。

perlアプリケーション(kazeburoさんversion)で実行
$ ./benchmarker bench --workload 8
18:17:59 type:info	message:launch benchmarker
18:17:59 type:warning	message:Result not sent to server because API key is not set
18:17:59 type:info	message:init environment
18:18:07 type:info	message:run benchmark workload: 8
18:19:07 type:info	message:finish benchmark workload: 8
18:19:12 type:info	message:check banned ips and locked users report
18:19:15 type:report	count:banned ips	value:593
18:19:15 type:report	count:locked users	value:4357
18:19:15 type:info	message:Result not sent to server because API key is not set
18:19:15 type:score	success:186360	fail:0	score:40258
Lapisアプリケーションで実行
$ ./benchmarker bench --workload 8
18:54:06 type:info	message:launch benchmarker
18:54:06 type:warning	message:Result not sent to server because API key is not set
18:54:06 type:info	message:init environment
18:54:14 type:info	message:run benchmark workload: 8
18:55:14 type:info	message:finish benchmark workload: 8
18:55:19 type:info	message:check banned ips and locked users report
18:55:22 type:report	count:banned ips	value:859
18:55:22 type:report	count:locked users	value:4747
18:55:22 type:info	message:Result not sent to server because API key is not set
18:55:22 type:score	success:221580	fail:0	score:47865

やはり速かった。



Lapis雑感

全体的につらい方が多い :(

つらい点

実例が少ない
Lapis(Lua)自体のユーザ数が少ないこともあり、ノウハウ的な情報はほぼ皆無です。
自力で頑張る必要があるでしょう。
Webに情報が少ない公式ドキュメント以外は情報少ないというかほぼ皆無です。
自力で頑張る必要があるでしょう。
エコシステムが弱い
そもそも便利ライブラリが少ない、またはメンテされていないのが多いので
普通のWebアプリケーションを作ろうとした時につらいです。
自力で頑張る必要があるでしょう。
MySQL非対応
PostgreSQLはバッチリ対応していますが、現時点で何故かMySQLは非対応です。
Pull Requestはされているようなのでその内当たるかも。
しかも現時点ではそのまま利用しようとすると動かないバグがあるので
1行パッチを当てる必要があります。(こちらのレシピでもパッチを実行しています)

良い点

Openrestyの遺産が使える
普通にngxの情報にアクセスできますし、Openrestyのライブラリも使えます。
これは結構な利点だと思います。
速い
パフォーマンスはだいぶ良いので
単純なアプリでパフォーマンスが必要であれば
選択肢として考えてもよいかもしれません。



まとめ

Lapisでisucon4予選問題アプリを書いてみました。
実際のWebアプリケーションを作るにはだいぶ茨の道だと思いますが
LLのように書ける割には速いですし
isuconのような一発アプリに使うのはアリかなと思いました。


またLua/MoonScript、実際書いてみるとわかるのですが
構文はJavaScript/CoffeeScriptに似ている部分があるので
実は(書くだけであれば)そんなに違和感なく書けたりします。
Go速いけどまだちょっと手を出しにくい…という人には
割とマッチするかもしれません。
ぼくはオススメはしませんが!!!

*1:ほぼデファクト