はじめに
この記事はRuby on Rails Advent Calendar 2023の記事です。
solid_cacheとは
solid_cache
とは最近(具体的には2023年10月)に最初のバージョンがリリースされたgemです。目的はRailsのcache storeの一つになることで、Redisなどを使わずRDBにキャッシュを保存することが特徴です。余談ながら、initial commitは2022年11月でしたので、約1年秘密裏に開発されていたことになります。
なぜRDBにキャッシュを保存するのか?
キャッシュをRDBに保存する動機付けについてはREADMEに書かれています。
Using SQL databases backed by SSDs we can have caches that are much larger and cheaper than traditional memory only Redis or Memcached backed caches.
Testing on HEY shows that reads and writes are 25%-50% slower than with a Redis cache (1.2ms vs 0.8-1ms per single-key read), but this is not a significant percentage of the overall request time.
If cache misses are expensive (up to 50x the cost of a hit on HEY), then there are big advantages to caches that can hold months rather than days of data.
確かにキャッシュ自体の速度は低下するものの、キャッシュを安く大容量化できるのがメリットということのようです。最後の文にあるように、キャッシュを数ヶ月保持しておくことでキャッシュミス(約50倍の低速化)を回避できるということですね。
どのようにRDBにキャッシュを保存するのか
RailsとRDBといえば当然ActiveRecord
が思い浮かびます。solid_cacheもARのインターフェースを使ってキャッシュを保存しています。
このクラスにメインのロジックが書かれているようです。このクラスはRecord
抽象クラスを経由してActiveRecord::Base
を継承しています。
def upsert_all_no_query_cache(attributes)
insert_all = ActiveRecord::InsertAll.new(self, attributes, unique_by: upsert_unique_by, on_duplicate: :update, update_only: [ :value ])
sql = connection.build_insert_sql(ActiveRecord::InsertAll::Builder.new(insert_all))
message = +"#{self} "
message << "Bulk " if attributes.many?
message << "Upsert"
# exec_query_method does not clear the query cache, exec_insert_all does
connection.send exec_query_method, sql, message
end
def select_all_no_query_cache(query, values)
uncached do
if connection.prepared_statements?
result = connection.select_all(sanitize_sql(query), "#{name} Load", Array(values), preparable: true)
else
result = connection.select_all(sanitize_sql([ query, values ]), "#{name} Load", nil, preparable: false)
end
result.cast_values(SolidCache::Entry.attribute_types)
end
end
この2つのメソッドはキャッシュストアが実装するべきインターフェースであるwrite
やread
の実装詳細です。ARの内部クラスを利用していたりして理解が少し難しいですが、詳細には踏み込まずともINSERT
やSELECT
を実行しているのはわかります。
まとめ
ということでsolid_cacheについて簡単に紹介しました。まだ新しいプロダクトであり、今後様々な改善が導入されることでしょう。実用例についてはすでに37Signals社のHEYがあるようですが、こちらも今後増加が見込まれます。
コードの行数は短く読みやすいので、コードリーディングの題材としても使えるかもしれません。今回この記事を書くに当たってコードを読んでいたところ、小さな改善ができそうだったのでPRを送ってみたのですが、新しいプロダクトではこういうことが出来るのも良いですね。