複雑なデータモデルをキャッシュするためのより高速な方法
データモデルが複雑になり、APIがその悲しい1秒の応答時間に達した場合、通常は簡単な修正があります::includes
。 モデルの関連付けをプリロードすると、SQL呼び出しはそれほど多くなりません。 そして、それはあなたにたくさんの時間を節約することができます。
しかし、その後、サイトの速度が再び低下し、応答のキャッシュについて考えます。そして今、あなたは問題を抱えています。キャッシュから応答を取得したい場合:
results = {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
cached_objects = Rails.cache.fetch_multi(results.keys) do |key|
Lawyer.find(results[key]).as_json
end
これで、すべての:includes
が失われました 。あなたは両方を持つことができますか? キャッシュされたオブジェクトに対して高速な応答を取得し、それでもキャッシュにないオブジェクトをすばやくロードするにはどうすればよいですか?
やることがたくさんあるので、それについて考えるのは難しいです。問題を細かく分割して、次の簡単なステップを考え出すと、より簡単になります。
では、最初にできることは何ですか? 多くのことを行うには、キャッシュ内にあるオブジェクトと、まだ見つける必要のあるオブジェクトを知る必要があります。
したがって、キャッシュキーがたくさんあるとしましょう:
cache_keys = [:key_1, :key_2, :key_3]
これらのどれがキャッシュにあるかをどうやって見分けることができますか?
ActiveSupport::Cache
read_multi
と呼ばれる便利なメソッドがあります :
# When only lawyer_1 is cached
cache_keys = [:lawyer_1, :lawyer_2, :lawyer_3]
Rails.cache.read_multi(cache_keys) # => {:lawyer_1 => {"id": 1, "name": "Bob the Lawyer"} }
read_multi
{key: value}
のハッシュを返します キャッシュで見つかったキーごとに。しかし、ではないすべてのキーをどのように見つけますか キャッシュに?簡単な方法で行うことができます。すべてのキャッシュキーを調べて、read_multi
のハッシュに含まれていないキーを見つけます。 返品:
cache_keys = [:lawyer_1, :lawyer_2, :lawyer_3]
uncached_keys = []
cached_keys_with_values = Rails.cache.read_multi(cache_keys)
cache_keys.each do |key|
uncached_keys << key unless cached_keys_with_values.has_key?(key)
end
それで、あなたは今何を持っていますか?
- オブジェクトが必要なすべてのキャッシュキーの配列。
-
{key: value}
のハッシュ キャッシュで見つけた各オブジェクトのペア。 - キャッシュになかったキーのリスト。
そして次に何が必要ですか?
- 値 キャッシュになかったキーの場合。できれば一度に取得します。
それがあなたの次のステップです。
間もなく、キャッシュキーを使用してオブジェクトを見つける必要があります。作業を簡単にするために、コードを次のように変更できます。
cache_identifiers = {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
cache_keys = cache_identifiers.keys
uncached_keys = []
cached_keys_with_values = Rails.cache.read_multi(cache_keys)
cache_keys.each do |key|
uncached_keys << key unless cached_keys_with_values.has_key?(key)
end
つまり、cache_identifiers
キャッシュキーを追跡するようになりましたおよび フェッチするオブジェクトID。
次に、キャッシュされていないキーを使用します:
uncached_keys # => [:lawyer_2, :lawyer_3]
そして、あなたのcache_identifiers
ハッシュ:
cache_identifiers # => {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
これらすべてのオブジェクトを一度にフェッチ、プリロード、およびシリアル化できます。
uncached_ids = uncached_keys.map { |key| cache_identifiers[key] }
uncached_lawyers = Lawyer.where(id: uncached_ids)
.includes([:address, :practice_areas, :awards, ...])
.map(&:as_json))
それで、あなたは今何を持っていますか?
- オブジェクトの最初に必要なすべてのキャッシュキーの配列。
-
{key: value}
のハッシュ キャッシュで見つかった各オブジェクトのペア。 - キャッシュになかったキーのリスト。
- キャッシュで見つからなかったすべての値。
そして次に何が必要ですか?
- フェッチしたばかりのすべての値をキャッシュするため、次回このプロセス全体を実行する必要はありません。
- キャッシュからのものかどうかに関係なく、すべてのオブジェクトの最終リスト。
2つのリストがあります。1つはキャッシュされていないキーのリストで、もう1つはキャッシュされていない値のリストです。 ただし、それらをキャッシュするには、1つあれば簡単です。 [key, value]
のリスト ペアになるので、value
key
のすぐ隣にあります 。これは、私のお気に入りの方法の1つであるzip
を使用する言い訳です。 :
[1, 2, 3].zip(["a", "b", "c"]) # => [[1, "a"], [2, "b"], [3, "c"]]
zip
を使用 、フェッチした値を簡単にキャッシュできます:
uncached_keys.zip(uncached_lawyers).each do |key, value|
Rails.cache.write(key, value)
end
あなたは今何を持っていますか?
- オブジェクトの最初に必要なすべてのキャッシュキーの配列。
-
{key: value}
のハッシュ キャッシュで見つかった各オブジェクトのペア。 - キャッシュしたばかりの以前はキャッシュされていなかった値のリスト。
そして、あなたはまだ何が必要ですか?
- キャッシュからのものかどうかに関係なく、すべてのオブジェクトの1つの大きなリスト。
これで、キャッシュキーの順序付きリストができました:
cache_keys = cache_identifiers.keys
キャッシュからフェッチしたオブジェクトのリスト:
cached_keys_with_values = Rails.cache.read_multi(cache_keys)
そして、データベースから取得したばかりのオブジェクトのリスト:
uncached_ids = uncached_keys.map { |key| cache_identifiers[key] }
uncached_lawyers = Lawyer.where(id: uncached_ids)
.includes([:address, :practice_areas, :awards, ...])
.map(&:as_json))
これで、すべてをまとめるのに最後のループが1つ必要になります:
results = []
cache_keys.each do |key|
results << cache_keys_with_values[key] || uncached_lawyers.shift
end
つまり、キャッシュキーごとに、そのキーのキャッシュで見つけたオブジェクトを取得します。そのキーが元々キャッシュになかった場合は、データベースからプルした次のオブジェクトを取得します。
その後、完了です!
全体は次のようになります。
cache_identifiers = {lawyer_1: 1, lawyer_2: 2, lawyer_3: 3}
cache_keys = cache_identifiers.keys
uncached_keys = []
# Fetch the cached values from the cache
cached_keys_with_values = Rails.cache.read_multi(cache_keys)
# Create the list of keys that weren't in the cache
cache_keys.each do |key|
uncached_keys << key unless cached_keys_with_values.has_key?(key)
end
# Fetch all the uncached values, in bulk
uncached_ids = uncached_keys.map { |key| cache_identifiers[key] }
uncached_lawyers = Lawyer.where(id: uncached_ids)
.includes([:address, :practice_areas, :awards, ...])
.map(&:as_json))
# Write the uncached values back to the cache
uncached_keys.zip(uncached_lawyers).each do |key, value|
Rails.cache.write(key, value)
end
# Create our final result set from the cached and uncached values
results = []
cache_keys.each do |key|
results << cache_keys_with_values[key] || uncached_lawyers.shift
end
results
それは価値がありました?多分。たくさんのコードです。 ただし、関連付けが多いオブジェクトをキャッシュしている場合は、数十または数百のSQL呼び出しを節約できます。 これにより、API応答の時間を大幅に短縮できます。
Avvoでは、このパターンは非常に便利です。多くのJSON APIは、このパターンを使用して、キャッシュされた応答を非常に迅速に返します。
このパターンは非常に便利だったので、bulk_cache_fetcherと呼ばれるカプセル化するgemを作成しました。 したがって、大きくて複雑なデータモデルをキャッシュしようとしていることに気付いた場合は、試してみてください。
-
Windows 10 の Chrome で Cookie とキャッシュを最速で消去する方法
Web サイトにアクセスすると、サイトの設定やプロファイル情報などの閲覧情報を保存するための Cookie が作成され、Web ページ、画像、CSS、オーディオ、ビデオ、その他のダウンロードされたコンテンツを保存するブラウザーのキャッシュにより、ページの読み込みが速くなります。より簡単に Web を閲覧できるようにします。ただし、すべての Cookie が適切であるとは限りません。このデータをハード ドライブに保存すると、プライバシーが漏洩し、ディスク容量が不足してコンピューターの速度が低下する可能性があります。 したがって、ブラウザの Cookie とキャッシュを定期的にクリアすることが重
-
ステガノグラフィ:マルウェアを広める新しい方法
ゼロデイ脅威、一般的なエクスプロイト、致命的な COVID-19 ウイルスと戦う準備が整っている間.ハッカーは、マシンにマルウェアを渡すための新しい手法を開発しています。 1499 年に導入された古代から存在する概念が新しい武器です。 「ステガノグラフィー」と呼ばれるこの新しい手法は、データを非表示の形式で送信して読み取ることができないようにするために使用されます。隠された、隠されているという意味のギリシャ語 (ステガノス) と、書くことを意味する「グラフィティ」の組み合わせは、危険な新しいトレンドになりつつあります。 今日のこの投稿では、この新しいフロンティアと、そこから保護され続ける方法