docker-composeを用いてRailsサーバをAPIとして立ち上げ,
Reactで書いたフロントからAPIを叩く構成でアプリケーションを開発しています.
API側の負荷を抑えるため, クエリ結果をキャッシュするためにRedisを導入した時のメモになります.
Docker, docker-composeを用いた環境構築やRedisの概要には触れていませんのでご了承ください.
開発環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.1
BuildVersion: 19B88
$ docker -v
Docker version 19.03.1, build 74b1e89
$ docker-compose -v
docker-compose version 1.24.1, build 4667896b
Redis導入前
FROM ruby:2.6.5-slim
# db, js関係の環境をインストール
RUN apt-get update -qq && apt-get install -y mariadb-client libmariadb-dev-compat build-essential apt-transport-https curl imagemagick && \
curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get install -y nodejs && \
curl -sS http://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update && apt-get install -y yarn
# Rails (bundle install)
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
version: "3"
services:
web:
build: .
command: /bin/sh -c "rm -f /myapp/tmp/pids/server.pid && bundle exec rails s -p '3001' -b '0.0.0.0'"
environment:
- DATABASE=myapp_development
- DATABASE_USER=root
- DATABASE_PASSWORD=password
- DATABASE_HOST=db
volumes:
- .:/myapp
ports:
- 3001:3001
depends_on:
- db
db:
image: mysql:5.7
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
environment:
- MYSQL_DATABASE=myapp_development
- MYSQL_ROOT_USER=root
- MYSQL_ROOT_PASSWORD=password
volumes:
- mysql_vol:/var/lib/mysql
ports:
- 3306:3306
volumes:
mysql_vol:
Rails.application.configure do
# 略
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
# 略
end
Redisの導入
1. キャッシュの有効化
先ほど載せたDockerfileを除く2つのファイルを編集する
...前に, 先にやっておくことがあります!!
config/environments/development.rb
のコメントにあるように,
Railsのdevelopment環境ではデフォルトでキャッシュが無効になっているのです.
これに気付かず, かなりハマってました...😅
Enable/disable caching. By default caching is disabled.
Run rails dev:cache to toggle caching.
ということで, 書いてあるコマンドをそのまま実行します.
$ docker-compose run web rails dev:cache
Starting myapp_db_1 ... done
Development mode is now being cached.
2. Redisコンテナの作成
docker-compose
で起動させるコンテナにRedisを追加します.
version: "3"
services:
web:
# 略
depends_on:
- db
+ - redis
db:
# 略
+ redis:
+ image: redis
+ ports:
+ - 6379:6379
+ volumes:
+ - "./app/redis:/data"
volumes:
mysql_vol:
3. キャッシュストアの設定
Gemfileに必要なgemを追加後, ビルドしてbundle install
を走らせます.
# 略
+ gem 'redis'
+ gem 'redis-rails'
$ docker-compose build
Railsでのキャッシュ先を, 先ほど追加したRedisコンテナに指定します.
後ほどの動作確認のため, 保存期限は短めに設定しておきます.
Rails.application.configure do
# 略
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
- config.cache_store = :memory_store
+ config.cache_store = :redis_store, 'redis://redis:6379/0', { expires_in: 1.minute }
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
# 略
end
設定は以上で完了です 🎉
4. 動作確認
Redisコンテナ
まずはコンテナを再起動させて, Redisコンテナが正常に動作していることを確認しましょう.
コンテナ内にアタッチしてredis-cli
を起動後, 以下のようにRedisのコマンドが実行できればokです.
$ docker-compose up -d
Creating myapp_db_1 ... done
Creating myapp_redis_1 ... done
Creating myapp_web_1 ... done
$ docker exec -it myapp_redis_1 /bin/bash
root@05aaca0b40db:/data# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name 'hoge'
OK
127.0.0.1:6379> get name
"hoge"
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> keys *
(empty list or set)
Rails.cacheを使ってみる
いよいよRailsでキャッシュを使ってみましょう.
ここでは以下のコマンドを使用します.
-
Rails.cache.write(key, value)
: キャッシュデータを保存 -
Rails.cache.exist?(key)
: key を持つキャッシュデータがあるか確認
Rails.application.routes.draw do
get 'hoge/:id', to: 'redis_samples#hoge'
end
class RedisSamplesController < ApplicationController
def hoge
Rails.cache.write('name', 'hogehoge') if params[:id].to_i > 0
render json: Rails.cache.exist?('name')
end
end
コンソールからAPIを叩きます.
最初はパラメータに id = 1
を与えてキャッシュデータを保存します.
もちろんtrue
が返ってきます.
$ curl localhost:3001/hoge/1
true
実際にRedisコンテナからキャッシュストアを見てみると,
先ほど保存したキャッシュデータが保存されていることが確認できます!
また, ttl
コマンドでキャッシュデータの有効期限の残りを秒単位で取得できます.
$ docker exec -it myapp_redis_1 /bin/bash
root@05aaca0b40db:/data# redis-cli
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
"\x04\bo: ActiveSupport::Cache::Entry\t:\x0b@valueI\..."
127.0.0.1:6379> ttl name
(integer) 49
指定した有効期限を経過した後に実行すると,
きちんとキャッシュデータが削除されていることも確認できます.
127.0.0.1:6379> keys *
(empty list or set)
最後に削除されたことをRails側からも確認しましょう.
パラメータを id = 0
としてAPIを叩くとfalse
が返ってきます.
$ curl localhost:3001/katagamis/hoge/0
false
終わりに
さくっとできるかと思いきや結構手間取ってしまい, 忘れないうちにメモとして残しておきました.
まるっとチュートリアル的な記事ではないので, 開発進めてく途中の参考程度になれば幸いです.
ご意見・質問などあれば遠慮なく!!