2R2Lキャッシング

キャッシングは、広く知られ、よく知られているトピックです。しかし、新しい解決策もそこに現れるかもしれません。特に-高レベルの製品の分野(たとえば、Web開発)。従来のアプローチの欠点に直面して、データの関連性が重要ではない場合の理想的なキャッシングスキームを推測しようとしました。それから私は同様のスキーム、またはより良い-既製のソリューションの説明を見つけようとしました。見つかりませんでした。したがって、私はそれを自分で名付けました-2R2L(2 Range 2 Location)-2レンジ2-「空間」キャッシング。おそらくすでにどこかで使用されていますが。



それはすべて、ユーザーの個人的な好みを考慮して、ユーザーに新製品を表示するという単純なタスクから始まりました。また、新製品の入手に問題がなかった場合は、新製品を好みと関連付ける(統計を分析する)ことで、すでに具体的な負荷が発生しています(たとえば、4秒で定義しましょう)。このタスクの特徴は、組織全体がユーザーとして機能できることでした。また、1人のユーザーに関連する200〜300のリクエストが、一度に(2〜3秒以内に)サーバーに到着することも珍しくありません。それら。同じブロックが一度に多くのユーザーに対して生成されます。



明らかな解決策は、RAMにキャッシュすることです(DBMSを暴力にさらすことはなく、大量の呼び出しを処理するように強制します)。古典的なスキーム:



  1. リクエストが来ました
  2. キャッシュをチェックしています。その中にデータがあり、それらが古くない場合、私たちはそれを返すだけです。
  3. データなし=>問題の発生
  4. ユーザーに送信します
  5. さらに、それをキャッシュに追加して、TTLを示します


このソリューションの欠点:キャッシュにデータがない場合、第1世代中に送信されたすべての要求がそれらを生成し、サーバーリソースをこれに費やします(負荷のピーク)。そしてもちろん、すべてのユーザーは「最初の呼び出し」で待機します。



また、個々のキャッシュ値を使用すると、レコードの数が非常に多くなり、使用可能なサーバーRAMが単に十分でないことに注意してください。次に、ローカルHDDサーバーをキャッシュストレージとして使用するのが理にかなっているようです。しかし、私たちはすぐにスピードを失います。



どうなる?



最初に頭に浮かぶのは、レコードを2つの場所(RAM(頻繁に要求される)とHDD(すべてまたはほとんど要求されない))に保存することです。最も純粋な形式の「ホットおよびコールドデータ」の概念。このアプローチには多くの実装があるため、これについては詳しく説明しません。このコンポーネントを2Lと指定しましょう。私の場合、ScyllaDBMSに基づいて正常に実装されています。



しかし、キャッシュが古くなったときにドローダウンを取り除く方法は?ここに2Rの概念を含めます。その意味は単純です。キャッシュレコードの場合、1つのTTL値ではなく、2を指定する必要があります。TTL1はタイムスタンプです。つまり、「データは古くなっています。再生成する必要がありますが、引き続き使用できます」。TTL2-「すべてが古すぎて使用できなくなっています。」



したがって、キャッシュのスキームが少し異なります。



  1. リクエストが来ました
  2. キャッシュ内のデータを探しています。データが存在し、古くなっていない場合(t <TTL1)-通常どおりユーザーにデータを返し、他には何もしません。
  3. データはそこにあり、古くなっていますが、(TTL1 <t <TTL2)を使用できます-ユーザーにデータを渡し、キャッシュレコードを更新する手順を初期化します
  4. データはまったくありません(TTL2の有効期限が切れると強制終了されます)。「通常どおり」データを生成し、キャッシュに書き込みます。
  5. コンテンツをユーザーに提供した後、または並列ストリームで提供した後、キャッシュレコードを更新する手順を実行します。


その結果、次のようになります。



  • キャッシュレコードが十分な頻度で使用されている場合、ユーザーは「キャッシュが更新されるのを待っている」状況に陥ることはありません。常に既成の結果を受け取ります。
  • 「更新」のキューが適切に編成されている場合、TTL1 <t <TTL2のレコードへの複数の同時アクセスの場合、キューには1つの更新タスクのみがあり、複数の同一のタスクはないという事実を実現できます。


例として、新製品フィードの場合、TTL1 = 1時間(ただし、新しいコンテンツはそれほど集中的に表示されません)、およびTTL2-1週間を指定できます。



最も単純なケースでは、2Rを実装するためのPHPコードは次のようになります。



$tmp = cache_get($key);
If (!$tmp){
	$items = generate_items();
	cache_set($items, 60*60, 60*60*24*7);
}else{
	$items = $tmp[‘items’];
	If (time()-$tmp[‘tm’] > 60*60){
		$need_rebuild[] = [‘to’=>$key, ‘method’=>’generate_items’];
}
}
//   
echo json_encode($items);
//     ,   
If (isset($need_rebuild) && count($need_rebuild)>0){
	foreach($need_rebuild as $k=>$v){
		$tmp = ['tm'=>time(), 'items'=>$$v[‘method’]];
		cache_set($tmp, 60*60, 60*60*24*7);
}
}


もちろん、実際には、実装はより困難になる可能性があります。たとえば、キャッシュレコードジェネレータは、サービスとして起動される別個のスクリプトです。キュー-Rabbit経由、「そのようなキーはすでに再生のためにキューにあります」という記号-RedisまたはScylla経由。



したがって、「2バンド」アプローチと「ホット/コールド」データの概念を組み合わせると、2R2Lが得られます。



ありがとう!



All Articles