memcachedを利用したsession管理


今更ながら、複数台サーバーに対応させるためsession管理をmemcachedを使って外部化したいと思います。

## Require

* rails 4
* unicorn
* memcached
* osx

## なんでmemcached

以前は[redis-store](https://github.com/redis-store/redis-store)を使ってみたのです。

レプリもできるし、複雑な型も扱えるからredisがいいなーと思っているので幸せが待っている臭いがします。

が、最近更新滞ってるし、、、っていう後ろ向きな理由でdalli + memcachedです。

[Memcache vs. Redis?](http://stackoverflow.com/questions/10558465/memcache-vs-redis)

## Install memcached and setup launchclt


とりあえず入れる

```bash
$ brew install memcached
memcached: stable 1.4.20 (bottled)
http://memcached.org/
Conflicts with: mysql-cluster
/opt/boxen/homebrew/Cellar/memcached/1.4.20 (10 files, 184K) *
  Built from source
From: https://github.com/Homebrew/homebrew/commits/master/Library/Formula/memcached.rb
==> Dependencies
Required: libevent ✔
==> Options
--enable-sasl
        Enable SASL support -- disables ASCII protocol!
--enable-sasl-pwdb
        Enable SASL with memcached's own plain text password db support -- disables ASCII protocol!
==> Caveats
To have launchd start memcached at login:
    ln -sfv /opt/boxen/homebrew/opt/memcached/*.plist ~/Library/LaunchAgents
Then to load memcached now:
    launchctl load ~/Library/LaunchAgents/homebrew.mxc
```

書いてある通りlaunchdCtlで自動起動設定

```
$ ln -sfv /opt/boxen/homebrew/opt/memcached/*.plist ~/Library/LaunchAgents
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
```

確認

```bash
# プロセス
$  ps axu | ag memcached
foo      84598   0.0  0.0  2464188    380   ??  S     9:16PM   0:00.06 /opt/boxen/homebrew/opt/memcached/bin/memcached -l localhost

# 繋げる
$ telnet localhost 11211
stats
...

```

ok


## rails側に設定

memcache clientは[dalli](https://github.com/mperham/dalli)を利用します

```bash
$ vim Gemfile
gem 'dalli'

$ bundle
```

とりあえずdevelopモードで動くようにします。

cacheとsession設定をdalli経由に変更

```ruby
$ vim config/environment/development.rb

AppName::Application.configure do
  ...
  config.cache_store = :dalli_store
  ...

$ vim config/initialize/session_store.rb
FooRails::Application.config.session_store ActionDispatch::Session::CacheStore, key: '_foo_session', expire_after: 1.month
```

consoleでcacheテスト

```ruby
$ rails c
pry> Rails.cache.write 'foo', 'bar'
Cache write: foo
Dalli::Server#connect 127.0.0.1:11211
=> 144115188075855872

pry> Rails.cache.read 'foo'
Cache read: foo
=> "bar"
```

ok

## deploy後に再接続

**dalli 2.0.4から再接続は不要です**
**https://github.com/petergoldstein/dalli/issues/208**

[unicorn](https://github.com/defunkt/unicorn)のafter fork時に、memcachedとのコネクションを張り直します。

```ruby
after_fork do |server,worker|
  ...
  if defined?(ActiveSupport::Cache::DalliStore) && Rails.cache.is_a?(ActiveSupport::Cache::DalliStore)
    Rails.cache.reset
    ObjectSpace.each_object(ActionDispatch::Session::DalliStore) { |obj| obj.reset }
  end
```

## 環境変数の外だし

最終的にはElasticCacheへの接続したい物の、VM内での構築試験するためにわざわざEC2経由するとかしたくないので、[dotenv gem](https://github.com/bkeepers/dotenv)を利用して設定を外部化します。

.evn設定

```
$ vim .env
# nil is connecting to local memcached
CACHE_STORE=nil
 
```

環境変数引っ張る様に変更

```
# developから外して
$ vim config/environment/development.rb

- AppName::Application.configure do
-   ...
-   config.cache_store = :dalli_store, ENV['CACHE_STORE']
-   ...

# productionのみ追加
$ vim config/environment/production.rb

AppName::Application.configure do
  ...
  config.cache_store = :dalli_store, ENV['CACHE_STORE']
```

こんな感じで。