Redis-内存淘汰策略

1. 过期删除策略

  1. 定期删除:在redis当中,默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。
  2. 惰性删除:redis在获取某个key的时候就会其进行检查,若这个key设置了过期时间,它就会进行判断是否过期,如果过期了此时就会删除,不会给你返回任何东西。

总结:定期删除是集中处理,惰性删除是零散处理。

2. 几种淘汰机制

  • volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
  • volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
  • allkeys-lru:从数据集中挑选最近最少使用的数据淘汰。
  • volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
  • no-enviction(驱逐):禁止驱逐数据,这也是默认策略。

3. PHP实现lru算法(lru淘汰策略实现)

  • ru算法是什么? 下图很好的解释了这一算法。
    在这里插入图片描述
  • 使用php实现lru策略
class LruNodeService
{
	private $key;
	//key对应的内容
	private $data;
	//结点右指针
	private $next;
	//结点左指针
	private $previous;
	
	/**
	* Node constructor.
	* @param $key
	* @param $data
	*/
	public function __construct($key, $data)
	{
		$this->key = $key;
		$this->data = $data;
	}
	
	/**
	* Sets a new value for the node data
	* @param string the new content of the node
	*/
	public function setData($data)
	{
		$this->data = $data;
	}
	
	/**
	* Sets a node as the next node
	* @param Node $next the next node
	*/
	public function setNext($next)
	{
		$this->next = $next;
	}
	
	/**
	* Sets a node as the previous node
	* @param Node $previous the previous node
	*/
	public function setPrevious($previous)
	{
		$this->previous = $previous;
	}
	
	/**
	* Returns the node key
	* @return string the key of the node
	*/
	public function getKey()
	{
		return $this->key;
	}
	
	/**
	* Returns the node data
	* @return mixed the content of the node
	*/
	public function getData()
	{
		return $this->data;
	}
	
	/**
	* Returns the next node
	* @return Node the next node of the node
	*/
	public function getNext()
	{
		return $this->next;
	}
	
	/**
	* Returns the previous node
	* @return Node the previous node of the node
	*/
	public function getPrevious()
	{
		return $this->previous;
	}
}
class LruService
{
	/*
	* 头部节点
	*/
	private $head;
	/*
	* 尾部节点
	*/
	private $tail;
	/*
	* 最大容量,大于淘汰部位节点指向上一个元素
	*/
	private $capacity;
	/*
	* 存储key对应的节点
	*/
	private $hashmap;
	
	public function __construct($capacity)
	{
		$this->capacity = $capacity;
		$this->hashmap = array();
		$this->head = new LruNodeService(null,null);
		$this->tail = new LruNodeService(null,null);
		$this->head->setNext($this->tail);
		$this->tail->setPrevious($this->head);
	}
	
	/**
	* 获取元素
	* @param $key
	* @return null
	*/
	public function get($key)
	{
		if (!isset($this->hashmap[$key])) {
			return null;
		}
		$node = $this->hashmap[$key];
		if (count($this->hashmap) == 1) {
			return $node->getData();
		}
		//先删除已经存在的结点
		$this->detach($node);
		//重新将新结点插入到头结点之后
		$this->attach($this->head, $node);
		return $node->getData();
	}
	
	/**
	* 设置key value
	* @param $key
	* @param $data
	* @return bool
	*/
	public function put($key, $data)
	{
		if ($this->capacity <= 0) {
			return false;
		}
		if (isset($this->hashmap[$key]) && !empty($this->hashmap[$key])) {
			$node = $this->hashmap[$key];
			//重置结点到头结点之后
			$this->detach($node);
			$this->attach($this->head, $node);
			$node->setData($data);
		} else {
			$node = new LruNodeService($key, $data);
			$this->hashmap[$key] = $node;
			//添加节点到头部节点之后
			$this->attach($this->head, $node);
			//检测容量是否达到最大值
			if (count($this->hashmap) > $this->capacity) {
				//如果达到最大值 删除尾节点左指针指向的元素
				$nodeToRemove = $this->tail->getPrevious();
				$this->detach($nodeToRemove);
				unset($this->hashmap[$nodeToRemove->getKey()]);
			}
		}
		return true;
	}
	
	/**
	* 删除key
	* @param $key
	* @return bool
	*/
	public function remove($key)
	{
		if (!isset($this->hashmap[$key])) {
			return false;
		}
		$nodeToRemove = $this->hashmap[$key];
		$this->detach($nodeToRemove);
		unset($this->hashmap[$nodeToRemove->getKey()]);
		return true;
	}
	
	/**
	* 添加新结点到头结点之后
	* @param $head
	* @param $node
	*/
	private function attach($head, $node)
	{
		//双向链表插入一个元素到头结点之后
		$node->setPrevious($head);
		$node->setNext($head->getNext());
		$node->getNext()->setPrevious($node);
		$node->getPrevious()->setNext($node);
	}
	
	/**
	* 删除结点
	* @param $node
	*/
	private function detach($node)
	{
		$node->getPrevious()->setNext($node->getNext());
		$node->getNext()->setPrevious($node->getPrevious());
	}
}

4. 多级缓存

4.1 Openresty安装

yum install readline-devel pcre-devel openssl-devel
wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz # 下载
tar xzvf ngx_openresty-1.9.7.1.tar.gz # 解压
cd ngx_openresty-1.9.7.1/
./configure
make
make install

4.2 使用Openresty创建lua脚本

ngx.header.content_type="application/json;charset=utf8"
local cjson = require("cjson") --引入模块
local mysql = require("resty.mysql") --引入mysql模块
local uri_args = ngx.req.get_uri_args()
local product_id = uri_args['product_id']
local db = mysql:new() --初始化数据库
db:set_timeout(1000) --设置超时时间
local props = {
	host = "192.168.59.100", --mysql ip地址
	port = 3306, --mysql 端口
	database = "shop", --mysql 数据库
	user = "root", password = "root" --用户名密码
}
local res = db:connect(props) --获得mysql连接
local select_sql = "select id,store from fm_products where id ='"..product_id.."'"--一条查询语句
res = db:query(select_sql) db:close() --执行
local redis = require("resty.redis") --引入redis
local red = redis:new() red:set_timeout(2000) --初始化 设置超时时间
local ip ="192.168.59.108"
local port = 6379
red:connect(ip,port)
red:auth("root")
red:set("product_"..product_id,cjson.encode(res)) --存储到redis
red:close()
ngx.say("{flag:true}")
ngx.header.content_type="application/json;charset=utf8"
local uri_args = ngx.req.get_uri_args()
local product_id = uri_args['product_id']
local cache_ngx = ngx.shared.dis_cache;
local adCache = cache_ngx:get('productcache'..product_id);
if adCache == "" or adCache == nil then
	local redis = require("resty.redis") --引入redis
	local red = redis:new() red:set_timeout(2000) --初始化 设置超时时间
	local ip ="192.168.59.108"
	local port = 6379
	red:connect(ip,port)
	red:auth("root")
	local rescontent=red:get("product_"..product_id)
	ngx.say(rescontent)
	red:close()
	cache_ngx:set('productcache'..product_id, rescontent, 10*60);
else
	ngx.say(adCache)
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值