apeescape2.com
  • メイン
  • 製品ライフサイクル
  • Kpiと分析
  • 投資家と資金調達
  • その他
バックエンド

フィールドレベルのRailsキャッシュの無効化:DSLソリューション

最新のWeb開発では、キャッシュは物事をスピードアップするための迅速で強力な方法です。キャッシュを正しく実行すると、アプリケーションの全体的なパフォーマンスが大幅に向上します。間違って行われると、間違いなく災害に終わります。

ご存知かもしれませんが、キャッシュの無効化は、コンピュータサイエンスで最も難しい3つの問題の1つです。他の2つは、名前の付け方と1つずつのエラーです。簡単な方法の1つは、何かが変更されるたびに、左右のすべてを無効にすることです。しかし、それはキャッシュの目的を無効にします。どうしても必要な場合にのみキャッシュを無効にします。

キャッシュを最大限に活用したい場合は、無効にするものに非常に注意を払い、繰り返しの作業で貴重なリソースを浪費しないようにアプリケーションを保存する必要があります。



フィールドレベルのRailsキャッシュの無効化

このブログ投稿では、Railsキャッシュの動作をより適切に制御するための手法、具体的には、フィールドレベルのキャッシュ無効化の実装について学習します。この手法はに依存しています Rails ActiveRecord およびActiveSupport::Concern touchの操作と同様にメソッドの動作。

このブログ投稿は、フィールドレベルのキャッシュ無効化を実装した後にパフォーマンスが大幅に向上したプロジェクトでの最近の経験に基づいています。これは、不要なキャッシュの無効化とテンプレートの繰り返しのレンダリングを減らすのに役立ちました。

Rails、Ruby、およびパフォーマンス

Rubyは最速の言語ではありませんが、全体として、開発速度が懸念される場合に適したオプションです。さらに、その メタプログラミング 組み込みのドメイン固有言語(DSL)機能により、開発者は非常に柔軟に対応できます。

のような研究がそこにあります ヤコブニールセンの研究 これは、タスクに10秒以上かかると、フォーカスが失われることを示しています。そして、私たちの焦点を取り戻すには時間がかかります。したがって、これは予想外にコストがかかる可能性があります。

残念ながら、Ruby on Railsでは、テンプレート生成でその10秒のしきい値を超えるのは非常に簡単です。 「HelloWorld」アプリや小規模なペットプロジェクトではこれが発生することはありませんが、多くのものが1つのページに読み込まれる実際のプロジェクトでは、テンプレートの生成は非常に簡単にドラッグを開始できます。

そして、それはまさに私が私のプロジェクトで解決しなければならなかったことです。

簡単な最適化

しかし、どのくらい正確に物事をスピードアップしますか?

答え:ベンチマークと最適化。

私のプロジェクトでは、最適化における2つの非常に効果的なステップは次のとおりです。

  • N +1クエリの排除
  • テンプレートの優れたキャッシュ手法の紹介

N +1クエリ

修正 N +1クエリ は簡単だ。できることは、ログファイルを確認することです。ログに以下のような複数のSQLクエリが表示された場合は、それらを積極的な読み込みに置き換えて削除します。

Learning Load (0.4ms) SELECT 'learnings'.* FROM 'learnings' WHERE 'project'.'id' = ? Learning Load (0.3ms) SELECT 'learnings'.* FROM 'learnings' WHERE 'project'.'id' = ? Learning Load (0.4ms) SELECT 'learnings'.* FROM 'learnings' WHERE 'project'.'id' = ?

これには、と呼ばれる宝石があります 弾丸 この非効率性を検出するのに役立ちます。また、各ユースケースをウォークスルーし、その間に、上記のパターンと照らし合わせてログを確認することもできます。 N + 1の非効率性をすべて排除することで、データベースに過負荷がかからず、ActiveRecordに費やす時間が大幅に短縮されることを確信できます。

これらの変更を行った後、私のプロジェクトはすでにより活発に実行されていました。しかし、私はそれを次のレベルに引き上げて、そのロード時間をさらに短縮できるかどうかを確認することにしました。テンプレートではまだかなりの不要なレンダリングが行われており、最終的にはフラグメントキャッシングが役立ちました。

フラグメントキャッシング

フラグメントキャッシングは通常、テンプレートの生成時間を大幅に短縮するのに役立ちます。しかし、デフォルトのRailsキャッシュの動作は、私のプロジェクトではそれをカットしていませんでした。

Railsフラグメントキャッシングの背後にある考え方は素晴らしいです。これは、非常にシンプルで効果的なキャッシュメカニズムを提供します。

Ruby On Railsの作者は、Signalv。Noiseに非常に優れた記事を書いています。 フラグメントキャッシュは機能します 。

エンティティのいくつかのフィールドを表示するユーザーインターフェイスが少しあるとしましょう。

  • ページの読み込み時に、Railsはcache_keyを計算しますエンティティのクラスとupdated_atに基づくフィールド。
  • そのcache_keyを使用して、そのキーに関連付けられたキャッシュに何かがあるかどうかを確認します。
  • キャッシュに何もない場合、そのフラグメントのHTMLコードがビュー用にレンダリングされます(新しくレンダリングされたコンテンツはキャッシュに保存されます)。
  • そのキーを持つ既存のコンテンツがキャッシュにある場合、ビューはキャッシュのコンテンツでレンダリングされます。

これは、キャッシュを明示的に無効にする必要がないことを意味します。エンティティを変更してページをリロードするたびに、エンティティの新しいキャッシュコンテンツがレンダリングされます。

Railsは、デフォルトで、子が変更された場合に親エンティティのキ​​ャッシュを無効にする機能も提供します。

belongs_to :parent_entity, touch: true

これをモデルに含めると、自動的に 接する 子供がいるときの親 触れた 。 touchについて詳しく知ることができます ここに 。これにより、Railsは、子エンティティのキ​​ャッシュと同時に親エンティティのキ​​ャッシュを無効にする簡単で効率的な方法を提供します。

Railsでのキャッシング

ただし、Railsでのキャッシュは、親エンティティを表すHTMLフラグメントに親の子エンティティのみを表すHTMLフラグメントが含まれるユーザーインターフェイスを提供するために作成されます。つまり、このパラダイムの子エンティティを表すHTMLフラグメントには、親エンティティのフィールドを含めることはできません。

しかし、それは現実の世界では起こりません。 Railsアプリケーションでこの条件に違反することを行う必要があるかもしれません。

ユーザーインターフェイスに、子エンティティを表すHTMLフラグメント内の親エンティティのフィールドが表示される状況をどのように処理しますか?

親エンティティのフィールドを参照する子エンティティのフラグメント

子に親エンティティのフィールドが含まれている場合は、Railsのデフォルトのキャッシュ無効化動作に問題があります。

親エンティティから提示されたこれらのフィールドが変更されるたびに、その親に属するすべての子エンティティに触れる必要があります。たとえば、Parent1の場合が変更された場合、Child1のキャッシュを確認する必要がありますおよびChild2ビューは両方とも無効になります。

明らかに、これは大きなパフォーマンスのボトルネックを引き起こす可能性があります。親が変更されるたびにすべての子エンティティに触れると、正当な理由もなく多くのデータベースクエリが発生します。

別の同様のシナリオは、エンティティがhas_and_belongs_toに関連付けられている場合です。アソシエーションがリストに表示され、それらのエンティティを変更すると、アソシエーションチェーンを通じてキャッシュ無効化のカスケードが開始されました。

class Event

したがって、上記のユーザーインターフェースの場合、ユーザーの場所が変更されたときに参加者またはイベントに触れるのは非論理的です。しかし、ユーザーの名前が変わったら、イベントと参加者の両方に触れる必要がありますね。

そのため、上記のように、Signalv。Noiseの記事の手法は特定のUI / UXインスタンスでは非効率的です。

Railsは単純なことには非常に効果的ですが、実際のプロジェクトには独自の複雑さがあります。

フィールドレベルのRailsキャッシュの無効化

私のプロジェクトでは、上記のような状況を処理するために小さなRubyDSLを使用しています。これにより、関連付けを通じてキャッシュの無効化をトリガーするフィールドを宣言的に指定できます。

それが本当に役立つ場所のいくつかの例を見てみましょう:

レスポンシブデザインの標準画面サイズ

例1:

class Event

このスニペットは、メタプログラミング機能と内部を活用します RubyのDSL機能 。

具体的には、イベントでの名前の変更のみが、関連するタスクのフラグメントキャッシュを無効にします。目的や場所など、イベントの他のフィールドを変更しても、タスクのフラグメントキャッシュは無効になりません。私はこれを呼ぶでしょう フィールドレベルのきめ細かいキャッシュ無効化制御 。

名前フィールドのみを持つイベントエンティティのフラグメント

例2:

has_manyによるキャッシュの無効化を示す例を見てみましょう。アソシエーションチェーン。

以下に示すユーザーインターフェイスフラグメントは、タスクとその所有者を示しています。

イベント所有者を持つイベントエンティティのフラグメント

このユーザーインターフェイスの場合、タスクを表すHTMLフラグメントは、タスクが変更されたとき、または所有者の名前が変更されたときにのみ無効にする必要があります。所有者の他のすべてのフィールド(タイムゾーンや設定など)が変更された場合、タスクキャッシュはそのままにしておく必要があります。

これは、ここに示すDSLを使用して実現されます。

class User

DSLの実装

DSLの主な本質はtouchです。方法。その最初の引数は関連付けであり、次の引数はtouchをトリガーするフィールドのリストです。その協会について:

touch :tasks, in_case_of_modified_fields: [:first_name, :last_name]

このメソッドはTouchableによって提供されますモジュール:

module Touchable extend ActiveSupport::Concern included do before_save :check_touchable_entities after_save :touch_marked_entities end module ClassMethods def touch association, options @touchable_associations ||= {} @touchable_associations[association] = options end end end

このコードで重要なのは、touchの引数を格納することです。コール。次に、エンティティを保存する前に、指定されたフィールドが変更された場合、関連付けをダーティとしてマークします。アソシエーションがダーティである場合は、保存後にそのアソシエーションのエンティティにアクセスします。

次に、懸念の私的な部分は次のとおりです。

... private def klass_level_meta_info self.class.instance_variable_get('@touchable_associations') end def meta_info @meta_info ||= {} end def check_touchable_entities return unless klass_level_meta_info.present? klass_level_meta_info.each_pair do |association, change_triggering_fields| if any_of_the_declared_field_changed?(change_triggering_fields) meta_info[association] = true end end end def any_of_the_declared_field_changed?(options) (options[:in_case_of_modified_fields] & changes.keys.map).present? end …

check_touchable_entitiesでメソッド、チェックします 宣言されたフィールドが変更された場合 。その場合、meta_info[association]を設定して、関連付けをダーティとしてマークします。 trueへ。

次に、エンティティを保存した後、 汚い協会 必要に応じて、その中のエンティティに触れます。

… def touch_marked_entities return unless klass_level_meta_info.present? klass_level_meta_info.each_key do |association_key| if meta_info[association_key] association = send(association_key) association.update_all(updated_at: Time.zone.now) meta_info[association_key] = false end end end …

そして、それだけです!これで、単純なDSLを使用してRailsでフィールドレベルのキャッシュ無効化を実行できます。

結論

Railsキャッシングは、比較的簡単にアプリケーションのパフォーマンスを向上させることを約束します。ただし、実際のアプリケーションは複雑になる可能性があり、多くの場合、固有の課題が発生します。デフォルトのRailsキャッシュの動作はほとんどのシナリオでうまく機能しますが、キャッシュの無効化をもう少し最適化することが大いに役立つ特定のシナリオがあります。

Railsでフィールドレベルのキャッシュ無効化を実装する方法がわかったので、アプリケーションのキャッシュの不要な無効化を防ぐことができます。

基本を理解する

DSLは何の略ですか?

DSLは「ドメイン固有言語」の略です。

ActiveRecordタッチメソッドは何をしますか?

touchメソッドは、updated_at / onフィールドを現在の時刻に設定し、レコードを保存します。

デザイナーのためのコーディング–どれだけ知っておくべきか?

Uxデザイン

デザイナーのためのコーディング–どれだけ知っておくべきか?
Google Cloud Natural LanguageAPIを使用したNLP

Google Cloud Natural LanguageAPIを使用したNLP

技術

人気の投稿
Sass Mixins:スタイルシートを乾いた状態に保つ
Sass Mixins:スタイルシートを乾いた状態に保つ
Kubernetesとは何ですか?コンテナ化と展開のガイド
Kubernetesとは何ですか?コンテナ化と展開のガイド
説得力と動き–モーションデザインの原則へのガイド
説得力と動き–モーションデザインの原則へのガイド
最高のデータ視覚化ツールの完全な概要
最高のデータ視覚化ツールの完全な概要
BlackBerryに何が起こったのか:ゾンビストックまたはカムバックキング?
BlackBerryに何が起こったのか:ゾンビストックまたはカムバックキング?
 
ウェブサイトの再設計の基礎–ケーススタディ
ウェブサイトの再設計の基礎–ケーススタディ
バイオテクノロジー評価の特異性とベストプラクティス
バイオテクノロジー評価の特異性とベストプラクティス
WebRTCアプリケーションを構築する1年:スタートアップエンジニアリングの教訓
WebRTCアプリケーションを構築する1年:スタートアップエンジニアリングの教訓
ゲシュタルトの設計原則を探る
ゲシュタルトの設計原則を探る
国際送金市場はどのように進化していますか?
国際送金市場はどのように進化していますか?
人気の投稿
  • ゲシュタルト心理学の基本原則
  • 設計の原則である_____には、要素の分散が含まれます。
  • 従業員計算機を雇うのにどれくらいの費用がかかりますか
  • 最初にcまたはc ++を学ぶ必要があります
  • ビッグデータの視覚化ツール
  • C言語が発明されたのはいつですか
カテゴリー
プロジェクト管理 製品ライフサイクル 収益と成長 その他 アジャイル バックエンド デザイナーライフ Uxデザイン 収益性と効率性 エンジニアリング管理

© 2021 | 全著作権所有

apeescape2.com