Yii2を例として使用して、バックエンドにアクセスせずにキャッシュを操作するバリアント

私はWeb開発者であり、それほど前ではありません(メイン作業の側面で作業しています)。書くには:ASPだけですか、それともVBScriptですか?)。



現時点で顧客のプロジェクト全体が500 MBのスクリプトで構成されていることをすぐに予約します(97年以降、まだ書き続けています)。



もちろん、これらすべての機能とはほど遠い、前線が必要でした。 Oracleデータベース(それは別の話です)とキャッシュを無効にできないという2つのことは満足できませんでした。 そして、このコマンドはキャッシュをまったく使用せず、どのような状況でも使用しません:思考の不活発さ、またはVBScript + Memcacheの難しさのために、むしろ単に500MB(これは上に書きました)。



一般的に、このような面白いパイは判明しているはずです:ASPのバックエンド、Yii2のフロントエンド。



入場の代わりでした。



すぐに発生した問題: キャッシュを使用する必要があります-データベース内でいつどのようなデータが変更されたかをどのように知るのですか? バックエンドからの無効化はなく、キーの削除もありません。 これのどれも見えませんでした。 プロジェクトの負荷はそれほど高くありませんが、なんとか柔軟かつ最適にしたかったのです。



私はサンドボックスコートに、おそらく最もエレガントではなく、解決策を提案します。 このサイトの多くの優れたソリューションが私を助けてくれたので、誰かがこれに遭遇し、この投稿が彼を助けるかもしれません。



それで、主なアイデアは何ですか:データベースで何が変更されたかに関する情報がないので、それを自分で収集します。



まず、インターフェースを作成します。



<?php /** *         . *       ,   ,    *      ..      . */ interface InvalidateModels { public function getInvalidateTime(); public function getInvalidateField(); }
      
      





私は通常phpDocに熱心に記入します-だからそれが多かれ少なかれ満杯の場合-私は特にコメントしません。



このインターフェイスを実装する各モデルは、キャッシュを無効にする準備ができていることを将来の無効化手順に伝えます。



 class Airport extends ActiveRecord implements InvalidateModels { /** *     * @return int */ public function getInvalidateTime() { return 60 * 60 * 24; } /** *        * @return string */ public function getInvalidateField() { return 'update_stamp'; }
      
      





(データベースアーキテクトが本当に悪い人ではない場合)そのようなテーブルのデータは決して変更されず、追加されるだけなので、テーブルにキャッチできるフィールドがない場合、たとえばOracleの場合は通常のROWNUMを使用できることに注意してください



それから小さいです 標準のコンソールコマンドYii2を作成していますが、これは、まともな時間に一度クラウンを呼び出します(5分ありました)。 そして、その中で次のようなことを行います。



 /** *        */ class InvalidateCacheController extends \yii\console\Controller { /** * ,      *       \common\interfaces\InvalidateModels * ,    * * @return array */ private function _getInvalidateModels() { return [ Airport::class, ]; } /** * Action    * 1.           * 2.              *        .       , *       . */ public function actionInvalidateCache() { $models = $this->_getInvalidateModels(); $reflectionObjects = []; foreach ($models as $modelName) { $reflectionObjects[] = new \ReflectionClass($modelName); } /** @var \ReflectionClass $refObject */ foreach ($reflectionObjects as $refObject) { //      InvalidateModels if (!$refObject->implementsInterface('\common\interfaces\InvalidateModels')) { continue; } $modelName = $refObject->getName(); /** @var \common\interfaces\InvalidateModels $model */ $model = new $modelName; $invalidateTime = $model->getInvalidateTime(); $cacheKey = 'LastInvalidateTime-' . $refObject->getName(); $lastInvalidateTime = \Yii::$app->memcache->get($cacheKey); if (false === $lastInvalidateTime) { $this->_invalidateCache($refObject); \Yii::$app->memcache->set($cacheKey, 1, $invalidateTime); } } } /** *    * * @param \ReflectionClass $refObject */ private function _invalidateCache(\ReflectionClass $refObject) { $modelName = $refObject->getName(); /** @var \common\interfaces\InvalidateModels $model */ $model = new $modelName; $invalidateField = $model->getInvalidateField(); /** @var \yii\db\ActiveRecord $model */ $lastChangedTime = $model::find()->max($invalidateField); $lastDataInCache = \Yii::$app->memcache->get('last-set-time.' . $model::tableName()); //                    if ($lastDataInCache < strtotime($lastChangedTime)) { \Yii::$app->memcache->invalidateTags([$model::tableName()]); } } }
      
      





残念ながら、特定のフォルダーのリフレクションを通過してファイルからクラスを抽出することが可能かどうかはよくわかりませんでした。そのため、おそらく、無効なモデルを繰り返す必要がある追加メソッド_getInvalidateModels()を作成しました。 もしそうなら、私は助けに非常に感謝します。



おわりに



もちろん、この方法を使用すると、タイムラグが発生し、キャッシュとデータベースのデータが100%一致することは保証されません。 しかし、このアプローチは(おそらくこれに重要ではないプロジェクトで)生命に対する権利を持っています。



ご清聴ありがとうございました!



私は批判について非常に前向きです。



All Articles