ワン:概要
- 管理のためのLRUキャッシュポリシー自体は中のLinux / Redisの/ MySQLで実施しています、。ただ、異なる実装。
- LRUアルゴリズム[ 最小最近使用(最低使用) ]
-過去のデータレコードに基づいてデータアクセスを排除するために、その核となるアイデアは、「データが最近訪問された場合には、将来のアクセスの確率も高くなっています。」されます
2:LRUアルゴリズム実装単独リンクリスト
- アイデア
- 単独リンクリスト達成するために
- プロセス
- 1. 新しいデータがリンクリストの先頭に挿入されています。
- 2 たびにキャッシュヒット(すなわち、キャッシュデータをアクセスする)、次いで、データがリンクされたリストの先頭に移動されます。
- 3. リストがいっぱいになると、データは破棄され、リンクされたリストの末尾。
- 利点
- シンプル。
- ホットデータ、LRU良い効率がある場合もございます。
- 欠点
- 散発的、定期的なバッチ操作は、LRUの急激な減少につながるヒット率、キャッシュ汚染は非常に深刻です。
- ヒットリストトラバースする必要がある、データ・ブロック・インデックス・ヒットを見つけ、その後、頭部にデータを移動する必要があります。
- フローチャート
-
- コードの実装(PHP)
-
-
/ * * *アイデア *単鎖を達成 *原理は *単鎖 *プロセス * 1.新しいデータがリンクリストの先頭に挿入される。 * 2キャッシュヒット(すなわち、キャッシュデータをアクセスする)、データはリストの先頭に移動されるたびに; * 3.リストがいっぱいになると、データは破棄され、リンクされたリストの末尾。 *メリット *シンプル。 *現在ホットスポットデータ、LRU効率よく。 *短所が 散発*、定期的なバッチ操作はLRUヒット率の急激な減少につながる、キャッシュ汚染は非常に深刻です。 ヒットリストは、データ・ブロック・インデックス・ヒットを見つけたとき*あなたは頭にデータを移動する必要があり、トラバースする必要があります。 * / クラスLRU { 公共 静的 $ lruList = []; // 順次記憶単鎖構造 パブリック 静的 $ = MAXLEN 5。 ; // 許可リストの最大長 パブリック 静的 $ nowLen = 0; // 現在の長さをリストする * / * 。* LRU_1コンストラクタ * PHP常駐プログラム処理ではないので、リストが初期化のMysql / Redisのことによって達成することができるように、 * / パブリック関数__construct() { 自己:: $ lruList = []; 自己: :$ nowLen = COUNT(自己:: $ lruList); } / * * * =キー>の値を取得します * @paramキーの$ *の@returnヌル * / パブリック関数GET (キー$) { $値は = ヌル; // LRUキューが空である、ダイレクトリターン IF(!:: $ lruListセルフ){ 自己lruList :: $ [] = [キー$ => $ この - >のgetData(キー$)]; //は、実際の状況のデータ項目を取得 自己:: $ nowLenを++ ; 戻り$値; } // LRUバッファを探す ために($ I = 0 ; $ Iは自己:: $ nowLen <; $ Iは++ ){ // キャッシュが存在する場合、プロセスは直接戻り、リスト・ヘッダ・データを再挿入 IF (ISSET(自己:: lruList $ [$ I] [キー$])){ $値 = 自己:: $ lruList [$ I] [キー$]; 解除($ lruList自己:: [$ I]); するarray_unshift(自己:: $ lruList 、[キー$ => $値]); BREAK; } } // もしノーキャッシュLRU IF(!{ISSET($値)) // 挿入ヘッドの するarray_unshift(自己:: $ lruList、[キー$ => $ この - >のgetData(キー$)]); // 実際の状況に応じてデータ項目を取得 自己:: $ nowLen ++ ; IF(自己:: $ nowLen> セルフMAXLEN :: $を){ 自己nowLen :: $ - ; array_pop(自己:: $ lruList); } } 戻り$値; } / * * *のLRU出力キュー * / パブリック関数echoLruList() { のvar_dump(自己:: $ lruList); } / * * *取得し、実際の環境データに基づいて * @paramキーの$ * @returnの文字列 * / パブリック関数のgetData(キー$) { リターン ' データ' ; } }
-
3:LruをKアルゴリズム
- アイデア
-するためにLRU「キャッシュ汚染」を回避し、問題
- キューに追加キャッシュが生じるの数を維持するために。核となるアイデアは、のために「最近使用した1時間」の基準を拡張することで、「最近使用したK回。」
- 原理
- LRUに比べ、LRU-Kは、アクセスされている歴史のキューを維持するために、より多くを必要とするすべてのキャッシュされたデータを記録しました。
-のみアクセスデータの数は、キャッシュにデータの前にK回に到達したとき。
- あなたはデータを排除する必要がある場合には、LRU-Kは、現在の時刻から最大のデータをK番目のアクセス時間を排除するであろう。
- プロセス
- 1.データが最初にアクセスされ、アクセス履歴リストに追加。
- 2履歴リスト内のデータ・アクセスは、場合K回数に達していない特定の規則に従って、アクセスをLRUを排除。
- 3の数は、データ・アクセス履歴キューがアクセスするとK倍に達し、データは、インデックス履歴キューから削除されますバッファキューにデータが、バッファおよびデータバッファキュー時間で再注文しました。
- 4.キャッシュ・データ・キューは、並べ替え、再度アクセスされます。
- データ・バッファ・キュー行を排除する5.必要性、すなわち、データの最後に、段階的に廃止:データ消去「今、最も古いから最後から二番目のK訪問を」。
- 利点
- LRU-Kが発生し、「キャッシュ汚染」の問題を低減し、ヒット率はLRUよりも高くなっています。
- 欠点
- LRU-K・キューは、優先キュー、アルゴリズムの複雑さとコストが比較的高いです。
- LRU-Kのでも歴史的コホートを維持する必要があるので、メモリ消費量がよりあろう。
- フローチャート
-
- コードの実装
-
-
/** * 思路 * 为了避免 LRU 的 '缓存污染' 问题 * 增加一个队列来维护缓存出现的次数。其核心思想是将“最近使用过1次”的判断标准扩展为“最近使用过K次”。 * 原理 * 相比LRU,LRU-K需要多维护一个队列,用于记录所有缓存数据被访问的历史。 * 只有当数据的访问次数达到K次的时候,才将数据放入缓存。 * 当需要淘汰数据时,LRU-K会淘汰第K次访问时间距当前时间最大的数据 * 流程 * 1.数据第一次被访问,加入到访问历史列表; * 2.如果数据在访问历史列表里后没有达到K次访问,则按照一定规则 LRU淘汰; * 3.当访问历史队列中的数据访问次数达到K次后,将数据索引从历史队列删除,将数据移到缓存队列中,并缓存此数据,缓存队列重新按照时间排序; * 4.缓存数据队列中被再次访问后,重新排序; * 5.需要淘汰数据时,淘汰缓存队列中排在末尾的数据,即:淘汰“倒数第K次访问离现在最久”的数据。 * 优点 * LRU-K降低了“缓存污染”带来的问题,命中率比LRU要高。 * 缺点 * LRU-K队列是一个优先级队列,算法复杂度和代价比较高。 * 由于LRU-K还需要维护历史队列,所以消耗的内存会更多。 */ class Lru_K { public static $historyList = []; // 访问历史队列 public static $lruList = []; // 顺序存储单链表结构 public static $maxLen = 5; // 链表允许最大长度 public static $nowLen = 0; // 链表当前长度 /** * LRU_K constructor. * 由于 PHP 不是常驻进程程序,所以链表初始化可以通过 Mysql/Redis 实现 */ public function __construct() { self::$lruList = []; self::$historyList = []; self::$nowLen = count(self::$lruList); } /** * 获取 key => value * @param $key * @return null */ public function get($key) { $value = null; // 查找 lru 缓存 for ($i = 0; $i < self::$nowLen; $i++) { // 如果存在缓存,则直接返回,并将数据重新插入链表头部 if (isset(self::$lruList[$i][$key])) { $value = self::$lruList[$i][$key]; unset(self::$lruList[$i]); array_unshift(self::$lruList, [$key => $value]); break; } } // 如果没有找到 lru 缓存, 则进入历史队列进行计数,当次数大于等于5时候,进入缓存队列 if (!isset($value)) { self::$historyList[$key]++; $value = $this->getData($key); // 进入缓存队列 if (self::$historyList[$key] >= 5) { array_unshift(self::$lruList, [$key => $value]); // 根据实际项目情况获取数据 self::$nowLen++; if (self::$nowLen > self::$maxLen) { self::$nowLen--; array_pop(self::$lruList); } unset(self::$historyList[$key]); // 历史队列推出 } } return $value; } /** * 输出 Lru 队列 */ public function echoLruList() { var_dump(self::$lruList); var_dump(self::$historyList); } /** * 根据真实环境获取数据 * @param $key * @return string */ public function getData($key) { return 'data'; } }
-