はじめに
インターン先でMemcashedに触れる機会があったので、どんなものか調べてみました。
Memcashedについて様々な素晴らしい記事があり、それらを参考に体型立ててまとめたものなので引用が多くなっております。
memcachedとは
とてもわかりやすい記事があったので、そちらを引用させていただきます。
memcachedは高性能な分散メモリキャッシュサーバ。データベースへの問い合わせ結果を一時的にキャッシュすることで,データベースへのアクセス回数を減らし,動的なウェブアプリケーションの高速化やスケーラビリティの向上のために利用されている。
引用元:
memcachedを知り尽くす ~第1回 memcachedの基本~
導入方法
###インストール
# brewでmemcachedをインストール
$ brew install memcached
###デーモンの自動起動設定
シンボリックリンクを作成し、launchctlで定期実行させるように設定します。
# シンボリックリンクの作成
$ ln -sfv /usr/local/opt/memcached/*.plist ~/Library/LaunchAgents
# 定期的にスクリプトを実行する設定
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
動作確認
###0. 前提知識
memcachedがどのような仕組みで値を格納しているのかのイメージを持っていないと、これからのコマンド操作などが理解しづらいと思いました。
とてもいい記事を見つけたので、引用させていただきます。
memcachedはSlabAllocatorという構造でデータを格納している。SlabAllocatorは、メモリを最初からある程度の量確保しておき、その確保したメモリを一定サイズの塊に分割してフラグメンテーションが起こらないようにした構造。memcachedはchunkという小さなメモリ領域に値を保存する。このchunkは決まったサイズので、chunkのサイズは複数ある。同一サイズのchunkをまとめたものがSlabと呼ばれる。memcachedはまずメモリをPageという単位で分割する。このPageはデフォルトで1MB。そのPageのなかにそれぞれのSlabが入り、Slabの中にはSlab固有のchunksizeのchunkたちが入っているという構造になっている。
引用元:キー一覧を見るためにmemcached入門
つまり、chunkというさまざまな大きさがある最小単位の入れ物があって、そのchunkを大きさごとにまとめたものがSlabっていうことみたいだ。格納する値の大きさによって使うchunkが変わってくるみたいです。
###1. プロセスが起動しているか確認
# デーモンの自動起動設定をしたため、ずっと動いているはず。以下のような出力されればOK
$ ps aux | grep memcached
username 93162 0.0 0.0 4962944 668 ?? S 水06PM 0:01.21 /usr/local/opt/memcached/bin/memcached -l localhost
username 5111 0.0 0.0 4427068 828 s000 S+ 10:36AM 0:00.00 grep memcached
###2. memcachedが実際に使えるか確認
rails consoleでmemcacheにアクセスするためのインスタンスを作る
[1] pry(main)> a = ActiveSupport::Cache::MemCacheStore.new('localhost:11211', expires_in: 60, namespace: 'NS_ABC', compress: true)
=> #<ActiveSupport::Cache::MemCacheStore:0x007f9e886df938
@data=#<Dalli::Client:0x007f9e886df690 @options={}, @ring=nil, @servers=["localhost:11211"]>,
@options={:expires_in=>60, :namespace=>"NS_ABC", :compress=>true}>
引数で渡しているもの
- localhost:11211 > ポート番号の指定
- expires_in: 60 > 時間の指定
- namespace: 'NS_ABC' > タグと認識している
- compress: true > compressにtrueを指定した時は、データ容量が特定の閾値(compress_thresholdで指定も可能)を超えた際に圧縮するという設定のよう
データをキャッシュさせたり取り出したりする
# キャッシュ
[3] pry(main)> a.write('key', 'val')
=> 5044031582654955520
# 取り出し
[4] pry(main)> a.read('key')
=> "val"
telnetでmemcachedに接続し、実際に値が格納されているか確認する
# telnetでmemcachedに接続する
$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
まずはstats items
でSlabの一覧を確認する。
stats items
STAT items:1:number 4
STAT items:1:number_hot 0
STAT items:1:number_warm 1
STAT items:1:number_cold 3
・
・
・
END
先程格納した値がどのSlabに格納されているかはstats cachedump [Slabの番号] [取得する要素数]で1つ1つ中身を確認していく。
#1つ1つのSlabを確認する stats cachedump [Slabの番号] [取得する要素数]
stats cachedump 1 100
stats cachedump 2 100
stats cachedump 3 100
・
・
・
stats cachedump 4 100
ITEM NS_ABC:key [102 b; 1638165259 s]
END
Slab番号4のところに、先程格納したものが[namespace]:[key]というファーマットで格納されていることがわかります。
get <キー>
で値を確認してみましょう。
get NS_ABC:key
VALUE NS_ABC:key 1 102
o: ActiveSupport::Cache::Entr:
@valueIval:ET:@created_atf1638164899.004805:@expires_in6e1
END
よくわからない値が出ましたが、これは格納した値がシリアライズされたものです。
したがって、ActiveSupport::Cache::Entry
にデータを詰め込んでシリアライズをすると、同じようなものが作れます。rails console
の方で値(val)をシリアライズしてみましょう。シリアライズはMarshal
というクラスを使うのがスタンダードらしいです。
[32] pry(main)> b = ActiveSupport::Cache::Entry.new('val', expires_in: 60)
=> #<ActiveSupport::Cache::Entry:0x007f8ee9c7e758 @created_at=1638165624.288047, @expires_in=60.0, @value="val">
# Marshalというクラスを使ってシリアライズする
[33] pry(main)> puts Marshal.dump(b) o: ActiveSupport::Cache::Entr:
@valueIval:ET:@created_atf1638165624.288047:@expires_in6e1
=> nil
memcached側で出力されたものと同じになるため、key/valでしっかり値が格納されていることがわかります。
memcached側で値を格納し、rails consoleで確認するような逆方向もできる
# 値を入れる set <キー> <フラグ> <有効期間> <サイズ>
set NS_ABC:hoge 0 60 8
hogehoge
STORED
# 値をmemcached側で確認してみる get <キー>
get NS_ABC:hoge
VALUE NS_ABC:hoge 0 8
hogehoge
END
しっかりと格納されていることがわかりました。
どうやら、インスタンスとnamespaceが対応づけられているみたいです。
また、実際に動いているアプリケーションのコンソールでも確認ができる
Cache read: "namespace"
Cache fetch_hit: "namespace"
casheが利用される時は、上記にあるように、fetch_hit
と出力されます。
cacheはconfig/environments/development.rb
でmemcached
が設定されています。
最後に
今回はローカル上での簡単な動作確認を行いました。速度改善などに役立ってくる機能なので、今後は実際の開発現場での活用法などをまとめていけたらと思います。至らない点が多くあると思うので、ご指摘などございましたらご教授いただけると幸いです。
最後まで読んでいただき、ありがとうございました。
参考にさせていただいた資料一覧
第1回 memcachedの基本:memcachedを知り尽くす
第2回 memcachedのメモリストレージを理解する
macでmemcachedを導入する手順 - Qiita
キー一覧を見るためにmemcached入門 - tumblr
RailsからMemcachedを使いつつその実体を垣間見てみる - 株式会社ランチェスター