1. 恒定缓存性能有哪些因素?
命中率、缓存更新策略、缓存最大数据量。
  • 命中率:指请求缓存次数和缓存返回正确结果次数的比例。比例越高,缓存的使用率越高,用来衡量缓存机智的好坏和效率。如果数据频繁更新,命中率就会降低,这个时候需要考虑缓存的合理性。命中率=命中次数/请求次数。
  • 缓存更新策略主要有三个:
    FIFO先进先出,如果一个数据最先进入缓存中,当缓存满了以后,就应该最早淘汰掉。
    LFU最近最少使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。即:当缓存满了以后,应当把最少被访问的数据淘汰。(LFU是淘汰一段时间内使用次数最少的数据。)
    LRU最近最久未使用,如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。即:当缓存满了以后,应当把最久没有被访问到的数据淘汰。(LRU是淘汰最长时间没有被使用的数据。)
  • 缓存最大数据量是在缓存中能处理元素的最大个数或所能使用的最大存储空间。
2. 如何根据这三者,去设计一个缓存?
问题补充:有时候,如果我们不想用Redis,就会自己设计一个缓存。比如首先是规定缓存的最大数据量,当缓存的最大容量定下来后我们就考虑更新策略,是用LRU还是LFU?如果用LFU,又该怎么实现这个LFU的功能?
设计LFU的思路:
LFU是最近最少使用,也就是一段时间内使用次数最少的数据最先淘汰。可以把这个数据当成key,value代表这个数据被访问的次数,初始可以设为0,每访问这个数据一次,value就+1,一段时间后,哪个value小,就淘汰掉哪个数据。
如何设计LFU的数据结构:
实现LFU在PHP里面可以通过数组实现,从以下几方面考虑:
首先,怎么取值?
其次,怎么清除老旧的数据,也就是怎么设计LFU?
最后,怎么存储?
LFU的实现过程:
  • 定义两个关联数组,key都一样,一个数组叫kv数组,存值,形如key=>value,一个数组叫kc数组,存值被访问的次数,形如key=>count。
  • 定义请求数requestNum和命中数hitNum,来获得命中率。
  • 定义缓存当前数据个数size和缓存总大小totalSize。
  • 定义方法包括:get、add、getHitRate、cleanup等。
    get:通过传入key,从kv数组中返回其值,同时,kc数组中该key对应的count值+1。
    add:通过传入key和value,将数据添加到存值的关联数组中。这时候要考虑LFU,如果缓存没满,直接加进去就行,但如果缓存已经满了,添加新的数据时,最近最少未被使用的数据就要踢掉(cleanup)。
    cleanup:当有数据需要更新的时候,先在kv数组中插入一个key=>value,在kc数组中根据value的访问次数count值,找出最少被访问的几个数据,通过它们的key,把kv数组中的值删掉。
    getHitRate:计算命中率。每当用户请求(get)数据一次,请求数requestNum就+1,如果请求的值在缓存里面找到了,命中数hitNum就+1,则命中率hitRate=hitNum/totalRequestNum。
设计LFU的总结
1)定义两个数组,一个数组存值,一个数组存该值的访问次数;
2)定义三个方法,get取值,add添加,cleanup清除缓存;
3)当用户访问某个数据时,如果查到,就返回;
4)当用户添加数据时,先判断缓存的容量,如果缓存没满,直接添加数据到缓存,如果缓存的容量满了,先将存访问次数的数组从大到小(或从小到大)进行排序,最小的那个即访问最少的数,将该数据删除后,再添加新数据;
5)清除缓存时,是将存访问次数那个数组排序,访问次数最小的就是要删除的数据;
6)缓存用来存储经常查询、更新的数据,其中取值和添加的方法没有先后之分,互不相关。
 
简单代码:
<?php
// 设计一个简单的缓存
class strCache {
// 缓存总大小
var $totalSize = 5;
// 访问数
var $requestNum = 0;
// 命中数
var $hitNum = 0; // 存值key=>value
var $arr1 = array();
// 存访问次数key=>count
var $arr2 = array(); public function get($key) {
$result = "";
$this->requestNum += 1;
if ($this->arr1[$key]) {
$this->hitNum += 1;
$count = 1;
if ($this->arr2[$key]) {
$count += $this->arr2[$key];
}
$arr2[$key] = $count;
$result = $this->arr1[$key];
}
return $result;
} public function add($key, $value) {
$this->cleanup();
$this->arr1[$key] = $value;
$this->arr2[$key] += 1;
return true;
} public function cleanup() {
if (count($this->arr1) == $this->totalSize) {
asort($this->arr2);
$keys = array_keys($this->arr2);
$k = $keys[0];
unset($this->arr1[$k]);
unset($this->arr2[$k]);
}
return true;
} public function getHitRate() {
$hitRate = 0;
if ($this->requestNum != 0) {
$hitRate = $this->hitNum / $this->requestNum;
}
return $hitRate;
}
} // 测试
$strObj = new strCache();
$strObj->add('a', 'wuhan');
$strObj->add('b', 'heilongjiang');
$strObj->add('c', 'shanghai');
$strObj->add('d', 'beijing'); print_r($strObj->arr1);
echo "<pre>";
echo $strObj->get('a');
echo "<pre>";
echo $strObj->get('aa');
echo "<pre>";
echo $strObj->hitNum;
echo "<pre>";
echo $strObj->getHitRate();

缓存的设计及PHP实现LFU的更多相关文章

  1. Redis缓存策略设计及常见问题

    Redis缓存设计及常见问题 缓存能够有效地加速应用的读写速度,同时也可以降低后端负载,对日常应用的开发至关重要.下面会介绍缓存使用技巧和设计方案,包含如下内容:缓存的收益和成本分析.缓存更新策略的选 ...

  2. .NET 缓存模块设计

    上一篇谈了我对缓存的概念,框架上的理解和看法,这篇承接上篇讲讲我自己的缓存模块设计实践. 基本的缓存模块设计 最基础的缓存模块一定有一个统一的CacheHelper,如下: public interf ...

  3. IOS编程 图片缓存模块设计

    手机客户端为什么会留存下来?而不是被一味的Wap替代掉?因为手机客户端有Wap无可替代的优势,就是自身较强的计算能力. 手机中不可避免的一环:图片缓存,在软件的整个运行过程中显得尤为重要. 先简单说一 ...

  4. 利用Java的读写锁实现缓存的设计

    Java中的读写锁: 多个读锁不互斥, 读锁与写锁互斥, 写锁与写锁互斥, 这是由JVM自行控制的,我们只要上好相应的锁即可. 缓存的设计: package com.cn.gbx; import ja ...

  5. atitit。浏览器缓存机制 and 微信浏览器防止缓存的设计 attilax 总结

    atitit.浏览器缓存机制 and 微信浏览器防止缓存的设计 attilax 总结 1. 缓存的一些机制 1 1.1. http 304 1 1.2. 浏览器刷新的处理机制 1 1.3. Expir ...

  6. 《深入理解mybatis原理7》 MyBatis的二级缓存的设计原理

    <深入理解mybatis原理> MyBatis的二级缓存的设计原理 MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能.本文将全面分 ...

  7. Redis缓存的设计、性能、应用与数据集群同步

    Redis缓存的设计.性能.应用与数据集群同步 http://youzhixueyuan.com/design-performance-and-application-of-redis-cache.h ...

  8. 简单服务端缓存API设计

    Want 我们希望设计一套缓存API,适应不同的缓存产品,并且基于Spring框架完美集成应用开发. 本文旨在针对缓存产品定义一个轻量级的客户端访问框架,目标支持多种缓存产品,面向接口编程,目前支持简 ...

  9. 《深入理解mybatis原理》 MyBatis的二级缓存的设计原理

    MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能.本文将全面分析MyBatis的二级缓存的设计原理. 如上图所示,当开一个会话时,一个SqlS ...

随机推荐

  1. 文档流&浮动&定位

    文档流指元素在文档中的位置由元素在html里的位置决定,块级元素独占一行,自上而下排列:内联元素从左到右排列脱离文档流的方式: 浮动,通过设置float属性 绝对定位,通过设置position:abs ...

  2. 剑指offer:扑克牌顺子

    题目描述: LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他 ...

  3. EMQ 与 mqtt 与 IOT设备

    1.IOT设备的特性 IOT(物联网things of internet)设备和传统的智能设备有什么区别,笔者总结下的IOT设备有如下特点: 硬件能力差(存储能力基本只有几MB,CPU频率低连使用HT ...

  4. 搭建高可用rabbitmq集群及spring boot实现集群配置

    java spring boot配置: //具体参看了配置的源码 org.springframework.boot.autoconfigure.amqp.RabbitProperties //Rabb ...

  5. 接口测试中模拟post四种请求数据

    https://www.jianshu.com/p/3b6d7aa2043a 一.背景介绍 在日常的接口测试工作中,模拟接口请求通常有两种方法,fiddler模拟和HttpClient模拟. Fidd ...

  6. # 61条面向对象设计的经验原则-《OOD启思录》Arthur J.Riel

    61条面向对象设计的经验原则-<OOD启思录>Arthur J.Riel 原文 http://blog.csdn.net/cpluser/article/details/129291 61 ...

  7. Docker打包部署前端项目与负载均衡

    设置淘宝镜像 npm install -g cnpm --registry=https://registry.npm.taobao.org //在home/fn1 home/fn2放入项目和nginx ...

  8. http请求传参问题解决

    1.接口参数:使用form-data形式传参如果值太多就会报错误. 2.接口参数:使用form-data形式传参如果值太多就会报错误.这样前端可以传json就可以避免这样问题

  9. vue中使用极验验证码(附demo)

    前言: vue中使用极验验证码,最好是在页面渲染的时候(mounted)进行验证码的初始化,然后在初始化回调中绑定触发弹出验证码的事件.这样在点击按钮或者进行特定操作时能够快速的弹出验证码. 关键代码 ...

  10. Oracle系列八 高级子查询

    子查询 子查询 (内查询) 在主查询执行之前执行 主查询(外查询)使用子查询的结果 多列子查询 主查询与子查询返回的多个列进行比较 多列子查询中的比较分为两种: 成对比较 问题:查询与141号或174 ...