
Solid Cache README: DBベースのキャッシュストア(翻訳)
Solid Cache v0.3.0以前からアップグレードする場合は、「v0.4.0以上にアップグレードする場合」ドキュメントを参照してください。
Solid Cacheは、データベースを利用したActive Supportキャッシュストアの実装です。
SSD上のSQLデータベースを利用することで、従来のRedisやMemcadhedのようなメモリ上のみのキャッシュよりもずっと大容量かつ安価なキャッシュを実現します。
利用法
Solid CacheをRailsのキャッシュとして設定するには、Railsアプリの環境コンフィグで以下を追加する必要があります。
config.cache_store = :solid_cache_store
Solid CacheはFIFO(first in, first out: 先入れ先出し)方式のキャッシュです。FIFOはLRU(least recently used: 直近で最も使われていないものから削除する)方式ほど効率は高くありませんが、キャッシュの寿命を長くすることで効率を補っています。
FIFOキャッシュは以下の理由で管理がずっと簡単です。
- 項目がいつ読み出されたかをトラッキングする必要がない。
- 最大IDと最小IDを比較することでキャッシュサイズの推定と制御が行える。
- テーブルの一方の端から削除し、反対側の端に追加することで断片化を回避できる(少なくともMySQLでは)。
インストール方法
アプリケーションのGemfileに以下の行を追加します。
gem "solid_cache"
続いて以下を実行します。
$ bundle
または、以下を実行して手動でインストールすることも可能です。
$ gem install solid_cache
続いて以下のマイグレーションを実行します。
$ bin/rails solid_cache:install:migrations
続いて以下を実行します。
$ bin/rails db:migrate
設定方法
config/solid_cache.yml
の設定ファイルが読み込まれます。このファイルの置き場所はSOLID_CACHE_CONFIG
環境変数で変更できます。
設定ファイルのフォーマットは以下のとおりです。
default:
store_options: &default_store_options
max_age: <%= 60.days.to_i %>
namespace: <%= Rails.env %>
size_estimate_samples: 1000
development: &development
database: development_cache
store_options:
<<: *default_store_options
max_size: <%= 256.gigabytes %>
production: &production
databases: [production_cache1, production_cache2]
store_options:
<<: *default_store_options
max_entries: <%= 256.gigabytes %>
store_options
の完全なリストについては、後述のキャッシュの設定を参照してください。キャッシュ探索に渡したオプションは、この設定ファイルで指定したオプションを上書きします。
コネクションの設定方法
この設定ファイルには、database
、databases
、connects_to
のいずれか1つを設定できます。これらは、SolidCache::Record#connects_to
でキャッシュデータベースを設定するのに使われます。
database
にcache_db
を指定すると、以下のように設定されます。
SolidCache::Record.connects_to database: { writing: :cache_db }
databases
に[cache_db, cache_db2]
を指定することは、以下と同等です。
SolidCache::Record.connects_to shards: { cache_db1: { writing: :cache_db1 }, cache_db2: { writing: :cache_db2 } }
connects_to
が設定されている場合は、直接渡されます。
上記のどの項目も設定されていない場合、Solid CacheはActiveRecord::Base
コネクションプールを利用します。この設定は、キャッシュの読み出しと書き込みが、データベーストランサクションの一部としてラップされることを意味します。
エンジンの設定方法
エンジンには以下の3つのオプションを設定できます。
executor
- RailsのExecutorを利用して非同期操作をラップします。デフォルトはアプリのExecutorです。
connects_to
- Active Recordの
SolidCache::Record
抽象モデルで利用するカスタム接続先の値です。メインアプリでシャーディングや別のキャッシュデータベースを利用する場合に必要です。このオプションを指定することでconfig/solid_cache.yml
ファイルの値が上書きされます。 size_estimate_samples
- キャッシュに
max_size
が設定されている場合、サイズの推定に利用するサンプル数を指定します。
これらのオプションは、以下のようにRailsの設定ファイルで指定できます。
Rails.application.configure do
config.solid_cache.size_estimate_samples = 1000
end
キャッシュの設定方法
Solid Cacheでは、標準のActiveSupport::Cache::Store
にあるオプションに加えて、以下のオプションもサポートしています。
error_handler
- 発生したすべての
ActiveRecord::ActiveRecordError
を処理するために呼び出すProcを指定します(デフォルト: エラーを"warning"としてログ出力する)。 expiry_batch_size
- 古いレコードを削除するときのバッチサイズ(デフォルト:
100
) expiry_method
- 期限を失効させる方法を
:thread
または:job
で指定します(デフォルト::thread
)。 expiry_queue
- 失効ジョブをどのキューに追加するかを指定します(デフォルト:
:default
) max_age
- キャッシュ内でエントリが失効せずに持続する最大期間(デフォルト:
2.weeks.to_i
)。nil
に設定することも可能ですが、次のmax_entries
でキャッシュサイズの上限を設定しない限り利用は推奨されません。 max_entries
- キャッシュに保存できるエントリの最大数を指定します(デフォルト:
nil
-- 上限なしを意味する)。 max_size
- キャッシュエントリの最大サイズを指定します(デフォルト:
nil
-- 上限なしを意味する)。 cluster
- キャッシュデータベースのクラスタに渡すオプションをハッシュで指定します(例:
{ shards: [:database1, :database2, :database3] }
)。 clusters
- 複数のキャッシュクラスタに渡すオプションをハッシュの配列で指定します(
:cluster
オプションが設定済みの場合は無視されます)。 active_record_instrumentation
- キャッシュのクエリをinstrumentation(計測)の対象にするかどうかを指定します(デフォルト:
true
)。 clear_with
- キャッシュを
:truncate
と:delete
のどちらでクリアするかを指定します(デフォルトは:truncate
ですが、Rails.env.test?
の場合は:delete
が使われます)。 max_key_bytesize
- 正規化されたキーの最大サイズをバイト単位で指定します(デフォルト:
1024
)。
キャッシュクラスタについて詳しくは、キャッシュをシャーディングするを参照してください。
キャッシュの失効
max_entries
またはmax_size
が設定済みの場合は、これらの値を超えたかどうかをチェックする
現在のエントリは、SolidCache::Entry
テーブルに登録されている最大のIDから最小のIDを減算することで推測します。
現在のサイズは、エントリのbyte_size
カラムをサンプリングすることで推測します。-
値を超えた場合は、
expiry_batch_size
の個数分のエントリを削除する - 超えていない場合は、
max_age
より長い期間存在しているエントリを最大expiry_batch_size
の個数分削除する
バッチサイズの50%の個数に達したら失効処理を行うようになっています。これにより、キャッシュサイズを削減する必要が生じたときに、キャッシュの書き込みよりも早期のタイミングでレコード上のキャッシュを失効させることが可能になります。
失効処理をトリガーするタイミングを書き込み時のみに限定しているので、キャッシュがアイドリング状態であればバックグラウンドのスレッドもアイドリング状態になります。
キャッシュの失効処理をスレッドではなくバックグラウンドで行いたい場合は、 expiry_method
に:job
を指定します。これにより、SolidCache::ExpiryJob
がエンキューされるようになります。
キャッシュ専用データベースを利用する場合
以下のようなデータベース設定をdatabase.yml
ファイルに追加します。
development:
cache:
database: cache_development
host: 127.0.0.1
migrations_paths: "db/cache/migrate"
以下を実行してデータベースを作成します。
$ bin/rails db:create
以下を実行してマイグレーションをインストールします。
$ bin/rails solid_cache:install:migrations
キャッシュ用のマイグレーションファイルをカスタムのマイグレーションフォルダに移動します。
$ mkdir -p db/cache/migrate
$ mv db/migrate/*.solid_cache.rb db/cache/migrate
以下のように、エンジンの設定ファイルで新しいデータベースを指すように設定します。
# config/solid_cache.yml
production:
database: cache
マイグレーションを実行します。
$ bin/rails db:migrate
キャッシュをシャーディングする
Solid Cacheでは、複数データベースにわたるキャッシュのシャーディング(sharding)で、Maglevの一貫したハッシュスキームを利用しています。
シャーディングを行う手順は次のとおりです。
database.yml
ファイルにデータベースシャーディング用の設定を追加するconfig.solid_cache.connects_to
でシャーディングを設定する- キャッシュのシャードをクラスタオプション経由で渡す
例:
# config/database.yml
production:
cache_shard1:
database: cache1_production
host: cache1-db
cache_shard2:
database: cache2_production
host: cache2-db
cache_shard3:
database: cache3_production
host: cache3-db
# config/solid_cache.yml
production:
databases: [cache_shard1, cache_shard2, cache_shard3]
セカンダリのキャッシュクラスタ
セカンダリのキャッシュクラスタを追加可能です。読み取りはプライマリクラスタ(=リストの冒頭にあるクラスタ)だけに送信されます。
書き込みはすべてのクラスタに対して行われます。プライマリクラスタへの書き込みは同期的に行われますが、セカンダリクラスタへの書き込みは非同期的に行われます。
以下の操作を実行することで、複数のクラスタを指定できます。
# config/solid_cache.yml
production:
databases: [cache_primary_shard1, cache_primary_shard2, cache_secondary_shard1, cache_secondary_shard2]
store_options:
clusters:
- shards: [cache_primary_shard1, cache_primary_shard2]
- shards: [cache_secondary_shard1, cache_secondary_shard2]
シャードに名前を付ける
シャーディングで利用するノードキーには、デフォルトでdatabase.yml
ファイルに記載されているデータベースの名前が使われます。
クラスター設定内で以下のようにシャーディング用の名前を追加できます。これにより、一貫性のあるハッシュを壊さずに、シャードをシャッフルしたり削除したりできるようになります。
production:
databases: [cache_primary_shard1, cache_primary_shard2, cache_secondary_shard1, cache_secondary_shard2]
store_options:
clusters:
- shards:
cache_primary_shard1: node1
cache_primary_shard2: node2
- shards:
cache_secondary_shard1: node3
cache_secondary_shard2: node4
暗号化を有効にする
イニシャライザに以下を追加します。
ActiveSupport.on_load(:solid_cache_entry) do
encrypts :value
end
インデックスの上限サイズ
Solid Cacheのマイグレーションでは、1024バイトのエントリを持つインデックスの作成を試行します。このサイズがデータベースに対して大きすぎる場合は、以下を行う必要があります。
- マイグレーションファイルでインデックスのサイズを編集する
- キャッシュの
max_key_bytesize
に新しい値を設定する
開発
bin/rake test
でテストを実行します。デフォルトではSQLiteに対して実行されます。
MySQLやPostgreSQLに対してテストを実行することも可能です。
最初にデータベースを起動します。
$ docker compose up -d
次に、以下を実行してデータベーススキーマをセットアップします。
$ TARGET_DB=mysql bin/rails db:setup
$ TARGET_DB=postgres bin/rails db:setup
次に、対象データベースに対してテストを実行します。
$ TARGET_DB=mysql bin/rake test
$ TARGET_DB=postgres bin/rake test
複数バージョンのRailsでテストする
Solid Cacheでは、複数バージョンのRailsをテストするためにappraisalに依存しています。
Railsのバージョンを指定してテストを実行するには、以下のようにします。
bundle exec appraisal rails-7-1 bin/rake test
Gemfile
内の依存関係を更新したときは、必ず以下を実行してください。
$ bundle
$ appraisal update
これにより、すべてのRailsバージョンで依存関係が確実に更新されます。
ライセンス
Solid Cache is licensed under MIT.
関連記事
The post Solid Cache README: DBベースのキャッシュストア(翻訳) first appeared on TechRacho.
概要
MITライセンスに基づいて翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。