IKEAのアームチェアに合うテーブルを見つけたので紹介する

IKEAのアームチェア

IKEAのアームチェア、ものすごくリラックスした体勢でゆったり過ごせるんですが、PCで作業するときにいい感じのテーブルがなかったんですね。いつも太ももの上にMacBookProを置いていたのですが、この体勢だと首への負担がすごいし、なによりMBPの熱が太ももに移って熱くて辛い。リラックスチェアを使うときは本を読んだりゲームをするときくらいになっていたのですが、妻がよさそうなテーブルを楽天で見つけてくれたので早速買ってみました。

フォールディングテーブルが届いた

使い方自由自在なサイドテーブル

早速組み立ててみました。高さ調節ができてよさそうですが、片方ずつしか調整できないので、一度ひっくり返して調整する必要があります。角度も調整できますが、角度調整するとMBPだとひっかかりが弱くて落ちそうになりました。ひっかかり部分が丸く加工されているので、ここが90度近くなっていればよかったんですがねぇ…。
とはいえ、水平にすれば使いやすいです。ただ値段が値段なだけに、結構グラグラはします。

IKEAの椅子とフォールディングテーブルを組み合わせてみる

IMG_1523

IKEAのアームチェアの幅にフォールディングテーブルの幅がすっぽりと収まるので、あのリラックスした体勢でPCの操作をすることができます。これは捗る!!今まで不満点だった首の疲れもないし、この値段でこの快適さは素晴らしい。

総評

PCでデュアルディスプレイをする人とかだと合わないと思いますが、部屋のスペースは狭いけれどPC用の机は欲しいし、いい椅子が欲しい、という人にとっては、かなりコストパフォーマンスの高い組み合わせだと思います。Amazonで揃えると1万円くらいだし。とりあえず1つ買っていますが、もう1つ買って自分用と妻用にしてもいいかなという感じ。

追記:着る毛布と組み合わせると最強

ふと思いついてたった今、着る毛布を着てみたのですが、この組み合わせはめっちゃいいです。これから寒くなる時期だから、これにしたら光熱費を節約しつつ快適に作業できそうっすねぇ。


HerokuでDynoあたりのworker数を考えたい

この前、Heroku環境にunicorn-worker-killerを入れてみたという記事を書いて、1日くらい経って、「うんうん、大丈夫だなー」と思っていたのだが、数日後にスワップが大量に発生してR14のエラーが大量に発生していた。未だに原因はよくわかっていない。

検証用の環境で、再度アクセスをいろいろとしてみたけれど、時間が経過&継続的なアクセスがないとこの大量スワップ発生現象は起きないみたいで、どうにも検証しづらい。
現在の検証環境では、unicorn-worker-killerのメモリ使用上限を200〜250MB、worker数を4にしていたのだが、今更ながらだが、unicornのmasterプロセスのメモリのことをあんまり意識してなかった。

参照URL:Secrets to Speedy Ruby Apps On Heroku

WEB_CONCURRENCYの計算はシンプルで、

WEB_CONCURRENCY = (Dynoのメモリ量 – unicornのmasterプロセスのメモリ使用量) / unicornのworkerプロセスのメモリ使用量

であるということなので、それを計算したかったのだが(どうせHerokuのStandard2Xなら2〜4であるとは思うが)、Herokuの環境で1workerプロセスあたりどれくらいメモリを使っているか、masterプロセスがどれくらいメモリを使っているかを調べる方法がいまいちわからなかった。

仕方ないのでとりあえずローカルでpsコマンドを打って確認してみた。まずはforeman経由でunicornを立ち上げる。

foreman start

その後、psコマンド。

ps aux | grep unicorn

何度かローカルのRailsアプリにアクセスして、unicornのworkerにメモリを食わせたのち、またps aux | grep unicornしてみる。

USER              PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
t-oko           30267   0.7  0.0  2451204    720 s001  S+    4:02PM   0:00.00 grep unicorn
t-oko           28033   0.0  1.2  2698140 202204 s000  S+    3:26PM   0:09.07 unicorn master -p 3000 -c ./config/unicorn.conf.rb
t-oko           28059   0.0  1.2  2736768 203616 s000  S+    3:27PM   0:04.48 unicorn worker[2] -p 3000 -c ./config/unicorn.conf.rb
t-oko           28058   0.0  1.4  3312496 228016 s000  S+    3:27PM   0:06.30 unicorn worker[1] -p 3000 -c ./config/unicorn.conf.rb
t-oko           28057   0.0  1.4  3315000 231100 s000  S+    3:27PM   0:07.29 unicorn worker[0] -p 3000 -c ./config/unicorn.conf.rb

RSSを見る限りだとmasterプロセスが200MBくらい、workerプロセスも200〜225MBくらいっぽい。まぁ負荷をかけたものじゃないので、本来はもっと増えそうに思う。というところで、WEB_CONCURRENCYに設定できそうな値は、

WEB_CONCURRENCY = (1024 – 200) / 250

くらいかなぁと思うのでやっぱり3くらいが妥当に思えた。

ところで参考URLを読んだときに、worker-killerを使うような場合はおそらくWEB_CONCURRENCYの値が大きすぎるんだ!と書いてあったので、unicorn-worker-killerを使うのは本当は良くないのかもしれない…。


Heroku環境にunicorn-worker-killerを入れてみた

Herokuの環境が、メモリが余っているにも関わらずなぜかスワップが発生しているので、パフォーマンスの見直しも兼ねてunicorn-worker-killerを入れてみました。
Unicornがメモリを大量に消費したら、workerを再起動させるというやつです。アクセス数に応じても再起動させることができます。

参考サイト

今まで、スワップが発生するからわざとworker数を少なめ(1Dynoにつき2とか)にしていたのですが、どっちにしてもスワップが発生していたし、これを使えば4とかにできそうなので、応答速度も向上しそうです。うちの場合、Standard-2Xを使っているので、メモリは1GBあるのに、600MB程度しか使えてませんでした。

とりあえずHerokuの環境で動作検証をしてみましたので、そこまでのメモを載せます。

ちなみに私の開発環境は以下の通り。

PC: Mac OSX Yosemite
Ruby: 2.2.3(RVM経由)
Rails: 4.2.4

unicorn-worker-killerのインストール

Gemfileに追加しましょう!

gem 'unicorn-worker-killer'

そしてbundle installしましょう。

config.ruの修正

以下を追加します。

# Unicorn self-process killer
require 'unicorn/worker_killer'

max_request_min =  ENV['UNICORN_MAX_REQUEST_MIN'].to_i || 3072
max_request_max =  ENV['UNICORN_MAX_REQUEST_MAX'].to_i || 4096

# Max requests per worker
use Unicorn::WorkerKiller::MaxRequests, max_request_min, max_request_max

oom_min = ((ENV['UNICORN_OOM_MIN'].to_i || 200) * (1024**2))
oom_max = ((ENV['UNICORN_OOM_MAX'].to_i || 250) * (1024**2))

# Max memory size (RSS) per worker
use Unicorn::WorkerKiller::Oom, oom_min, oom_max

これは、
require ::File.expand_path(‘../config/environment’, __FILE__)
よりも前に書く必要があるようです。

ここまでやったらgitでcommitしておきましょう。
お試しでやってみたい場合はブランチを適当に切ってください。

Herokuに反映させる

じゃあHerokuにとりあえず反映させておきましょう。
remoteはheroku、ブランチはfeature-unicorn-worker-killerを作っていたとします。

git push -f heroku feature-unicorn-worker-killer:master

Herokuで検証する

Heroku Labs: log-runtime-metricsを参考に、log-runtime-metricsを有効にします。これは、Dynoのメモリ使用量などをログに出してくれるようになります。メモリ使用量の増減を見張るために入れます。
–appで指定するアプリ名は適宜変更してください。

heroku labs:enable log-runtime-metrics --app sample-app
heroku restart

次に、ログを垂れ流しにしときます。その際に、余計なログがでてきても困るので、grepします。2つターミナルを立ち上げます。

まず1つめは、Unicornという文字を見張ります。

heroku logs -t --ps web --app sample-app | grep Unicorn

2つめは、memoryという文字を見張ります。

heroku logs -t --ps web --app sample-app | grep memory

config.ruにて、環境変数で設定を変更できるようにしてあるので、これをいろいろ変えてみましょう。

アクセス数に応じて再起動するのを確認

heroku config:set WEB_CONCURRENCY=2 --app sample-app
heroku config:set UNICORN_MAX_REQUEST_MIN=3 --app sample-app
heroku config:set UNICORN_MAX_REQUEST_MAX=5 --app sample-app

Herokuにデプロイしているアプリのworkerに3回以上リクエストがあるとworkerが再起動する設定です(workerが2つなので実際には6回程度)。メモリ使用量(memory_rss)の増減と、workerにkillシグナルが送られているのを確認しましょう。

2015-10-16T07:10:55.935856+00:00 app[web.1]: W, [2015-10-16T07:10:55.935740 #312]  WARN -- : #<Unicorn::HttpServer:0x007f7e19d1a148>: worker (pid: 312) exceeds max number of requests (limit: 5)
2015-10-16T07:10:55.935866+00:00 app[web.1]: W, [2015-10-16T07:10:55.935841 #312]  WARN -- : Unicorn::WorkerKiller send SIGQUIT (pid: 312) alive: 1 sec (trial 1)

ちゃんとシグナルが送られています。

2015-10-16T07:13:40.243479+00:00 heroku[web.1]: source=web.1 dyno=heroku.20197221.f034b862-2494-4332-973f-22341abde3e9 sample#memory_total=223.88MB sample#memory_rss=223.61MB sample#memory_cache=0.01MB sample#memory_swap=0.26MB sample#memory_pgpgin=1231227pages sample#memory_pgpgout=1173982pages
2015-10-16T07:14:00.232265+00:00 heroku[web.1]: source=web.1 dyno=heroku.20197221.f034b862-2494-4332-973f-22341abde3e9 sample#memory_total=202.09MB sample#memory_rss=201.82MB sample#memory_cache=0.01MB sample#memory_swap=0.26MB sample#memory_pgpgin=1500092pages sample#memory_pgpgout=1448424pages

そして、workerが再起動したのでメモリの使用量も減っています。いい感じですね。

さて、これはあくまで確認のためなので、この設定は上限値をあげるか、環境変数を削除しておきましょう。
Unicornのworkerのプロセス数は、Dynoのサイズやアプリのサイズによって適切な値は異なるので、適当に決めてください。
このあたりを参考に。
Heroku Dev Center: Optimizing Dyno Usage

heroku config:set WEB_CONCURRENCY=4 --app sample-app
heroku config:set UNICORN_MAX_REQUEST_MIN=500 --app sample-app
heroku config:set UNICORN_MAX_REQUEST_MAX=1000 --app sample-app

メモリ使用量の変化で再起動するのを確認

あとは、workerのメモリ使用量でちゃんと再起動するかどうかです。とりあえずメモリをたくさん使いそうなページに連続してアクセスしながら、メモリの増減を確認します。

2015-10-16T07:28:50.539770+00:00 heroku[web.1]: source=web.1 dyno=heroku.20197221.dd2b019e-a946-4973-9b1a-16dd7fe0c02f sample#memory_total=695.95MB sample#memory_rss=695.95MB sample#memory_cache=0.00MB sample#memory_swap=0.00MB sample#memory_pgpgin=224829pages sample#memory_pgpgout=46666pages
2015-10-16T07:29:07.142475+00:00 app[web.1]: W, [2015-10-16T07:29:07.142369 #20]  WARN -- : #<Unicorn::HttpServer:0x007f118b0181c0>: worker (pid: 20) exceeds memory limit (229944832.0 bytes > 213930009 bytes)
2015-10-16T07:29:10.431747+00:00 heroku[web.1]: source=web.1 dyno=heroku.20197221.dd2b019e-a946-4973-9b1a-16dd7fe0c02f sample#memory_total=631.29MB sample#memory_rss=631.28MB sample#memory_cache=0.00MB sample#memory_swap=0.00MB sample#memory_pgpgin=262182pages sample#memory_pgpgout=100573pages

workerのメモリが200MB以上になったのでworkerが再起動され、Dynoが695.95MBのメモリを使っていたのが、631.28MBに減りました。

この設定ですが、200MBを超えたら即killされるわけではないので、カツカツに設定するとスワップが発生する可能性もあるので、とりあえず200〜250MBの間にしておきました。この実験中は850MBくらいまでメモリを使った事もあったので、これくらいがいいのかなと思います(あくまでもうちの環境では、の話だけれど)。

まとめ

unicornのworkerの再起動が多すぎても少なすぎてもよくないと思うので、そこらへんは探り探りやっていきましょう。まぁそれでも、わりとworkerを再起動させる設定にしてアクセスしてみましたが、そこまでめちゃくちゃ遅くなるということはありませんでした。なので、アクセス回数もだけれど、メモリの使用量は大雑把に指定していてもいいかなと思います。
これでHerokuのサーバーの性能が安定するといいなぁ。


RubyでOpenSSL::SSL::SSLErrorが出たので対応した

私の環境について

  • Mac OS 10.10.5
  • homebrewを使用
  • RVMを使用

通信をするプログラムを動かしたら、SSLのエラーが出ました。

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

参考ページを見ながらやりましたが、どうもうまくいきませんでした…。

参考ページ: qiita: OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

CA証明書のパスがおかしい

参考ページのコメントのところに則って、対応をしてみたのですが、CA証明書のパスがおかしいのです。

#rubyで読み込むCA証明書のパス確認
ruby -ropenssl -e "p OpenSSL::X509::DEFAULT_CERT_FILE"
# => "/etc/openssl/cert.pem"

/usr/local/etc/openssl/cert.pem とならないといけないのに、そうなりません。
参考ページでは、環境変数SSL_CERT_FILEに/usr/local/etc/openssl/cert.pemと指定すればいいとあります。そうしてみたのですが、結果は変わりませんでした。一体なにがおかしいのか…。

RVMは環境変数を考慮しない?

色々検索していたら、RVMのissueを発見しました。

github: Install tries to update /etc/openssl instead of /usr/local/etc/openssl

後半のほうで、環境変数を考慮しないよ、みたいに書いてあるっぽいなと思ったので、–disable-binaryオプションをつけて、Rubyを再インストールしたところ、homebrewのOpenSSLを考慮してくれるようになりました!

RVM: How to fix broken certificates in your operating system.

また、RVMのサイトにも書いてあるコマンドがあったのでこれもやってみました。

やったことを書いていく

# opensslの更新
brew update
brew uninstall openssl --force && brew install openssl
brew link openssl --force

# CA証明書をDLして移動する
curl -O http://curl.haxx.se/ca/cacert.pem
sudo mv cacert.pem /usr/local/etc/openssl/certs/
/usr/local/opt/openssl/bin/c_rehash

# ここからはどれかは必要ないかもしれない
rvm autolibs homebrew
rvm osx-ssl-certs update all

# Rubyの再インストール。これは必要。
rvm reinstall 2.2.3 --disable-binary

# rubyで読み込むCA証明書のパス確認
ruby -ropenssl -e "p OpenSSL::X509::DEFAULT_CERT_FILE"
# => "/usr/local/etc/openssl/cert.pem"

これで、通信ができるようになりました。

まとめ

突然エラーになったので、めっちゃ慌てました…。
再現性がないので、後半のコマンドのどれかはいらないかもしれません。


Grails3.0.4でfieldsプラグインを使う場合の注意点

Grails3.0.4を入れると、fieldsプラグインは、デフォルトで(?)バージョン2.0.3が入るようです。
しかし、この2.0.3ですが、なぜか1.5以降のテンプレート指定のようにいきません。

参考ページ: fieldsプラグインのリファレンス(2.1.0のスナップショット)

1.5以前とそれ以降では、テンプレート名が以下に変わると書いてありました。
_field.gsp => _wrapper.gsp
_input.gsp =>_widget.gsp
_display.gsp =>_displayWrapper.gsp
N/A => _displayWidget.gsp

しかし、2.0.3だとなんの反応もなかったので、_field.gspを作ったところ、反応しました。
1.5以降じゃないやん…。

とりあえずの解決策

ということで、bintrayでfieldsプラグインを探してみたら、2.1.0がありました。
最新すぎて怪しい感じもしましたが、とりあえずこれを入れてみました。

dependencies {
    // 略
    compile "org.grails.plugins:fields:2.1.0"
    // 略
}

こうしたら、_field.gspじゃなくて_wrapper.gspがテンプレートになりました。

fieldsプラグインのテンプレート置き場のパス

とりあえず、デフォルトだけでいうと、
grails-app/views/_fields/default以下に、_wrapper.gsp, _widget.gsp, _displayWrapper.gsp, _displayWidget.gspを作ればよさそうです。あとは、型やdomainクラスのプロパティ名などで参照されるテンプレートが変わるようです。優先順位があって、該当ファイルがなかったらどんどん検索していってなければdefault内のテンプレートが指定される模様。

型からテンプレートを変えることができれば、入力フォームも楽ができそうですね。
しかしここまで調べるのえらい時間かかった…。