使用redis-objects在Rails API中添加缓存机制
这是什么
-
- rails APIにredisによるキャッシュ機構を導入する際、接続するredisの設定や各キャッシュの設定(キー・期限など)を隠蔽してくれるredis-objectsが役に立ちます。今回、RailsAPIにRedisキャッシュ機構を実装したので、メモを残しておきます。
-
- 検証時の各種ライブラリのバージョンは以下です
redis-objects 1.4.3
rails 5.2.3
ruby 2.6.1p33
前提
redis是什么
内存型键值存储(In-Memory KVS)。数据的存储和获取速度非常快。请详细搜索了解更多信息。
另外,虽然本文没有提及,在引入redis-object之前,使用redis-cli尝试操作一些命令可能会更加增进理解。
现金是什么?
由于每次收到API请求后都要去数据库获取数据是低效的,所以对于具有相同参数的请求,可以在API服务器上保存响应,然后在第二次及之后的请求中直接返回它。这样可以减少数据库访问次数,减轻数据库服务器负载,并提高响应速度等效果。
需要注意的是,如果不设置缓存的有效期限,可能无法反映内容的更改,或者会给缓存服务器带来压力。因此,最好设置一个合适的有效期限(本例中为1小时)。
本次引入的现金机制
我们采用了一种被称为Cache-Aside模式的缓存模式。
-
- APIに対してリクエストがきた際、特定のルールに基づいてパラメータからキー(文字列)を生成
-
- そのキーに対応するキャッシュがあるかredisサーバーに問い合わせる
あった場合
redisサーバーから受け取った値を(必要に応じて整形し)レスポンスとして返す
なかった場合
DBに値を問い合わせ、先ほど生成したキーとDBから受け取った値をredisサーバーに格納
DBから受け取った値をレスポンスとして返す
这样的感觉。
引导步骤
重要的事项
/items?item_category_id=${カテゴリID}というエンドポイントへのリクエストに対するレスポンスを、カテゴリIDごとにJSON型でキャッシュする
キャッシュの期限は1時間とする
引入Redis-objects
gem "redis-objects", "~> 1.4.3"
bundle install
为redis-objects添加配置
-
- 今回のプロジェクトにはglobalが導入されていたので、Global.redis.host という感じに環境ごとのホストとポートの設定を読み込めるよう、設定ファイルを config/globals/ に追加します
- 今回の記事では本番環境などの場合の環境変数は省略しますが、必要な場合は適当に追加してください。
default: &default
host: <%= ENV.fetch("REDIS_HOST", "redis") %>
port: <%= ENV.fetch("REDIS_PORT", "6379") %> # 6379はredisのデフォルトポート番号
development:
<<: *default
test:
<<: *default
- Railsアプリ起動時にRedisObjectとRedisサーバーの紐付けを行うために、config/initializersにredisの接続設定を記載します
host = Global.redis.host
port = Global.redis.port
Redis::Objects.redis = Redis.new(host: host, port: port)
创建用于缓存的类 yú de
- 今回はレスポンス用のJSONをまるごとキャッシュするので、model/配下にredis-objectsをincludesした*Response.rbというクラスを作成します
class ItemsResponse
include Redis::Objects
value :resource, expireat: -> { Time.current + 1.hour } # 有効期限1時間の設定
def initialize(item_category_id)
@item_category_id = item_category_id
end
def id # redis-objectがキーを生成するのに使用する。設定するキャッシュ単位ごとに一意である必要がある
@item_category_id
end
end
在控制器端创建缓存功能。
class ItemsController < ApplicationController
def show
if cache_exists
result.resource = JSON.parse(@cached_value)
else
... # DBからitemsを取得する処理
store_cache(result.resource)
end
render json: result.resource
end
private
def cache_exists
@cached_value = ItemsResponse.new(params[:item_id]).resource.value
end
def store_cache(resource)
ItemsResponse.new(params[:item_id]).resource = resource.to_json
end
end
其他
更改密钥
- redisに格納する際のキーはデフォルトでは”#{モデル名}:#{self.id}:#{フィールド名}”ですが、これを変えるときは、valueの宣言時にkeyオプションを渡すことでキーの変更が可能です。
class ItemsResponse
include Redis::Objects
value :resource, key: ->(instance) { "it:is:new:key:#{instance.id}:good" }
...
end
class ItemsResponse
include Redis::Objectsfff
value :resource, key: 'it:is:new:key:#{instance.id}:good' # 文字列はシングルクオートで囲って渡す点に注意
...
end
更改Redis数据库
如果在应用程序中使用多个 Redis 缓存类,可以对每个类进行 Redis 数据库的切换。
class ItemsRespnose
include Redis::Objects
...
end
class UsersRespnose
include Redis::Objects
...
end
host = Global.redis.host
port = Global.redis.port
ItemsResponse.redis = Redis.new(host: host, port: port, db: 0) # デフォルトは0
UsersResponse.redis = Redis.new(host: host, port: port, db: 1)