crontabのsyntax checkをTravis-CIで行う
crontabファイルをrespositoryで管理していますが、テストができてなかったので、それを解消すべくTravis-CIでやってみました。
.travis.yml
language: ruby script: - cat crontab.ok.txt | crontab - cat crontab.fail.txt | crontab
travisで実行された様子
意外なことに簡単に動いた。
Travisはcrontabが登録されても実際にはコマンドが動かない、はず。
songmuさんのParse::Crontabも非常に良いのですが、今のプロジェクトはPerlのプロジェクトではないので若干入れにくい。
参考
2007-2015 YAPC::Asia Tokyo で喋ってきたまとめ
今年のblogはまだ書いてないけど書きました、これまでYAPC::Asia Tokyo で喋ってきたblog記事をまとめてみました
2007年から2015年まで10回中9回、トーク(2007年はLT)をさせて頂きました。
2015 ISUCONの勝ち方
isucon優勝するぞー!
2014 Dockerで遊んでみよっかー
2014年はDockerの話をしました
2013 PSGI/Plack・Monocerosで学ぶハイパフォーマンスWebアプリケーションサーバの作り方
2013年はPlackのサーバを作る話。前夜祭LTもやりました
2012 1台から500台までのMySQL運用(YAPC::Asia編)
2012年はDB運用の話
2011 運用しやすいWebアプリケーションの構築方法
2011年は運用しやすいWebアプリケーションというテーマで、ログやSQLについて
2010 Introduction to CloudForecast
cloudforecastの話。最近はkuradoというのを作って使ってます
2009 大規模画像配信とPerl
大規模画像配信の話
2008 memcached in mixi
mixiのエンジニアblogで書いてました。2つトークをしていて、1つはmemcachedの話、もう一つはmod_perlをつかったjob処理でした
2007 Expectをつかった Expectをつかったサーバ管理レシピ
LTでコマンドを複数のサーバで実行する話をしました
Rhebok, a High Performance Rack Handler/Server 2x faster than Unicorn
Last December I released Rhebok to rubygems. Rhebok is a High Performance Rack Handler/Server.
rhebok | RubyGems.org | your community gem host
Rhebok is a standalone Preforking Web Server. This server is optimized for running HTTP application server behind a reverse proxy like nginx. When start Rhebok as upstream server of nginx and connect via unix domain socket, Rhebok is 2 times faster than Unicorn.
Benchmark
"nginx static file" represents req/sec when delivering 13 bytes static files from nginx
Benchmark details is here.
Features
Rhebok supports following features.
- ultra fast HTTP processing using picohttpparser
- uses accept4(2) if OS support
- uses writev(2) for output responses
- prefork and graceful shutdown using prefork_engine
- hot deploy using start_server (here is golang version by lestrrat-san)
- supports HTTP/1.1. But does not have Keepalive.
- supports OobGC
Installation and Usage
Add this line to your application's Gemfile and execute bundle install
gem 'rhebok'
Or install it yourself as
$ gem install rhebok
To run Rhebok, use the rackup command.
$ rackup -s Rhebok --port 8080 -O MaxWorkers=5 -O MaxRequestPerChild=1000 -O OobGC=yes -E production config.ru
For more details, please read README.md. If you found problems and bug, please send p-r or issue to github
SqaleでRailsアプリを高速サーバ「Rhebok」を使って起動する
Herokuに続き、Unicornの2倍のパフォーマンス発揮するRackサーバ「Rhebok」をパパボさんのPaaSであるSqaleで動かしてみる。15日間は無料お試しが出来るそうですよ。
Sqale - 開発者のためのホスティングサービス【スケール】 Ruby on Rails 対応。
Gemfileの用意
まず Gemfileを用意します。適当なディレクトリで
$ bundle init
して Gemfileを編集します
cat Gemfile # A sample Gemfile source "https://rubygems.org" gem "rails", "4.2.0"
とりあえず最新のRails 4.2.0で固定して、bundle install
$ bundle install --path vendor/bundle
Railsアプリケーションの作成
$ bundle exec rails new . --skip-bundle
すると、途中でGemfileを上書きするか聞かれるので、そのままリターンで続行
conflict Gemfile Overwrite /Users/kazeburo/Develop/sqale-rhebok/Gemfile? (enter "h" for help) [Ynaqdh]
上書きされたGemfileにRhebokを追加する
$ tail Gemfile gem 'gctools' gem 'rhebok', '>= 0.2.1'
OobGCを使う為にgctoolsも入れる。
ここまで出来たらbundle install
$ bundle install
Hello Worldだけでは面白くないので、Scaffoldを使ってアプリケーションのひな形を作る
$ bundle exec rails g scaffold msg nick:string body:text $ bundle exec rake db:migrate
ローカル環境で動くかどうか確認します。
$ bundle rails s
ローカルでRhebokを起動するには以下のコマンド
$ bundle exec rackup -s Rhebok -O MaxWorkers=1 -O OobGC=yes -O MaxRequestPerChild=0
Rhebokに変更しても問題なく動作すると思われます。
デプロイ準備
secrets.ymlのsecret_key_baseを設定する必要があります。今回はとりあえず環境変数にて設定してみました。
echo 'SECRET_KEY_BASE="'$(bundle exec rake secret)'"' > .env
Sqaleは.env
というファイルに環境変数を書いておくと起動時に読み込んでくれます。ちなみに、SqaleではデータベースにMySQLを使う事ができますが、今回はテストなのでSQLiteのままいきます
Rhebokでアプリケーションを起動したいので、Procfileも書きます。
$ cat Procfile app: bundle exec rackup -s Rhebok -O Path=/var/run/app/app.sock -O MaxWorkers=3 -O OobGC=yes -O MaxRequestPerChild=1000 -O MinRequestPerChild=500
Sqaleのコンテナはnginxとアプリケーションサーバが起動していて、間の通信にUnix Domain Socketを使うのが大きな特徴。なので、RhebokもUnix Domain SocketをListenさせる。
Rubyのバージョンを2.1.4に変更。ちなみに手元はrbenvを使わずにxbuildで2.1.5をいれてる
echo '2.1.4' > .ruby-version
vendorディレクトリをgitで管理しないようにして、git commit
$ echo '/vendor' >> .gitignore $ git init $ git add . $ git commit -m 'init'
最後に、sqaleにpush。
$ git remote add sqale ssh://sqale@gateway.sqale.jp:2222/userid/app_name.git $ git push sqale master
最初は起動までに数分かかりました。2回目からは1分ぐらいでデプロイされた。
ブラウザでみると、こんなページができました。
SqaleにSSHして確認
ちゃんとRhebokで起動したか、SSHでコンテナにログインして ps コマンドを打ってみました。
$ ssh -p 2222 sqale@gateway.sqale.jp sqale@app_name-1:~$ ps fax PID TTY STAT TIME COMMAND 6816 ? S 0:07 sshd: sqale@pts/0 6817 pts/0 Ss 0:00 \_ -bash 11236 pts/0 R+ 0:00 \_ ps fax 92 ? S 0:00 nginx: worker process 11133 ? Sl 0:00 foreman: master 11218 ? Sl 0:02 \_ ruby /home/sqale/current/vendor/bundle/ruby/2.1.0/bin/rackup -s Rhebok -O Path=/var/run/app/app.sock -O MaxWorkers=3 -O OobGC=yes -O MaxRequestPerC 11223 ? Sl 0:00 \_ ruby /home/sqale/current/vendor/bundle/ruby/2.1.0/bin/rackup -s Rhebok -O Path=/var/run/app/app.sock -O MaxWorkers=3 -O OobGC=yes -O MaxRequest 11226 ? Sl 0:00 \_ ruby /home/sqale/current/vendor/bundle/ruby/2.1.0/bin/rackup -s Rhebok -O Path=/var/run/app/app.sock -O MaxWorkers=3 -O OobGC=yes -O MaxRequest 11229 ? Sl 0:00 \_ ruby /home/sqale/current/vendor/bundle/ruby/2.1.0/bin/rackup -s Rhebok -O Path=/var/run/app/app.sock -O MaxWorkers=3 -O OobGC=yes -O MaxRequest
ちゃんと起動出来ているようですね〜
SSHで入ってログ見たり、straceでデバックしたり、killコマンドでアプリケーションの再起動できたりするのでSqale便利!
HerokuでSinatraのアプリを「Rhebok」で起動する
Unicornの2倍のパフォーマンス発揮するRackサーバ「Rhebok」をherokuで動かしてみる
アプリケーションは
heroku で Sinatra のアプリを動かす - Please Sleep
を参考にさせて頂きました。
Gemfile
まずGemfileを用意します
$ cat Gemfile source 'https://rubygems.org' ruby "2.1.5" gem 'sinatra' gem 'gctools' gem 'rhebok'
rubyのバージョンは2.1系を使い、gctoolsもいれます。Rhebokはgctoolsに含まれるGC::OOBを利用し、リクエスト処理終了後(Out Of Band)のGCを効率的に行います。
日本語訳: Ruby 2.1: Out-of-Band GC — sawanoboly.net
app.rb
"hello world"を出力するアプリケーションです。
$ cat app.rb require 'sinatra' get '/' do @text = "hello world\n" erb :index end
views/index.erb
テンプレート
$ cat views/index.erb <!DOCTYPE html> <html> <body> <%= @text %> </body> </html>
config.ru
config.ruファイルもつくります。
$ cat config.ru require './app' run Sinatra::Application
bundle install
依存モジュールのインストール
$ bundle install --path vendor/bundle
.gitignoreの用意
vendor、.bundleディレクトリを対象外とします
cat .gitignore vendor .bundle
手元で起動
$ bundle exec rackup -s Rhebok config.ru Rhebok starts Listening on localhost:9292 Pid:77840
9292ポートで起動するのでブラウザやcurlで確認します。
Procfile
Rhebokでアプリケーションが起動するようにProcfileを書きます
$ cat Procfile web: bundle exec rackup --port $PORT -s Rhebok -O OobGC=yes config.ru
OobGCを有効にしてみました。デフォルトで5個のworkerが起動します。
herokuへpush
git commitしてherokuへpushします
$ git init $ git add . $ git commit -m '…' $ heroku create APP_NAME $ git push heroku master
これでアプリケーションがherokuにて起動します。
curlでアクセスして確認します。
$ curl -v https://APP_NAME.herokuapp.com/ ... < HTTP/1.1 200 OK < Connection: keep-alive < Server: Rhebok < Content-Type: text/html;charset=utf-8 < Content-Length: 59 < X-Xss-Protection: 1; mode=block < X-Content-Type-Options: nosniff < X-Frame-Options: SAMEORIGIN < Date: Thu, 25 Dec 2014 02:47:58 GMT < Via: 1.1 vegur < <!DOCTYPE html> <html> <body> hello world </body> </html>
Server: Rhebok
と表示されたので、無事にRhebokにてアプリケーションが起動したことが確認できました。
同じアクセス数を処理している場合、RhebokはUnicornと比べてCPU使用率が低いという特徴もあるので、ぜひ試してくださいませ
picohttpparserのRubyバインディングとPreforkサーバを書く時に便利なgemをリリースしたので、Rackサーバ書いてみた
GazelleでやったことをRubyでもやってみようと思い、まず picohttpparser の Ruby バインディングと、perforkなサーバを書く時に便利なモジュールであるParallel::PreforkのRuby版を書いてリリースしました。
pico_http_parser
http://rubygems.org/gems/pico_http_parser
prefork_engine
http://rubygems.org/gems/prefork_engine
そしてこの2つを使って、StarletのRuby版を書いてみました。ソースコードはprefork_engineのrepositoryにあります。
https://github.com/kazeburo/prefork_engine/blob/master/example/starlet.rb
動かし方
まず上の2つのgemをいれます。bundlerを使っても良いですね
$ gem install pico_http_parser prefork_engine
prefork_engineのrepositoryをcloneしてきてexampleディレクトリに移動
$ git clone https://github.com/kazeburo/prefork_engine.git
$ cd prefork_engine/example
hello worldなサンプルアプリケーションも同梱されているので、そいつを動かしてみます
$ rackup -r ./starlet.rb -s Starlet -O MaxWorkers=5 -O MaxRequestPerChild=1000 config.ru
curlでアクセスすると
$ curl -sv http://localhost:9292/|less
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9292 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:9292
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Connection: close
< Content-Type: text/html
< Date: Thu, 11 Dec 2014 07:00:30 GMT
< Server: RubyStarlet
<
{ [data not shown]
* Closing connection 0
hello world
ちゃんと出て来た。大丈夫そう!
軽くベンチマーク
環境はEC2のc3.4xlarge、Amazon Linuxを使いました。nginxのうしろにアプリケーションサーバとして動作させた場合を想定してます。
ベンチマーク準備
Rubyはxbuildを使っていれます。unix domain socketで通信する為にstart_serverというPerl製のコマンドが必要になるのでPerlもいれます。
$ git clone https://github.com/tagomoris/xbuild.git $ ./xbuild/ruby-install 2.1.5 ~/local/ruby-2.1 $ xbuild/perl-install 5.20.1 ~/local/perl-5.20 -j4 $ export PATH=/home/ec2-user/local/ruby-2.1/bin:$PATH $ export PATH=/home/ec2-user/local/perl-5.20/bin:$PATH
nginxはyumでインストールし、次のように設定をしました
worker_processes 4; events { worker_connections 10000; } http { include mime.types; access_log off; sendfile on; tcp_nopush on; tcp_nodelay on; etag off; upstream app { server unix:/dev/shm/app.sock; } server { location / { proxy_pass http://app; } } }
比較のためにunicornもいれました。
$ gem install pico_http_parser prefork_engine unicorn
ruby版Starletの起動コマンド
$ start_server --path /dev/shm/app.sock -- rackup -r ./starlet.rb -E production -s Starlet -O MaxWorkers=12 -O MaxRequestPerChild=500000 config.ru
unicornのconfigと起動コマンド
$ cat unicorn.rb worker_processes 8 preload_app true listen "/dev/shm/app.sock" $ unicorn -E production -c unicorn.rb config.ru
ベンチマーク結果
ruby版Starlet
$ ./wrk -t 2 -c 32 -d 30 http://localhost/ Running 30s test @ http://localhost/ 2 threads and 32 connections Thread Stats Avg Stdev Max +/- Stdev Latency 401.75us 114.12us 5.67ms 80.92% Req/Sec 40.83k 2.90k 53.56k 72.18% 2291892 requests in 30.00s, 384.58MB read Requests/sec: 76397.24 Transfer/sec: 12.82MB
$ ./wrk -t 2 -c 32 -d 30 http://localhost/ Running 30s test @ http://localhost/ 2 threads and 32 connections Thread Stats Avg Stdev Max +/- Stdev Latency 393.75us 188.08us 4.41ms 78.60% Req/Sec 42.66k 6.64k 62.33k 71.41% 2389390 requests in 30.00s, 437.40MB read Requests/sec: 79647.31 Transfer/sec: 14.58MB
picohttpparserがすごく速いというのはありますが、それ以外の部分がRubyだけで書かれているにしては良いベンチマーク結果になっている気がします
Released Gazelle, new Simple and Fast Plack Handler
I released Gazelle, new Plack handler
Gazelle - Preforked Plack Handler for performance freaks - metacpan.org
Gazelle is a Plack Handler/PSGI server. This server is optimized for running HTTP application server behind a reverse proxy like nginx. When start Gazelle behind nginx and connect via unix domain socket, Gazelle is 3 times faster than starman.
Here is benchmark of Gazelle, starman and Starlet.
Benchmark details is here.
Gazelle supports following features.
- only supports HTTP/1.0. But not support KeepAlive feature
- All of network i/o code are written in XS
- ultra fast HTTP processing using picohttpparser
- uses accept4(2) if OS support
- uses writev(2) for output responses
- prefork and graceful shutdown using Parallel::Prefork
- hot deploy using Server::Starter
If you found problems and bug, please send p-r or issue to github