Cache invalidations can be missed on rollout of schema changes
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 30/100
調査の方向性
README の注意事項から始め、CACHE_VERSION と denormalized_schema_hash 周辺にある既存のプライマリキャッシュインデックスの処理を調査してください。Issue で説明されているキャッシュの補填および無効化の経路を追跡し、その後、スキーマのロールアウトによって無効化が維持され、通常動作時のパフォーマンスに大きな影響が生じないことを確認してください。
索引モデルが issue の本文から書いたものです。
説明
The problem is mentioned in the README caveats:
Expected sources of lost cache invalidations include:
...
Rollout of cache namespace changes (e.g. from upgrading IdentityCache, adding columns, cached associations or from application changes to IdentityCache.cache_namespace) can result in cache fills to the new namespace that aren't invalidated by cache invalidations from a process still using the old namespace
This is particularly a problem for slower rollouts of code, such with canary deploys, which leave a larger window of time for database updates to happen with only one of the cache keys being invalidated.
It is also hard to argue that developers should expect this source of lost cache invalidations, since the developer's change may just be to the models ignored_columns attribute for a column that isn't otherwise being used. As in, this is action at a distance, which can cause confusion for developers deploying the change, as well as for users that see the stale data.
As such, I think this is a problem worth fixing. Although, I have had a hard time thinking of a way to do this, since we don't want to compromise performance significantly for this edge case and we don't want to expect developers making the change to be aware of the issue and make other changes to enable something like double cache invalidations (for both keys with the old and new denormalized_schema_hash in their cache key prefix).
Proposed Solution
I think the solution can be focused on the primary cache index, since that is what is affected by column changes. In the past, we have often bumped IdentityCache::CACHE_VERSION when changes have been made to the format of just the primary cache index, but I think we could instead introduce a cache version prefix into the denormalized_schema_hash so that we can focus on changes to that schema hash.
Given that we desire a solution that doesn't involve manual work by the developer when changing the schema and wouldn't know the schema hash for different versions of the application, we could solve that problem by moving the schema hash out of the key and into the value. The primary cache index already encodes records as a Hash for serialization, so can additional keys for versioning. The schema hash can then be checked after loading the value in order to avoid the value on a mismatch.
When we detect a schema version mismatch when loading from this new key that doesn't include the schema hash, then we don't want to just replace it with one with the correct schema version, since that could lead to contention between two versions of the application during a deploy that keep replacing each others cache values. However, this can be solved by falling back to a schema hash versioned key (e.g. we could use the same keys that we currently use), so the value can be stored for both schema versions. I'll refer to these keys as the main key (without a schema hash in the key) and the fallback key (that includes the schema hash in the key).
We won't be replacing the fallback key on cache invalidation, in fact we won't even be able to build that key for another version of the app. Instead, we can include a new SecureRandom.uuid data_version in the cache invalidation value, which will then also be copied into the corresponding value when doing a cache fill of either the main key or fallback key. That way, the cache invalidation can be detected, even after a cache invalidation and cache fill of the main key with a different schema cache version, by checking the data_version of the main key against the fallback key and treating a mismatch as if the fallback key value has been invalidated.
The performance of the proposed solution during normal operation will be comparable to the current performance, since it would just be using the main key when there aren't any schema hash mismatches. A deploy of a schema change would lead to extra latency to load the fallback key after a schema hash mismatch, but it would only be when loading caches of records for the model that had its schema changed and wouldn't introduce additional database load. After the deploy completes, it will start to convert back to just using the main key as the cache entries for the old schema get invalidated or expire.
An additional optimization can help with improving performance during schema mismatches and reduce time to convergence: after filling the fallback key as a result of a schema mismatch, copy the cache value in the main key into its corresponding fallback key, then replace the main key with multi-schema value marker with the associated data_version and a timestamp for the current time. The marker value would be much smaller, so would reduce unnecessary data transfer to load the value from the cache. A configurable duration can be used to determine when the multi-schema value marker should be replaced with the fallback key for the currently running code, so it can converge faster than the general cache value expiration duration.
- 主要言語
- Ruby
- スター
- 2k
- フォーク
- 175
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Shopify/identity_cache のほかの issue
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
Shopify/identity_cache#568 · コメント 1 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
Shopify/identity_cache#555 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
Shopify/identity_cache#539 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
Shopify/identity_cache#533 · コメント 1 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
Shopify/identity_cache#525 · コメント 4 件 ·
Shopify/identity_cache の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
-
:bank: debt
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
cucumber/cucumber-ruby-core#346 · コメント 1 件 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 75/100
TheOdinProject/curriculum#31467 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
message-patterns
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
sisimai/rb-sisimai#468 ·