跳过正文
  1. 全部/
  2. 笔记/
  3. 面试/
  4. 数据库/
  5. Redis/

01 Redis

·
Redis
目录
typedef struct redisObject {
	unsigned type:4;
	unsigned encoding:4;
	unsigned lru:LRU_BITS;
	int refcount;
	void *ptr;
} robj;

Pasted image 20260517155042.png
Redis 单线程

1.多线程引入的复杂性是极大的​

  1. 首先,多线程引入之后,Redis原来的顺序执行特性就不复存在,为了支持事务的原子性、隔离性,Redis就不得不引入一些很复杂的实现;​
  2. 其次,Redis的数据结构,可以说是极其高效,在单线程模式下做了很多特性的优化,如果引入多线程,那么所有底层数据结构都要改造为线程安全,这会是极其复杂的工作;

2.多线程带来额外的成本​ 除了引入复杂度,多线程还会带来额外的成本。包括:​

  1. 上下文切换成本,多线程调度需要切换线程上下文,这个操作先存储当前线程的本地数据、程序指针等,然后载入另一个线程数据,这种内核操作的成本不可忽视。​
  2. 同步机制的开销,一些公共资源,在单线程模式下直接访问就行了,多线程需要通过加锁等方式去进行同步,这也是不可忽视的CPU开销;​
  3. 一个线程本身也占据内存大小,对Redis这种内存数据库而言,内存非常珍贵,多线程本身带来的内存使用的成本也需要谨慎决策。

性能 第一,Redis 的大部分操作在内存上完成,内存操作本身就特别快;​ 第二,Redis追求极致,选择了很多高效的数据结构,并做了非常多的优化,比如ziplist, hash,跳表,有时候一种对象底层有几种实现以应对不同场景。​ 第三,Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐量。

内存淘汰策略
#

Pasted image 20260517161005.png
LRU:采样

标准LRU需要维护双链表,内存成本巨大,所以Redis采用近似LRU采样来做淘汰,具体步骤是随机采样 n 个 key,这个采样个数默认为 5,然后根据时间戳淘汰掉最旧的那个 key,如果淘汰后内存还是不足,就继续随机采样来淘汰。​

在3.0之后,Redis还针对近似LRU算法做了淘汰池优化,也就是维护一个候选池,池中的数据根据访问时间进行排序。第一次随机选取的key都会放入池中,然后淘汰掉最久未访问的,比如第一次选了5个,淘汰了1个,剩下4个继续留在池子里。​

当池子装满了后,每次随机选取的key只有空闲时间大于 池子里当前空闲时间最小的key时,才会放入池中,并替换池子中空闲时间最小的 key , 然后将池中空闲时间最大的key“淘汰”掉;

LFU:使用带时间衰减的近似 LFU

Pasted image 20260517161626.png

Reply by Email