golang实现简单的redis服务4(实现过期时间功能)

仓库地址: https://github.com/dengjiayue/my-redis-v2.0-RESP-.git

为什么要做过期时间?

: 因为redis是内存数据库,空间是有限并且昂贵的,如果我们只存数据很快就会资源耗尽.
所以我们需要清理数据腾出空间储存其他的数据

redis失效时间是如何做的

redis是使用失效时间字典去存放失效时间的
key为对应数据的指针,val为失效时间戳(毫秒级)
在这里插入图片描述

redis有那些过期策略,优缺点,实现原理?
  1. 立即清除,key到过期时间立即清除
    优点:内存友好,能够快速释放出空间
    缺点: cpu消耗大,不停执行清除,如果遇到请求压力大的时候会额外增加cpu的负担
    实现方案: 使用时间轮调度器,每设置一个失效时间就加一个延时调度删除方法,到过期时间会调度删除方法删除该数据

  2. 惰性清除: 当使用key的时候检查是否过期,如果过期就清除该数据
    优点: cpu友好,不需要时刻执行清除
    缺点: 内存不友好,有一些不使用的过期数据会无法清除,浪费空间资源(redis空间很宝贵)
    实现方案: 当调用查询的时候先检查是否过期,如果过期清除数据并返回空

  3. 定时清除: 定时扫描过期字典,将过期的数据清除
    这是一个折中的方案,既不会向立即清除那样消耗太多的cpu,又不会让不使用的数据长期停留在数据库中
    实现方案: 做一个定时任务,定时扫描过期字典并清除过期数据

redis使用的什么方案

redis使用的是定时以惰性删除结合的方案

package src

import (
	"my_redis/src/timewheel"
	"strconv"
	"time"
)

//过期时间实现
//

// 扫描部分key并检查是否过期
func (s *Server) CheckExpire(num int) {
	// 遍历所有key
	for k, v := range s.Ex {
		if v < time.Now().Unix() {
			// 过期了
			delete(s.Ex, k)
			// 删除key
			delete(s.M, k)
		}
		num--
		if num == 0 {
			break
		}
	}
}

// 定时过期
func (s *Server) TimingExpire() {
	// 定时执行
	ticker := time.NewTicker(time.Second)
	for {
		<-ticker.C
		// 定时执行
		s.CheckExpire(100)
	}
}

// 惰性过期(输出是否过期 )
func (s *Server) LazyExpire(key string) bool {
	// 检查key是否过期
	if s.Ex[key] < time.Now().Unix() {
		// 过期了
		delete(s.Ex, key)
		// 删除key
		delete(s.M, key)
		return true
	}
	return false
}

// 立即过期
// 使用时间轮实现立即过期
// exTime为毫秒过期时间
func (s *Server) ImmediatelyExpire(key string, exTime int64) {
	late := time.Millisecond * time.Duration(exTime)
	timewheel.Delay(late, key, func() {
		// 删除数据
		delete(s.Ex, key)
		// 过期时间记录
		delete(s.M, key)
	})
}

// 设置过期时间: 向Ex写数据
// exTime为过期时间(毫秒)
func (s *Server) SetExTime(key string, exTime string) error {
	//将exTime转换为数字
	exTimeNum, err := strconv.Atoi(exTime)
	if err != nil {
		return err
	}
	// 将exTime转换为过期时间戳(毫秒级)
	ex := time.Now().UnixMilli() + int64(exTimeNum)
	s.Ex[key] = ex
	return nil
}

参考:https://github.com/dawnzzz/simple-redis

redis 有那些内存淘汰策略?常用的是什么,为什么?

noeviction: 不处理

这种在内存资源耗尽的时候写会报错!

lru: 未使用时间最久的key

原理: 使用一个队列进行维护,如果一个key被使用那么就将这个key放在对头,如果队列满了(空间满了)再加入数据就会从队尾淘汰一个数据,再将新数据加到对头

这种是最常用的,因为一个key在一段时间内没有被使用那么它在后面被使用的概率就会比较低.

lfu: 使用次数最少的key

原理: 统计每一个key的使用次数,需要淘汰的时候,淘汰使用次数最少的key.
这个有一个问题就是新key加进来使用次数比较低,在内存淘汰的时候新可以容易被淘汰掉

random: 随机key

就是随机挑选一个key进行淘汰.
这个基本很少用

volatile与allkeys的区别

volatile就是淘汰设置了过期时间的key
allkeys就是淘汰所有的key

根据实际需求选择合适的内存淘汰机制,一般会使用volatile进行淘汰,因为没设置过期时间一般默认为需要长期缓存的数据.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值