使用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)
广告
将在 10 秒后关闭
bannerAds